From 94529507c0026652a8e372767a5f93adc3c7dea4 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 5 Nov 2026 11:41:40 -0500 Subject: [PATCH 01/13] Apply Alabama's June 2026 and Idaho's January 2025 child care income limits Alabama's June 1, 2026 fact sheet tops the new-applicant scale at 150% of the poverty guideline and the continuing scale at 170%. Idaho's department moved new applicants to 130% when it reopened applications on January 13, 2025, and posts limits on the 2025 guideline. Both formulas now print the same dollars as the state's table. Co-Authored-By: Claude Opus 5.5 --- changelog.d/child-care-posted-limits.fixed.md | 1 + .../dhr/ccsp/income/limit/fpl_continuing.yaml | 8 +- .../al/dhr/ccsp/income/limit/fpl_initial.yaml | 8 +- .../id/dhw/iccp/income/fpg_year_lag.yaml | 22 +++ .../income/fpl_rate/initial_eligibility.yaml | 8 + .../al/dhr/ccsp/al_ccsp_income_eligible.yaml | 170 ++++++++++++++++++ .../id/dhw/iccp/eligibility/id_iccp_fpg.yaml | 92 ++++++++++ .../eligibility/id_iccp_income_eligible.yaml | 153 +++++++++++++++- .../eligibility/al_ccsp_income_eligible.py | 11 +- .../id/dhw/iccp/eligibility/id_iccp_fpg.py | 19 ++ .../eligibility/id_iccp_income_eligible.py | 14 +- 11 files changed, 493 insertions(+), 13 deletions(-) create mode 100644 changelog.d/child-care-posted-limits.fixed.md create mode 100644 policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpg_year_lag.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_fpg.yaml create mode 100644 policyengine_us/variables/gov/states/id/dhw/iccp/eligibility/id_iccp_fpg.py diff --git a/changelog.d/child-care-posted-limits.fixed.md b/changelog.d/child-care-posted-limits.fixed.md new file mode 100644 index 00000000000..5c075416709 --- /dev/null +++ b/changelog.d/child-care-posted-limits.fixed.md @@ -0,0 +1 @@ +Bring state child care income limits into line with what states post, starting with Alabama's June 2026 limits and Idaho's January 2025 move to 130% of the poverty guideline. diff --git a/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_continuing.yaml b/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_continuing.yaml index 37c974933f7..0fae90df52e 100644 --- a/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_continuing.yaml +++ b/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_continuing.yaml @@ -1,6 +1,8 @@ description: Alabama caps continuing-eligibility family income at this share of the federal poverty guideline under the Child Care Subsidy Program. values: 2024-01-01: 2.0 + # The June 2026 continuing scale stops at the 161-170% column. + 2026-06-01: 1.7 metadata: unit: /1 @@ -9,5 +11,9 @@ metadata: reference: - title: Alabama CCDF State Plan 2025-2027, Section 2.5.2(c)(iii) href: https://dhr.alabama.gov/wp-content/uploads/2023/04/2025-2027-CCDF-State-Plan-with-Approval-Letter.pdf#page=39 - - title: Alabama Child Care Fact Sheet + - title: Alabama Child Care Fact Sheet, January 1, 2024 href: https://dhr.alabama.gov/wp-content/uploads/2024/01/Child-Care-Fact-Sheet-2024.pdf + - title: Alabama Child Care Fact Sheet, January 1, 2026 (Continuing Eligibility Monthly Income Scale, top column 191-200% FPL) + href: https://dhr.alabama.gov/wp-content/uploads/2025/12/CHILD-CARE-FACT-SHEET-Jan2026.pdf#page=1 + - title: Alabama Child Care Fact Sheet, June 1, 2026 (Continuing Eligibility Monthly Income Scale, top column 161-170% FPL) + href: https://dhr.alabama.gov/wp-content/uploads/2026/06/CHILD-CARE-FACT-SHEET-Jun2026-1.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_initial.yaml b/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_initial.yaml index 6036f37af07..027842a21ab 100644 --- a/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_initial.yaml +++ b/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_initial.yaml @@ -1,6 +1,8 @@ description: Alabama caps initial-application family income at this share of the federal poverty guideline under the Child Care Subsidy Program. values: 2024-01-01: 1.8 + # The June 2026 scale stops at the 141-150% column and tells new applicants to enter under it. + 2026-06-01: 1.5 metadata: unit: /1 @@ -9,5 +11,9 @@ metadata: reference: - title: Alabama CCDF State Plan 2025-2027, Section 2.2.4 href: https://dhr.alabama.gov/wp-content/uploads/2023/04/2025-2027-CCDF-State-Plan-with-Approval-Letter.pdf#page=26 - - title: Alabama Child Care Fact Sheet (Initial Eligibility Monthly Income Scale) + - title: Alabama Child Care Fact Sheet, January 1, 2024 (Initial Eligibility Monthly Income Scale) href: https://dhr.alabama.gov/wp-content/uploads/2024/01/Child-Care-Fact-Sheet-2024.pdf + - title: Alabama Child Care Fact Sheet, January 1, 2026 (Initial Eligibility Monthly Income Scale, top column 171-180% FPL) + href: https://dhr.alabama.gov/wp-content/uploads/2025/12/CHILD-CARE-FACT-SHEET-Jan2026.pdf#page=1 + - title: Alabama Child Care Fact Sheet, June 1, 2026 (Initial Eligibility Monthly Income Scale, top column 141-150% FPL) + href: https://dhr.alabama.gov/wp-content/uploads/2026/06/CHILD-CARE-FACT-SHEET-Jun2026-1.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpg_year_lag.yaml new file mode 100644 index 00000000000..3e0dc8562f2 --- /dev/null +++ b/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpg_year_lag.yaml @@ -0,0 +1,22 @@ +description: Idaho uses the federal poverty guideline from this many years before the current date to set initial income limits under the Idaho Child Care Program. +# The department reopened applications on January 13, 2025 at 130% of the 2024 +# guideline ($33,566 a year for three). Its table effective October 2025 uses the +# 2025 guideline ($2,888 a month for three), and the page still showed that table +# on November 5, 2026, so a lag of one holds it through 2026. A new table adds a +# date here. No source dates the guideline year before 2025, so the list keeps +# the current year until then. +values: + 2015-01-01: 0 + 2025-01-13: 1 + 2025-10-01: 0 + 2026-01-01: 1 + +metadata: + unit: year + period: year + label: Idaho Child Care Program poverty guideline year lag + reference: + - title: Idaho Department of Health and Welfare, Apply for Child Care (limits effective October 2025; page last updated September 30, 2025) + href: https://healthandwelfare.idaho.gov/services-programs/children-families/apply-child-care + - title: Idaho Department of Health and Welfare, DHW will resume applications for the Idaho Child Care Program in January (November 14, 2024) + href: https://healthandwelfare.idaho.gov/news/dhw-will-resume-applications-idaho-child-care-program-january diff --git a/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml b/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml index 486e3851b79..55b510f5707 100644 --- a/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml +++ b/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml @@ -1,6 +1,10 @@ description: Idaho limits initial income to this share of the federal poverty guidelines under the Idaho Child Care Program. +# IDAPA 16.06.12.070.01 still prints 175%. The department moved new applicants +# to 130% when it reopened applications on January 13, 2025, and posts its +# limits at that rate. The model follows what the department applies. values: 2023-04-06: 1.75 + 2025-01-13: 1.3 metadata: unit: /1 @@ -11,3 +15,7 @@ metadata: href: https://adminrules.idaho.gov/rules/current/16/160612.pdf#page=7 - title: Idaho Department of Health and Welfare, Idaho Child Care Program href: https://healthandwelfare.idaho.gov/services-programs/children-families-older-adults/idaho-child-care-program + - title: Idaho Department of Health and Welfare, DHW will resume applications for the Idaho Child Care Program in January (November 14, 2024) + href: https://healthandwelfare.idaho.gov/news/dhw-will-resume-applications-idaho-child-care-program-january + - title: Idaho Department of Health and Welfare, Apply for Child Care (limits effective October 2025; page last updated September 30, 2025) + href: https://healthandwelfare.idaho.gov/services-programs/children-families/apply-child-care diff --git a/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_income_eligible.yaml index c5dad7f2e3b..0eaadd11d9b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_income_eligible.yaml @@ -256,3 +256,173 @@ output: # 75,145.96 > 75,145.95 (85% SMI cap) -> SMI cap fails. al_ccsp_income_eligible: false + +# Family of three on the 2025 guideline ($26,650): the January 1, 2026 fact sheet +# tops at 180% ($3,998) for new applicants and 200% ($4,442) for continuing families; +# the June 1, 2026 fact sheet tops at 150% ($3,331) and 170% ($3,775). +- name: New applicant of three at 3,998 dollars qualifies in May 2026. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 28 + person3: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + al_ccsp_countable_income: 3_998 + al_ccsp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: AL + output: + al_ccsp_income_eligible: true + +- name: New applicant of three at the June 2026 top of 3,331 dollars qualifies. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 28 + person3: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + al_ccsp_countable_income: 3_331 + al_ccsp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: AL + output: + al_ccsp_income_eligible: true + +- name: New applicant of three at 3,332 dollars doesn't qualify from June 2026. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 28 + person3: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + al_ccsp_countable_income: 3_332 + al_ccsp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: AL + output: + al_ccsp_income_eligible: false + +- name: Continuing family of three at the January 2026 top of 4,442 dollars stays eligible in May 2026. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 28 + person3: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + al_ccsp_countable_income: 4_442 + al_ccsp_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: AL + output: + al_ccsp_income_eligible: true + +- name: Continuing family of three at the June 2026 top of 3,775 dollars stays eligible. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 28 + person3: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + al_ccsp_countable_income: 3_775 + al_ccsp_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: AL + output: + al_ccsp_income_eligible: true + +- name: Continuing family of three at 3,776 dollars loses eligibility from June 2026. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 28 + person3: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + al_ccsp_countable_income: 3_776 + al_ccsp_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: AL + output: + al_ccsp_income_eligible: false + +- name: A half-dollar limit prints up, so a family of two at 3,173 dollars qualifies in May 2026. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + # 21,150 x 1.8 / 12 = 3,172.50, printed as 3,173 on the January 2026 fact sheet. + al_ccsp_countable_income: 3_173 + al_ccsp_enrolled: false + households: + household: + members: [person1, person2] + state_code: + 2026: AL + output: + al_ccsp_income_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_fpg.yaml b/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_fpg.yaml new file mode 100644 index 00000000000..8ff84ada4fc --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_fpg.yaml @@ -0,0 +1,92 @@ +# The guideline year follows the department's posted tables: 2024 for applications +# from January 13, 2025, 2025 from October 2025, and 2025 again through 2026 because +# the page still showed that table on November 5, 2026. +- name: Case 1, February 2025 uses the 2024 guideline. + period: 2025-02 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + output: + # 25,820 / 12 + id_iccp_fpg: 2_151.67 + +- name: Case 2, October 2025 uses the 2025 guideline. + period: 2025-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + output: + # 26,650 / 12 + id_iccp_fpg: 2_220.83 + +- name: Case 3, November 2026 still uses the 2025 guideline. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + output: + id_iccp_fpg: 2_220.83 + +- name: Case 4, dates before 2025 keep the current year's guideline. + period: 2024-06 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + output: + id_iccp_fpg: 2_151.67 diff --git a/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.yaml index 51f9292a6dc..509b50c0fea 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.yaml @@ -1,4 +1,6 @@ -- name: Case 1, initial eligibility uses 175 percent of the federal poverty guideline. +# Limits for new applicants come from the department's Apply for Child Care page +# (effective October 2025): 130% of the 2025 guideline, rounded up to a dollar. +- name: Case 1, initial eligibility uses 130 percent of the guideline from January 2025. period: 2026-01 input: people: @@ -11,13 +13,13 @@ spm_units: spm_unit: members: [person1] - id_iccp_countable_income: 3_500 + id_iccp_countable_income: 2_600 id_iccp_enrolled: false - spm_unit_fpg: 24_000 + id_iccp_fpg: 2_000 output: id_iccp_income_eligible: true -- name: Case 2, initial eligibility fails above 175 percent of the federal poverty guideline. +- name: Case 2, initial eligibility fails above 130 percent of the guideline. period: 2026-01 input: people: @@ -30,9 +32,9 @@ spm_units: spm_unit: members: [person1] - id_iccp_countable_income: 3_501 + id_iccp_countable_income: 2_601 id_iccp_enrolled: false - spm_unit_fpg: 24_000 + id_iccp_fpg: 2_000 output: id_iccp_income_eligible: false @@ -73,3 +75,142 @@ hhs_smi: 60_000 output: id_iccp_income_eligible: false + +- name: Case 5, a family of three at the posted limit of 2,888 dollars qualifies as a new applicant. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + id_iccp_countable_income: 2_888 + id_iccp_enrolled: false + output: + id_iccp_income_eligible: true + +- name: Case 6, a family of three one dollar above the posted limit doesn't qualify as a new applicant. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + id_iccp_countable_income: 2_889 + id_iccp_enrolled: false + output: + id_iccp_income_eligible: false + +- name: Case 7, the old 175 percent rate still applies in January 2025, before the department's change takes hold. + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + # 175% of the 2025 guideline for three: 26,650 x 1.75 / 12 = 3,886.46, so 3,887. + id_iccp_countable_income: 3_887 + id_iccp_enrolled: false + output: + id_iccp_income_eligible: true + +- name: Case 8, new applicants from February 2025 face 130 percent of the 2024 guideline. + period: 2025-02 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + # 25,820 x 1.3 / 12 = 2,797.17, so 2,798 (33,566 a year, as reported in November 2024). + id_iccp_countable_income: 2_798 + id_iccp_enrolled: false + output: + id_iccp_income_eligible: true + +- name: Case 9, one dollar above 130 percent of the 2024 guideline fails in February 2025. + period: 2025-02 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + id_iccp_countable_income: 2_799 + id_iccp_enrolled: false + output: + id_iccp_income_eligible: false + +- name: Case 10, an enrolled family keeps the 85 percent of state median income limit after the change. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + id_iccp_countable_income: 2_889 + id_iccp_enrolled: true + output: + id_iccp_income_eligible: true diff --git a/policyengine_us/variables/gov/states/al/dhr/ccsp/eligibility/al_ccsp_income_eligible.py b/policyengine_us/variables/gov/states/al/dhr/ccsp/eligibility/al_ccsp_income_eligible.py index 6aa3bd959dc..854240be9a1 100644 --- a/policyengine_us/variables/gov/states/al/dhr/ccsp/eligibility/al_ccsp_income_eligible.py +++ b/policyengine_us/variables/gov/states/al/dhr/ccsp/eligibility/al_ccsp_income_eligible.py @@ -7,7 +7,10 @@ class al_ccsp_income_eligible(Variable): label = "Eligible for Alabama CCSP based on income" definition_period = MONTH defined_for = StateCode.AL - reference = "https://dhr.alabama.gov/wp-content/uploads/2023/04/2025-2027-CCDF-State-Plan-with-Approval-Letter.pdf#page=24" + reference = ( + "https://dhr.alabama.gov/wp-content/uploads/2023/04/2025-2027-CCDF-State-Plan-with-Approval-Letter.pdf#page=24", + "https://dhr.alabama.gov/wp-content/uploads/2026/06/CHILD-CARE-FACT-SHEET-Jun2026-1.pdf#page=1", + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.al.dhr.ccsp.income.limit @@ -24,7 +27,11 @@ def formula(spm_unit, period, parameters): p.fpl_continuing, p.fpl_initial, ) - fpl_eligible = monthly_income <= monthly_fpg * fpl_limit_ratio + # The fact sheet prints each limit to the nearest dollar, with half a + # dollar going up ($3,172.50 prints as $3,173). Round to cents first so + # floating-point noise can't move a tie. + fpl_limit = np.floor(np.round(monthly_fpg * fpl_limit_ratio, 2) + 0.5) + fpl_eligible = monthly_income <= fpl_limit monthly_smi = spm_unit("hhs_smi", period) smi_eligible = monthly_income <= monthly_smi * p.smi_cap diff --git a/policyengine_us/variables/gov/states/id/dhw/iccp/eligibility/id_iccp_fpg.py b/policyengine_us/variables/gov/states/id/dhw/iccp/eligibility/id_iccp_fpg.py new file mode 100644 index 00000000000..f2a7f57bb51 --- /dev/null +++ b/policyengine_us/variables/gov/states/id/dhw/iccp/eligibility/id_iccp_fpg.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class id_iccp_fpg(Variable): + value_type = float + entity = SPMUnit + unit = USD + definition_period = MONTH + label = "Idaho Child Care Program monthly federal poverty guideline" + defined_for = StateCode.ID + reference = "https://healthandwelfare.idaho.gov/services-programs/children-families/apply-child-care" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.id.dhw.iccp.income + size = spm_unit("spm_unit_size", period.this_year) + state_group = spm_unit.household("state_group_str", period.this_year) + annual_fpg = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) + return annual_fpg / MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.py b/policyengine_us/variables/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.py index 1ef7402618b..910558f4753 100644 --- a/policyengine_us/variables/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.py +++ b/policyengine_us/variables/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.py @@ -7,14 +7,22 @@ class id_iccp_income_eligible(Variable): definition_period = MONTH label = "Income eligible for the Idaho Child Care Program" defined_for = StateCode.ID - reference = "https://adminrules.idaho.gov/rules/current/16/160612.pdf#page=7" + reference = ( + "https://adminrules.idaho.gov/rules/current/16/160612.pdf#page=7", + "https://healthandwelfare.idaho.gov/services-programs/children-families/apply-child-care", + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.id.dhw.iccp.income countable_income = spm_unit("id_iccp_countable_income", period) enrolled = spm_unit("id_iccp_enrolled", period) - initial_limit = ( - spm_unit("spm_unit_fpg", period) * p.fpl_rate.initial_eligibility + # The department's table rounds each limit up to a whole dollar. Round + # to cents first so floating-point noise can't push a whole-dollar limit + # up by one. + initial_limit = np.ceil( + np.round( + spm_unit("id_iccp_fpg", period) * p.fpl_rate.initial_eligibility, 2 + ) ) continuing_limit = spm_unit("hhs_smi", period) * p.smi_rate.continuing return countable_income <= where(enrolled, continuing_limit, initial_limit) From 2af532cedc532c7ede4eb7da0db59e7241a98d49 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 5 Nov 2026 14:50:58 -0500 Subject: [PATCH 02/13] Date the poverty guideline Missouri, Indiana, West Virginia and Montana apply Each state applies a guideline year that lags the calendar, and each prints the limit its chart posts only when the model reads that year: - Missouri: 150% of the 2025 guideline through 2026 ($3,331 for three, not $3,415). Transitional Level 3 ends July 1, 2026. - Indiana: 150% of the 2025 guideline through April 4, 2026 ($3,331), then 135% of the 2026 guideline ($3,074). - West Virginia: Appendix A's 2024 guideline ($3,981 for three at 185%). - Montana: 185% from July 2023 under MCA 52-2-715, on the 2025 guideline from the July 2025 scale ($4,109), with a 200% graduated tier from that scale. All four round to the nearest dollar, half up, as their tables print. Co-Authored-By: Claude Opus 5.5 --- .../in/fssa/ccdf/income/fpg_year_lag.yaml | 31 + .../in/fssa/ccdf/income/get_on_fpg_rate.yaml | 2 + .../mo/dese/ccs/income/fpg_year_lag.yaml | 16 + .../income/fpl_rate/initial_eligibility.yaml | 2 + .../ccs/income/fpl_rate/transitional.yaml | 4 + .../dese/ccs/transitional/funding_rate.yaml | 3 +- .../mt/dphhs/ccap/copayment/copay_rate.yaml | 5 +- .../ccap/income/fpg_limit/graduated.yaml | 16 +- .../dphhs/ccap/income/fpg_limit/initial.yaml | 14 +- .../mt/dphhs/ccap/income/fpg_year_lag.yaml | 22 + .../wv/dhhr/ccap/income/fpg_year_lag.yaml | 19 + .../in/fssa/ccdf/copay/in_ccdf_copay.yaml | 32 +- .../in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml | 154 +++ .../eligibility/in_ccdf_income_eligible.yaml | 635 ++++++++- .../gov/states/in/fssa/ccdf/in_ccdf.yaml | 10 +- .../gov/states/in/fssa/ccdf/integration.yaml | 12 +- .../mo/dese/ccs/eligibility/mo_ccs_fpg.yaml | 87 ++ .../eligibility/mo_ccs_income_eligible.yaml | 284 +++- .../gov/states/mt/dphhs/ccap/integration.yaml | 56 +- .../gov/states/mt/dphhs/ccap/mt_ccap.yaml | 12 +- .../states/mt/dphhs/ccap/mt_ccap_copay.yaml | 49 +- .../mt/dphhs/ccap/mt_ccap_eligible.yaml | 2 +- .../gov/states/mt/dphhs/ccap/mt_ccap_fpg.yaml | 110 ++ .../dphhs/ccap/mt_ccap_income_eligible.yaml | 1172 ++++++++++++++++- .../gov/states/wv/dhhr/ccap/edge_cases.yaml | 63 +- .../gov/states/wv/dhhr/ccap/integration.yaml | 24 +- .../states/wv/dhhr/ccap/wv_ccap_copay.yaml | 43 +- .../gov/states/wv/dhhr/ccap/wv_ccap_fpg.yaml | 67 + .../wv/dhhr/ccap/wv_ccap_income_eligible.yaml | 561 +++++++- .../in/fssa/ccdf/copay/in_ccdf_copay.py | 2 +- .../in/fssa/ccdf/eligibility/in_ccdf_fpg.py | 19 + .../eligibility/in_ccdf_income_eligible.py | 13 +- .../mo/dese/ccs/eligibility/mo_ccs_fpg.py | 19 + .../ccs/eligibility/mo_ccs_income_eligible.py | 12 +- .../gov/states/mo/dese/ccs/mo_ccs.py | 2 +- .../mt/dphhs/ccap/eligibility/mt_ccap_fpg.py | 19 + .../eligibility/mt_ccap_income_eligible.py | 38 +- .../gov/states/mt/dphhs/ccap/mt_ccap_copay.py | 2 +- .../wv/dhhr/ccap/eligibility/wv_ccap_fpg.py | 19 + .../eligibility/wv_ccap_income_eligible.py | 7 +- .../gov/states/wv/dhhr/ccap/wv_ccap_copay.py | 2 +- 41 files changed, 3407 insertions(+), 254 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/in/fssa/ccdf/income/fpg_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpg_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/fpg_year_lag.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/eligibility/mo_ccs_fpg.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_fpg.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_fpg.yaml create mode 100644 policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.py create mode 100644 policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_fpg.py create mode 100644 policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_fpg.py create mode 100644 policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_fpg.py diff --git a/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/fpg_year_lag.yaml new file mode 100644 index 00000000000..ae3fbc9f65d --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/fpg_year_lag.yaml @@ -0,0 +1,31 @@ +description: Indiana uses the federal poverty guideline from this many years before the current date under the Child Care and Development Fund program. +# Indiana moves to a new year's guideline when it posts a new eligibility package, +# months into that year, and the old guideline holds until then: +# - March 31, 2024: the state plan prints 150% limits on the 2024 guideline ($3,228 for three). +# - May 1, 2025: FSSA's 2025 sliding fee schedule carries that date in its file name +# (CCDFSlidingFeeSchedule_w-Copays_2025_050125.pdf). +# - April 5, 2026: FSSA's chart prints 135% of the 2026 guideline ($3,074 for three). +# So a family of three faces 150% of the 2025 guideline ($3,331) through April 4, 2026. +values: + 2015-01-01: 0 + 2024-01-01: 1 + 2024-03-31: 0 + 2025-01-01: 1 + 2025-05-01: 0 + 2026-01-01: 1 + 2026-04-05: 0 + 2027-01-01: 1 + +metadata: + unit: year + period: year + label: Indiana CCDF poverty guideline year lag + reference: + - title: Indiana CCDF State Plan FFY 2025-2027, Amendment 2, Section 2.2.4 (limits effective March 31, 2024) + href: https://www.in.gov/dA/6307709ae5/ACF-118CCDFFFY2025-2027IndianaAmendment.pdf?language_id=1 + - title: Indiana FSSA, CCDF Sliding Fee Schedule with copays, 2025, file dated May 1, 2025 + href: https://secure.in.gov/fssa/carefinder/files/CCDFSlidingFeeSchedule_w-Copays_2025_050125.pdf + - title: Indiana FSSA, Income to Get on CCDF (effective April 5, 2026) + href: https://www.in.gov/dA/3271c7180e/Income-Get-on-CCDF.pdf + - title: Indiana FSSA, CCDF Sliding Fee Schedule with copays, 2026 (effective April 5, 2026) + href: https://www.in.gov/dA/7fc32972de/CCDFSlidingFeeSchedule_withCopays_2026.pdf diff --git a/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/get_on_fpg_rate.yaml b/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/get_on_fpg_rate.yaml index 41ae02fa544..9b0467c5406 100644 --- a/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/get_on_fpg_rate.yaml +++ b/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/get_on_fpg_rate.yaml @@ -17,5 +17,7 @@ metadata: href: https://www.in.gov/fssa/carefinder/files/CCDF-Policy-Manual.pdf#page=5 - title: Income to Get on CCDF href: https://www.in.gov/fssa/carefinder/files/Income-Get-on-CCDF.pdf + - title: Indiana CCDF State Plan FFY 2025-2027, Amendment 2, Section 2.2.4 (150% limits effective March 31, 2024) + href: https://www.in.gov/dA/6307709ae5/ACF-118CCDFFFY2025-2027IndianaAmendment.pdf?language_id=1 - title: OECOSL bulletin, New CCDF Reimbursement Rates and Expanded Income Eligibility (127% to 150% FPL eff. Aug 1, 2023) href: https://www.in.gov/fssa/carefinder/system-updates-2023 diff --git a/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpg_year_lag.yaml new file mode 100644 index 00000000000..77dfcb94282 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpg_year_lag.yaml @@ -0,0 +1,16 @@ +description: Missouri uses the federal poverty guideline from this many years before the current date under the Child Care Subsidy program. +# DESE's chart headed November 2025 and updated July 1, 2026 prints 150% of the 2025 +# guideline ($3,331 a month for three). A lag of one holds the 2025 guideline through +# 2026; a new chart adds a date here. No source dates the guideline year before the +# October 2025 chart, so the list keeps the current year until then. +values: + 2015-01-01: 0 + 2026-01-01: 1 + +metadata: + unit: year + period: year + label: Missouri Child Care Subsidy poverty guideline year lag + reference: + - title: November 2025 Child Care Eligibility Income Guidelines and Sliding Fee Chart (updated July 1, 2026) + href: https://dese.mo.gov/sites/g/files/zuston521/files/media/pdf/2026/07/Income%20Elig%20_Updated%206.29.26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpl_rate/initial_eligibility.yaml b/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpl_rate/initial_eligibility.yaml index 6d9b7307be2..44d3c95e486 100644 --- a/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpl_rate/initial_eligibility.yaml +++ b/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpl_rate/initial_eligibility.yaml @@ -13,3 +13,5 @@ metadata: href: https://web.archive.org/web/20250831220820id_/https://dese.mo.gov/childhood/quality-programs/child-care-subsidy/child-care-manual/2010/045/00 - title: November 2025 Child Care Eligibility Income Guidelines and Sliding Fee Chart href: https://dese.mo.gov/sites/g/files/zuston521/files/media/pdf/2025/10/10.2025%20Income%20Eligibility%20Table%20%282%29.pdf#page=1 + - title: November 2025 Child Care Eligibility Income Guidelines and Sliding Fee Chart, updated July 1, 2026 + href: https://dese.mo.gov/sites/g/files/zuston521/files/media/pdf/2026/07/Income%20Elig%20_Updated%206.29.26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpl_rate/transitional.yaml b/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpl_rate/transitional.yaml index 9b6f524919b..2e6e842e45c 100644 --- a/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpl_rate/transitional.yaml +++ b/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpl_rate/transitional.yaml @@ -1,6 +1,8 @@ description: Missouri limits adjusted gross income to this multiple of the federal poverty guideline for existing families under the Child Care Subsidy program. values: 2025-10-01: 2.42 + # DESE removed Transitional Level 3 (216-242%) on July 1, 2026, leaving Level 2 at the top. + 2026-07-01: 2.15 metadata: unit: /1 @@ -17,3 +19,5 @@ metadata: href: https://www.law.cornell.edu/regulations/missouri/5-CSR-25-200-060 - title: November 2025 Child Care Eligibility Income Guidelines and Sliding Fee Chart href: https://dese.mo.gov/sites/g/files/zuston521/files/media/pdf/2025/10/10.2025%20Income%20Eligibility%20Table%20%282%29.pdf#page=1 + - title: November 2025 Child Care Eligibility Income Guidelines and Sliding Fee Chart, updated July 1, 2026 ("Transitional Level 3 removed July 1, 2026") + href: https://dese.mo.gov/sites/g/files/zuston521/files/media/pdf/2026/07/Income%20Elig%20_Updated%206.29.26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/mo/dese/ccs/transitional/funding_rate.yaml b/policyengine_us/parameters/gov/states/mo/dese/ccs/transitional/funding_rate.yaml index 5f3b92b7ad9..789d082af59 100644 --- a/policyengine_us/parameters/gov/states/mo/dese/ccs/transitional/funding_rate.yaml +++ b/policyengine_us/parameters/gov/states/mo/dese/ccs/transitional/funding_rate.yaml @@ -2,7 +2,8 @@ description: Missouri funds this share of the base reimbursement rate by federal # Traditional families (at or below 150% FPL) are funded at the full base rate. # Transitional Child Care families are funded at a reduced share: # Level 1 (above 150% up to 185%) = 80%, Level 2 (above 185% up to 215%) = 60%, -# Level 3 (above 215% up to 242%) = 50%. +# Level 3 (above 215% up to 242%) = 50%. DESE removed Level 3 on July 1, 2026, so no +# eligible family reaches the 50% share from that date. metadata: type: single_amount threshold_unit: /1 diff --git a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/copayment/copay_rate.yaml b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/copayment/copay_rate.yaml index 019e5f2b962..1d78c219785 100644 --- a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/copayment/copay_rate.yaml +++ b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/copayment/copay_rate.yaml @@ -7,9 +7,8 @@ description: Montana sets this share of gross monthly income as the copayment un # FPG (inclusive) up to but not including 115% FPG. PolicyEngine single_amount is "at # or above threshold," and the scale places a family exactly at a step into the higher # tier (e.g. 105% -> 1.0%), so thresholds use the named % directly with no shift. The -# published scale's top tier (7.0%) runs through 200% FPG, but income eligibility caps -# at 185% FPG for non-TANF families (ARM 37.80.202(2)), so the tiers above 185% are -# unreachable for eligible families and retained only to mirror the published scale. +# published scale's top tier (7.0%) runs through 200% FPG, which enrolled families reach +# through graduated eligibility. # # (S6) The graduated-eligibility STRUCTURE dates to 2016-11-01, but these copay # percentages come from the 2025 Best Beginnings Sliding Fee Scale (2025 Federal diff --git a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/graduated.yaml b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/graduated.yaml index c7686161ba6..cf5022338ab 100644 --- a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/graduated.yaml +++ b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/graduated.yaml @@ -1,17 +1,23 @@ description: Montana limits gross income to this share of the federal poverty guideline for graduated eligibility at redetermination under the Best Beginnings Child Care Scholarship program. -# ARM 37.80.202(2): a non-TANF household whose income exceeds 150% and is below -# 185% of the FPG qualifies for graduated eligibility at annual redetermination -# (12-month eligibility period). We proxy "at redetermination / continuing -# recipient" with the mt_ccap_enrolled input; first-time applicants use the -# initial 150% share (see initial.yaml). +# ARM 37.80.202(2) still prints 185%. The department's scale effective July 1, 2025 +# runs Graduated Eligibility to 200% for families already on the Non-TANF program at +# annual redetermination. That scale is the earliest dated source for 200%, so the +# list moves on its date; with the initial share at 185% from July 2023, the two match +# until then. We proxy "at redetermination / continuing recipient" with the +# mt_ccap_enrolled input; first-time applicants use the initial share (see initial.yaml). values: 2016-11-01: 1.85 + 2025-07-01: 2 metadata: unit: /1 period: year label: Montana CCAP graduated income limit share of federal poverty guideline reference: + - title: Best Beginnings Child Care Sliding Fee Scale (document header "Effective 07-01-2025"; URL filename says 2023) + href: https://dphhs.mt.gov/assets/ecfsd/childcare/policymanual/SlidingFeeScale07012023.pdf#page=1 + - title: MCA 52-2-715(2) (En. Sec. 2, Ch. 773, L. 2023), maximum qualifying income level + href: https://archive.legmt.gov/bills/MCA/title_0520/chapter_0020/part_0070/section_0150/0520-0020-0070-0150.html - title: Mont. Admin. R. 37.80.202(2) href: https://rules.mt.gov/gateway/ruleno.asp?RN=37.80.202 - title: Mont. Admin. R. 37.80.202(2) — Cornell LII diff --git a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml index d26f80f7574..c682812ca35 100644 --- a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml +++ b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml @@ -1,16 +1,22 @@ description: Montana limits gross income to this share of the federal poverty guideline for initial eligibility under the Best Beginnings Child Care Scholarship program. -# ARM 37.80.202(1): a household whose income is below 150% of the FPG is eligible. -# This is the initial / first-time applicant standard; continuing recipients at -# annual redetermination use the higher graduated share (see graduated.yaml), -# selected via the mt_ccap_enrolled input. +# ARM 37.80.202(1) still prints 150%. MCA 52-2-715, enacted by House Bill 648 in 2023, +# requires a threshold of no less than 185%, and the department's scale ends Standard +# Eligibility at 185%. The model follows the statute and the scale. This is the initial / +# first-time applicant standard; continuing recipients at annual redetermination use +# the higher graduated share (see graduated.yaml), selected via the mt_ccap_enrolled input. values: 2016-11-01: 1.5 + 2023-07-01: 1.85 metadata: unit: /1 period: year label: Montana CCAP initial income limit share of federal poverty guideline reference: + - title: MCA 52-2-715 (En. Sec. 2, Ch. 773, L. 2023), Income eligibility for best beginnings child care scholarship program + href: https://archive.legmt.gov/bills/MCA/title_0520/chapter_0020/part_0070/section_0150/0520-0020-0070-0150.html + - title: Best Beginnings Child Care Sliding Fee Scale (document header "Effective 07-01-2025"; URL filename says 2023) + href: https://dphhs.mt.gov/assets/ecfsd/childcare/policymanual/SlidingFeeScale07012023.pdf#page=1 - title: Mont. Admin. R. 37.80.202(1) href: https://rules.mt.gov/gateway/ruleno.asp?RN=37.80.202 - title: Mont. Admin. R. 37.80.202(1) — Cornell LII diff --git a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_year_lag.yaml new file mode 100644 index 00000000000..ed5e1cac151 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_year_lag.yaml @@ -0,0 +1,22 @@ +description: Montana uses the federal poverty guideline from this many years before the current date under the Best Beginnings Child Care Scholarship program. +# The Sliding Fee Scale effective July 1, 2025 prints the 2025 guideline (its footnote +# cites Federal Register Vol. 90, No. 11, January 17, 2025, though it says "2023"), so +# a lag of one holds that scale through 2026. ACF's January 2025 table prints 185% of +# the 2024 guideline ($3,981 a month for three), so a lag of one also covers the first +# half of 2025. A new scale adds a date here. No source dates the guideline year before +# 2025, so the list keeps the current year until then. +values: + 2015-01-01: 0 + 2025-01-01: 1 + 2025-07-01: 0 + 2026-01-01: 1 + +metadata: + unit: year + period: year + label: Montana CCAP poverty guideline year lag + reference: + - title: Best Beginnings Child Care Sliding Fee Scale (document header "Effective 07-01-2025"; URL filename says 2023) + href: https://dphhs.mt.gov/assets/ecfsd/childcare/policymanual/SlidingFeeScale07012023.pdf#page=1 + - title: ACF, CCDF Family Income Eligibility Levels by State (January 2025) + href: https://acf.gov/sites/default/files/documents/occ/CCDF-Family-Income-Eligibility-Levels-by-State.pdf diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/fpg_year_lag.yaml new file mode 100644 index 00000000000..ade29af2827 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/fpg_year_lag.yaml @@ -0,0 +1,19 @@ +description: West Virginia uses the federal poverty guideline from this many years before the current date under the Child Care Assistance Program. +# Appendix A's sliding fee scale, created October 1, 2024, prints the 2024 guideline +# (headed "FY 2024 Federal Poverty Level"; $3,981 a month for three at 185%). The +# Bureau's Child Care Policy page still linked that scale on November 5, 2026, so the +# lag grows to keep the 2024 guideline. A new scale adds a date here. +values: + 2015-01-01: 0 + 2025-01-01: 1 + 2026-01-01: 2 + +metadata: + unit: year + period: year + label: West Virginia CCAP poverty guideline year lag + reference: + - title: WV Child Care Subsidy Appendix A, Sliding Fee Scale (FY 2024 Federal Poverty Level) + href: https://bfa.wv.gov/media/6826/download?inline#page=1 + - title: WV Bureau for Family Assistance, Child Care Policy + href: https://bfa.wv.gov/bfa-policy-and-plans/child-care-policy diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/copay/in_ccdf_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/copay/in_ccdf_copay.yaml index 7582ba49531..6e1769ac29e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/copay/in_ccdf_copay.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/copay/in_ccdf_copay.yaml @@ -5,7 +5,8 @@ # copay to monthly (* 52 / 12). $0 at or below 100% FPL. # Policy Manual Section 2.6; 2026 Sliding Fee Schedule. # defined_for = in_ccdf_eligible, so each unit is a fully eligible family -# (working parent, dependent citizen child). 2-person FPG 2026 = 21,640/yr. +# (working parent, dependent citizen child). January 2026 still uses the 2025 +# guideline: 2-person FPG = 21,150/yr. - name: Case 1, income at 100% FPL, zero copay. period: 2026-01 @@ -14,7 +15,7 @@ people: person1: age: 35 - employment_income: 21_640 # exactly 100% FPL + employment_income: 21_150 # exactly 100% FPL person2: age: 5 is_tax_unit_dependent: true @@ -29,7 +30,7 @@ # <= 100% FPL bracket fee factor is 0. in_ccdf_copay: 0 -- name: Case 2, income about 105% FPL, 0.0116 factor. +- name: Case 2, income about 107% FPL, 0.0116 factor. period: 2026-01 absolute_error_margin: 0.1 input: @@ -48,11 +49,11 @@ members: [person1, person2] state_code: IN output: - # income 1,893.33/mo, ratio ~1.05 -> factor 0.0116 + # income 1,893.33/mo, ratio ~1.07 -> factor 0.0116 # 1,893.33 * 0.0116 = 21.96/week -> 21.96 * 52/12 = 95.17/month in_ccdf_copay: 95.17 -- name: Case 3, income about 115% FPL, 0.0140 factor. +- name: Case 3, income about 118% FPL, 0.0140 factor. period: 2026-01 absolute_error_margin: 0.1 input: @@ -71,11 +72,11 @@ members: [person1, person2] state_code: IN output: - # income 2,073.67/mo, ratio ~1.15 -> factor 0.0140 + # income 2,073.67/mo, ratio ~1.18 -> factor 0.0140 # 2,073.67 * 0.0140 = 29.03/week -> 29.03 * 52/12 = 125.80/month in_ccdf_copay: 125.80 -- name: Case 4, income about 125% FPL, 0.0163 factor. +- name: Case 4, income about 128% FPL, 0.0163 factor. period: 2026-01 absolute_error_margin: 0.1 input: @@ -94,7 +95,7 @@ members: [person1, person2] state_code: IN output: - # income 2,254.17/mo, ratio ~1.25 -> factor 0.0163 + # income 2,254.17/mo, ratio ~1.28 -> factor 0.0163 # 2,254.17 * 0.0163 = 36.74/week -> 36.74 * 52/12 = 159.22/month in_ccdf_copay: 159.22 @@ -128,7 +129,7 @@ # Countable income is negative; floored at 0 before the multiply. in_ccdf_copay: 0 -# --- 100% FPL copay-zero cutoff boundary (2-person FPG 2026 = 21,640/yr) --- +# --- 100% FPL copay-zero cutoff boundary (2-person FPG in January 2026 = 21,150/yr) --- # The first non-zero fee-factor bracket starts above 100% FPL (threshold 1.0001 # of FPG), so income at or below 100% FPL yields a zero copay. @@ -139,7 +140,7 @@ people: person1: age: 35 - employment_income: 21_628 # just below 100% FPL (21,640) + employment_income: 21_138 # just below 100% FPL (21,150) person2: age: 5 is_tax_unit_dependent: true @@ -161,7 +162,7 @@ people: person1: age: 35 - employment_income: 21_900 # 1,825/mo, ratio ~1.012 FPL + employment_income: 21_900 # 1,825/mo, ratio ~1.035 FPL person2: age: 5 is_tax_unit_dependent: true @@ -180,9 +181,10 @@ # --- Operative fee-schedule era (effective 2026-04-05) --- # The fee_factor parameter starts 2026-04-05, so the 2026-01 cases above back- # extrapolate it. This case runs at 2027-01 to exercise the schedule as the -# live (forward) value. The 2027 2-person FPG is uprated to 22,147.39, so the -# ratio falls from ~1.05 to ~1.026 — still inside the 101-109% bracket (0.0116) — -# and since the copay multiplies income (not FPG), the expected value is unchanged. +# live (forward) value. January 2027 still uses the 2026 guideline (2-person FPG +# 21,640), so the ratio falls from ~1.07 to ~1.05 — still inside the 101-109% +# bracket (0.0116) — and since the copay multiplies income (not FPG), the expected +# value is unchanged. - name: Case 8, operative era at 2027-01, about 105% FPL, 0.0116 factor. period: 2027-01 @@ -203,6 +205,6 @@ members: [person1, person2] state_code: IN output: - # income 1,893.33/mo, ratio ~1.026 -> factor 0.0116 + # income 1,893.33/mo, ratio ~1.05 -> factor 0.0116 # 1,893.33 * 0.0116 = 21.96/week -> 21.96 * 52/12 = 95.17/month in_ccdf_copay: 95.17 diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml new file mode 100644 index 00000000000..21e5cd4729f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml @@ -0,0 +1,154 @@ +# Tests for in_ccdf_fpg (SPMUnit, MONTH). Indiana moves to a new year's guideline when it +# posts a new eligibility package: March 31, 2024, May 1, 2025 and April 5, 2026. +- name: 2024-03 uses the 2023 guideline. + period: 2024-03 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2024: IN + output: + in_ccdf_fpg: 2_071.67 + +- name: 2024-04 uses the 2024 guideline. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2024: IN + output: + in_ccdf_fpg: 2_151.67 + +- name: 2025-04 uses the 2024 guideline. + period: 2025-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2025: IN + output: + in_ccdf_fpg: 2_151.67 + +- name: 2025-05 uses the 2025 guideline. + period: 2025-05 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2025: IN + output: + in_ccdf_fpg: 2_220.83 + +- name: 2026-04 uses the 2025 guideline. + period: 2026-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2026: IN + output: + in_ccdf_fpg: 2_220.83 + +- name: 2026-05 uses the 2026 guideline. + period: 2026-05 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2026: IN + output: + in_ccdf_fpg: 2_276.67 + +- name: 2027-01 uses the 2026 guideline. + period: 2027-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: IN + output: + in_ccdf_fpg: 2_276.67 diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml index c74576a46be..29fdc356ae0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml @@ -6,7 +6,8 @@ # value takes effect 2026-04-05, so it is exercised with a 2027-01 period. # --- Applicant (get-on), 1.5 FPL era at 2026-01 --- -# 2-person FPG 2026 = 21,640/yr; limit = 1.5 * 21,640 = 32,460/yr. +# January 2026 still uses the 2025 guideline: 2-person FPG = 21,150/yr. The limit is +# 1.5 * 21,150 / 12 = 2,643.75, printed as 2,644 a month, or 31,728 a year. - name: Case 1, applicant income below get-on limit, eligible. period: 2026-01 @@ -35,7 +36,7 @@ people: person1: age: 35 - employment_income: 32_460 # 1.5 * 21,640 FPG + employment_income: 31_728 # 12 * 2,644, the rounded limit person2: age: 5 is_tax_unit_dependent: true @@ -57,7 +58,7 @@ people: person1: age: 35 - employment_income: 33_000 # above 32,460 limit + employment_income: 33_000 # above 31,728 limit person2: age: 5 is_tax_unit_dependent: true @@ -183,12 +184,11 @@ in_ccdf_income_eligible: false # --- 135% FPL applicant boundary at 2027-01 (1.35 era) --- -# 2-person 2027 FPG = 22,147.39/yr; 135% = 29,898.98/yr. The 2027 FPG is a -# CBO-CPI-forecast-uprated value that shifts when the actual 2027 guideline is -# published, so these cases keep a comfortable margin on each side of the -# limit rather than pinning the exact boundary (the inclusive <= boundary is -# exercised at 2026 with the published FPG in Case 2). The ineligible income -# stays below the 1.5-era limit (33,221), proving the 1.35 rate applies. +# January 2027 still uses the 2026 guideline: 2-person FPG = 21,640/yr; 135% prints +# as 2,435 a month, or 29,220 a year. These cases keep a comfortable margin on each +# side of the limit (the inclusive <= boundary is exercised at 2026 in Case 2). The +# ineligible income stays below the 1.5-era limit (32,460), proving the 1.35 rate +# applies. - name: Case 9, applicant income below 135% FPL, eligible. period: 2027-01 @@ -196,7 +196,7 @@ people: person1: age: 35 - employment_income: 29_000 # comfortably below the ~29,899 limit + employment_income: 29_000 # comfortably below the 29,220 limit person2: age: 5 is_tax_unit_dependent: true @@ -217,7 +217,7 @@ people: person1: age: 35 - employment_income: 30_800 # above the ~29,899 limit, below 1.5 * FPG + employment_income: 30_800 # above the 29,220 limit, below 1.5 * FPG person2: age: 5 is_tax_unit_dependent: true @@ -343,3 +343,616 @@ # 5-person FPG 2026 = 38,680/yr; 150% limit = 58,020/yr (4,835/mo). # 3,333/mo < 4,835/mo -> eligible. A 2-person unit at this income fails. in_ccdf_income_eligible: true + +# Tops by family of three: 150% of the 2023 guideline ($3,108) until March 31, 2024; of +# the 2024 guideline ($3,228, state plan section 2.2.4) until May 1, 2025; of the 2025 +# guideline ($3,331) until April 5, 2026; then 135% of the 2026 guideline ($3,074, FSSA's +# chart). A monthly period reads each change from the next month's first day. + +- name: New applicant of 3 at 3,108 dollars qualifies in 2024-03. + period: 2024-03 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 3_108 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2024: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 3 at 3,109 dollars doesn't qualify in 2024-03. + period: 2024-03 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 3_109 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2024: IN + output: + in_ccdf_income_eligible: false + +- name: New applicant of 3 at 3,228 dollars qualifies in 2024-04. + period: 2024-04 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 3_228 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2024: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 3 at 3,229 dollars doesn't qualify in 2024-04. + period: 2024-04 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 3_229 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2024: IN + output: + in_ccdf_income_eligible: false + +- name: New applicant of 3 at 3,228 dollars qualifies in 2025-04. + period: 2025-04 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 3_228 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2025: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 3 at 3,229 dollars doesn't qualify in 2025-04. + period: 2025-04 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 3_229 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2025: IN + output: + in_ccdf_income_eligible: false + +- name: New applicant of 3 at 3,331 dollars qualifies in 2025-05. + period: 2025-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 3_331 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2025: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 3 at 3,332 dollars doesn't qualify in 2025-05. + period: 2025-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 3_332 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2025: IN + output: + in_ccdf_income_eligible: false + +- name: New applicant of 3 at 3,331 dollars qualifies in 2026-04. + period: 2026-04 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 3_331 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 3 at 3,332 dollars doesn't qualify in 2026-04. + period: 2026-04 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 3_332 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: false + +- name: New applicant of 2 at 2,435 dollars qualifies in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + in_ccdf_countable_income: 2_435 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 2 at 2,436 dollars doesn't qualify in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + in_ccdf_countable_income: 2_436 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: false + +- name: New applicant of 3 at 3,074 dollars qualifies in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 3_074 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 3 at 3,075 dollars doesn't qualify in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 3_075 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: false + +- name: New applicant of 4 at 3,713 dollars qualifies in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + in_ccdf_countable_income: 3_713 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 4 at 3,714 dollars doesn't qualify in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + in_ccdf_countable_income: 3_714 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: false + +- name: New applicant of 5 at 4,352 dollars qualifies in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + in_ccdf_countable_income: 4_352 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 5 at 4,353 dollars doesn't qualify in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + in_ccdf_countable_income: 4_353 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: false + +- name: New applicant of 6 at 4,991 dollars qualifies in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6] + in_ccdf_countable_income: 4_991 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 6 at 4,992 dollars doesn't qualify in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6] + in_ccdf_countable_income: 4_992 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: false + +- name: New applicant of 7 at 5,630 dollars qualifies in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + in_ccdf_countable_income: 5_630 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 7 at 5,631 dollars doesn't qualify in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + in_ccdf_countable_income: 5_631 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: false + +- name: New applicant of 8 at 6,269 dollars qualifies in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + person8: + age: 16 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + in_ccdf_countable_income: 6_269 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 8 at 6,270 dollars doesn't qualify in 2026-05. + period: 2026-05 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + person8: + age: 16 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + in_ccdf_countable_income: 6_270 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: + 2026: IN + output: + in_ccdf_income_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/in_ccdf.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/in_ccdf.yaml index c71d2d3017a..270c8cc44ad 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/in_ccdf.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/in_ccdf.yaml @@ -12,7 +12,7 @@ people: person1: age: 35 - employment_income: 22_720 # ~105% FPL -> copay factor 0.0116 + employment_income: 22_720 # ~107% FPL -> copay factor 0.0116 person2: age: 0.5 is_tax_unit_dependent: true @@ -65,7 +65,7 @@ people: person1: age: 35 - employment_income: 27_050 # ~125% FPL, factor 0.0163 + employment_income: 27_050 # ~128% FPL, factor 0.0163 person2: age: 8 is_tax_unit_dependent: true @@ -176,7 +176,7 @@ people: person1: age: 35 - employment_income: 22_720 # ~83% FPL (3-person) -> zero copay + employment_income: 22_720 # ~85% FPL (3-person) -> zero copay person2: age: 0.5 # infant is_tax_unit_dependent: true @@ -198,6 +198,6 @@ output: # Infant rate 374.4 * 52/12 = 1,622.40; school-age before/after 71.5 * # 52/12 = 309.83; combined rate = 1,932.23. Expenses 5,000/mo capped to - # 1,932.23. Copay: 3-person FPG 2026 = 27,320/yr; income 22,720 -> ratio - # ~0.83 < 100% FPL -> zero copay. Benefit = 1,932.23 - 0 = 1,932.23. + # 1,932.23. Copay: 3-person FPG in January 2026 = 26,650/yr; income 22,720 -> ratio + # ~0.85 < 100% FPL -> zero copay. Benefit = 1,932.23 - 0 = 1,932.23. in_ccdf: 1_932.23 diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/integration.yaml index 7128eb4c8a6..478a5c57344 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/integration.yaml @@ -4,8 +4,8 @@ # All monetary rates are Marion County FY2023 weekly rates after the Oct 5, # 2025 percentage cuts, * (52 / 12); the copay fee factor is the new-enrollee # (Year 1-3) tier of the 2026 schedule. -# 2-person FPG 2026 = 21,640/yr; 4-person = 33,000/yr. At 2026-01 the get-on -# rate is 1.5 (150% FPL). +# January 2026 still uses the 2025 guideline: 2-person FPG = 21,150/yr; 4-person = +# 32,150/yr. At 2026-01 the get-on rate is 1.5 (150% FPL). - name: Case 1, single working parent, infant in PTQ-4 licensed center, high expenses. period: 2026-01 @@ -14,7 +14,7 @@ people: person1: age: 30 - employment_income: 22_720 # ~105% FPL + employment_income: 22_720 # ~107% FPL person2: age: 0.5 is_tax_unit_dependent: true @@ -73,7 +73,7 @@ state_code: IN output: in_ccdf_eligible: true - # 4-person income 2,333.33/mo < 100% FPL (2,750) -> copay 0. + # 4-person income 2,333.33/mo < 100% FPL (2,679.17) -> copay 0. # toddler 176.4 + three-to-five 133.45 = 309.85/wk * 52/12 = 1,342.68/mo. # expenses 2,000 capped at 1,342.68; benefit = 1,342.68 - 0 = 1,342.68/mo in_ccdf: 1_342.68 @@ -102,7 +102,7 @@ state_code: IN output: in_ccdf_eligible: true - # income 3,750/mo, ratio ~2.08 FPL -> factor 0.0372. + # income 3,750/mo, ratio ~2.13 FPL -> factor 0.0372. # rate 374.4 * 52/12 = 1,622.40; copay 3,750 * 0.0372 = 139.50/wk -> 604.50/mo. # benefit = 1,622.40 - 604.50 = 1,017.90/mo in_ccdf: 1_017.90 @@ -114,7 +114,7 @@ people: person1: age: 40 - employment_income: 21_640 # 100% FPL -> copay 0 + employment_income: 21_150 # 100% FPL -> copay 0 person2: age: 15 is_tax_unit_dependent: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/eligibility/mo_ccs_fpg.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/eligibility/mo_ccs_fpg.yaml new file mode 100644 index 00000000000..68b08e4849a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/eligibility/mo_ccs_fpg.yaml @@ -0,0 +1,87 @@ +# Tests for mo_ccs_fpg (SPMUnit, MONTH). DESE's chart updated July 1, 2026 prints the +# 2025 guideline, and a lag of one holds it through 2026. +- name: 2025-11 uses the 2025 guideline. + period: 2025-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MO + output: + mo_ccs_fpg: 2_220.83 + +- name: 2026-01 uses the 2025 guideline. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: MO + output: + mo_ccs_fpg: 2_220.83 + +- name: 2026-10 uses the 2025 guideline. + period: 2026-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + mo_ccs_fpg: 2_220.83 + +- name: 2027-01 uses the 2026 guideline. + period: 2027-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: MO + output: + mo_ccs_fpg: 2_276.67 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.yaml index 17c8a3afbd2..a576d90dc12 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.yaml @@ -180,7 +180,7 @@ people: person1: age: 30 - employment_income: 51_183 + employment_income: 51_180 person2: age: 5 spm_units: @@ -192,7 +192,7 @@ members: [person1, person2] state_code: MO output: - # Monthly income = 51,183 / 12 = 4,265.25 = 242% FPL limit -> <= -> eligible. + # 242% FPL prints as 4,265 on the chart; 51,180 / 12 = 4,265 -> <= -> eligible. mo_ccs_income_eligible: true - name: Case 10, existing family just above 242 percent FPL is ineligible. @@ -299,3 +299,283 @@ # (85% SMI) -> the 85% SMI cap binds -> ineligible (would be eligible on the # FPL limit alone). mo_ccs_income_eligible: false + +# Tops from DESE's chart headed November 2025 and updated July 1, 2026: 150% of the +# 2025 guideline to the nearest dollar for new applicants, and Transitional Level 2 +# (215%) for existing families from July 1, 2026, when DESE removed Level 3. + +- name: New applicant of 2 at 2,644 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + mo_ccs_adjusted_income: 2_644 + mo_ccs_enrolled: false + households: + household: + members: [person1, person2] + state_code: + 2026: MO + output: + mo_ccs_income_eligible: true + +- name: New applicant of 2 at 2,645 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + mo_ccs_adjusted_income: 2_645 + mo_ccs_enrolled: false + households: + household: + members: [person1, person2] + state_code: + 2026: MO + output: + mo_ccs_income_eligible: false + +- name: New applicant of 3 at 3,331 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 3_331 + mo_ccs_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + mo_ccs_income_eligible: true + +- name: New applicant of 3 at 3,332 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 3_332 + mo_ccs_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + mo_ccs_income_eligible: false + +- name: New applicant of 4 at 4,019 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + mo_ccs_adjusted_income: 4_019 + mo_ccs_enrolled: false + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: MO + output: + mo_ccs_income_eligible: true + +- name: New applicant of 4 at 4,020 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + mo_ccs_adjusted_income: 4_020 + mo_ccs_enrolled: false + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: MO + output: + mo_ccs_income_eligible: false + +- name: New applicant of 3 at 3,331 dollars qualifies in 2025-11. + period: 2025-11 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 3_331 + mo_ccs_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MO + output: + mo_ccs_income_eligible: true + +- name: New applicant of 3 at 3,332 dollars doesn't qualify in 2025-11. + period: 2025-11 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 3_332 + mo_ccs_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MO + output: + mo_ccs_income_eligible: false + +- name: Continuing family of 3 at 5,374 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 5_374 + mo_ccs_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + mo_ccs_income_eligible: true + +- name: Continuing family of 3 at 5,375 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 5_375 + mo_ccs_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + mo_ccs_income_eligible: false + +- name: Continuing family of 3 at 4,775 dollars qualifies in 2026-07. + period: 2026-07 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 4_775 + mo_ccs_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + mo_ccs_income_eligible: true + +- name: Continuing family of 3 at 4,776 dollars doesn't qualify in 2026-07. + period: 2026-07 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 4_776 + mo_ccs_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + mo_ccs_income_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/integration.yaml index 7b7f2378f87..34e7a7e9a1f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/integration.yaml @@ -1,9 +1,9 @@ # Integration tests for Montana Best Beginnings Child Care Scholarship (CCAP). # End-to-end scenarios exercising age classification, the 3-D provider rate lookup, -# the sliding-scale copay, the TANF flat-$10 copay, the income test (150% FPG -# initial / 185% FPG graduated, 85% SMI overlay), the activity requirement, and +# the sliding-scale copay, the TANF flat-$10 copay, the income test (185% FPG +# initial / 200% FPG graduated, 85% SMI overlay), the activity requirement, and # the final benefit + the state and federal child-care-subsidy aggregators. -# 2026 (contiguous) FPG: size 2 = 21,640; size 3 = 27,320 (annual). +# January 2026 uses the scale's 2025 FPG (contiguous): size 2 = 21,150; size 3 = 26,650 (annual). # Provider rates effective 07-01-2025 (BBS Provider Reimbursement Monthly Rates). - name: Case 1, single parent + preschooler at an FFN provider, full-time. @@ -13,7 +13,7 @@ people: person1: age: 28 - employment_income: 26_000 # size 2, ratio 26,000/21,640 = 1.2015 -> 1.5% + employment_income: 26_000 # size 2, ratio 26,000/21,150 = 1.2293 -> 1.5% weekly_hours_worked_before_lsr: 40 # ~173 hrs/month >> 60 person2: age: 4 # 48 months -> PRESCHOOL @@ -48,7 +48,7 @@ people: person1: age: 33 - employment_income: 41_520 # size 3, ratio 41,520/27,320 = 1.52 -> 3.5% + employment_income: 40_508 # size 3, ratio 40,508/26,650 = 1.52 -> 3.5% weekly_hours_worked_before_lsr: 20 # ~86.7 hrs/month person2: age: 31 @@ -74,10 +74,10 @@ mt_ccap_activity_eligible: true # combined ~173 hrs/month >= 120 mt_ccap_eligible: true mt_ccap_max_rate: [0, 0, 1_056] # group home infant/toddler full-time = 1,056 - mt_ccap_countable_income: 3_460 # 41,520 / 12 - mt_ccap_copay: 121.1 # 3,460 * 3.5% - # charge 2,000 > max rate 1,056 -> capped at 1,056; benefit = 1,056 - 121.10 - mt_ccap: 934.9 + mt_ccap_countable_income: 3_375.67 # 40,508 / 12 + mt_ccap_copay: 118.15 # 3,375.67 * 3.5% + # charge 2,000 > max rate 1,056 -> capped at 1,056; benefit = 1,056 - 118.15 + mt_ccap: 937.85 - name: Case 3, single parent + two children at a family home, 100% FPG. period: 2026-01 @@ -86,7 +86,7 @@ people: person1: age: 30 - employment_income: 27_320 # size 3, ratio 1.00 -> 0.5% + employment_income: 26_650 # size 3, ratio 1.00 -> 0.5% weekly_hours_worked_before_lsr: 40 person2: age: 4 # PRESCHOOL @@ -111,10 +111,10 @@ mt_ccap_income_eligible: true mt_ccap_eligible: true mt_ccap_max_rate: [0, 880, 880] # family home preschool / school age full-time = 880 - mt_ccap_countable_income: 2_276.67 # 27,320 / 12 - mt_ccap_copay: 11.38 # 2,276.67 * 0.5% - # each child: min(1,000, 880) = 880; sum 1,760; benefit = 1,760 - 11.38 - mt_ccap: 1_748.62 + mt_ccap_countable_income: 2_220.83 # 26,650 / 12 + mt_ccap_copay: 11.10 # 2,220.83 * 0.5% + # each child: min(1,000, 880) = 880; sum 1,760; benefit = 1,760 - 11.10 + mt_ccap: 1_748.90 - name: Case 4, TANF over-income family at a relative-care-exempt provider. period: 2026-01 @@ -154,7 +154,7 @@ people: person1: age: 33 - employment_income: 60_000 # size 3, ratio 2.196 -> above the 150% applicant limit (40,980) + employment_income: 60_000 # size 3, ratio 2.25 -> above the 185% applicant limit (49,308) weekly_hours_worked_before_lsr: 40 person2: age: 31 @@ -174,7 +174,7 @@ state_code: MT output: mt_ccap_eligible_child: [false, false, true] - mt_ccap_income_eligible: false # above the 150% applicant limit -> FPG limit binds + mt_ccap_income_eligible: false # above the 185% applicant limit -> FPG limit binds mt_ccap_eligible: false mt_ccap: 0 mt_child_care_subsidies: 0 @@ -251,12 +251,12 @@ - name: Case 8, family at 182% FPG (continuing recipient), center preschooler, full-time. period: 2026-01 absolute_error_margin: 0.1 - # ratio 39,384/21,640 = 1.82 -> 6.5% copay bracket; continuing recipient eligible (182% < 185% graduated limit, below 85% SMI). + # ratio 38,493/21,150 = 1.82 -> 6.5% copay bracket; continuing recipient eligible (182% < 200% graduated limit, below 85% SMI). input: people: person1: age: 31 - employment_income: 39_384 # size 2, 182% of FPG (3,282/mo) + employment_income: 38_493 # size 2, 182% of FPG (3,207.75/mo) weekly_hours_worked_before_lsr: 40 person2: age: 4 # PRESCHOOL @@ -274,24 +274,24 @@ state_code: MT output: mt_ccap_eligible_child: [false, true] - mt_ccap_income_eligible: true # 182% FPG < 185% graduated limit (enrolled), below 85% SMI + mt_ccap_income_eligible: true # 182% FPG < 200% graduated limit (enrolled), below 85% SMI mt_ccap_activity_eligible: true mt_ccap_eligible: true mt_ccap_max_rate: [0, 1_210] # center preschool full-time - mt_ccap_countable_income: 3_282 # 39,384 / 12 - mt_ccap_copay: 213.33 # 3,282.00 * 6.5% - # charge 1,500 > max rate 1,210 -> capped at 1,210; benefit = 1,210 - 213.33 - mt_ccap: 996.67 + mt_ccap_countable_income: 3_207.75 # 38,493 / 12 + mt_ccap_copay: 208.50 # 3,207.75 * 6.5% + # charge 1,500 > max rate 1,210 -> capped at 1,210; benefit = 1,210 - 208.50 + mt_ccap: 1_001.50 - name: Case 9, eligible family whose copay exceeds the small reimbursement (benefit floors at 0). period: 2026-01 absolute_error_margin: 0.1 - # continuing recipient with a tiny provider charge; copay 213.33 > reimbursement 200 -> benefit floored at 0 even though the family is eligible. + # continuing recipient with a tiny provider charge; copay 208.50 > reimbursement 200 -> benefit floored at 0 even though the family is eligible. input: people: person1: age: 31 - employment_income: 39_384 # 182% FPG, 6.5% copay bracket + employment_income: 38_493 # 182% FPG, 6.5% copay bracket weekly_hours_worked_before_lsr: 40 person2: age: 4 @@ -310,8 +310,8 @@ output: mt_ccap_eligible: true mt_ccap_max_rate: [0, 1_210] - mt_ccap_copay: 213.33 # 3,282.00 * 6.5% - # reimbursement = min(200, 1,210) = 200; max(200 - 213.33, 0) = 0 + mt_ccap_copay: 208.50 # 3,207.75 * 6.5% + # reimbursement = min(200, 1,210) = 200; max(200 - 208.50, 0) = 0 mt_ccap: 0 - name: Case 10, infant at a center, full-time (highest single max rate). @@ -322,7 +322,7 @@ people: person1: age: 26 - employment_income: 18_000 # size 2, ~83% FPG -> 0.5% bracket, copay at the $10 floor + employment_income: 18_000 # size 2, ~85% FPG -> 0.5% bracket, copay at the $10 floor weekly_hours_worked_before_lsr: 40 person2: age: 0 # newborn, INFANT_TODDLER diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap.yaml index 50cc498d61b..3a3c41a66d0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap.yaml @@ -3,7 +3,7 @@ # - household copay, 0). # Per-child charge comes from pre_subsidy_childcare_expenses, which prorates # spm_unit_pre_subsidy_childcare_expenses (annual) evenly across children. -# 2026 (contiguous) FPG: size 2 = 21,640 annual; size 3 = 27,320 annual. +# January 2026 uses the scale's 2025 FPG (contiguous): size 2 = 21,150 annual; size 3 = 26,650 annual. - name: Case 1, one child at a center, charge exceeds the max rate (capped at max rate). period: 2026-01 absolute_error_margin: 0.1 @@ -11,7 +11,7 @@ people: person1: age: 30 - employment_income: 24_000 # size 2, ~111% FPG -> 1.0% copay bracket + employment_income: 24_000 # size 2, ~113% FPG -> 1.0% copay bracket weekly_hours_worked_before_lsr: 40 person2: age: 4 # preschool @@ -66,7 +66,7 @@ people: person1: age: 30 - employment_income: 30_000 # size 3, ~110% FPG -> 1.0% copay bracket + employment_income: 30_000 # size 3, ~113% FPG -> 1.0% copay bracket weekly_hours_worked_before_lsr: 40 person2: age: 4 @@ -228,12 +228,12 @@ - name: Case 9, copay exceeds the reimbursement so the benefit floors at 0. period: 2026-01 absolute_error_margin: 0.1 - # continuing recipient with a small provider charge; copay 213.33 > reimbursement 200 -> benefit floored at 0. + # continuing recipient with a small provider charge; copay 208.50 > reimbursement 200 -> benefit floored at 0. input: people: person1: age: 30 - employment_income: 39_384 # size 2, 182% FPG (3,282/mo) -> 6.5% copay bracket + employment_income: 38_493 # size 2, 182% FPG (3,207.75/mo) -> 6.5% copay bracket weekly_hours_worked_before_lsr: 40 person2: age: 4 @@ -251,5 +251,5 @@ state_code: MT output: # reimbursement = min(200, 1,210) = 200 - # copay = 3,282.00 * 6.5% = 213.33 > 200 -> max(200 - 213.33, 0) = 0 + # copay = 3,207.75 * 6.5% = 208.50 > 200 -> max(200 - 208.50, 0) = 0 mt_ccap: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_copay.yaml index a96aa27db4e..2d3b439a88d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_copay.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_copay.yaml @@ -2,7 +2,8 @@ # Non-TANF: copay = max(gross_monthly_income * copay_rate.calc(fpg_ratio), $10). # TANF (is_tanf_enrolled): flat $10. # fpg_ratio = countable monthly income / monthly FPG. -# 2026 FPG (contiguous), size 3 (1 parent + 2 children): 27,320 annual = 2,276.67/mo. +# January 2026 uses the scale's 2025 FPG (contiguous), size 3 (1 parent + 2 children): +# 26,650 annual = 2,220.83/mo. # Income inputs are annual; the MONTH formula reads the monthly portion. - name: Case 1, low income copay floors at the $10 minimum. period: 2026-01 @@ -11,7 +12,7 @@ people: person1: weekly_hours_worked_before_lsr: 40 - employment_income: 20_490 # 75% FPG; 0.5% of 1,707.50 = 8.54 < 10 + employment_income: 20_490 # 77% FPG; 0.5% of 1,707.50 = 8.54 < 10 person2: age: 4 person3: @@ -34,7 +35,7 @@ people: person1: weekly_hours_worked_before_lsr: 40 - employment_income: 27_320 # 100% FPG, ratio 1.0 -> 0.5% + employment_income: 26_650 # 100% FPG, ratio 1.0 -> 0.5% person2: age: 4 person3: @@ -48,17 +49,17 @@ members: [person1, person2, person3] state_code: MT output: - mt_ccap_copay: 11.38 # 2,276.67 * 0.005 = 11.38 + mt_ccap_copay: 11.10 # 2,220.83 * 0.005 = 11.10 - name: Case 3, continuing recipient at 152% FPG pays the 3.5% copay. period: 2026-01 absolute_error_margin: 0.1 - # 41,520 annual (152% FPG) -> 3.5% tier; enrolled (eligible up to 185% FPG). + # 40,508 annual (152% FPG) -> 3.5% tier; enrolled (eligible up to 200% FPG). input: people: person1: weekly_hours_worked_before_lsr: 40 - employment_income: 41_520 # 3,460/mo, 152% of size-3 FPG + employment_income: 40_508 # 3,375.67/mo, 152% of size-3 FPG person2: age: 4 person3: @@ -73,17 +74,17 @@ members: [person1, person2, person3] state_code: MT output: - mt_ccap_copay: 121.1 # 3,460.00 * 0.035 + mt_ccap_copay: 118.15 # 3,375.67 * 0.035 - name: Case 4, continuing recipient at 182% FPG pays the 6.5% copay. period: 2026-01 absolute_error_margin: 0.1 - # 49,716 annual (182% FPG) -> 6.5% tier; enrolled (eligible up to 185% FPG). + # 48,503 annual (182% FPG) -> 6.5% tier; enrolled (eligible up to 200% FPG). input: people: person1: weekly_hours_worked_before_lsr: 40 - employment_income: 49_716 # 4,143/mo, 182% of size-3 FPG + employment_income: 48_503 # 4,041.92/mo, 182% of size-3 FPG person2: age: 4 person3: @@ -98,17 +99,17 @@ members: [person1, person2, person3] state_code: MT output: - mt_ccap_copay: 269.3 # 4,143.00 * 0.065 + mt_ccap_copay: 262.72 # 4,041.92 * 0.065 - name: Case 5, continuing recipient at 172% FPG pays the 5.5% copay. period: 2026-01 absolute_error_margin: 0.1 - # 46,992 annual (172% FPG) -> 5.5% tier; enrolled (eligible up to 185% FPG). + # 45,838 annual (172% FPG) -> 5.5% tier; enrolled (eligible up to 200% FPG). input: people: person1: weekly_hours_worked_before_lsr: 40 - employment_income: 46_992 # 3,916/mo, 172% of size-3 FPG + employment_income: 45_838 # 3,819.83/mo, 172% of size-3 FPG person2: age: 4 person3: @@ -123,7 +124,7 @@ members: [person1, person2, person3] state_code: MT output: - mt_ccap_copay: 215.38 # 3,916.00 * 0.055 + mt_ccap_copay: 210.09 # 3,819.83 * 0.055 - name: Case 6, TANF recipient pays the flat $10 copay regardless of income. period: 2026-01 @@ -149,7 +150,7 @@ mt_ccap_copay: 10 # flat $10 for TANF, not the 119.53 scale amount # --- Edge cases: $10 floor exactly, zero income, and FPG-step bracket boundaries. -# Size 3 monthly FPG = 27,320 / 12 = 2,276.67. Per the sliding scale footnote, each +# Size 3 monthly FPG = 26,650 / 12 = 2,220.83. Per the sliding scale footnote, each # labeled % is the FLOOR of its tier: a family AT a step enters the higher tier and # just below stays in the lower tier (single_amount is "at or above threshold"). --- - name: Case 7, zero income copay floors at the $10 minimum. @@ -179,7 +180,7 @@ - name: Case 8, copay exactly at the $10 floor (scale amount equals the minimum). period: 2026-01 absolute_error_margin: 0.1 - # GMI 2,000/mo (24,000 annual, ~87.8% FPG) -> 0.5% bracket; 2,000 * 0.005 = 10 = minimum. + # GMI 2,000/mo (24,000 annual, ~90.1% FPG) -> 0.5% bracket; 2,000 * 0.005 = 10 = minimum. input: people: person1: @@ -203,13 +204,13 @@ - name: Case 9, just above 100% FPG stays in the 0.5% bracket (floor reading). period: 2026-01 absolute_error_margin: 0.1 - # ratio 28,140/27,320 = 1.03; floor keeps income below 105% in the 0.5% tier + # ratio 27,450/26,650 = 1.03; floor keeps income below 105% in the 0.5% tier # (a ceiling reading of the scale would instead charge 1.0% here). input: people: person1: weekly_hours_worked_before_lsr: 40 - employment_income: 28_140 # 103% of size-3 FPG (2,345/mo) + employment_income: 27_450 # 103% of size-3 FPG (2,287.50/mo) person2: age: 4 person3: @@ -223,17 +224,17 @@ members: [person1, person2, person3] state_code: MT output: - mt_ccap_copay: 11.73 # 2,345.00/mo * 0.005 + mt_ccap_copay: 11.44 # 2,287.50/mo * 0.005 - name: Case 10, above 105% FPG is in the 1.0% bracket. period: 2026-01 absolute_error_margin: 0.1 - # ratio 29,520/27,320 = 1.08; floor 1.0% tier runs 105% up to 115%. + # ratio 29,520/26,650 = 1.11; floor 1.0% tier runs 105% up to 115%. input: people: person1: weekly_hours_worked_before_lsr: 40 - employment_income: 29_520 # 108% of size-3 FPG (2,460/mo) + employment_income: 29_520 # 111% of size-3 FPG (2,460/mo) person2: age: 4 person3: @@ -252,13 +253,13 @@ - name: Case 11, just above 110% FPG stays in the 1.0% bracket (floor reading). period: 2026-01 absolute_error_margin: 0.1 - # ratio 30,600/27,320 = 1.12; floor keeps 110-115% in the 1.0% tier + # ratio 30,600/26,650 = 1.148; floor keeps 110-115% in the 1.0% tier # (a ceiling reading of the scale would instead charge 1.5% here). input: people: person1: weekly_hours_worked_before_lsr: 40 - employment_income: 30_600 # 112% of size-3 FPG (2,550/mo) + employment_income: 30_600 # 114.8% of size-3 FPG (2,550/mo) person2: age: 4 person3: @@ -277,12 +278,12 @@ - name: Case 12, above 115% FPG is in the 1.5% bracket. period: 2026-01 absolute_error_margin: 0.1 - # ratio 32,280/27,320 = 1.18; floor 1.5% tier runs 115% up to 125%. + # ratio 32,280/26,650 = 1.21; floor 1.5% tier runs 115% up to 125%. input: people: person1: weekly_hours_worked_before_lsr: 40 - employment_income: 32_280 # 118% of size-3 FPG (2,690/mo) + employment_income: 32_280 # 121% of size-3 FPG (2,690/mo) person2: age: 4 person3: diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_eligible.yaml index 10c00d0cd7b..eb48f39210e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_eligible.yaml @@ -8,7 +8,7 @@ people: person1: age: 30 - employment_income: 30_000 # ~110% FPG for size 2 + employment_income: 30_000 # ~142% FPG for size 2 weekly_hours_worked_before_lsr: 40 person2: age: 4 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_fpg.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_fpg.yaml new file mode 100644 index 00000000000..29e43aa010f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_fpg.yaml @@ -0,0 +1,110 @@ +# Tests for mt_ccap_fpg (SPMUnit, MONTH). The Sliding Fee Scale effective 07-01-2025 prints +# the 2025 guideline; ACF's January 2025 table prints the 2024 guideline. +- name: 2024-08 uses the 2024 guideline. + period: 2024-08 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2024: MT + output: + mt_ccap_fpg: 2_151.67 + +- name: 2025-03 uses the 2024 guideline. + period: 2025-03 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MT + output: + mt_ccap_fpg: 2_151.67 + +- name: 2025-08 uses the 2025 guideline. + period: 2025-08 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MT + output: + mt_ccap_fpg: 2_220.83 + +- name: 2026-06 uses the 2025 guideline. + period: 2026-06 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MT + output: + mt_ccap_fpg: 2_220.83 + +- name: 2027-01 uses the 2026 guideline. + period: 2027-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + mt_ccap_fpg: 2_276.67 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_income_eligible.yaml index f05b7859733..3ce0465ebfd 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_income_eligible.yaml @@ -1,17 +1,19 @@ # Unit tests for mt_ccap_income_eligible (SPMUnit, MONTH). -# ARM 37.80.202(1): first-time applicants eligible below 150% FPG. -# ARM 37.80.202(2): non-TANF continuing recipients (mt_ccap_enrolled) eligible at -# annual redetermination up to 185% FPG. TANF families are categorically eligible. -# An 85% SMI overlay applies to all non-TANF families (rarely binds). -# 2026 (contiguous), size 3 (1 parent + 2 children): FPG = 27,320 annual; -# 150% FPG = 40,980; 185% FPG = 50,542; 85% SMI = 81,374 (does not bind at size 3). +# MCA 52-2-715(1) and the Sliding Fee Scale effective 07-01-2025: applicants eligible +# through 185% FPG. The scale's Graduated Eligibility: non-TANF continuing recipients +# (mt_ccap_enrolled) eligible at annual redetermination through 200% FPG. TANF families +# are categorically eligible. An 85% SMI overlay applies to all non-TANF families +# (rarely binds). +# January 2026 uses the scale's 2025 guideline (contiguous), size 3 (1 parent + 2 +# children): FPG = 26,650 annual. The scale prints 185% as 4,109 a month (49,308 a year) +# and 200% as 4,442 a month (53,304 a year); 85% SMI = 81,374 (does not bind at size 3). # Income inputs are annual; the MONTH formula compares monthly portions. -- name: Case 1, applicant well below 150% FPG is eligible. +- name: Case 1, applicant well below 185% FPG is eligible. period: 2026-01 input: people: person1: - employment_income: 30_000 # ~110% FPG + employment_income: 30_000 # ~113% FPG person2: age: 4 person3: @@ -28,13 +30,13 @@ output: mt_ccap_income_eligible: true -- name: Case 2, applicant just below the 150% FPG limit is eligible. +- name: Case 2, applicant just below the 185% FPG limit is eligible. period: 2026-01 - # 40,500 annual (148.2% FPG) -> below the 150% initial limit. + # 49,000 annual (183.9% FPG) -> below the 185% initial limit. input: people: person1: - employment_income: 40_500 + employment_income: 49_000 person2: age: 4 person3: @@ -51,13 +53,13 @@ output: mt_ccap_income_eligible: true -- name: Case 3, applicant just above the 150% FPG limit is ineligible. +- name: Case 3, applicant just above the 185% FPG limit is ineligible. period: 2026-01 - # 41,500 annual (151.9% FPG) -> above the 150% initial limit; not enrolled. + # 49,500 annual (185.7% FPG) -> above the 185% initial limit; not enrolled. input: people: person1: - employment_income: 41_500 + employment_income: 49_500 person2: age: 4 person3: @@ -74,13 +76,13 @@ output: mt_ccap_income_eligible: false -- name: Case 4, continuing recipient between 150% and 185% FPG is eligible (graduated). +- name: Case 4, continuing recipient between 185% and 200% FPG is eligible (graduated). period: 2026-01 - # 44,000 annual (161% FPG): over the 150% applicant limit but under 185%; enrolled. + # 51,000 annual (191.4% FPG): over the 185% applicant limit but under 200%; enrolled. input: people: person1: - employment_income: 44_000 + employment_income: 51_000 person2: age: 4 person3: @@ -97,13 +99,13 @@ output: mt_ccap_income_eligible: true -- name: Case 5, continuing recipient just below the 185% FPG limit is eligible. +- name: Case 5, continuing recipient just below the 200% FPG limit is eligible. period: 2026-01 - # 50,000 annual (183% FPG) -> below the 185% graduated limit; enrolled. + # 53,000 annual (198.9% FPG) -> below the 200% graduated limit; enrolled. input: people: person1: - employment_income: 50_000 + employment_income: 53_000 person2: age: 4 person3: @@ -120,13 +122,13 @@ output: mt_ccap_income_eligible: true -- name: Case 6, continuing recipient just above the 185% FPG limit is ineligible. +- name: Case 6, continuing recipient just above the 200% FPG limit is ineligible. period: 2026-01 - # 51,500 annual (188.5% FPG) -> above the 185% graduated limit; enrolled. + # 53,500 annual (200.8% FPG) -> above the 200% graduated limit; enrolled. input: people: person1: - employment_income: 51_500 + employment_income: 53_500 person2: age: 4 person3: @@ -143,21 +145,16 @@ output: mt_ccap_income_eligible: false -# Tight boundary coverage around the exact-cent FPG limits (size 3, 2026): -# 150% FPG = 40,980/yr (3,415.00/mo); 185% FPG = 50,542/yr (4,211.83/mo). -# The formula uses an exclusive `<`, so the threshold is tested $1 on either -# side. NOTE: the exact-cent limit (e.g. income == 40,980) is float32-precision -# sensitive — monthly countable income and monthly FPG are each derived by -# dividing annual figures by 12, and the round-trip can leave the two within a -# float ULP of each other. These $1-offset cases pin the intended behavior -# without depending on that ambiguous exact-boundary rounding. -- name: Case 6a, applicant one dollar below the 150% FPG limit is eligible. +# Tight boundary coverage around the scale's printed limits (size 3, January 2026): +# 185% FPG = 4,109/mo (49,308/yr); 200% FPG = 4,442/mo (53,304/yr). +# A family at the printed limit qualifies, and one dollar a month above it doesn't. +- name: Case 6a, applicant at the scale's 185% FPG limit is eligible. period: 2026-01 - # 40,979/yr -> 3,414.92/mo, just under the 3,415.00/mo (150% FPG) initial limit. + # 49,308/yr -> 4,109/mo, the scale's Standard Eligibility top for three. input: people: person1: - employment_income: 40_979 + employment_income: 49_308 person2: age: 4 person3: @@ -174,13 +171,13 @@ output: mt_ccap_income_eligible: true -- name: Case 6b, applicant one dollar above the 150% FPG limit is ineligible. +- name: Case 6b, applicant one dollar a month above the 185% FPG limit is ineligible. period: 2026-01 - # 40,981/yr -> 3,415.08/mo, just over the 3,415.00/mo (150% FPG) initial limit. + # 49,320/yr -> 4,110/mo, just over the 4,109/mo (185% FPG) initial limit. input: people: person1: - employment_income: 40_981 + employment_income: 49_320 person2: age: 4 person3: @@ -197,13 +194,13 @@ output: mt_ccap_income_eligible: false -- name: Case 6c, continuing recipient one dollar below the 185% FPG limit is eligible. +- name: Case 6c, continuing recipient at the scale's 200% FPG limit is eligible. period: 2026-01 - # 50,541/yr -> 4,211.75/mo, just under the 4,211.83/mo (185% FPG) graduated limit. + # 53,304/yr -> 4,442/mo, the scale's Graduated Eligibility top for three. input: people: person1: - employment_income: 50_541 + employment_income: 53_304 person2: age: 4 person3: @@ -220,13 +217,13 @@ output: mt_ccap_income_eligible: true -- name: Case 6d, continuing recipient one dollar above the 185% FPG limit is ineligible. +- name: Case 6d, continuing recipient one dollar a month above the 200% FPG limit is ineligible. period: 2026-01 - # 50,543/yr -> 4,211.92/mo, just over the 4,211.83/mo (185% FPG) graduated limit. + # 53,316/yr -> 4,443/mo, just over the 4,442/mo (200% FPG) graduated limit. input: people: person1: - employment_income: 50_543 + employment_income: 53_316 person2: age: 4 person3: @@ -245,7 +242,7 @@ - name: Case 7, TANF recipient over the 185% FPG limit is still income-eligible. period: 2026-01 - # 52,000 annual (190% FPG): over the non-TANF limits, but categorically eligible. + # 52,000 annual (195% FPG): over the applicant limit, but categorically eligible. input: people: person1: @@ -310,13 +307,13 @@ output: mt_ccap_income_eligible: false -# --- 85% SMI overlay isolation (large household where 0.85*SMI < 1.85*FPG). -# Size 13 (2 parents + 11 children) 2026, contiguous: 185% FPG = 155,622 annual -# (12,968.50/mo); 85% SMI = 140,554 annual (11,712.84/mo). Between these two the SMI +# --- 85% SMI overlay isolation (large household where 0.85*SMI < 2.0*FPG). +# Size 13 (2 parents + 11 children) January 2026, contiguous: 200% FPG = 163,300 annual +# (13,608.33/mo); 85% SMI = 140,554 annual (11,712.84/mo). Between these two the SMI # overlay rejects an otherwise FPG-eligible continuing recipient. --- -- name: Case 10, continuing recipient above 85% SMI but below 185% FPG is ineligible (SMI overlay). +- name: Case 10, continuing recipient above 85% SMI but below 200% FPG is ineligible (SMI overlay). period: 2026-01 - # 148,000 annual = 12,333.33/mo: above 0.85 SMI (11,712.84) yet below 1.85 FPG (12,968.50). + # 148,000 annual = 12,333.33/mo: above 0.85 SMI (11,712.84) yet below 2.0 FPG (13,608.33). input: people: person1: @@ -360,7 +357,7 @@ - name: Case 11, continuing recipient below 85% SMI is eligible (companion to Case 10). period: 2026-01 - # 138,000 annual = 11,500.00/mo: below both 0.85 SMI (11,712.84) and 1.85 FPG (12,968.50). + # 138,000 annual = 11,500.00/mo: below both 0.85 SMI (11,712.84) and 2.0 FPG (13,608.33). input: people: person1: @@ -401,3 +398,1078 @@ state_code: MT output: mt_ccap_income_eligible: true + +# Tops from the Sliding Fee Scale effective 07-01-2025 (2025 guideline, nearest dollar), +# plus the same rates on the guideline years behind earlier published limits. + +- name: New applicant of 2 at 3,261 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + mt_ccap_countable_income: 3_261 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: New applicant of 2 at 3,262 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + mt_ccap_countable_income: 3_262 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: New applicant of 3 at 4,109 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 4_109 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: New applicant of 3 at 4,110 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 4_110 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: New applicant of 4 at 4,956 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + mt_ccap_countable_income: 4_956 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: New applicant of 4 at 4,957 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + mt_ccap_countable_income: 4_957 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: New applicant of 5 at 5,804 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + mt_ccap_countable_income: 5_804 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: New applicant of 5 at 5,805 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + mt_ccap_countable_income: 5_805 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: New applicant of 6 at 6,652 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6] + mt_ccap_countable_income: 6_652 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: New applicant of 6 at 6,653 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6] + mt_ccap_countable_income: 6_653 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: New applicant of 7 at 7,500 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + mt_ccap_countable_income: 7_500 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: New applicant of 7 at 7,501 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + mt_ccap_countable_income: 7_501 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: New applicant of 8 at 8,348 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + person8: + age: 16 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + mt_ccap_countable_income: 8_348 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: New applicant of 8 at 8,349 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + person8: + age: 16 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + mt_ccap_countable_income: 8_349 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: Continuing family of 2 at 3,525 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + mt_ccap_countable_income: 3_525 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: Continuing family of 2 at 3,526 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + mt_ccap_countable_income: 3_526 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: Continuing family of 3 at 4,442 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 4_442 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: Continuing family of 3 at 4,443 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 4_443 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: Continuing family of 4 at 5,358 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + mt_ccap_countable_income: 5_358 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: Continuing family of 4 at 5,359 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + mt_ccap_countable_income: 5_359 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: Continuing family of 5 at 6,275 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + mt_ccap_countable_income: 6_275 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: Continuing family of 5 at 6,276 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + mt_ccap_countable_income: 6_276 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: Continuing family of 6 at 7,192 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6] + mt_ccap_countable_income: 7_192 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3, person4, person5, person6] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: Continuing family of 6 at 7,193 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6] + mt_ccap_countable_income: 7_193 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3, person4, person5, person6] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: Continuing family of 7 at 8,108 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + mt_ccap_countable_income: 8_108 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: Continuing family of 7 at 8,109 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + mt_ccap_countable_income: 8_109 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: Continuing family of 8 at 9,025 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + person8: + age: 16 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + mt_ccap_countable_income: 9_025 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: true + +- name: Continuing family of 8 at 9,026 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + person8: + age: 16 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + mt_ccap_countable_income: 9_026 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: + 2026: MT + output: + mt_ccap_income_eligible: false + +- name: New applicant of 3 at 4,109 dollars qualifies in 2025-08. + period: 2025-08 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 4_109 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MT + output: + mt_ccap_income_eligible: true + +- name: New applicant of 3 at 4,110 dollars doesn't qualify in 2025-08. + period: 2025-08 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 4_110 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MT + output: + mt_ccap_income_eligible: false + +- name: Continuing family of 3 at 4,442 dollars qualifies in 2025-08. + period: 2025-08 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 4_442 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MT + output: + mt_ccap_income_eligible: true + +- name: Continuing family of 3 at 4,443 dollars doesn't qualify in 2025-08. + period: 2025-08 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 4_443 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MT + output: + mt_ccap_income_eligible: false + +- name: New applicant of 3 at 3,981 dollars qualifies in 2025-03. + period: 2025-03 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 3_981 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MT + output: + mt_ccap_income_eligible: true + +- name: New applicant of 3 at 3,982 dollars doesn't qualify in 2025-03. + period: 2025-03 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 3_982 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MT + output: + mt_ccap_income_eligible: false + +- name: Continuing family of 3 at 3,981 dollars qualifies in 2025-03. + period: 2025-03 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 3_981 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MT + output: + mt_ccap_income_eligible: true + +- name: Continuing family of 3 at 3,982 dollars doesn't qualify in 2025-03. + period: 2025-03 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 3_982 + is_tanf_enrolled: false + mt_ccap_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2025: MT + output: + mt_ccap_income_eligible: false + +- name: New applicant of 3 at 3,833 dollars qualifies in 2023-08. + period: 2023-08 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 3_833 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2023: MT + output: + mt_ccap_income_eligible: true + +- name: New applicant of 3 at 3,834 dollars doesn't qualify in 2023-08. + period: 2023-08 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 3_834 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2023: MT + output: + mt_ccap_income_eligible: false + +- name: New applicant of 3 at 3,108 dollars qualifies in 2023-03. + period: 2023-03 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 3_108 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2023: MT + output: + mt_ccap_income_eligible: true + +- name: New applicant of 3 at 3,109 dollars doesn't qualify in 2023-03. + period: 2023-03 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + mt_ccap_countable_income: 3_109 + is_tanf_enrolled: false + mt_ccap_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2023: MT + output: + mt_ccap_income_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/edge_cases.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/edge_cases.yaml index cc5ed1c6c19..ad5278b0e2f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/edge_cases.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/edge_cases.yaml @@ -1,10 +1,11 @@ # WV CCAP Edge Case Tests # Income test: 185% FPL initial intake cap (Manual §3.2.1, Appendix A). -# 2025 FPG (Contiguous US): first_person = 15_650, additional = 5_500. -# Family of 2 FPG = 21_150/yr = 1_762.50/mo; family of 3 = 26_650/yr. -# 185% FPL family of 2 = 21_150 * 1.85 = 39_127.50/yr -# 185% FPL family of 3 = 26_650 * 1.85 = 49_302.50/yr -# 185% FPL family of 11 = 70_650 * 1.85 = 130_702.50/yr +# Appendix A uses the 2024 FPG (Contiguous US): first_person = 15_060, additional = 5_380. +# Family of 2 FPG = 20_440/yr = 1_703.33/mo; family of 3 = 25_820/yr. +# Intake cap (185% FPL, nearest dollar a month): +# family of 2 = 3_151/mo = 37_812/yr +# family of 3 = 3_981/mo = 47_772/yr +# family of 11 = 68_860 * 1.85 / 12 -> 10_616/mo = 127_392/yr # ============================================================ # Income threshold boundaries (185% FPL) @@ -39,7 +40,7 @@ members: [person1, person2] state_code: WV output: - # $24,000/yr is well below 185% FPL family of 2 ($39,127.50/yr) → eligible. + # $24,000/yr is well below the family of 2 cap ($37,812/yr) → eligible. wv_ccap_income_eligible: true - name: Case 2, income just below 185% FPL eligible. @@ -49,8 +50,8 @@ person1: age: 30 weekly_hours_worked_before_lsr: 40 - # 185% FPL family of 2 = $39,127.50/yr - employment_income: 39_000 + # Family of 2 cap = $37,812/yr + employment_income: 37_800 immigration_status: CITIZEN person2: age: 3 @@ -82,8 +83,8 @@ person1: age: 30 weekly_hours_worked_before_lsr: 40 - # Just above 185% FPL family of 2 ($39,127.50/yr) - employment_income: 39_200 + # Just above the family of 2 cap ($37,812/yr) + employment_income: 37_900 immigration_status: CITIZEN person2: age: 3 @@ -119,8 +120,8 @@ person1: age: 30 weekly_hours_worked_before_lsr: 40 - # 185% FPL family of 3 = $49,302.50/yr - employment_income: 48_000 + # Family of 3 cap = $47,772/yr + employment_income: 47_700 immigration_status: CITIZEN person2: age: 3 @@ -178,8 +179,8 @@ person1: age: 30 weekly_hours_worked_before_lsr: 40 - # Just above 185% FPL family of 3 ($49,302.50/yr) - employment_income: 50_000 + # Just above the family of 3 cap ($47,772/yr) + employment_income: 47_800 immigration_status: CITIZEN person2: age: 3 @@ -214,8 +215,8 @@ person1: age: 30 weekly_hours_worked_before_lsr: 40 - # 185% FPL family of 11 = $130,702.50/yr - employment_income: 131_000 + # Family of 11 cap = $127,392/yr + employment_income: 127_500 immigration_status: CITIZEN person2: age: 3 @@ -278,7 +279,7 @@ person1: age: 30 weekly_hours_worked_before_lsr: 40 - # Below 185% FPL family of 11 ($130,702.50/yr) + # Below the family of 11 cap ($127,392/yr) employment_income: 100_000 immigration_status: CITIZEN person2: @@ -560,8 +561,8 @@ person1: age: 30 weekly_hours_worked_before_lsr: 40 - # 40% FPL family of 2 = 21_150 * 0.4 = 8_460/yr - employment_income: 8_460 + # 40% FPL family of 2 = 20_440 * 0.4 = 8_176/yr + employment_income: 8_176 immigration_status: CITIZEN person2: age: 3 @@ -583,8 +584,8 @@ members: [person1, person2] state_code: WV output: - # monthly income = 8_460 / 12 = 705 - # FPL ratio = 705 / 1_762.50 = 0.4 + # monthly income = 8_176 / 12 = 681.33 + # FPL ratio = 681.33 / 1_703.33 = 0.4 # Threshold for non-zero copay is 0.4001, so 0.4 -> 0% bracket wv_ccap_copay: 0 @@ -597,8 +598,8 @@ age: 30 weekly_hours_worked_before_lsr: 40 # Just above 40% FPL: need FPL ratio > 0.4001 - # 21_150 * 0.4001 = 8_462.12/yr; use 8_475 -> ratio ~0.4008 - employment_income: 8_475 + # 20_440 * 0.4001 = 8_178.04/yr; use 8_190 -> ratio ~0.4007 + employment_income: 8_190 immigration_status: CITIZEN person2: age: 3 @@ -620,10 +621,10 @@ members: [person1, person2] state_code: WV output: - # Monthly income = 8_475 / 12 = $706.25. FPL ratio = 0.4007 > 0.4001 → bracket + # Monthly income = 8_190 / 12 = $682.50. FPL ratio = 0.4007 > 0.4001 → bracket # "above 40% up to 50%" → Appendix A 2-person "50%" row daily fee = $2.00/child. # copay = $2.00 × 22 × 1 = $44. - # 7% cap = $706.25 × 0.07 = $49.44; cap does not bind. + # 7% cap = $682.50 × 0.07 = $47.78; cap does not bind. wv_ccap_copay: 44 # ============================================================ @@ -638,8 +639,8 @@ person1: age: 30 weekly_hours_worked_before_lsr: 40 - # ~170% FPL family of 2: 21_150 * 1.7 = 35_955/yr. - employment_income: 35_955 + # ~170% FPL family of 2: 20_440 * 1.7 = 34_748/yr. + employment_income: 34_748 immigration_status: CITIZEN person2: age: 3 @@ -661,10 +662,10 @@ members: [person1, person2] state_code: WV output: - # Monthly income = $2_996.25. FPL ratio = 1.7000 → bracket "above 160% up to 170%" + # Monthly income = $2_895.67. FPL ratio = 1.7000 → bracket "above 160% up to 170%" # → Appendix A 2-person "170%" row daily fee = $8.25/child. # uncapped copay = $8.25 × 22 × 1 = $181.50. - # 7% cap = $2_996.25 × 0.07 = $209.74; cap does not bind. + # 7% cap = $2_895.67 × 0.07 = $202.70; cap does not bind. wv_ccap_copay: 181.5 - name: Case 19, large family with three children triggers 7 percent cap. @@ -856,7 +857,7 @@ state_code: WV output: # Foster child -> copay = $0 regardless of income - # FPL ratio would be ~1.42 -> normally 3.5% bracket + # FPL ratio would be ~1.47 -> normally 3.5% bracket # But foster child exemption overrides wv_ccap_copay: 0 @@ -1509,7 +1510,7 @@ # daily benefit = min(45, 13.64) = 13.64 wv_ccap_daily_benefit: [0, 13.64] - # 2-person family, FPL ratio = 2_000 / 1_762.50 = 1.1348. + # 2-person family, FPL ratio = 2_000 / 1_703.33 = 1.1742. # Appendix A 2-person "120%" row daily fee = $5.75/child; 22 days. # copay = $5.75 × 22 = $126.50. # 22 days > 20 → per-day billing; per_child = min($45 × 22, $300) = $300. diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/integration.yaml index e2f4a607820..ca9ffdf6021 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/integration.yaml @@ -1,8 +1,8 @@ # WV CCAP Integration Tests -# 2025 FPG (Contiguous US): -# first_person = 15_650, additional = 5_500 -# Family of 2: 21_150 -# Family of 3: 26_650 +# Appendix A uses the 2024 FPG (Contiguous US): +# first_person = 15_060, additional = 5_380 +# Family of 2: 20_440 +# Family of 3: 25_820 - name: Case 1, basic eligible family with center care. period: 2025-01 @@ -37,7 +37,7 @@ # === Eligibility === wv_ccap_eligible_child: [false, true] - # 185% FPL family of 2 = $39,127.50/yr; $24,000/yr → eligible. + # The family of 2 cap = $37,812/yr; $24,000/yr → eligible. wv_ccap_income_eligible: true is_ccdf_asset_eligible: true wv_ccap_eligible: true @@ -51,7 +51,7 @@ wv_ccap_daily_rate: [0, 37] # === Copay === - # 2-person family, FPL ratio = 2_000 / 1_762.50 = 1.1348. + # 2-person family, FPL ratio = 2_000 / 1_703.33 = 1.1742. # Appendix A 2-person "120%" row daily fee = $5.75/child. # 1 eligible child × 22 monthly days. # copay = $5.75 × 22 × 1 = $126.50. @@ -107,7 +107,7 @@ # Family Home Tier I Infant = $30/day wv_ccap_daily_rate: [0, 30] - # FPL ratio = 500 / 1_762.50 = 0.2837 < 0.40 -> 0% copay + # FPL ratio = 500 / 1_703.33 = 0.2935 < 0.40 -> 0% copay wv_ccap_copay: 0 # daily charge = 500 / 22 = 22.73 @@ -124,7 +124,7 @@ people: person1: age: 35 - # Above 185% FPL family of 2 ($39,127.50/yr). + # Above the family of 2 cap ($37,812/yr). employment_income: 60_000 immigration_status: CITIZEN weekly_hours_worked: 40 @@ -148,7 +148,7 @@ members: [person1, person2] state_code: WV output: - # $60,000/yr > 185% FPL family of 2 ($39,127.50/yr). + # $60,000/yr > the family of 2 cap ($37,812/yr). wv_ccap_income_eligible: false wv_ccap_eligible: false wv_ccap: 0 @@ -200,7 +200,7 @@ # daily charge = (10_000/12) / 22 = 37.88; daily benefit = min(35+3, 37.88) = 37.88. wv_ccap_daily_benefit: [0, 37.88] - # Copay: same 2-person FPL 1.1348 → Appendix A "120%" row $5.75/day × 22 = $126.50. + # Copay: same 2-person FPL 1.1742 → Appendix A "120%" row $5.75/day × 22 = $126.50. wv_ccap_copay: 126.5 # 22 days/month > 20 → per-day billing for base. @@ -272,7 +272,7 @@ wv_ccap_daily_rate: [0, 37] # 17 days/month is in the 13-20 monthly-rate range. # Base reimbursement (monthly rate): $37 × 20 = $740. - # Copay: 2-person FPL 1.1348 → Appendix A "120%" row $5.75/day × 17 = $97.75. + # Copay: 2-person FPL 1.1742 → Appendix A "120%" row $5.75/day × 17 = $97.75. wv_ccap_copay: 97.75 # benefit = max($740 - $97.75, 0) = $642.25. wv_ccap: 642.25 @@ -357,7 +357,7 @@ # 9 days/month is below the 13-day monthly-rate threshold. # Center Tier I Toddler = $37/day; daily charge = $1_000 / 9 = $111.11. wv_ccap_daily_benefit: [0, 37] - # Copay: 2-person FPL 1.1348 → Appendix A "120%" row $5.75/day × 9 = $51.75. + # Copay: 2-person FPL 1.1742 → Appendix A "120%" row $5.75/day × 9 = $51.75. wv_ccap_copay: 51.75 # Per-child reimbursement is capped before copay: # max(min($1_000 expense, $37 × 9 max rate) - $51.75, 0) = $281.25. diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_copay.yaml index 0192752bd40..4c4c3f34b77 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_copay.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_copay.yaml @@ -3,7 +3,7 @@ # Manual §6.4.3.2: fees are daily, charged for each child in care. # Manual §6.4.3.4: capped at the three youngest children. # CCDF Plan §3.1.1: total family fee capped at 7% of gross income. -# 2025 FPG family of 2 monthly: $1_762.50. +# Appendix A's 2024 FPG for a family of 2: $1_703.33 a month. - name: Case 1, income below 40% FPL pays zero copay. period: 2025-01 @@ -27,7 +27,7 @@ members: [person1, person2] state_code: WV output: - # FPL ratio = 500 / 1_762.50 = 0.2837 < 0.40 -> fee = $0/day. + # FPL ratio = 500 / 1_703.33 = 0.2935 < 0.40 -> fee = $0/day. wv_ccap_copay: 0 - name: Case 2, mid-range income copay from Appendix A daily fee. @@ -52,7 +52,7 @@ members: [person1, person2] state_code: WV output: - # Monthly income $1_500; FPL ratio = 1_500 / 1_762.50 = 0.8511. + # Monthly income $1_500; FPL ratio = 1_500 / 1_703.33 = 0.8806. # Appendix A 2-person "90%" row daily fee = $4.25/child. # 1 eligible child × 22 monthly days. # copay = $4.25 × 22 × 1 = $93.50. @@ -80,7 +80,7 @@ members: [person1, person2] state_code: WV output: - # Monthly income $3_000; FPL ratio = 3_000 / 1_762.50 = 1.7021. + # Monthly income $3_000; FPL ratio = 3_000 / 1_703.33 = 1.7613. # Appendix A 2-person "180%" row daily fee = $8.75/child. # uncapped copay = $8.75 × 22 = $192.50. # 7% cap = $3_000 × 0.07 = $210. Cap does not bind for 2-person, 1-child. @@ -156,7 +156,7 @@ state_code: WV output: # Family size 12 defaults to the 11-person column. - # FPL ratio = 5_400 / 6_345.83 = 0.8511, so Appendix A 11-person "90%" row = $4.50/day. + # FPL ratio = 5_400 / 6_186.67 = 0.8729, so Appendix A 11-person "90%" row = $4.50/day. # 1 eligible child × 22 monthly days. # copay = $4.50 × 22 = $99. wv_ccap_copay: 99 @@ -192,9 +192,34 @@ members: [person1, person2, person3, person4, person5] state_code: WV output: - # Family size 5, FPL ratio = 2_500 / 3_137.50 = 0.7968. - # Appendix A 5-person "80%" row daily fee = $2.25/child. + # Family size 5, FPL ratio = 2_500 / 3_048.33 = 0.8201. + # Appendix A 5-person "90%" row daily fee = $2.50/child. # 4 eligible children × 22 monthly days = 88 monthly days. # Three-child cap scales billed days by 3/4: 88 × 3/4 = 66. - # copay = $2.25 × 66 = $148.50. - wv_ccap_copay: 148.5 + # copay = $2.50 × 66 = $165. + wv_ccap_copay: 165 + +- name: A family of three at 3,000 dollars a month pays the 140 percent row in 2026. + period: 2026-01 + absolute_error_margin: 0.01 + # FPL ratio = 3,000 / 2,151.67 = 1.394, Appendix A's row from $2,797.01 to $3,012, + # at $4.25 a day. 4.25 x 22 days = 93.50; the 7% cap of $210 doesn't bind. + input: + people: + person1: + age: 30 + person2: + age: 4 + childcare_attending_days_per_month: 22 + person3: + age: 12 + spm_units: + spm_unit: + members: [person1, person2, person3] + wv_ccap_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: WV + output: + wv_ccap_copay: 93.5 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_fpg.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_fpg.yaml new file mode 100644 index 00000000000..3c8756f1524 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_fpg.yaml @@ -0,0 +1,67 @@ +# Tests for wv_ccap_fpg (SPMUnit, MONTH). Appendix A prints the 2024 guideline, and the +# Bureau still linked that scale on November 5, 2026. +- name: 2024-11 uses the 2024 guideline. + period: 2024-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2024: WV + output: + wv_ccap_fpg: 2_151.67 + +- name: 2025-06 uses the 2024 guideline. + period: 2025-06 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2025: WV + output: + wv_ccap_fpg: 2_151.67 + +- name: 2026-11 uses the 2024 guideline. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2026: WV + output: + wv_ccap_fpg: 2_151.67 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml index 0c1b030eda2..51bf833065f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml @@ -1,6 +1,6 @@ # WV CCAP Income Eligibility Tests # Initial intake cap: 185% FPL (Manual §3.2.1, Appendix A) -# 185% FPL for a 2-person family (2025) = $39,127.50/yr +# Appendix A prints the 185% cap for a 2-person family at $3,151/mo, or $37,812/yr, on the 2024 FPG - name: Case 1, income below 185% FPL eligible. period: 2025-01 @@ -54,8 +54,8 @@ people: person1: age: 30 - # 2-person family: 185% FPL ≈ $39,127.50 - employment_income: 39_000 + # 2-person family: cap = $37,812/yr + employment_income: 37_800 person2: age: 5 tax_units: @@ -97,3 +97,558 @@ # NOTE: we don't model "TANF children-only" cases (§3.2.1.4) that must # still meet the income test at the moment. wv_ccap_income_eligible: true + +# Appendix A's intake caps on the 2024 guideline, which the Bureau still linked on +# November 5, 2026. + +- name: New applicant of 3 at 3,981 dollars qualifies in 2024-11. + period: 2024-11 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + wv_ccap_countable_income: 3_981 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: WV + output: + wv_ccap_income_eligible: true + +- name: New applicant of 3 at 3,982 dollars doesn't qualify in 2024-11. + period: 2024-11 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + wv_ccap_countable_income: 3_982 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: WV + output: + wv_ccap_income_eligible: false + +- name: New applicant of 3 at 3,981 dollars qualifies in 2025-06. + period: 2025-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + wv_ccap_countable_income: 3_981 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: WV + output: + wv_ccap_income_eligible: true + +- name: New applicant of 3 at 3,982 dollars doesn't qualify in 2025-06. + period: 2025-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + wv_ccap_countable_income: 3_982 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: WV + output: + wv_ccap_income_eligible: false + +- name: New applicant of 1 at 2,322 dollars qualifies in 2026-01. + period: 2026-01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + wv_ccap_countable_income: 2_322 + households: + household: + members: [person1] + state_code: WV + output: + wv_ccap_income_eligible: true + +- name: New applicant of 1 at 2,323 dollars doesn't qualify in 2026-01. + period: 2026-01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + wv_ccap_countable_income: 2_323 + households: + household: + members: [person1] + state_code: WV + output: + wv_ccap_income_eligible: false + +- name: New applicant of 2 at 3,151 dollars qualifies in 2026-01. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + wv_ccap_countable_income: 3_151 + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_income_eligible: true + +- name: New applicant of 2 at 3,152 dollars doesn't qualify in 2026-01. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + wv_ccap_countable_income: 3_152 + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_income_eligible: false + +- name: New applicant of 3 at 3,981 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + wv_ccap_countable_income: 3_981 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: true + +- name: New applicant of 3 at 3,982 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + wv_ccap_countable_income: 3_982 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: false + +- name: New applicant of 4 at 4,810 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + wv_ccap_countable_income: 4_810 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: true + +- name: New applicant of 4 at 4,811 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + wv_ccap_countable_income: 4_811 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: false + +- name: New applicant of 5 at 5,639 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + wv_ccap_countable_income: 5_639 + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: true + +- name: New applicant of 5 at 5,640 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + wv_ccap_countable_income: 5_640 + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: false + +- name: New applicant of 6 at 6,469 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6] + wv_ccap_countable_income: 6_469 + households: + household: + members: [person1, person2, person3, person4, person5, person6] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: true + +- name: New applicant of 6 at 6,470 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6] + wv_ccap_countable_income: 6_470 + households: + household: + members: [person1, person2, person3, person4, person5, person6] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: false + +- name: New applicant of 7 at 7,298 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + wv_ccap_countable_income: 7_298 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: true + +- name: New applicant of 7 at 7,299 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + wv_ccap_countable_income: 7_299 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: false + +- name: New applicant of 8 at 8,128 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + person8: + age: 16 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + wv_ccap_countable_income: 8_128 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: true + +- name: New applicant of 8 at 8,129 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + person8: + age: 16 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + wv_ccap_countable_income: 8_129 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: false + +- name: New applicant of 9 at 8,957 dollars qualifies in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + person8: + age: 16 + person9: + age: 17 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + wv_ccap_countable_income: 8_957 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: true + +- name: New applicant of 9 at 8,958 dollars doesn't qualify in 2026-06. + period: 2026-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + person4: + age: 9 + person5: + age: 11 + person6: + age: 13 + person7: + age: 15 + person8: + age: 16 + person9: + age: 17 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + wv_ccap_countable_income: 8_958 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + state_code: + 2026: WV + output: + wv_ccap_income_eligible: false diff --git a/policyengine_us/variables/gov/states/in/fssa/ccdf/copay/in_ccdf_copay.py b/policyengine_us/variables/gov/states/in/fssa/ccdf/copay/in_ccdf_copay.py index 1a14cf6e753..b7a0be5bfe9 100644 --- a/policyengine_us/variables/gov/states/in/fssa/ccdf/copay/in_ccdf_copay.py +++ b/policyengine_us/variables/gov/states/in/fssa/ccdf/copay/in_ccdf_copay.py @@ -18,7 +18,7 @@ def formula(spm_unit, period, parameters): # Income is floored at zero so a self-employment loss cannot produce a # negative copay. countable_income = max_(spm_unit("in_ccdf_countable_income", period), 0) - fpg = spm_unit("spm_unit_fpg", period) + fpg = spm_unit("in_ccdf_fpg", period) fpg_ratio = where(fpg > 0, countable_income / fpg, 0) # The sliding fee schedule also varies by years on the program (Year # 1-3 through Year 10+); we don't track program tenure at the moment, diff --git a/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.py b/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.py new file mode 100644 index 00000000000..fa91749dfb0 --- /dev/null +++ b/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class in_ccdf_fpg(Variable): + value_type = float + entity = SPMUnit + unit = USD + definition_period = MONTH + label = "Indiana CCDF monthly federal poverty guideline" + defined_for = StateCode.IN + reference = "https://www.in.gov/dA/3271c7180e/Income-Get-on-CCDF.pdf" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states["in"].fssa.ccdf.income + size = spm_unit("spm_unit_size", period.this_year) + state_group = spm_unit.household("state_group_str", period.this_year) + annual_fpg = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) + return annual_fpg / MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.py b/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.py index 55ee7ee1917..416447c229c 100644 --- a/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.py +++ b/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.py @@ -7,7 +7,10 @@ class in_ccdf_income_eligible(Variable): label = "Indiana CCDF income eligible" definition_period = MONTH defined_for = StateCode.IN - reference = "https://www.in.gov/fssa/carefinder/files/CCDF-Policy-Manual.pdf#page=5" + reference = ( + "https://www.in.gov/fssa/carefinder/files/CCDF-Policy-Manual.pdf#page=5", + "https://www.in.gov/dA/3271c7180e/Income-Get-on-CCDF.pdf", + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states["in"].fssa.ccdf.income @@ -16,8 +19,12 @@ def formula(spm_unit, period, parameters): # Initial applicants are tested against the get-on share of the # federal poverty guideline (127% through Jul 2023, 150% from Aug # 2023, 135% from Apr 2026); enrolled recipients are tested at 85% - # of the state median income. - initial_limit = spm_unit("spm_unit_fpg", period) * p.get_on_fpg_rate + # of the state median income. FSSA's charts print each limit to the + # nearest dollar, with half a dollar going up ($3,073.50 prints as + # $3,074). Round to cents first so floating-point noise can't move a tie. + initial_limit = np.floor( + np.round(spm_unit("in_ccdf_fpg", period) * p.get_on_fpg_rate, 2) + 0.5 + ) continuing_limit = spm_unit("hhs_smi", period) * p.stay_on_smi_rate income_limit = where(enrolled, continuing_limit, initial_limit) return countable_income <= income_limit diff --git a/policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_fpg.py b/policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_fpg.py new file mode 100644 index 00000000000..5210c819b13 --- /dev/null +++ b/policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_fpg.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class mo_ccs_fpg(Variable): + value_type = float + entity = SPMUnit + unit = USD + definition_period = MONTH + label = "Missouri Child Care Subsidy monthly federal poverty guideline" + defined_for = StateCode.MO + reference = "https://dese.mo.gov/sites/g/files/zuston521/files/media/pdf/2026/07/Income%20Elig%20_Updated%206.29.26.pdf#page=1" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.mo.dese.ccs.income + size = spm_unit("spm_unit_size", period.this_year) + state_group = spm_unit.household("state_group_str", period.this_year) + annual_fpg = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) + return annual_fpg / MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.py b/policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.py index dbf13b948a6..58ac993e8d4 100644 --- a/policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.py +++ b/policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.py @@ -10,21 +10,21 @@ class mo_ccs_income_eligible(Variable): reference = ( "https://web.archive.org/web/20250831220820id_/https://dese.mo.gov/childhood/quality-programs/child-care-subsidy/child-care-manual/2010/045/00", "https://www.law.cornell.edu/regulations/missouri/5-CSR-25-200-060", + "https://dese.mo.gov/sites/g/files/zuston521/files/media/pdf/2026/07/Income%20Elig%20_Updated%206.29.26.pdf#page=1", ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.mo.dese.ccs.income.fpl_rate p_ccdf = parameters(period).gov.hhs.ccdf adjusted_income = spm_unit("mo_ccs_adjusted_income", period) - monthly_fpg = spm_unit("spm_unit_fpg", period) + monthly_fpg = spm_unit("mo_ccs_fpg", period) # New applicants use the traditional FPG limit; existing families may # qualify up to the higher transitional limit. enrolled = spm_unit("mo_ccs_enrolled", period) - fpg_limit = where( - enrolled, - monthly_fpg * p.transitional, - monthly_fpg * p.initial_eligibility, - ) + fpg_rate = where(enrolled, p.transitional, p.initial_eligibility) + # DESE's chart prints each limit to the nearest dollar. Round to cents + # first so floating-point noise can't move a tie. + fpg_limit = np.floor(np.round(monthly_fpg * fpg_rate, 2) + 0.5) # Adjusted gross income may also not exceed 85% of the state median # income at application (Manual sec. 4.7). In practice the FPG limit is # the binding ceiling at all realistic household sizes; the 85% SMI cap diff --git a/policyengine_us/variables/gov/states/mo/dese/ccs/mo_ccs.py b/policyengine_us/variables/gov/states/mo/dese/ccs/mo_ccs.py index e535d7f52ac..662a66c9a55 100644 --- a/policyengine_us/variables/gov/states/mo/dese/ccs/mo_ccs.py +++ b/policyengine_us/variables/gov/states/mo/dese/ccs/mo_ccs.py @@ -29,7 +29,7 @@ def formula(spm_unit, period, parameters): # families are funded at the full rate, so the multiplier is 1 and the # order has no effect. adjusted_income = spm_unit("mo_ccs_adjusted_income", period) - monthly_fpg = spm_unit("spm_unit_fpg", period) + monthly_fpg = spm_unit("mo_ccs_fpg", period) fpl_ratio = where(monthly_fpg > 0, adjusted_income / monthly_fpg, 0) funding_rate = p.transitional.funding_rate.calc(fpl_ratio) return funding_rate * max_(total_reimbursement - copay, 0) diff --git a/policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_fpg.py b/policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_fpg.py new file mode 100644 index 00000000000..c930ebc8f9c --- /dev/null +++ b/policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_fpg.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class mt_ccap_fpg(Variable): + value_type = float + entity = SPMUnit + unit = USD + definition_period = MONTH + label = "Montana CCAP monthly federal poverty guideline" + defined_for = StateCode.MT + reference = "https://dphhs.mt.gov/assets/ecfsd/childcare/policymanual/SlidingFeeScale07012023.pdf#page=1" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.mt.dphhs.ccap.income + size = spm_unit("spm_unit_size", period.this_year) + state_group = spm_unit.household("state_group_str", period.this_year) + annual_fpg = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) + return annual_fpg / MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_income_eligible.py b/policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_income_eligible.py index d5730918738..ded6470b9a7 100644 --- a/policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_income_eligible.py +++ b/policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_income_eligible.py @@ -9,39 +9,31 @@ class mt_ccap_income_eligible(Variable): defined_for = StateCode.MT reference = ( "https://www.law.cornell.edu/regulations/montana/Mont-Admin-r-37.80.202", + "https://archive.legmt.gov/bills/MCA/title_0520/chapter_0020/part_0070/section_0150/0520-0020-0070-0150.html", "https://dphhs.mt.gov/assets/ecfsd/childcare/policymanual/SlidingFeeScale07012023.pdf#page=1", ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.mt.dphhs.ccap.income countable_income = spm_unit("mt_ccap_countable_income", period) - fpg = spm_unit("spm_unit_fpg", period) - # ARM 37.80.202(1): initial eligibility for income below 150% FPG (first- - # time applicant). ARM 37.80.202(2): graduated eligibility for non-TANF - # households at annual redetermination, income below 185% FPG. We proxy "at - # redetermination / continuing recipient" with the mt_ccap_enrolled input; - # first-time applicants (the default) use the 150% initial limit. + fpg = spm_unit("mt_ccap_fpg", period) + # MCA 52-2-715(1) sets the threshold for applicants at no less than 185% + # FPG, and the Sliding Fee Scale ends Standard Eligibility at that row. + # ARM 37.80.202 still prints 150% and 185%; the statute and the scale + # govern. The scale's Graduated Eligibility runs to 200% FPG for families + # already on the program at annual redetermination. We proxy "at + # redetermination / continuing recipient" with the mt_ccap_enrolled input. # - # NOTE on the ARM (185%) vs operational Sliding Fee Scale (200% "EXIT") - # ceiling: the published scale runs its graduated tier to 200% FPG, but - # ARM 37.80.202(2)'s rule text caps graduated eligibility at 185% FPG. We - # follow the ARM rule text (gov.states.mt.dphhs.ccap.income.fpg_limit. - # graduated = 1.85). Raising it to 2.0 to match the operational scale is a - # policy question pending DPHHS confirmation, so it is documented, not - # changed. The copay scale retains its 190/195/200% brackets to mirror the - # published table even though they are unreachable at the 185% ceiling. - # - # FPG uses an exclusive `<` ("below" in the ARM text); the 85% SMI overlay - # below uses `<=` because 45 CFR 98.20(a)(2) frames it as remaining "at or - # below" 85% SMI. The two comparators intentionally differ. (The exact-cent - # FPG boundary is float32-precision sensitive since monthly income and - # monthly FPG are each annual/12; unit tests pin the +/- $1 behavior.) + # The scale prints the top income of each row to the nearest dollar, and a + # family at that income belongs to the row, so the test is at or below the + # rounded limit. Round to cents first so floating-point noise can't move a tie. enrolled = spm_unit("mt_ccap_enrolled", period) fpg_rate = where(enrolled, p.fpg_limit.graduated, p.fpg_limit.initial) - fpg_eligible = countable_income < fpg * fpg_rate + fpg_limit = np.floor(np.round(fpg * fpg_rate, 2) + 0.5) + fpg_eligible = countable_income <= fpg_limit # 85% SMI ineligibility overlay (45 CFR 98.20(a)(2) / Sliding Fee Scale). - # With the 185% FPG ceiling the FPG limit binds first for all but the - # largest households, so this rarely controls eligibility. + # The FPG limit binds first for all but the largest households, so this + # rarely controls eligibility. smi = spm_unit("hhs_smi", period) smi_eligible = countable_income <= smi * p.income_limit_smi_rate income_eligible = fpg_eligible & smi_eligible diff --git a/policyengine_us/variables/gov/states/mt/dphhs/ccap/mt_ccap_copay.py b/policyengine_us/variables/gov/states/mt/dphhs/ccap/mt_ccap_copay.py index a5b665264bd..00616891007 100644 --- a/policyengine_us/variables/gov/states/mt/dphhs/ccap/mt_ccap_copay.py +++ b/policyengine_us/variables/gov/states/mt/dphhs/ccap/mt_ccap_copay.py @@ -16,7 +16,7 @@ class mt_ccap_copay(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.mt.dphhs.ccap.copayment gmi = spm_unit("mt_ccap_countable_income", period) - fpg = spm_unit("spm_unit_fpg", period) + fpg = spm_unit("mt_ccap_fpg", period) fpg_ratio = where(fpg > 0, gmi / fpg, 0) # Non-TANF families pay the greater of GMI times the sliding-scale diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_fpg.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_fpg.py new file mode 100644 index 00000000000..f3f95efdfa0 --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_fpg.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg + + +class wv_ccap_fpg(Variable): + value_type = float + entity = SPMUnit + unit = USD + definition_period = MONTH + label = "West Virginia CCAP monthly federal poverty guideline" + defined_for = StateCode.WV + reference = "https://bfa.wv.gov/media/6826/download?inline#page=1" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.wv.dhhr.ccap.income + size = spm_unit("spm_unit_size", period.this_year) + state_group = spm_unit.household("state_group_str", period.this_year) + annual_fpg = fpg(size, state_group, period, parameters, year_lag=p.fpg_year_lag) + return annual_fpg / MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_income_eligible.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_income_eligible.py index 2ff825bb907..428e17f9f85 100644 --- a/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_income_eligible.py +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_income_eligible.py @@ -20,7 +20,10 @@ def formula(spm_unit, period, parameters): # full TANF — is_tanf_enrolled treats both as categorically eligible. p = parameters(period).gov.states.wv.dhhr.ccap.income countable_income = spm_unit("wv_ccap_countable_income", period) - fpg = spm_unit("spm_unit_fpg", period) - fpl_eligible = countable_income <= fpg * p.fpl_limit + fpg = spm_unit("wv_ccap_fpg", period) + # Appendix A prints each limit to the nearest dollar. Round to cents + # first so floating-point noise can't move a tie. + fpl_limit = np.floor(np.round(fpg * p.fpl_limit, 2) + 0.5) + fpl_eligible = countable_income <= fpl_limit is_tanf = spm_unit("is_tanf_enrolled", period) return is_tanf | fpl_eligible diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_copay.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_copay.py index 5899b1d011b..79cf7a03e81 100644 --- a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_copay.py +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_copay.py @@ -20,7 +20,7 @@ def formula(spm_unit, period, parameters): # in care. Manual §6.4.3.4: capped at three youngest children. p = parameters(period).gov.states.wv.dhhr.ccap.copayment countable_income = spm_unit("wv_ccap_countable_income", period) - fpg = spm_unit("spm_unit_fpg", period) + fpg = spm_unit("wv_ccap_fpg", period) fpl_ratio = where(fpg > 0, countable_income / fpg, 0) family_size = spm_unit("spm_unit_size", period.this_year) # Look up daily fee per child from Appendix A by family size column. From 5e0a1ca1f45c8d8070d98a0473ca980118aca8cb Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 6 Nov 2026 09:39:42 -0500 Subject: [PATCH 03/13] Date Nevada's child care income limits and copay schedules Nevada's limit for new applicants stood at 85% of state median income through 2017, fell to a first tier of about 130% of poverty by October 2018, returned to 85% on July 1, 2022, and fell to 41% on October 1, 2024. Enrolled families kept 85% until renewals moved to 49% on October 1, 2024. Copayments follow three dated rules: federal funds reimbursed them from July 1, 2022 through March 2024; the chart effective October 1, 2023 charged 0% to 7% of gross income from April through September 2024; and the flat $0, $90 or $150 starts October 1, 2024. The per-size schedules transcribe the state's chart. Co-Authored-By: Claude Opus 5.5 --- .../gov/states/nv/dwss/ccdp/copay/amount.yaml | 4 + .../copay/percent_of_income/in_effect.yaml | 18 + .../ccdp/copay/percent_of_income/size_1.yaml | 50 + .../ccdp/copay/percent_of_income/size_10.yaml | 50 + .../ccdp/copay/percent_of_income/size_11.yaml | 50 + .../ccdp/copay/percent_of_income/size_12.yaml | 50 + .../ccdp/copay/percent_of_income/size_13.yaml | 50 + .../ccdp/copay/percent_of_income/size_14.yaml | 50 + .../ccdp/copay/percent_of_income/size_2.yaml | 50 + .../ccdp/copay/percent_of_income/size_3.yaml | 50 + .../ccdp/copay/percent_of_income/size_4.yaml | 50 + .../ccdp/copay/percent_of_income/size_5.yaml | 50 + .../ccdp/copay/percent_of_income/size_6.yaml | 50 + .../ccdp/copay/percent_of_income/size_7.yaml | 50 + .../ccdp/copay/percent_of_income/size_8.yaml | 50 + .../ccdp/copay/percent_of_income/size_9.yaml | 50 + .../states/nv/dwss/ccdp/copay/reimbursed.yaml | 19 + .../nv/dwss/ccdp/income/smi_intake.yaml | 39 +- .../nv/dwss/ccdp/income/smi_renewal.yaml | 23 +- .../nv/dwss/ccdp/copay/nv_ccdp_copay.yaml | 977 ++++++++++++++++++ .../eligibility/nv_ccdp_income_eligible.yaml | 840 +++++++++++++++ .../gov/states/nv/dwss/ccdp/nv_ccdp.yaml | 4 +- .../nv/dwss/ccdp/copay/nv_ccdp_copay.py | 37 +- .../eligibility/nv_ccdp_income_eligible.py | 21 +- 24 files changed, 2657 insertions(+), 25 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_1.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_10.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_11.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_12.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_13.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_14.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_2.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_3.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_4.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_5.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_6.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_7.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_8.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_9.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/reimbursed.yaml diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/amount.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/amount.yaml index 3dfa29d2d80..d6bb3cb7bba 100644 --- a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/amount.yaml +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/amount.yaml @@ -12,6 +12,10 @@ metadata: - title: Nevada DWSS Policy Transmittal CC PT 06-25 (Oct 2, 2025) — Annual Income Changes href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/CC_PT_06-25_ANNUAL_INCOME_CHANGES_10.02.2025.pdf#page=1 +# Before October 2024 the formula reads reimbursed and percent_of_income instead. +# Before July 2022 Nevada set the copayment by income, county, age of child and type +# of care (FFY 2022-2024 plan, Section 3.2.2). The model does not carry that schedule, +# so this one stands in for those dates. # The flat $0/$90/$150 copay and two-tier copay structure took effect # Oct 1, 2024 (State Plan Section 2.4.v); CC PT 06-25 is the Oct 1, 2025 annual # income-chart refresh that restates the same percentages and bands. diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/in_effect.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/in_effect.yaml new file mode 100644 index 00000000000..0f2f866225c --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/in_effect.yaml @@ -0,0 +1,18 @@ +description: Nevada sets family copayments as a percent of gross income under the Child Care and Development Program when this indicator is true. +# The chart effective October 1, 2023 prints the percent-of-income schedule. Families +# paid nothing until copayments returned on April 1, 2024, and the flat schedule replaced +# this one on October 1, 2024. +values: + 2015-01-01: false + 2024-04-01: true + 2024-10-01: false + +metadata: + unit: bool + period: month + label: Nevada CCDP percent-of-income copayment schedule in effect + reference: + - title: Nevada DWSS, Changes to the Child Care and Development Subsidy Program (March 27, 2024) + href: https://nevadachildcare.netlify.app/static/200a0b5ae99f788e8c99d6f7824dc92b/Child-Care-Updates-Parents-.pdf#page=1 + - title: Nevada DWSS, Copayment Webinar Questions and Answers (November 2024) + href: https://nevadachildcare.netlify.app/static/bba7e54af87b3b89e51dd500b42629bf/Copayment-Webinar-QA_FINAL_NOV24.pdf#page=3 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_1.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_1.yaml new file mode 100644 index 00000000000..9c1a7961581 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_1.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a one-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($3,290.14 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for one-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 1475.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 1735.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 1995.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 2255.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 2515.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 2775.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 3035.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_10.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_10.yaml new file mode 100644 index 00000000000..3a411361084 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_10.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a ten-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($9,111.15 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for ten-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 5576.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 6082.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 6588.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 7094.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 7600.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 8106.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 8612.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_11.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_11.yaml new file mode 100644 index 00000000000..b7dfba2595e --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_11.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a eleven-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($9,300.97 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for eleven-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 5974.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 6450.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 6926.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 7402.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 7878.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 8354.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 8830.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_12.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_12.yaml new file mode 100644 index 00000000000..913b2726bc4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_12.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a twelve-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($9,490.78 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for twelve-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 6373.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 6819.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 7265.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 7711.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 8157.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 8603.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 9049.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_13.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_13.yaml new file mode 100644 index 00000000000..4e475517e51 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_13.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a thirteen-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($9,680.60 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for thirteen-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 6772.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 7189.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 7606.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 8023.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 8440.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 8857.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 9274.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_14.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_14.yaml new file mode 100644 index 00000000000..0191f1bcd11 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_14.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a fourteen-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($9,870.41 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for fourteen-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 7170.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 7557.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 7944.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 8331.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 8718.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 9105.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 9492.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_2.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_2.yaml new file mode 100644 index 00000000000..c5c587d4e6f --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_2.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a two-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($4,302.49 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for two-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 1976.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 2309.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 2642.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 2975.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 3308.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 3641.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 3974.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_3.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_3.yaml new file mode 100644 index 00000000000..d62a9e24c04 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_3.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a three-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($5,314.84 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for three-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 2478.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 2884.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 3290.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 3696.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 4102.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 4508.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 4914.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_4.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_4.yaml new file mode 100644 index 00000000000..5ef5359e793 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_4.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a four-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($6,327.19 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for four-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 2979.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 3458.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 3937.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 4416.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 4895.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 5374.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 5853.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_5.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_5.yaml new file mode 100644 index 00000000000..b7f4fb3cc0a --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_5.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a five-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($7,339.54 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for five-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 3480.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 4032.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 4584.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 5136.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 5688.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 6240.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 6792.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_6.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_6.yaml new file mode 100644 index 00000000000..9009726c0f0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_6.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a six-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($8,351.89 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for six-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 3982.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 4607.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 5232.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 5857.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 6482.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 7107.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 7732.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_7.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_7.yaml new file mode 100644 index 00000000000..6392f073083 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_7.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a seven-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($8,541.70 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for seven-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 4381.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 4977.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 5573.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 6169.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 6765.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 7361.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 7957.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_8.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_8.yaml new file mode 100644 index 00000000000..6de0e94d4aa --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_8.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a eight-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($8,731.52 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for eight-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 4779.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 5345.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 5911.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 6477.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 7043.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 7609.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 8175.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_9.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_9.yaml new file mode 100644 index 00000000000..898f9e4c6dd --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/percent_of_income/size_9.yaml @@ -0,0 +1,50 @@ +description: Nevada sets the family copayment at this share of gross income for a nine-person household under the Child Care and Development Program. +# Chart effective October 1, 2023. Each threshold sits just above the top of the +# printed row, so income at a row's top stays in that row. Income tops out at 85% of +# SMI ($8,921.33 a month), where the copayment reaches 7%. +metadata: + type: single_amount + threshold_unit: currency-USD + amount_unit: /1 + threshold_period: month + period: month + label: Nevada CCDP copayment share of income for nine-person household + reference: + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 + - title: Nevada Child Care Policy Manual (July 1, 2024), MS 170, Household Size Monthly Income Chart + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=32 + +brackets: + - threshold: + 2024-04-01: 0 + amount: + 2024-04-01: 0 + - threshold: + 2024-04-01: 5178.0001 + amount: + 2024-04-01: 0.01 + - threshold: + 2024-04-01: 5714.0001 + amount: + 2024-04-01: 0.02 + - threshold: + 2024-04-01: 6250.0001 + amount: + 2024-04-01: 0.03 + - threshold: + 2024-04-01: 6786.0001 + amount: + 2024-04-01: 0.04 + - threshold: + 2024-04-01: 7322.0001 + amount: + 2024-04-01: 0.05 + - threshold: + 2024-04-01: 7858.0001 + amount: + 2024-04-01: 0.06 + - threshold: + 2024-04-01: 8394.0001 + amount: + 2024-04-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/reimbursed.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/reimbursed.yaml new file mode 100644 index 00000000000..3b81ef7ab27 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/reimbursed.yaml @@ -0,0 +1,19 @@ +description: Nevada reimburses family copayments under the Child Care and Development Program when this indicator is true. +# Urban's 2022 Book of Tables says families received reimbursement from March 2023 for +# copayments paid back to July 1, 2022. DWSS's letter of March 27, 2024 says American +# Rescue Plan funds let the program eliminate copayments, and that most families pay a +# copayment again as of April 1, 2024. +values: + 2015-01-01: false + 2022-07-01: true + 2024-04-01: false + +metadata: + unit: bool + period: month + label: Nevada CCDP copayments reimbursed + reference: + - title: Urban Institute, CCDF Policies Database Book of Tables 2022, Table 30 notes + href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202022%20Book%20of%20Tables%20%28final%29.pdf#page=288 + - title: Nevada DWSS, Changes to the Child Care and Development Subsidy Program (March 27, 2024) + href: https://nevadachildcare.netlify.app/static/200a0b5ae99f788e8c99d6f7824dc92b/Child-Care-Updates-Parents-.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_intake.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_intake.yaml index a7b1fa4e923..9ab3aedf4b6 100644 --- a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_intake.yaml +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_intake.yaml @@ -1,5 +1,22 @@ description: Nevada limits new applicants to income at or below this share of state median income under the Child Care and Development Program. +# Nevada has moved the limit for new applicants three times: +# - Through 2017 Urban's CCDF Policies Database prints 85% of SMI each October ($3,954, +# $4,104 and $4,127 a month for three in 2015, 2016 and 2017). No Nevada document +# from those years survives on its site. +# - By October 2018 Urban shows a lower first tier with 85% kept for families already +# enrolled. The state's plan documents and NWLC print 130% of the poverty guideline +# ($27,012 a year for three in February 2019; $2,353 a month from October 2020; $2,379 +# in October 2021, which the FFY 2022-2024 plan reports as 41% of SMI). 41% stands in +# for that guideline-based limit, which ran up to about four points higher for three +# in earlier years (NWLC prints 45% for February 2019). +# - The FFY 2022-2024 plan moves new applicants to 85% of SMI effective July 1, 2022 +# ($5,066 for three), and CC PT 07-23 keeps 85% for October 2023 ($5,314.84). +# - From October 1, 2024 new applicants face 41% and renewals 49%. The chart effective +# October 1, 2026 keeps both shares. values: + 2015-01-01: 0.85 + 2018-10-01: 0.41 + 2022-07-01: 0.85 2024-10-01: 0.41 metadata: @@ -7,11 +24,25 @@ metadata: period: year label: Nevada CCDP intake income limit share of state median income reference: + - title: Urban Institute, CCDF Policies Database Book of Tables 2015, Table 14 + href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202015%20Book%20of%20Tables%20%28final%2011%2023%2016%29.pdf#page=124 + - title: Urban Institute, CCDF Policies Database Book of Tables 2017, Table 14 + href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202017%20Book%20of%20Tables%20%28final%2010%2009%2018%29.pdf#page=122 + - title: Urban Institute, CCDF Policies Database Book of Tables 2018, Table 14 + href: https://ccdf.urban.org/sites/default/files/CrossStateVariationCCDFPolicies2018%20%28final%2011%2021%202019%29.pdf#page=123 + - title: National Women's Law Center, Nevada child care subsidy profile 2019 + href: https://nwlc.org/wp-content/uploads/2020/02/nevada-childcare-subsidy2019_v1.pdf#page=1 + - title: Nevada draft CCDF State Plan FFY 2022-2024, Section 3.1.3 (limits effective October 1, 2020) + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Home/Features/2022-2024%20Child%20Care%20PrePrint%20Draft(1).pdf#page=45 + - title: Urban Institute, CCDF Policies Database Book of Tables 2021, Table B-1 + href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202021%20Book%20of%20Tables%20%28final%29_1.pdf#page=393 + - title: Nevada CCDF State Plan FFY 2022-2024, Amendment approved May 16, 2023, Section 3.1.3 (85% of SMI effective July 1, 2022) + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/Amended%20State%20Plan.pdf#page=51 + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=1 - title: Nevada DWSS Policy Transmittal CC PT 06-25 (Oct 2, 2025) — Annual Income Changes href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/CC_PT_06-25_ANNUAL_INCOME_CHANGES_10.02.2025.pdf#page=1 - title: Nevada CCDF State Plan FFY 2025-2027, Section 2.5.5 — Eligibility income thresholds (initial and graduated) href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/ACF-118_CCDF_FFY_2025-2027_For_Nevada__3.pdf#page=35 - -# The flat $0/$90/$150 copay and two-tier 41%/49% SMI eligibility took effect -# Oct 1, 2024 (State Plan Section 2.4.v); CC PT 06-25 is the Oct 1, 2025 annual -# income-chart refresh that restates the same percentages and bands. + - title: Nevada DSS Policy Transmittal, Annual Changes to the CCDP Household Size and Monthly Income Limits (October 1, 2026) + href: https://prod.dss.nv.gov/siteassets/dwss.nv.gov/ccdp-annual-income-changes-2026_1.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_renewal.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_renewal.yaml index db8109ba9f4..2443371d12b 100644 --- a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_renewal.yaml +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_renewal.yaml @@ -1,5 +1,12 @@ description: Nevada limits renewing households to income at or below this share of state median income under the Child Care and Development Program. +# Urban's CCDF Policies Database prints 85% of SMI for enrolled families every October +# from 2015 through 2022 ($4,260 a month for three in 2018, while new applicants faced +# $2,366). The FFY 2022-2024 plan and CC PT 07-23 keep 85% through September 2024. +# From October 1, 2024 renewals face 49%. The Nevada DWSS copay Q&A of November 2024 +# says the change reaches a family only at its first renewal after that date. The model +# has no certificate dates, so every enrolled family moves on October 1, 2024. values: + 2015-01-01: 0.85 2024-10-01: 0.49 metadata: @@ -7,11 +14,19 @@ metadata: period: year label: Nevada CCDP renewal income limit share of state median income reference: + - title: Urban Institute, CCDF Policies Database Book of Tables 2017, Table 16 + href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202017%20Book%20of%20Tables%20%28final%2010%2009%2018%29.pdf#page=122 + - title: Urban Institute, CCDF Policies Database Book of Tables 2022, Table F-3 (initial and continuing limits, 2018-2022) + href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202022%20Book%20of%20Tables%20%28final%29.pdf#page=428 + - title: Nevada CCDF State Plan FFY 2022-2024, Amendment approved May 16, 2023, Section 3.1.3 + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/Amended%20State%20Plan.pdf#page=51 + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=1 + - title: Nevada DWSS, Copayment Webinar Questions and Answers (November 2024) + href: https://nevadachildcare.netlify.app/static/bba7e54af87b3b89e51dd500b42629bf/Copayment-Webinar-QA_FINAL_NOV24.pdf#page=1 - title: Nevada DWSS Policy Transmittal CC PT 06-25 (Oct 2, 2025) — Annual Income Changes href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/CC_PT_06-25_ANNUAL_INCOME_CHANGES_10.02.2025.pdf#page=1 - title: Nevada CCDF State Plan FFY 2025-2027, Section 2.5.5 — Graduated phase-out of assistance at redetermination href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/ACF-118_CCDF_FFY_2025-2027_For_Nevada__3.pdf#page=36 - -# The flat $0/$90/$150 copay and two-tier 41%/49% SMI eligibility took effect -# Oct 1, 2024 (State Plan Section 2.4.v); CC PT 06-25 is the Oct 1, 2025 annual -# income-chart refresh that restates the same percentages and bands. + - title: Nevada DSS Policy Transmittal, Annual Changes to the CCDP Household Size and Monthly Income Limits (October 1, 2026) + href: https://prod.dss.nv.gov/siteassets/dwss.nv.gov/ccdp-annual-income-changes-2026_1.pdf#page=1 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.yaml index 5a9abf5968c..fd7c636f715 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.yaml @@ -1,4 +1,8 @@ # nv_ccdp_copay: SPMUnit, float (USD), MONTH +# July 2022 through March 2024: federal funds reimburse the copayment, so it reads $0. +# April through September 2024: a share of gross income from the chart effective +# October 1, 2023, by household size. +# From October 2024, and standing in before July 2022, the flat schedule below applies. # Flat copay by income as a share of SMI (eff. Oct 1, 2024; State Plan 2.4.v): # <= 32.99% SMI -> $0; 33%-42% SMI -> $90; above 42% SMI -> $150. # The $150 band begins just above 42% SMI (threshold 0.4201) per the operational @@ -383,3 +387,976 @@ # 3_333/mo / 6_721.82 = 0.4959 >= 0.4201 -> $150; no eligible child in # protective care, so the waiver does not apply. nv_ccdp_copay: 150 + +- name: The flat schedule stands in for June 2022. + period: 2022-06 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2022: 30_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2022: NV + output: + # 2_500 / (82_509 * 0.84 / 12) = 0.4328 -> $150. + nv_ccdp_copay: 150 + +- name: In July 2022 federal funds reimburse the copayment. + period: 2022-07 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2022: 30_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2022: NV + output: + nv_ccdp_copay: 0 + +- name: In March 2024 federal funds still reimburse the copayment. + period: 2024-03 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 48_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + nv_ccdp_copay: 0 + +- name: In April 2024 the chart charges a family of three at $4,000 four percent. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 48_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + # Row $3,697 to $4,102 prints 4%. + nv_ccdp_copay: 160 + +- name: Under the April 2024 chart a family of 1 at $1,475 pays $0. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2024: 17_700 + households: + household: + members: [person1] + state_code: + 2024: NV + output: + nv_ccdp_copay: 0 + +- name: Under the April 2024 chart a family of 1 at $1,476 pays $14.76. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2024: 17_712 + households: + household: + members: [person1] + state_code: + 2024: NV + output: + nv_ccdp_copay: 14.76 + +- name: Under the April 2024 chart a family of 1 at $1,735 pays $17.35. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2024: 20_820 + households: + household: + members: [person1] + state_code: + 2024: NV + output: + nv_ccdp_copay: 17.35 + +- name: Under the April 2024 chart a family of 1 at $1,736 pays $34.72. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2024: 20_832 + households: + household: + members: [person1] + state_code: + 2024: NV + output: + nv_ccdp_copay: 34.72 + +- name: Under the April 2024 chart a family of 1 at $3,035 pays $182.1. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2024: 36_420 + households: + household: + members: [person1] + state_code: + 2024: NV + output: + nv_ccdp_copay: 182.1 + +- name: Under the April 2024 chart a family of 1 at $3,036 pays $212.52. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2024: 36_432 + households: + household: + members: [person1] + state_code: + 2024: NV + output: + nv_ccdp_copay: 212.52 + +- name: Under the April 2024 chart a family of 1 at $3,290.14 pays $230.31. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2024: 39_481.68 + households: + household: + members: [person1] + state_code: + 2024: NV + output: + nv_ccdp_copay: 230.31 + +- name: Under the April 2024 chart a family of 3 at $2,072 pays $0. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 24_864 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + nv_ccdp_copay: 0 + +- name: Under the April 2024 chart a family of 3 at $2,478 pays $0. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 29_736 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + nv_ccdp_copay: 0 + +- name: Under the April 2024 chart a family of 3 at $2,479 pays $24.79. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 29_748 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + nv_ccdp_copay: 24.79 + +- name: Under the April 2024 chart a family of 3 at $2,884 pays $28.84. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 34_608 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + nv_ccdp_copay: 28.84 + +- name: Under the April 2024 chart a family of 3 at $2,885 pays $57.7. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 34_620 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + nv_ccdp_copay: 57.7 + +- name: Under the April 2024 chart a family of 3 at $4,914 pays $294.84. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 58_968 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + nv_ccdp_copay: 294.84 + +- name: Under the April 2024 chart a family of 3 at $4,915 pays $344.05. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 58_980 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + nv_ccdp_copay: 344.05 + +- name: Under the April 2024 chart a family of 3 at $5,314.84 pays $372.04. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 63_778.08 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + nv_ccdp_copay: 372.04 + +- name: Under the April 2024 chart a family of 4 at $2,979 pays $0. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + person4: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + nv_ccdp_countable_income: + 2024: 35_748 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2024: NV + output: + nv_ccdp_copay: 0 + +- name: Under the April 2024 chart a family of 4 at $2,980 pays $29.8. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + person4: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + nv_ccdp_countable_income: + 2024: 35_760 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2024: NV + output: + nv_ccdp_copay: 29.8 + +- name: Under the April 2024 chart a family of 4 at $6,327.19 pays $442.9. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + person4: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + nv_ccdp_countable_income: + 2024: 75_926.28 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2024: NV + output: + nv_ccdp_copay: 442.9 + +- name: Under the April 2024 chart a family of 7 at $4,381 pays $0. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + person4: + age: + 2024: 5 + person5: + age: + 2024: 5 + person6: + age: + 2024: 5 + person7: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + nv_ccdp_countable_income: + 2024: 52_572 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2024: NV + output: + nv_ccdp_copay: 0 + +- name: Under the April 2024 chart a family of 7 at $4,382 pays $43.82. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + person4: + age: + 2024: 5 + person5: + age: + 2024: 5 + person6: + age: + 2024: 5 + person7: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + nv_ccdp_countable_income: + 2024: 52_584 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2024: NV + output: + nv_ccdp_copay: 43.82 + +- name: Under the April 2024 chart a family of 7 at $8,541.7 pays $597.92. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + person4: + age: + 2024: 5 + person5: + age: + 2024: 5 + person6: + age: + 2024: 5 + person7: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + nv_ccdp_countable_income: + 2024: 102_500.4 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2024: NV + output: + nv_ccdp_copay: 597.92 + +- name: Under the April 2024 chart a family of 14 at $7,170 pays $0. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + person4: + age: + 2024: 5 + person5: + age: + 2024: 5 + person6: + age: + 2024: 5 + person7: + age: + 2024: 5 + person8: + age: + 2024: 5 + person9: + age: + 2024: 5 + person10: + age: + 2024: 5 + person11: + age: + 2024: 5 + person12: + age: + 2024: 5 + person13: + age: + 2024: 5 + person14: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + nv_ccdp_countable_income: + 2024: 86_040 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + state_code: + 2024: NV + output: + nv_ccdp_copay: 0 + +- name: Under the April 2024 chart a family of 14 at $7,171 pays $71.71. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + person4: + age: + 2024: 5 + person5: + age: + 2024: 5 + person6: + age: + 2024: 5 + person7: + age: + 2024: 5 + person8: + age: + 2024: 5 + person9: + age: + 2024: 5 + person10: + age: + 2024: 5 + person11: + age: + 2024: 5 + person12: + age: + 2024: 5 + person13: + age: + 2024: 5 + person14: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + nv_ccdp_countable_income: + 2024: 86_052 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + state_code: + 2024: NV + output: + nv_ccdp_copay: 71.71 + +- name: Under the April 2024 chart a family of 14 at $9,870.41 pays $690.93. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + person4: + age: + 2024: 5 + person5: + age: + 2024: 5 + person6: + age: + 2024: 5 + person7: + age: + 2024: 5 + person8: + age: + 2024: 5 + person9: + age: + 2024: 5 + person10: + age: + 2024: 5 + person11: + age: + 2024: 5 + person12: + age: + 2024: 5 + person13: + age: + 2024: 5 + person14: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + nv_ccdp_countable_income: + 2024: 118_444.92 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + state_code: + 2024: NV + output: + nv_ccdp_copay: 690.93 + +- name: Copayments stay a share of income through September 2024. + period: 2024-09 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 30_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + # Row $2,479 to $2,884 prints 1%. + nv_ccdp_copay: 25 + +- name: Flat copayments start in October 2024. + period: 2024-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 30_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + # 2_500 / (96_026 * 0.84 / 12) = 0.3719 -> $90. + nv_ccdp_copay: 90 + +- name: Homeless households pay nothing under the April 2024 chart. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 48_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + is_homeless: + 2024: true + output: + nv_ccdp_copay: 0 + +- name: TANF families pay nothing under the April 2024 chart. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 48_000 + is_tanf_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + nv_ccdp_copay: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.yaml index 332d78ad21a..70d18739d7e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.yaml @@ -1,6 +1,8 @@ # nv_ccdp_income_eligible: SPMUnit, bool, MONTH +# From October 2024: # New applicants (not enrolled): monthly countable income <= 41% SMI (intake). # Enrolled families: monthly countable income <= 49% SMI (renewal/redetermination). +# Earlier dates carry their own shares; see the cases at the end of this file. # The 85% SMI federal mid-certification protection (45 CFR 98.21) is not modeled # because we don't track certification periods at the moment. # Family of 3, period 2025-01 -> monthly SMI = 6_721.82: @@ -308,3 +310,841 @@ # intake limit = 0.41 * 11_042.99 = 4_527.63/mo. # 50_000 / 12 = 4_166.67/mo <= 4_527.63 -> eligible. nv_ccdp_income_eligible: true + +- name: Through 2017 a new applicant of three qualifies up to 85% of SMI. + period: 2017-10 + input: + people: + person1: + age: + 2017: 30 + person2: + age: + 2017: 5 + person3: + age: + 2017: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2017: 49_512 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2017: NV + output: + # Urban 2017 Table 14 prints $4,127: 85% * 69_361 * 0.84 / 12 = 4_126.98. + nv_ccdp_income_eligible: true + +- name: Through 2017 a new applicant of three above 85% of SMI fails. + period: 2017-10 + input: + people: + person1: + age: + 2017: 30 + person2: + age: + 2017: 5 + person3: + age: + 2017: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2017: 49_536 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2017: NV + output: + nv_ccdp_income_eligible: false + +- name: In October 2018 a new applicant of three at $4,000 fails the lower first tier. + period: 2018-10 + input: + people: + person1: + age: + 2018: 30 + person2: + age: + 2018: 5 + person3: + age: + 2018: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2018: 48_000 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2018: NV + output: + # 41% * 71_593 * 0.84 / 12 = 2_054.72. + nv_ccdp_income_eligible: false + +- name: In October 2018 an enrolled family of three at $4,000 stays within 85% of SMI. + period: 2018-10 + input: + people: + person1: + age: + 2018: 30 + person2: + age: + 2018: 5 + person3: + age: + 2018: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2018: 48_000 + nv_ccdp_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2018: NV + output: + # Urban 2022 Table F-3 prints $4,260 for continuing families: 85% * 71_593 * 0.84 / 12 = 4_259.78. + nv_ccdp_income_eligible: true + +- name: In June 2022 a new applicant of three at $4,000 still fails. + period: 2022-06 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2022: 48_000 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2022: NV + output: + # 41% * 82_509 * 0.84 / 12 = 2_368.01. + nv_ccdp_income_eligible: false + +- name: In July 2022 a new applicant of three at $4,000 qualifies under 85% of SMI. + period: 2022-07 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2022: 48_000 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2022: NV + output: + # 85% * 82_509 * 0.84 / 12 = 4_909.29, the top of the October 2021 sliding fee scale. + nv_ccdp_income_eligible: true + +- name: Under the October 2023 chart a new applicant of 1 at $3,290 qualifies. + period: 2023-10 + input: + people: + person1: + age: + 2023: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2023: 39_480 + nv_ccdp_enrolled: false + households: + household: + members: [person1] + state_code: + 2023: NV + output: + # The chart's ceiling for 1 is $3,290.14. + nv_ccdp_income_eligible: true + +- name: Under the October 2023 chart a new applicant of 1 at $3,291 fails. + period: 2023-10 + input: + people: + person1: + age: + 2023: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2023: 39_492 + nv_ccdp_enrolled: false + households: + household: + members: [person1] + state_code: + 2023: NV + output: + nv_ccdp_income_eligible: false + +- name: Under the October 2023 chart a new applicant of 3 at $5,314 qualifies. + period: 2023-10 + input: + people: + person1: + age: + 2023: 30 + person2: + age: + 2023: 5 + person3: + age: + 2023: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2023: 63_768 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2023: NV + output: + # The chart's ceiling for 3 is $5,314.84. + nv_ccdp_income_eligible: true + +- name: Under the October 2023 chart a new applicant of 3 at $5,315 fails. + period: 2023-10 + input: + people: + person1: + age: + 2023: 30 + person2: + age: + 2023: 5 + person3: + age: + 2023: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2023: 63_780 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2023: NV + output: + nv_ccdp_income_eligible: false + +- name: Under the October 2023 chart a new applicant of 4 at $6,327 qualifies. + period: 2023-10 + input: + people: + person1: + age: + 2023: 30 + person2: + age: + 2023: 5 + person3: + age: + 2023: 5 + person4: + age: + 2023: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + nv_ccdp_countable_income: + 2023: 75_924 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2023: NV + output: + # The chart's ceiling for 4 is $6,327.19. + nv_ccdp_income_eligible: true + +- name: Under the October 2023 chart a new applicant of 4 at $6,328 fails. + period: 2023-10 + input: + people: + person1: + age: + 2023: 30 + person2: + age: + 2023: 5 + person3: + age: + 2023: 5 + person4: + age: + 2023: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + nv_ccdp_countable_income: + 2023: 75_936 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2023: NV + output: + nv_ccdp_income_eligible: false + +- name: Under the October 2023 chart a new applicant of 7 at $8,541 qualifies. + period: 2023-10 + input: + people: + person1: + age: + 2023: 30 + person2: + age: + 2023: 5 + person3: + age: + 2023: 5 + person4: + age: + 2023: 5 + person5: + age: + 2023: 5 + person6: + age: + 2023: 5 + person7: + age: + 2023: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + nv_ccdp_countable_income: + 2023: 102_492 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2023: NV + output: + # The chart's ceiling for 7 is $8,541.70. + nv_ccdp_income_eligible: true + +- name: Under the October 2023 chart a new applicant of 7 at $8,542 fails. + period: 2023-10 + input: + people: + person1: + age: + 2023: 30 + person2: + age: + 2023: 5 + person3: + age: + 2023: 5 + person4: + age: + 2023: 5 + person5: + age: + 2023: 5 + person6: + age: + 2023: 5 + person7: + age: + 2023: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7] + nv_ccdp_countable_income: + 2023: 102_504 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: + 2023: NV + output: + nv_ccdp_income_eligible: false + +- name: Under the October 2023 chart a new applicant of 14 at $9,870 qualifies. + period: 2023-10 + input: + people: + person1: + age: + 2023: 30 + person2: + age: + 2023: 5 + person3: + age: + 2023: 5 + person4: + age: + 2023: 5 + person5: + age: + 2023: 5 + person6: + age: + 2023: 5 + person7: + age: + 2023: 5 + person8: + age: + 2023: 5 + person9: + age: + 2023: 5 + person10: + age: + 2023: 5 + person11: + age: + 2023: 5 + person12: + age: + 2023: 5 + person13: + age: + 2023: 5 + person14: + age: + 2023: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + nv_ccdp_countable_income: + 2023: 118_440 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + state_code: + 2023: NV + output: + # The chart's ceiling for 14 is $9,870.41. + nv_ccdp_income_eligible: true + +- name: Under the October 2023 chart a new applicant of 14 at $9,871 fails. + period: 2023-10 + input: + people: + person1: + age: + 2023: 30 + person2: + age: + 2023: 5 + person3: + age: + 2023: 5 + person4: + age: + 2023: 5 + person5: + age: + 2023: 5 + person6: + age: + 2023: 5 + person7: + age: + 2023: 5 + person8: + age: + 2023: 5 + person9: + age: + 2023: 5 + person10: + age: + 2023: 5 + person11: + age: + 2023: 5 + person12: + age: + 2023: 5 + person13: + age: + 2023: 5 + person14: + age: + 2023: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + nv_ccdp_countable_income: + 2023: 118_452 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + state_code: + 2023: NV + output: + nv_ccdp_income_eligible: false + +- name: The deck family of three at $40,000 qualifies as a new applicant in September 2024. + period: 2024-09 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 39_999.96 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + # 85% * 89_325 * 0.84 / 12 = 5_314.84. + nv_ccdp_income_eligible: true + +- name: The deck family of three at $40,000 fails as a new applicant in October 2024. + period: 2024-10 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 39_999.96 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + # 41% * 96_026 * 0.84 / 12 = 2_755.95; FFY 2025 chart prints $2,756. + nv_ccdp_income_eligible: false + +- name: The deck family of three at $40,000 fails at renewal in October 2024. + period: 2024-10 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 39_999.96 + nv_ccdp_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + # 49% * 96_026 * 0.84 / 12 = 3_293.69. + nv_ccdp_income_eligible: false + +- name: Under the October 2026 chart a new applicant of 3 at $3,014 qualifies. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2026: 36_168 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: NV + output: + nv_ccdp_income_eligible: true + +- name: Under the October 2026 chart a new applicant of 3 at $3,015 fails. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2026: 36_180 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: NV + output: + nv_ccdp_income_eligible: false + +- name: Under the October 2026 chart a renewing family of 3 at $3,602 qualifies. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2026: 43_224 + nv_ccdp_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: NV + output: + nv_ccdp_income_eligible: true + +- name: Under the October 2026 chart a renewing family of 3 at $3,603 fails. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2026: 43_236 + nv_ccdp_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: NV + output: + nv_ccdp_income_eligible: false + +- name: Under the October 2026 chart a new applicant of 4 at $3,588 qualifies. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + person4: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + nv_ccdp_countable_income: + 2026: 43_056 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: NV + output: + nv_ccdp_income_eligible: true + +- name: Under the October 2026 chart a new applicant of 4 at $3,589 fails. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + person4: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + nv_ccdp_countable_income: + 2026: 43_068 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: NV + output: + nv_ccdp_income_eligible: false + +- name: Under the October 2026 chart a renewing family of 4 at $4,288 qualifies. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + person4: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + nv_ccdp_countable_income: + 2026: 51_456 + nv_ccdp_enrolled: true + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: NV + output: + nv_ccdp_income_eligible: true + +- name: Under the October 2026 chart a renewing family of 4 at $4,290 fails. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + person4: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + nv_ccdp_countable_income: + 2026: 51_480 + nv_ccdp_enrolled: true + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: NV + output: + nv_ccdp_income_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/nv_ccdp.yaml b/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/nv_ccdp.yaml index 242cf0bff4a..4e7fbd8fe1f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/nv_ccdp.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/nv_ccdp.yaml @@ -388,10 +388,10 @@ # Income 17_160 / 12 = 1_430 per month; care 7_894 / 12 = 657.83 per month. # Age 5 -> PRESCHOOL; max rate = 51.50 * 21.67 = 1_116.005, so the charge binds. # 2015-09, FFY 2015 table: SMI = 65_832 * 0.68 / 12 = 3_730.48. - # 1_430 <= 41% * 3_730.48 = 1_529.50 -> eligible. + # 1_430 <= 85% * 3_730.48 = 3_170.91 -> eligible. # Ratio 1_430 / 3_730.48 = 0.3833 -> $90 copay (33% to 42% band). # 2015-10, FFY 2016 table: SMI = 66_461 * 0.68 / 12 = 3_766.12. - # 1_430 <= 41% * 3_766.12 = 1_544.11 -> eligible. + # 1_430 <= 85% * 3_766.12 = 3_201.20 -> eligible. # Ratio 1_430 / 3_766.12 = 0.3797 -> $90 copay. # benefit = min(657.83, 1_116.005) - 90 = 567.83 in both months. nv_ccdp_smi: diff --git a/policyengine_us/variables/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.py b/policyengine_us/variables/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.py index f7e9b80b51a..7cbcbcd0d6a 100644 --- a/policyengine_us/variables/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.py +++ b/policyengine_us/variables/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.py @@ -8,22 +8,45 @@ class nv_ccdp_copay(Variable): label = "Nevada CCDP monthly family co-payment" definition_period = MONTH defined_for = StateCode.NV - reference = "https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/CC_PT_06-25_ANNUAL_INCOME_CHANGES_10.02.2025.pdf#page=1" + reference = ( + "https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/CC_PT_06-25_ANNUAL_INCOME_CHANGES_10.02.2025.pdf#page=1", + "https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2", + "https://nevadachildcare.netlify.app/static/200a0b5ae99f788e8c99d6f7824dc92b/Child-Care-Updates-Parents-.pdf#page=1", + ) def formula(spm_unit, period, parameters): - # Flat monthly copay keyed by income as a share of SMI, effective - # Oct 1, 2024 (State Plan Section 2.4.v); CC PT 06-25 is the Oct 1, 2025 - # annual refresh. <= 32.99% SMI -> $0; 33%-42% SMI -> $90; >42% -> $150. + # Nevada's copayment has followed three dated rules: + # - July 1, 2022 through March 31, 2024: American Rescue Plan funds covered + # every family's copayment. + # - April 1 through September 30, 2024: a percent of gross income, 0% to 7%, + # from the chart effective October 1, 2023, by household size and income. + # Households above fourteen people use the fourteen-person column. + # - From October 1, 2024: a flat monthly amount by income as a share of SMI + # (State Plan Section 2.4.v): <= 32.99% SMI -> $0; 33%-42% SMI -> $90; + # >42% -> $150. The flat schedule also stands in for dates before July 2022. p = parameters(period).gov.states.nv.dwss.ccdp.copay + if p.reimbursed: + return spm_unit.empty_array() # Floor income at 0 before taking the ratio: negative self-employment # income would otherwise produce a negative ratio and the wrong band. monthly_income = max_( spm_unit("nv_ccdp_countable_income", period.this_year) / MONTHS_IN_YEAR, 0, ) - monthly_smi = spm_unit("nv_ccdp_smi", period) - smi_ratio = where(monthly_smi > 0, monthly_income / monthly_smi, 0) - copay = p.amount.calc(smi_ratio) + if p.percent_of_income.in_effect: + size = spm_unit("spm_unit_size", period.this_year) + scales = p.percent_of_income + sizes = range(1, 14) + share = select( + [size == n for n in sizes], + [scales[f"size_{n}"].calc(monthly_income) for n in sizes], + default=scales.size_14.calc(monthly_income), + ) + copay = share * monthly_income + else: + monthly_smi = spm_unit("nv_ccdp_smi", period) + smi_ratio = where(monthly_smi > 0, monthly_income / monthly_smi, 0) + copay = p.amount.calc(smi_ratio) # Manual MS 180/181 (Co-Payments) waives the copay for exactly three # categories: TANF/NEON referrals, CPS/foster placements, and homeless # households (plus a discretionary case-by-case waiver by the CCDP diff --git a/policyengine_us/variables/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.py b/policyengine_us/variables/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.py index e51d6f70e3a..869b3a14d79 100644 --- a/policyengine_us/variables/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.py +++ b/policyengine_us/variables/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.py @@ -7,7 +7,11 @@ class nv_ccdp_income_eligible(Variable): label = "Eligible for Nevada CCDP based on income" definition_period = MONTH defined_for = StateCode.NV - reference = "https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/CC_PT_06-25_ANNUAL_INCOME_CHANGES_10.02.2025.pdf#page=1" + reference = ( + "https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/CC_PT_06-25_ANNUAL_INCOME_CHANGES_10.02.2025.pdf#page=1", + "https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=1", + "https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/Amended%20State%20Plan.pdf#page=51", + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.nv.dwss.ccdp.income @@ -18,13 +22,14 @@ def formula(spm_unit, period, parameters): ) monthly_smi = spm_unit("nv_ccdp_smi", period) enrolled = spm_unit("nv_ccdp_enrolled", period) - # New applicants must be at or below 41% SMI (intake). Enrolled families - # are redetermined at or below 49% SMI (renewal); this matches the - # published renewal income/copay chart (CC PT 06-25), whose copay bands - # top out at 49% SMI. A separate federal protection (45 CFR - # 98.21(a)(1)(ii)) bars terminating a family mid-certification until - # income exceeds 85% SMI, but we don't track certification periods at - # the moment, so the 85% mid-period ceiling is not modeled. + # New applicants face smi_intake and enrolled families face smi_renewal, both + # dated. From October 1, 2024 they are 41% and 49% of SMI, which match the + # published charts (CC PT 06-25 and the October 2026 transmittal). From July 1, + # 2022 through September 2024 both were 85%, the ceiling in the state's chart + # effective October 1, 2023. Since October 2024 a separate federal protection + # (45 CFR 98.21(a)(1)(ii)) bars terminating a family mid-certification until + # income exceeds 85% SMI, but we don't track certification periods at the + # moment, so the 85% mid-period ceiling is not modeled. # MS 216.4.3.1 (Foster) and MS 216.4.4.1 (CPS) treat a foster or CPS # child as a household of one and do NOT count the traditional # household's income ("Income received by the traditional household is From 729a91d5462bd5c9fd3e318d6b45c501e3fb774e Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 6 Nov 2026 10:08:36 -0500 Subject: [PATCH 04/13] Add Ohio's Child Care Choice Voucher Program Families over the Publicly Funded Child Care intake limit and at or below 200% of poverty qualify for a monthly voucher. Procedure Letter 36 prices it by age and provider from November 2025, and H.B. 96 moves it to the program's unenhanced rates by November 1, 2026. Co-Authored-By: Claude Opus 5.5 --- .../hhs/ccdf/child_care_subsidy_programs.yaml | 6 +- .../oh/dcy/ccap/ccvp/child_age_limit.yaml | 15 + .../gov/states/oh/dcy/ccap/ccvp/fpl_rate.yaml | 17 + .../states/oh/dcy/ccap/ccvp/in_effect.yaml | 19 + .../gov/states/oh/dcy/ccap/ccvp/payment.yaml | 39 + .../dcy/ccap/ccvp/pfcc_rates_in_effect.yaml | 17 + policyengine_us/programs.yaml | 2 +- .../gov/states/oh/dcy/ccap/ccvp/oh_ccvp.yaml | 309 ++++++ .../oh/dcy/ccap/ccvp/oh_ccvp_eligible.yaml | 945 ++++++++++++++++++ .../dcy/ccap/ccvp/oh_ccvp_eligible_child.yaml | 101 ++ .../states/oh/dcy/ccap/ccvp/oh_ccvp_rate.yaml | 419 ++++++++ .../ccap/ccvp/oh_child_care_subsidies.yaml | 61 ++ .../states/oh/dcy/ccap/oh_ccap_base_rate.yaml | 6 +- .../gov/states/oh/dcy/ccap/ccvp/oh_ccvp.py | 26 + .../oh/dcy/ccap/ccvp/oh_ccvp_eligible.py | 49 + .../dcy/ccap/ccvp/oh_ccvp_eligible_child.py | 27 + .../states/oh/dcy/ccap/ccvp/oh_ccvp_rate.py | 25 + .../states/oh/dcy/ccap/oh_ccap_base_rate.py | 5 +- .../oh/dcy/ccap/oh_child_care_subsidies.py | 2 +- 19 files changed, 2081 insertions(+), 9 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/child_age_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/fpl_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/payment.yaml create mode 100644 policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/pfcc_rates_in_effect.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible_child.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_child_care_subsidies.yaml create mode 100644 policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.py create mode 100644 policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.py create mode 100644 policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible_child.py create mode 100644 policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.py diff --git a/policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml b/policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml index 23ed336402b..e618d61dfd8 100644 --- a/policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml +++ b/policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml @@ -33,7 +33,7 @@ values: - nh_child_care_subsidies # New Hampshire Child Care Scholarship Program - pa_child_care_subsidies # Pennsylvania Child Care Works - nj_child_care_subsidies # New Jersey Child Care Assistance Program - - oh_child_care_subsidies # Ohio Publicly Funded Child Care + - oh_child_care_subsidies # Ohio Publicly Funded Child Care and Child Care Choice Voucher Program - nv_child_care_subsidies # Nevada Child Care and Development Program (CCDP) - ny_child_care_subsidies # New York Child Care Assistance Program - ri_child_care_subsidies # Rhode Island Child Care Assistance Program @@ -80,7 +80,7 @@ values: - nh_child_care_subsidies # New Hampshire Child Care Scholarship Program - pa_child_care_subsidies # Pennsylvania Child Care Works - nj_child_care_subsidies # New Jersey Child Care Assistance Program - - oh_child_care_subsidies # Ohio Publicly Funded Child Care + - oh_child_care_subsidies # Ohio Publicly Funded Child Care and Child Care Choice Voucher Program - nv_child_care_subsidies # Nevada Child Care and Development Program (CCDP) - or_child_care_subsidies # Oregon Employment Related Day Care - ri_child_care_subsidies # Rhode Island Child Care Assistance Program @@ -129,7 +129,7 @@ values: - nh_child_care_subsidies # New Hampshire Child Care Scholarship Program - pa_child_care_subsidies # Pennsylvania Child Care Works - nj_child_care_subsidies # New Jersey Child Care Assistance Program - - oh_child_care_subsidies # Ohio Publicly Funded Child Care + - oh_child_care_subsidies # Ohio Publicly Funded Child Care and Child Care Choice Voucher Program - nv_child_care_subsidies # Nevada Child Care and Development Program (CCDP) - or_child_care_subsidies # Oregon Employment Related Day Care - ri_child_care_subsidies # Rhode Island Child Care Assistance Program diff --git a/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/child_age_limit.yaml b/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/child_age_limit.yaml new file mode 100644 index 00000000000..4a3a3e06df7 --- /dev/null +++ b/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/child_age_limit.yaml @@ -0,0 +1,15 @@ +description: Ohio limits child eligibility to under this age under the Child Care Choice Voucher Program. + +# The voucher's school-age row runs to age 15, two years past the Publicly +# Funded Child Care limit of 13. Its special-needs limit of 18 matches that +# program, so eligibility/special_needs_child_age_limit.yaml serves both. +values: + 2025-11-01: 15 + +metadata: + unit: year + period: year + label: Ohio CCVP child age limit + reference: + - title: DCY Procedure Letter 36, voucher payment rates, school age row (October 29, 2025) + href: https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=3 diff --git a/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/fpl_rate.yaml b/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/fpl_rate.yaml new file mode 100644 index 00000000000..dd292f9e8c0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/fpl_rate.yaml @@ -0,0 +1,17 @@ +description: Ohio limits family income to this share of the federal poverty guideline under the Child Care Choice Voucher Program. +values: + 2025-11-01: 2 + +metadata: + unit: /1 + period: year + label: Ohio CCVP income limit rate + reference: + - title: DCY Procedure Letter 36, Child Care Choice Voucher Program (October 29, 2025) + href: https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=3 + - title: DCY Procedure Letter 21, 2025 income eligibility standards (August 29, 2025) + href: https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_21.pdf#page=2 + - title: DCY Procedure Letter 45, 2026 income eligibility standards (August 18, 2026) + href: https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners%20and%20Providers/Rules%20and%20Resources/2026/PL_45.pdf#page=2 + - title: LSC Final Analysis of H.B. 96 (136th General Assembly), Section 423.190 + href: https://www.lsc.ohio.gov/assets/legislation/136/hb96/en0/files/hb96-kid-bill-analysis-as-enacted-136th-general-assembly.pdf#page=10 diff --git a/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/in_effect.yaml b/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/in_effect.yaml new file mode 100644 index 00000000000..6ba7c915e37 --- /dev/null +++ b/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/in_effect.yaml @@ -0,0 +1,19 @@ +description: Ohio uses this indicator to determine whether the modeled Child Care Choice Voucher Program rules apply. + +# DCY launched the voucher administratively in April 2024 (H.B. 96 final +# analysis). The model starts it in November 2025, when the Procedure Letter 36 +# payment chart and the modeled Publicly Funded Child Care rules both begin. +# This MONTH-period parameter is read at the month start. +values: + 2000-01-01: false + 2025-11-01: true + +metadata: + unit: bool + period: month + label: Ohio CCVP rules in effect + reference: + - title: DCY Procedure Letter 36, Child Care Choice Voucher Program (October 29, 2025) + href: https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=2 + - title: LSC Final Analysis of H.B. 96 (136th General Assembly), Section 423.190 + href: https://www.lsc.ohio.gov/assets/legislation/136/hb96/en0/files/hb96-kid-bill-analysis-as-enacted-136th-general-assembly.pdf#page=10 diff --git a/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/payment.yaml b/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/payment.yaml new file mode 100644 index 00000000000..13c1b18739b --- /dev/null +++ b/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/payment.yaml @@ -0,0 +1,39 @@ +description: Ohio provides this monthly amount per child under the Child Care Choice Voucher Program until the program adopts the Publicly Funded Child Care payment rates. +metadata: + propagate_metadata_to_children: true + period: month + unit: currency-USD + label: Ohio CCVP monthly voucher payment + breakdown: + - oh_ccap_provider_type + - oh_ccap_child_age_group + reference: + - title: DCY Procedure Letter 36, voucher payment rates for enrollment and attendance on or after November 1, 2025 + href: https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=2 + +# Procedure Letter 36 charts centers and school-based programs apart from +# type A and type B family child care homes, with one school-age row, so the +# school-age summer group takes the school-age amount. It prices enrollment and +# attendance from November 1, 2025; the model carries no earlier chart. +CENTER: + INFANT: + 2025-11-01: 900 + TODDLER: + 2025-11-01: 800 + PRESCHOOL: + 2025-11-01: 750 + SCHOOL_AGE: + 2025-11-01: 375 + SCHOOL_AGE_SUMMER: + 2025-11-01: 375 +HOME: + INFANT: + 2025-11-01: 600 + TODDLER: + 2025-11-01: 550 + PRESCHOOL: + 2025-11-01: 500 + SCHOOL_AGE: + 2025-11-01: 300 + SCHOOL_AGE_SUMMER: + 2025-11-01: 300 diff --git a/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/pfcc_rates_in_effect.yaml b/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/pfcc_rates_in_effect.yaml new file mode 100644 index 00000000000..a32d9b478d0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/pfcc_rates_in_effect.yaml @@ -0,0 +1,17 @@ +description: Ohio uses this indicator to determine whether the Child Care Choice Voucher Program pays at the Publicly Funded Child Care payment rates. + +# H.B. 96, Section 423.190, requires the voucher to use those rates, without +# the Step Up to Quality enhancement, not later than November 1, 2026. This +# parameter uses that deadline because the DCY procedure letters we could read +# name no other date. +values: + 2000-01-01: false + 2026-11-01: true + +metadata: + unit: bool + period: month + label: Ohio CCVP pays Publicly Funded Child Care rates + reference: + - title: LSC Final Analysis of H.B. 96 (136th General Assembly), Section 423.190 + href: https://www.lsc.ohio.gov/assets/legislation/136/hb96/en0/files/hb96-kid-bill-analysis-as-enacted-136th-general-assembly.pdf#page=10 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 15c6105f9bd..4fd38544599 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -853,7 +853,7 @@ programs: - state: OH status: complete name: Ohio Publicly Funded Child Care - full_name: Ohio Child Care Assistance Program (Publicly Funded Child Care) + full_name: Ohio Child Care Assistance Program (Publicly Funded Child Care and Child Care Choice Voucher Program) variable: oh_child_care_subsidies parameter_prefix: gov.states.oh.dcy.ccap - state: PA diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.yaml new file mode 100644 index 00000000000..22e20c2bda4 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.yaml @@ -0,0 +1,309 @@ +# Procedure Letter 36, pages 2 and 4: one monthly payment per child, up to the provider's private rate. + +- name: Family of three earning $40,000 with a toddler and a preschooler at centers. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + person3: + age: 4 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_333.33 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + # Procedure Letter 36: 800 + 750. + oh_ccap_eligible: false + oh_ccap: 0 + oh_ccvp_eligible: true + oh_ccvp: 1_550 + +- name: The charge caps the payment for each child. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 6_000 + person3: + age: 4 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + # min(800, 6,000 / 12 = 500) + min(750, 2,000) = 1,250. + oh_ccvp: 1_250 + +- name: Each child takes its own provider's rate. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + person3: + age: 4 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + oh_ccap_provider_type: HOME + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + # Center toddler 800 + home preschooler 500. + oh_ccvp: 1_300 + +- name: A child without a charge draws no payment. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 0 + person3: + age: 4 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + oh_ccvp: 750 + +- name: A family over the limit draws no payment. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + person3: + age: 4 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 4_443 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + oh_ccvp_eligible: false + oh_ccvp: 0 + +- name: A family on Publicly Funded Child Care draws no voucher payment. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + person3: + age: 4 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 2_000 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + oh_ccap_eligible: true + oh_ccvp: 0 + +- name: November 2026 pays the Publicly Funded Child Care rates. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + pre_subsidy_childcare_expenses: + 2026: 24_000 + childcare_hours_per_week: + 2026: 40 + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + pre_subsidy_childcare_expenses: + 2026: 24_000 + childcare_hours_per_week: + 2026: 40 + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # Category 1 center full-time: 780 + 693.33. + oh_ccvp: 1_473.33 + +- name: November 2026 adds no quality enhancement. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + pre_subsidy_childcare_expenses: + 2026: 24_000 + childcare_hours_per_week: + 2026: 40 + oh_ccap_quality_tier: GOLD + oh_ccap_is_accredited: true + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + pre_subsidy_childcare_expenses: + 2026: 24_000 + childcare_hours_per_week: + 2026: 40 + oh_ccap_quality_tier: GOLD + oh_ccap_is_accredited: true + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # H.B. 96, Section 423.190, rules out Step Up to Quality rates. Accreditation stays out too; + # the pull request lists this as a reading. + oh_ccvp: 1_473.33 + +- name: November 2026 caps the payment at the charge. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + pre_subsidy_childcare_expenses: + 2026: 6_000 + childcare_hours_per_week: + 2026: 40 + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + pre_subsidy_childcare_expenses: + 2026: 24_000 + childcare_hours_per_week: + 2026: 40 + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # min(780, 500) + min(693.33, 2,000) = 1,193.33. + oh_ccvp: 1_193.33 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.yaml new file mode 100644 index 00000000000..39c21d605ba --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.yaml @@ -0,0 +1,945 @@ +# Ohio Child Care Choice Voucher Program eligibility. +# Procedure Letter 36 (October 29, 2025), pages 3-4: income of 146-200% of poverty, all other +# Publicly Funded Child Care conditions, and no family eligible for that program. +# Procedure Letter 21, page 2, and Procedure Letter 45, page 2, print the monthly limits. +# H.B. 96, Section 423.190, sets the same income conditions in law. + +- name: Family of three at the January 2026 Publicly Funded Child Care intake limit stays on that program. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_221 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + # Procedure Letter 21: 145% prints $3,221 for three. + oh_ccap_income_eligible: true + oh_ccvp_eligible: false + +- name: One dollar over the January 2026 intake limit qualifies for the voucher. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_222 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + oh_ccap_income_eligible: false + oh_ccvp_eligible: true + +- name: January 2026 voucher limit. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 4_442 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + # Procedure Letter 21: 200% prints $4,442 for three. + oh_ccvp_eligible: true + +- name: One dollar over the January 2026 voucher limit. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 4_443 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + oh_ccvp_eligible: false + +- name: September 2026 still reads the 2025 guideline. + period: 2026-09 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_222 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: OH + output: + oh_ccap_income_eligible: false + oh_ccvp_eligible: true + +- name: October 2026 moves the same family back to Publicly Funded Child Care. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_222 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: OH + output: + # Procedure Letter 45: 145% prints $3,302 for three from October 1, 2026. + oh_ccap_income_eligible: true + oh_ccvp_eligible: false + +- name: October 2026 intake limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_302 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: OH + output: + oh_ccap_income_eligible: true + oh_ccvp_eligible: false + +- name: One dollar over the October 2026 intake limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_303 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: OH + output: + oh_ccap_income_eligible: false + oh_ccvp_eligible: true + +- name: October 2026 voucher limit for three. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 4_554 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: OH + output: + # Procedure Letter 45: 200% prints $4,554 for three. + oh_ccvp_eligible: true + +- name: One dollar over the October 2026 voucher limit for three. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 4_555 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: OH + output: + oh_ccvp_eligible: false + +- name: October 2026 voucher limit for 2. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + oh_ccap_countable_income: 3_607 + households: + household: + members: [person1, person2] + state_code: + 2026: OH + output: + oh_ccvp_eligible: true + +- name: One dollar over the October 2026 voucher limit for 2. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + oh_ccap_countable_income: 3_608 + households: + household: + members: [person1, person2] + state_code: + 2026: OH + output: + oh_ccvp_eligible: false + +- name: October 2026 voucher limit for 4. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person4: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + oh_ccap_countable_income: 5_500 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: OH + output: + oh_ccvp_eligible: true + +- name: One dollar over the October 2026 voucher limit for 4. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person4: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + oh_ccap_countable_income: 5_501 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: OH + output: + oh_ccvp_eligible: false + +- name: October 2026 voucher limit for 8. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person4: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person5: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person6: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person7: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person8: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + oh_ccap_countable_income: 9_287 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: + 2026: OH + output: + oh_ccvp_eligible: true + +- name: One dollar over the October 2026 voucher limit for 8. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person4: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person5: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person6: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person7: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person8: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + oh_ccap_countable_income: 9_288 + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: + 2026: OH + output: + oh_ccvp_eligible: false + +- name: Enrolled Publicly Funded Child Care family keeps that program, not the voucher. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_400 + oh_ccap_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + # Procedure Letter 36: families eligible for Publicly Funded Child Care are not eligible for the voucher. + oh_ccap_eligible: true + oh_ccvp_eligible: false + +- name: Special-needs family at 150% stays on Publicly Funded Child Care. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + is_disabled: true + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_332 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + # Procedure Letter 21: 150% prints $3,332 for three. + oh_ccap_income_eligible: true + oh_ccvp_eligible: false + +- name: Special-needs family one dollar over 150% qualifies for the voucher. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + is_disabled: true + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_333 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + oh_ccap_income_eligible: false + oh_ccvp_eligible: true + +- name: Employed family in the transitional period stays on Publicly Funded Child Care at 150%. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + oh_ccap_owf_transitional: true + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_300 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + oh_ccap_income_eligible: true + oh_ccvp_eligible: false + +- name: Caretaker without a qualifying activity gets no voucher. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 0 + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + oh_ccap_activity_eligible: false + oh_ccvp_eligible: false + +- name: Full-time student caretaker qualifies for the voucher. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 0 + is_full_time_student: true + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + oh_ccap_activity_eligible: true + oh_ccvp_eligible: true + +- name: Assets at the federal limit pass. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + bank_account_assets: 1_000_000 + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + oh_ccvp_eligible: true + +- name: Assets over the federal limit fail. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + bank_account_assets: 1_000_001 + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + oh_ccvp_eligible: false + +- name: Homeless family goes to Publicly Funded Child Care whatever its income. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: OH + is_homeless: true + output: + oh_ccap_eligible: true + oh_ccvp_eligible: false + +- name: Protective care family goes to Publicly Funded Child Care whatever its income. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + receives_or_needs_protective_services: true + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: OH + output: + oh_ccap_eligible: true + oh_ccvp_eligible: false + +- name: October 2025 precedes the modeled voucher. + period: 2025-10 + input: + people: + person1: + age: + 2025: 30 + weekly_hours_worked_before_lsr: + 2025: 40 + person2: + age: + 2025: 2 + immigration_status: + 2025: CITIZEN + person3: + age: + 2025: 4 + immigration_status: + 2025: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: OH + output: + oh_ccvp_eligible: false + +- name: November 2025 starts the modeled voucher. + period: 2025-11 + input: + people: + person1: + age: + 2025: 30 + weekly_hours_worked_before_lsr: + 2025: 40 + person2: + age: + 2025: 2 + immigration_status: + 2025: CITIZEN + person3: + age: + 2025: 4 + immigration_status: + 2025: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: OH + output: + oh_ccvp_eligible: true + +- name: A 14-year-old qualifies the family for the voucher but not for Publicly Funded Child Care. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 14 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccap_eligible: false + oh_ccvp_eligible: true + +- name: A 15-year-old does not qualify the family. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 15 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_eligible: false + +- name: Below the intake limit a family with only a 14-year-old fails both programs. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 14 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + oh_ccap_countable_income: 2_500 + households: + household: + members: [person1, person2] + state_code: OH + output: + # H.B. 96, Section 423.190: the voucher serves families that fail the income conditions for Publicly Funded Child Care. + oh_ccap_income_eligible: true + oh_ccap_eligible: false + oh_ccvp_eligible: false + +- name: A family outside Ohio gets no voucher. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: PA + output: + oh_ccvp_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible_child.yaml new file mode 100644 index 00000000000..9f11f92cd5a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible_child.yaml @@ -0,0 +1,101 @@ +# Procedure Letter 36, page 3: school age runs to under 15, or under 18 with special needs. + +- name: Infant qualifies. + period: 2026-01 + input: + people: + person1: + age: 0 + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: OH + output: + oh_ccvp_eligible_child: true + +- name: A 13-year-old qualifies, past the Publicly Funded Child Care limit. + period: 2026-01 + input: + people: + person1: + age: 13 + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: OH + output: + oh_ccvp_eligible_child: true + +- name: Just under 15 qualifies. + period: 2026-01 + input: + people: + person1: + age: 14.99 + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: OH + output: + oh_ccvp_eligible_child: true + +- name: A 15-year-old does not qualify. + period: 2026-01 + input: + people: + person1: + age: 15 + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: OH + output: + oh_ccvp_eligible_child: false + +- name: Special-needs child just under 18 qualifies. + period: 2026-01 + input: + people: + person1: + age: 17.99 + immigration_status: CITIZEN + is_disabled: true + households: + household: + members: [person1] + state_code: OH + output: + oh_ccvp_eligible_child: true + +- name: Special-needs child at 18 does not qualify. + period: 2026-01 + input: + people: + person1: + age: 18 + immigration_status: CITIZEN + is_disabled: true + households: + household: + members: [person1] + state_code: OH + output: + oh_ccvp_eligible_child: false + +- name: An undocumented child does not qualify. + period: 2026-01 + input: + people: + person1: + age: 5 + immigration_status: UNDOCUMENTED + households: + household: + members: [person1] + state_code: OH + output: + oh_ccvp_eligible_child: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.yaml new file mode 100644 index 00000000000..15a90ea1e1e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.yaml @@ -0,0 +1,419 @@ +# Procedure Letter 36, pages 2-3: monthly voucher payment by provider type and age from November 1, 2025. +# H.B. 96, Section 423.190: Publicly Funded Child Care payment rates by November 1, 2026, without the +# Step Up to Quality enhancement. + +- name: January 2026 center rate for an infant. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 0.5 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 900] + +- name: January 2026 home rate for an infant. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 0.5 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + oh_ccap_provider_type: HOME + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 600] + +- name: January 2026 center rate for a toddler. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 2 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 800] + +- name: January 2026 home rate for a toddler. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 2 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + oh_ccap_provider_type: HOME + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 550] + +- name: January 2026 center rate for a preschooler. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 750] + +- name: January 2026 home rate for a preschooler. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + oh_ccap_provider_type: HOME + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 500] + +- name: January 2026 center rate for a school-age child. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 7 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 375] + +- name: January 2026 home rate for a school-age child. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 7 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + oh_ccap_provider_type: HOME + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 300] + +- name: A 14-year-old takes the school-age rate. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 14 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 375] + +- name: A 16-year-old with special needs takes the school-age rate. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 16 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + is_disabled: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 375] + +- name: A 15-year-old without special needs has no rate. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 15 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 0] + +- name: The chart has no summer row, so July keeps the school-age center rate. + period: 2026-07 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 7 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + output: + oh_ccvp_rate: [0, 375] + +- name: The chart has no summer row, so July keeps the school-age home rate. + period: 2026-07 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 7 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + oh_ccap_provider_type: HOME + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + output: + oh_ccvp_rate: [0, 300] + +- name: The flat chart still applies in October 2026. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + output: + oh_ccvp_rate: [0, 800] + +- name: November 2026 pays the Publicly Funded Child Care rate for a toddler at a center. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # OAC 5180:6-1-10 Appendix A, category 1 center toddler full-time: 180 a week x 52 / 12 = 780. + oh_ccvp_rate: [0, 780] + +- name: November 2026 pays the Publicly Funded Child Care rate for a toddler at a home. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + oh_ccap_provider_type: HOME + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # OAC 5180:6-1-10 Appendix A, category 1 home toddler full-time: 162.71 a week x 52 / 12 = 705.08. + oh_ccvp_rate: [0, 705.08] + +- name: November 2026 pays a 14-year-old the school-age rate. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 14 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # Category 1 center school-age full-time: 107.71 a week x 52 / 12 = 466.74. + oh_ccvp_rate: [0, 466.74] + +- name: November 2026 pays nothing for a child without care hours. + period: 2026-11 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 0 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + oh_ccvp_rate: [0, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_child_care_subsidies.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_child_care_subsidies.yaml new file mode 100644 index 00000000000..0bcb5252815 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_child_care_subsidies.yaml @@ -0,0 +1,61 @@ +- name: Annual subsidies add voucher payments across 2026. + period: 2026 + absolute_error_margin: 0.05 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + employment_income: 42_000 + person2: + age: 2 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + person3: + age: 4 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: OH + county_str: BROWN_COUNTY_OH + output: + # 10 months x 1,550 + 2 months x 1,473.33. + oh_child_care_subsidies: 18_446.67 + +- name: Annual subsidies count only the modeled months of 2025. + period: 2025 + absolute_error_margin: 0.05 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + employment_income: 42_000 + person2: + age: 2 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + person3: + age: 4 + immigration_status: CITIZEN + pre_subsidy_childcare_expenses: 24_000 + childcare_hours_per_week: 40 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: OH + county_str: BROWN_COUNTY_OH + output: + # November and December x 1,550. + oh_child_care_subsidies: 3_100 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/oh_ccap_base_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/oh_ccap_base_rate.yaml index 5388cf8c588..d093bf1c1a8 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/oh_ccap_base_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/oh_ccap_base_rate.yaml @@ -1,10 +1,10 @@ -# Tests for oh_ccap_base_rate (Person, MONTH, defined_for oh_ccap_eligible_child). +# Tests for oh_ccap_base_rate (Person, MONTH, defined_for StateCode.OH). # 5180:6-1-10 Appendix A: maximum reimbursement ceilings keyed by county rate # category, age group, provider type, and time category. Hourly cells are # per-hour amounts applied to the child's authorized monthly hours; part-time # and full-time cells are weekly amounts converted to monthly (x 52 / 12). -# Rates start 2025-11-01, so cases use period 2026. The parent (person1) is not -# an eligible child, so its base rate is 0. +# Rates start 2025-11-01, so cases use period 2026. The parent (person1) has no +# care hours, so its base rate is 0. - name: Case 1, category 1 center infant full-time. period: 2026-01 absolute_error_margin: 0.01 diff --git a/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.py b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.py new file mode 100644 index 00000000000..e87352c6c9e --- /dev/null +++ b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class oh_ccvp(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "Ohio Child Care Choice Voucher Program monthly payment" + definition_period = MONTH + defined_for = "oh_ccvp_eligible" + reference = ( + "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=2", + "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=4", + ) + + def formula(spm_unit, period, parameters): + # Procedure Letter 36: the voucher pays one program per child each + # month, and that payment plus the family's portion may not exceed the + # provider's private rate, so the charge caps the payment. The voucher + # has no Publicly Funded Child Care copayment; the letter encourages + # programs to hold the family's portion to 9% of income without + # requiring it. + person = spm_unit.members + rate = person("oh_ccvp_rate", period) + charge = person("pre_subsidy_childcare_expenses", period) + return spm_unit.sum(min_(rate, charge)) diff --git a/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.py b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.py new file mode 100644 index 00000000000..98a978826d2 --- /dev/null +++ b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.py @@ -0,0 +1,49 @@ +from policyengine_us.model_api import * + + +class oh_ccvp_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for the Ohio Child Care Choice Voucher Program" + definition_period = MONTH + defined_for = StateCode.OH + reference = ( + "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=3", + "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=4", + "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners%20and%20Providers/Rules%20and%20Resources/2026/PL_45.pdf#page=2", + "https://www.lsc.ohio.gov/assets/legislation/136/hb96/en0/files/hb96-kid-bill-analysis-as-enacted-136th-general-assembly.pdf#page=10", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.oh.dcy.ccap.ccvp + if not p.in_effect: + return np.zeros_like( + spm_unit("spm_unit_size", period.this_year), dtype=bool + ) + has_eligible_child = add(spm_unit, period, ["oh_ccvp_eligible_child"]) > 0 + # H.B. 96, Section 423.190: the family fails the income conditions for + # Publicly Funded Child Care and income does not exceed 200% of the + # poverty line. Procedure Letters 21 and 45 print this limit rounded up + # to the next whole dollar, as they print the other limits. + income_limit = np.ceil(spm_unit("oh_ccap_fpg", period) * p.fpl_rate) + within_limit = spm_unit("oh_ccap_countable_income", period) <= income_limit + fails_pfcc_income_test = ~spm_unit("oh_ccap_income_eligible", period) + # Procedure Letter 36: families meet every other Publicly Funded Child + # Care requirement. + activity_eligible = spm_unit("oh_ccap_activity_eligible", period) + asset_limit = parameters(period).gov.hhs.ccdf.asset_limit + asset_eligible = ( + add(spm_unit, period.this_year, ["bank_account_assets"]) <= asset_limit + ) + # Procedure Letter 36: families eligible for Publicly Funded Child Care + # cannot use the voucher. Protective care and homeless families qualify + # for that program without its income test. + pfcc_eligible = spm_unit("oh_ccap_eligible", period) + return ( + has_eligible_child + & within_limit + & fails_pfcc_income_test + & activity_eligible + & asset_eligible + & ~pfcc_eligible + ) diff --git a/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible_child.py b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible_child.py new file mode 100644 index 00000000000..2a3490f93bb --- /dev/null +++ b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible_child.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class oh_ccvp_eligible_child(Variable): + value_type = bool + entity = Person + label = "Eligible child for the Ohio Child Care Choice Voucher Program" + definition_period = MONTH + defined_for = StateCode.OH + reference = "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=3" + + def formula(person, period, parameters): + # Procedure Letter 36 prices school-age children under 15, or under 18 + # with special needs, and requires families to meet the other Publicly + # Funded Child Care conditions, which include the child's immigration + # status. + p = parameters(period).gov.states.oh.dcy.ccap + age = person("age", period.this_year) + age_eligible = where( + person("oh_ccap_special_needs", period), + age < p.eligibility.special_needs_child_age_limit, + age < p.ccvp.child_age_limit, + ) + immigration_eligible = person( + "is_ccdf_immigration_eligible_child", period.this_year + ) + return age_eligible & immigration_eligible diff --git a/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.py b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.py new file mode 100644 index 00000000000..5d90124645e --- /dev/null +++ b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class oh_ccvp_rate(Variable): + value_type = float + entity = Person + unit = USD + label = "Ohio Child Care Choice Voucher Program monthly payment rate" + definition_period = MONTH + defined_for = "oh_ccvp_eligible_child" + reference = ( + "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=2", + "https://www.lsc.ohio.gov/assets/legislation/136/hb96/en0/files/hb96-kid-bill-analysis-as-enacted-136th-general-assembly.pdf#page=10", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.oh.dcy.ccap.ccvp + # H.B. 96, Section 423.190, moves the voucher to the Publicly Funded + # Child Care payment rates by November 1, 2026, without the Step Up to + # Quality enhancement, so the rate before add-ons applies from then on. + if p.pfcc_rates_in_effect: + return person("oh_ccap_base_rate", period) + provider_type = person("oh_ccap_provider_type", period) + age_group = person("oh_ccap_child_age_group", period) + return p.payment[provider_type][age_group] diff --git a/policyengine_us/variables/gov/states/oh/dcy/ccap/oh_ccap_base_rate.py b/policyengine_us/variables/gov/states/oh/dcy/ccap/oh_ccap_base_rate.py index e23d55b60fa..75e9cea2a46 100644 --- a/policyengine_us/variables/gov/states/oh/dcy/ccap/oh_ccap_base_rate.py +++ b/policyengine_us/variables/gov/states/oh/dcy/ccap/oh_ccap_base_rate.py @@ -13,7 +13,10 @@ class oh_ccap_base_rate(Variable): unit = USD label = "Ohio CCAP monthly maximum reimbursement rate before add-ons" definition_period = MONTH - defined_for = "oh_ccap_eligible_child" + # Both readers apply their own child test: oh_ccap_rate_with_addons for + # Publicly Funded Child Care and oh_ccvp_rate for the voucher, which also + # covers 13- and 14-year-olds. + defined_for = StateCode.OH reference = "https://codes.ohio.gov/assets/laws/administrative-code/pdfs/5180/6/1/5180$6-1-10_PH_FF_N_APP1_20251020_1028.pdf#page=1" def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/states/oh/dcy/ccap/oh_child_care_subsidies.py b/policyengine_us/variables/gov/states/oh/dcy/ccap/oh_child_care_subsidies.py index 7715fdcaa36..b3b8f090ca5 100644 --- a/policyengine_us/variables/gov/states/oh/dcy/ccap/oh_child_care_subsidies.py +++ b/policyengine_us/variables/gov/states/oh/dcy/ccap/oh_child_care_subsidies.py @@ -8,4 +8,4 @@ class oh_child_care_subsidies(Variable): unit = USD definition_period = YEAR defined_for = StateCode.OH - adds = ["oh_ccap"] + adds = ["oh_ccap", "oh_ccvp"] From 9e679112c000ec974fec43b90a1980293daf72d0 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 6 Nov 2026 18:29:26 -0500 Subject: [PATCH 05/13] Date Georgia's CAPS income limits and add its priority groups DECAL's letters date each limit for new applicants: 50% of state median income from October 2016, 85% from November 1, 2021, 50% again from December 16, 2022, 30% from September 1, 2024, 40% from October 6, 2025 and 50% from March 2, 2026. Main applied 50% at every date. Enrolled families keep 85% throughout. From August 1, 2016, DECAL serves a new applicant only in a priority group (CAPS/00-7, 7.3.1), and redetermination drops that requirement (7.3.1.3). The model now checks each group it can observe: protective services and court supervision, DFCS custody, disability, Georgia's Pre-K, minor and student parents, TANF, homelessness, very low income, domestic violence, natural disasters and Grandparents Raising Grandchildren. Foster parents of children in DFCS custody skip the income and activity tests (7.5), and GRG parents skip the activity test (7.13). The income test reads the state median income table at the month, rounds the annual limit up to the dollar as Appendix A prints it, and compares it with twelve times monthly income (Manual 8.8.4). Co-Authored-By: Claude Opus 5.5 --- changelog.d/child-care-posted-limits.added.md | 1 + .../income/smi_rate/initial_eligibility.yaml | 31 +- .../income/smi_rate/ongoing_eligibility.yaml | 15 +- .../decal/caps/priority_groups/in_effect.yaml | 20 + .../priority_groups/minor_parent_age.yaml | 16 + .../student_parent_in_effect.yaml | 14 + .../very_low_income_fpg_rate.yaml | 39 + policyengine_us/programs.yaml | 1 + .../caps/eligibility/ga_caps_eligible.yaml | 21 +- .../ga_caps_eligible_priority_groups.yaml | 315 ++++ .../eligibility/ga_caps_income_eligible.yaml | 76 +- .../ga_caps_income_eligible_by_date.yaml | 1020 +++++++++++++ .../ga_caps_priority_group_eligible.yaml | 1296 +++++++++++++++++ .../gov/states/ga/decal/caps/ga_caps.yaml | 20 +- .../gov/states/ga/decal/caps/integration.yaml | 66 +- .../eligibility/ga_caps_activity_eligible.py | 21 +- .../caps/eligibility/ga_caps_eligible.py | 19 +- .../eligibility/ga_caps_income_eligible.py | 29 +- .../ga_caps_domestic_violence.py | 10 + ...caps_grandparents_raising_grandchildren.py | 10 + .../ga_caps_natural_disaster.py | 10 + .../priority_groups/ga_caps_pre_k_enrolled.py | 10 + .../ga_caps_priority_group_eligible.py | 70 + 23 files changed, 3041 insertions(+), 89 deletions(-) create mode 100644 changelog.d/child-care-posted-limits.added.md create mode 100644 policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/minor_parent_age.yaml create mode 100644 policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/student_parent_in_effect.yaml create mode 100644 policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/very_low_income_fpg_rate.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_eligible_priority_groups.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible_by_date.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.yaml create mode 100644 policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_domestic_violence.py create mode 100644 policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_grandparents_raising_grandchildren.py create mode 100644 policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_natural_disaster.py create mode 100644 policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_pre_k_enrolled.py create mode 100644 policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.py diff --git a/changelog.d/child-care-posted-limits.added.md b/changelog.d/child-care-posted-limits.added.md new file mode 100644 index 00000000000..f72924184a0 --- /dev/null +++ b/changelog.d/child-care-posted-limits.added.md @@ -0,0 +1 @@ +Add Ohio's Child Care Choice Voucher Program and the priority groups that decide which new applicants Georgia's Childcare and Parent Services program serves. diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/income/smi_rate/initial_eligibility.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/income/smi_rate/initial_eligibility.yaml index d0ed56c1b32..6d7f294a791 100644 --- a/policyengine_us/parameters/gov/states/ga/decal/caps/income/smi_rate/initial_eligibility.yaml +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/income/smi_rate/initial_eligibility.yaml @@ -1,5 +1,18 @@ description: Georgia limits the Childcare and Parent Services program to new applicants with income at or below this share of state median income. + +# DECAL's letters date every change. An emergency waiver raised the limit to 85% +# from November 1, 2021, through December 15, 2022. The 2024 spending plan's +# "November 2021 - September 2024" and the governor's "through October 1, 2024" +# describe the funding window, and DECAL's December 2022 letter and emergency +# memorandum end the income waiver earlier. DECAL applies each limit by application +# received date. The model carries no application date, so it moves every new +# applicant at the first month that starts on or after the effective date. values: + 2016-10-01: 0.5 + 2021-11-01: 0.85 + 2022-12-16: 0.5 + 2024-09-01: 0.3 + 2025-10-06: 0.4 2026-03-02: 0.5 metadata: @@ -9,5 +22,19 @@ metadata: reference: - title: Georgia CAPS Policy Manual, Section 8.3 (Gross Income) href: https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=49 - - title: Georgia CAPS Appendix A - Maximum Income Limits by Family Size (effective March 2, 2026) - href: https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf + - title: Georgia CAPS Appendix A, Maximum Income Limits (effective October 5, 2026) + href: https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 + - title: Georgia DECAL, Letter to CAPS Families (October 21, 2021), 50% to 85% from November 1, 2021 + href: https://caps.decal.ga.gov/assets/downloads/CAPS_Letter_from_Elisabetta_Kasfir_Families_10-21-21.pdf#page=1 + - title: Georgia DECAL, Letter to CAPS Families (December 19, 2022), back to 50% from December 16, 2022 + href: https://caps.decal.ga.gov/assets/downloads/CAPS_Letter_to_Parents_Change_in_Income_Limits_12.19.2022.pdf#page=1 + - title: Georgia DECAL, CAPS Emergency Policy Memorandum, income limit waiver dates + href: https://caps.decal.ga.gov/assets/downloads/CAPS_Emergency_Policy_Memorandum.pdf#page=3 + - title: Georgia DECAL, Letter to CAPS Families (September 3, 2024), 50% to 30% from September 1, 2024 + href: https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_from_Elisabetta_Kasfir_Families_09.03.2024.pdf#page=1 + - title: Georgia DECAL, Letter to CAPS Families (October 6, 2025), 30% to 40% from October 6, 2025 + href: https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_to_Families_Policy_Revisions_10.06.25.pdf#page=1 + - title: Georgia DECAL, Letter to CAPS Families (March 2, 2026), 40% to 50% from March 2, 2026 + href: https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_to_Families_Policy_Revisions_03.02.26.pdf#page=1 + - title: Georgia CCDF Plan FFY 2025-2027, Section 2.2.4, 40% of state median income effective October 6, 2025 + href: https://www.decal.ga.gov/documents/attachments/CCDFStatePlan25-27.pdf#page=22 diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/income/smi_rate/ongoing_eligibility.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/income/smi_rate/ongoing_eligibility.yaml index 2231f1669c9..3b46f1731cc 100644 --- a/policyengine_us/parameters/gov/states/ga/decal/caps/income/smi_rate/ongoing_eligibility.yaml +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/income/smi_rate/ongoing_eligibility.yaml @@ -1,6 +1,11 @@ description: Georgia limits the Childcare and Parent Services program to enrolled families with income at or below this share of state median income. + +# DECAL's June 2018 letter raises the limit at annual redetermination from 50% to +# 85% on March 26, 2018. Urban Institute's 2016 tables print 85% within the +# eligibility period and 50% at redetermination before that. The model carries one +# limit for enrolled families, so it reads 85% at every date. values: - 2026-03-02: 0.85 + 2016-10-01: 0.85 metadata: unit: /1 @@ -9,5 +14,9 @@ metadata: reference: - title: Georgia CAPS Policy Manual, Section 8.3 (Gross Income) href: https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=49 - - title: Georgia CAPS Appendix A - Maximum Income Limits by Family Size (effective March 2, 2026) - href: https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf + - title: Georgia CAPS Appendix A, Maximum Income Limits (effective October 5, 2026) + href: https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 + - title: Georgia DECAL, Letter to CAPS Child Care Providers (June 18, 2018), 85% at redetermination from March 26, 2018 + href: https://caps.decal.ga.gov/assets/downloads/CAPS_Letter_from_Elisabetta_Kasfir_6-18-2018.pdf#page=1 + - title: Georgia DECAL, Letter to CAPS Families (March 2, 2026), ongoing limit stays at 85% + href: https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_to_Families_Policy_Revisions_03.02.26.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/in_effect.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/in_effect.yaml new file mode 100644 index 00000000000..21f9beb997e --- /dev/null +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/in_effect.yaml @@ -0,0 +1,20 @@ +description: Georgia uses this indicator to determine whether the Childcare and Parent Services program requires new applicants to belong to a priority group. + +# DECAL restricted funding to priority groups for new applicants from August 1, +# 2016. The funding Q&A adds the homeless, domestic violence and very low income +# groups on October 1, 2016, and the model counts them from August 1. +values: + 2015-01-01: false + 2016-08-01: true + +metadata: + unit: bool + period: month + label: Georgia CAPS priority group requirement in effect + reference: + - title: Georgia DECAL, Questions about CAPS Funding Restrictions (2016) + href: https://www.decal.ga.gov/documents/attachments/fundingrestrictionsqa.pdf#page=1 + - title: Georgia CAPS Policy CAPS/00-7, Section 7.3.1 (revised October 5, 2026) + href: https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=1 + - title: Georgia CCDF Plan FFY 2025-2027, Section 2.2.7 + href: https://www.decal.ga.gov/documents/attachments/CCDFStatePlan25-27.pdf#page=25 diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/minor_parent_age.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/minor_parent_age.yaml new file mode 100644 index 00000000000..ba4ca2ee2a3 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/minor_parent_age.yaml @@ -0,0 +1,16 @@ +description: Georgia limits the minor parent priority group to parents at or below this age under the Childcare and Parent Services program. + +# The 2016 funding Q&A names minor parents in school without an age. The revision +# history of CAPS/00-7 records no change to the age. +values: + 2016-08-01: 20 + +metadata: + unit: year + period: year + label: Georgia CAPS minor parent priority group age limit + reference: + - title: Georgia CAPS Policy CAPS/00-7, Section 7.14 (revised October 5, 2026) + href: https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=8 + - title: Georgia CCDF Plan FFY 2025-2027, Section 2.3.2 + href: https://www.decal.ga.gov/documents/attachments/CCDFStatePlan25-27.pdf#page=34 diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/student_parent_in_effect.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/student_parent_in_effect.yaml new file mode 100644 index 00000000000..25ed8b4ca73 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/student_parent_in_effect.yaml @@ -0,0 +1,14 @@ +description: Georgia uses this indicator to determine whether student parents form a priority group under the Childcare and Parent Services program. +values: + 2015-01-01: false + 2022-05-01: true + +metadata: + unit: bool + period: month + label: Georgia CAPS student parent priority group in effect + reference: + - title: Georgia CAPS Policy CAPS/00-7, revision history (May 1, 2022) + href: https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=10 + - title: Georgia CAPS Policy CAPS/00-7, Section 7.16 (revised October 5, 2026) + href: https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=9 diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/very_low_income_fpg_rate.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/very_low_income_fpg_rate.yaml new file mode 100644 index 00000000000..016132940cd --- /dev/null +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/very_low_income_fpg_rate.yaml @@ -0,0 +1,39 @@ +description: Georgia limits the very low income priority group to families with income at or below this share of the federal poverty guideline under the Childcare and Parent Services program. + +# DECAL's letters date every change. DECAL applies each rate by application received +# date. The model carries no application date, so it moves every new applicant at +# the first month that starts on or after the effective date. The 50% back to +# October 2016 rests on the June 2018 letter's "previously". +values: + 2016-10-01: 0.5 + 2018-05-30: 1 + 2019-07-01: 0.5 + 2021-11-01: 1.5 + 2022-12-16: 0.5 + 2024-07-01: 0.1 + 2025-10-06: 0.3 + 2026-03-02: 0.5 + +metadata: + unit: /1 + period: year + label: Georgia CAPS very low income priority group poverty guideline rate + reference: + - title: Georgia CAPS Policy CAPS/00-7, Section 7.12 (revised October 5, 2026) + href: https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=7 + - title: Georgia CAPS Appendix A, Maximum Income Limits (effective October 5, 2026) + href: https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 + - title: Georgia DECAL, Letter to CAPS Child Care Providers (June 18, 2018), 50% to 100% from May 30, 2018 + href: https://caps.decal.ga.gov/assets/downloads/CAPS_Letter_from_Elisabetta_Kasfir_6-18-2018.pdf#page=1 + - title: Georgia DECAL, CAPS Policy Webinar (July 10, 2019), slide 4, back to 50% for applications from July 1, 2019 + href: http://caps.decal.ga.gov/Assets/downloads/CAPS_Policy_Webinar_for_Child_Care_Providers_7-10-19.pdf#page=4 + - title: Georgia DECAL, Letter to CAPS Families (October 21, 2021), 50% to 150% from November 1, 2021 + href: https://caps.decal.ga.gov/assets/downloads/CAPS_Letter_from_Elisabetta_Kasfir_Families_10-21-21.pdf#page=1 + - title: Georgia DECAL, Letter to CAPS Families (December 19, 2022), back to 50% from December 16, 2022 + href: https://caps.decal.ga.gov/assets/downloads/CAPS_Letter_to_Parents_Change_in_Income_Limits_12.19.2022.pdf#page=1 + - title: Georgia DECAL, Letter to CAPS Families (July 1, 2024), 50% to 10% from July 1, 2024 + href: https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_from_Elisabetta_Kasfir_Families_07.01.2024.pdf#page=2 + - title: Georgia DECAL, Letter to CAPS Families (October 6, 2025), 10% to 30% from October 6, 2025 + href: https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_to_Families_Policy_Revisions_10.06.25.pdf#page=1 + - title: Georgia DECAL, Letter to CAPS Families (March 2, 2026), 30% to 50% from March 2, 2026 + href: https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_to_Families_Policy_Revisions_03.02.26.pdf#page=1 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 4fd38544599..c787c5d52bf 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -911,6 +911,7 @@ programs: full_name: Georgia Childcare and Parent Services variable: ga_caps parameter_prefix: gov.states.ga.decal.caps + notes: Models the dated limits for new applicants since 2016 (50% of state median income from October 2016, 85% from November 2021, 50% from December 2022, 30% from September 2024, 40% from October 2025 and 50% from March 2026), the 85% limit for enrolled families, and the priority groups that decide which new applicants DECAL serves from August 2016. Not modeled - application dates, the 2020 Essential Services Workforce group, and DECAL's discretionary waivers - state: ND status: partial name: North Dakota CCAP diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_eligible.yaml index c2d75fa0596..fde18e265e3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_eligible.yaml @@ -1,9 +1,12 @@ # GA CAPS family eligibility -# Requires: eligible child, income eligible, activity eligible, asset eligible +# Requires: eligible child, income eligible, activity eligible, asset eligible, +# and a priority group or current enrollment # -# GA SMI for 4-person household at 2026-01: $116,773.19 (uprated) -# Family of 2: 116,773.19 * 0.68 = $79,405.77 -# 50% SMI = $39,702.88 +# GA SMI 4-person at 2026-01 (October 2025 table): $110,736 +# New applicants in January 2026 face 40% of it, rounded up to the next dollar: +# Family of 2: 110,736 * 0.68 * 0.4 -> $30,121 +# Family of 3: 110,736 * 0.84 * 0.4 -> $37,208 +# Family of 4: 110,736 * 1.00 * 0.4 -> $44,295 - name: Case 1, eligible family with child under 13 and low income. period: 2026-01 @@ -24,6 +27,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true households: household: members: [person1, person2] @@ -31,7 +35,7 @@ output: ga_caps_eligible: true -- name: Case 2, ineligible due to income above 50 percent SMI. +- name: Case 2, ineligible due to income above the initial limit. period: 2026-01 input: people: @@ -49,12 +53,13 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true households: household: members: [person1, person2] state_code: GA output: - # income 40,000 > 39,702.88 (50% SMI for family of 2) -> ineligible + # income 40,000 > 30,121 (40% SMI for family of 2) -> ineligible ga_caps_eligible: false - name: Case 3, ineligible with no eligible child. @@ -71,6 +76,7 @@ spm_units: spm_unit: members: [person1] + ga_caps_priority_group_eligible: true households: household: members: [person1] @@ -97,6 +103,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true spm_unit_assets: 1_500_000 households: household: @@ -123,6 +130,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true households: household: members: [person1, person2] @@ -150,6 +158,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true households: household: members: [person1, person2] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_eligible_priority_groups.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_eligible_priority_groups.yaml new file mode 100644 index 00000000000..51b4d370f2f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_eligible_priority_groups.yaml @@ -0,0 +1,315 @@ +# GA CAPS eligibility with the priority group requirement. + +- name: New family earning $40,000 meets the October 2026 income limit but has no priority group. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_333.33 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + # CAPS/00-7, 7.3.1: new applicants outside a priority group are denied. + ga_caps_income_eligible: true + ga_caps_priority_group_eligible: false + ga_caps_eligible: false + +- name: Enrolled family at the same income keeps CAPS without a priority group. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_333.33 + ga_caps_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + # CAPS/00-7, 7.3.1.3: no priority group at annual redetermination. + ga_caps_priority_group_eligible: false + ga_caps_eligible: true + +- name: New family at the same income with a child in Georgia's Pre-K qualifies. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + ga_caps_pre_k_enrolled: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_333.33 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + ga_caps_priority_group_eligible: true + ga_caps_eligible: true + +- name: A family earning $40,000 fails the January 2026 limit even with a priority group. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + immigration_status: CITIZEN + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + ga_caps_pre_k_enrolled: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_333.33 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_income_eligible: false + ga_caps_priority_group_eligible: true + ga_caps_eligible: false + +- name: Before August 2016 a family needed no priority group. + period: 2016-07 + input: + people: + person1: + age: + 2016: 30 + weekly_hours_worked_before_lsr: + 2016: 40 + immigration_status: + 2016: CITIZEN + person2: + age: + 2016: 2 + immigration_status: + 2016: CITIZEN + person3: + age: + 2016: 4 + immigration_status: + 2016: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2016: GA + output: + ga_caps_eligible: true + +- name: From August 2016 the same family needs one. + period: 2016-08 + input: + people: + person1: + age: + 2016: 30 + weekly_hours_worked_before_lsr: + 2016: 40 + immigration_status: + 2016: CITIZEN + person2: + age: + 2016: 2 + immigration_status: + 2016: CITIZEN + person3: + age: + 2016: 4 + immigration_status: + 2016: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2016: GA + output: + ga_caps_eligible: false + +- name: DFCS custody waives the income and activity requirements. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 0 + immigration_status: CITIZEN + person2: + age: 2 + immigration_status: CITIZEN + is_in_foster_care: true + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 9_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.5: foster parents need not meet income or activity requirements. + ga_caps_income_eligible: true + ga_caps_activity_eligible: true + ga_caps_priority_group_eligible: true + ga_caps_eligible: true + +- name: Grandparents raising grandchildren need no qualifying activity. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 0 + immigration_status: CITIZEN + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + ga_caps_grandparents_raising_grandchildren: true + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.13. + ga_caps_activity_eligible: true + ga_caps_eligible: true + +- name: Grandparents raising grandchildren still meet the income limit. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 0 + immigration_status: CITIZEN + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 5_000 + ga_caps_grandparents_raising_grandchildren: true + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_activity_eligible: true + ga_caps_income_eligible: false + ga_caps_eligible: false + +- name: Without the group the same family needs a qualifying activity. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 0 + immigration_status: CITIZEN + person2: + age: 2 + immigration_status: CITIZEN + person3: + age: 4 + immigration_status: CITIZEN + ga_caps_pre_k_enrolled: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_activity_eligible: false + ga_caps_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.yaml index 7f085dc5cd1..81ded6be77f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.yaml @@ -1,13 +1,13 @@ # GA CAPS income eligibility -# Initial (not enrolled): income <= 50% SMI -# Ongoing (enrolled): income <= 85% SMI +# Initial (not enrolled) in January 2026: income <= 40% SMI, rounded up +# Ongoing (enrolled): income <= 85% SMI, rounded up # # GA SMI for 4-person household at 2026-01 (2025-10-01 entry): $110,736 # Family of 2: 110,736 * 0.68 = $75,300.48 -# 50% SMI = $37,650.24 -# 85% SMI = $64,005.41 +# 40% SMI = $30,120.19 -> $30,121 +# 85% SMI = $64,005.41 -> $64,006 -- name: Case 1, new applicant income below 50 percent SMI. +- name: Case 1, new applicant income below 40 percent SMI. period: 2026-01 input: people: @@ -24,10 +24,10 @@ members: [person1, person2] state_code: GA output: - # income 30,000 <= 37,650.24 (50% SMI for family of 2) -> eligible + # income 30,000 <= 30,121 (40% SMI for family of 2) -> eligible ga_caps_income_eligible: true -- name: Case 2, new applicant income above 50 percent SMI. +- name: Case 2, new applicant income above 40 percent SMI. period: 2026-01 input: people: @@ -44,10 +44,10 @@ members: [person1, person2] state_code: GA output: - # income 40,000 > 37,650.24 (50% SMI for family of 2) -> ineligible + # income 40,000 > 30,121 (40% SMI for family of 2) -> ineligible ga_caps_income_eligible: false -- name: Case 3, enrolled family income between 50 and 85 percent SMI. +- name: Case 3, enrolled family income between 40 and 85 percent SMI. period: 2026-01 input: people: @@ -65,7 +65,7 @@ members: [person1, person2] state_code: GA output: - # enrolled: income 50,000 <= 64,005.41 (85% SMI) -> eligible + # enrolled: income 50,000 <= 64,006 (85% SMI) -> eligible ga_caps_income_eligible: true - name: Case 4, enrolled family income above 85 percent SMI. @@ -86,10 +86,10 @@ members: [person1, person2] state_code: GA output: - # enrolled: income 68,000 > 64,005.41 (85% SMI) -> ineligible + # enrolled: income 68,000 > 64,006 (85% SMI) -> ineligible ga_caps_income_eligible: false -- name: Case 5, non-enrolled family between 50 and 85 percent SMI. +- name: Case 5, non-enrolled family between 40 and 85 percent SMI. period: 2026-01 input: people: @@ -107,7 +107,7 @@ members: [person1, person2] state_code: GA output: - # not enrolled: income 50,000 > 37,650.24 (50% SMI) -> ineligible + # not enrolled: income 50,000 > 30,121 (40% SMI) -> ineligible ga_caps_income_eligible: false - name: Case 6, zero income family is eligible. @@ -130,18 +130,18 @@ # Additional family sizes for boundary tests: # Family of 3: 110,736 * 0.84 = $93,018.24 -# 50% SMI = $46,509.12; 85% SMI = $79,065.51 +# 40% SMI -> $37,208; 85% SMI -> $79,066 # Family of 5: 110,736 * 1.16 = $128,453.76 -# 50% SMI = $64,226.88; 85% SMI = $109,185.70 +# 40% SMI -> $51,382; 85% SMI -> $109,186 -- name: Case 7, income exactly at 50 percent SMI threshold for family of 2. +- name: Case 7, income exactly at 40 percent SMI threshold for family of 2. period: 2026-01 input: people: person1: age: 30 - # 50% SMI for family of 2 is $37,650.24/yr - employment_income: 37_650 + # 40% SMI for family of 2 rounds up to $30,121/yr + employment_income: 30_121 person2: age: 5 spm_units: @@ -152,16 +152,16 @@ members: [person1, person2] state_code: GA output: - # income 37,650 <= 37,650.24 -> eligible (just at threshold) + # income 30,121 <= 30,121 -> eligible (at threshold) ga_caps_income_eligible: true -- name: Case 8, income one dollar above 50 percent SMI threshold. +- name: Case 8, income one dollar above 40 percent SMI threshold. period: 2026-01 input: people: person1: age: 30 - employment_income: 37_651 + employment_income: 30_122 person2: age: 5 spm_units: @@ -172,7 +172,7 @@ members: [person1, person2] state_code: GA output: - # income 37,651 > 37,650.24 -> ineligible + # income 30,122 > 30,121 -> ineligible ga_caps_income_eligible: false - name: Case 9, enrolled income exactly at 85 percent SMI threshold. @@ -181,7 +181,7 @@ people: person1: age: 30 - employment_income: 64_005 + employment_income: 64_006 person2: age: 5 spm_units: @@ -193,7 +193,7 @@ members: [person1, person2] state_code: GA output: - # enrolled: income 64,005 <= 64,005.41 -> eligible + # enrolled: income 64,006 <= 64,006 -> eligible ga_caps_income_eligible: true - name: Case 10, enrolled income one dollar above 85 percent SMI. @@ -202,7 +202,7 @@ people: person1: age: 30 - employment_income: 64_006 + employment_income: 64_007 person2: age: 5 spm_units: @@ -214,7 +214,7 @@ members: [person1, person2] state_code: GA output: - # enrolled: income 64,006 > 64,005.41 -> ineligible + # enrolled: income 64,007 > 64,006 -> ineligible ga_caps_income_eligible: false - name: Case 11, very high income family ineligible. @@ -236,13 +236,13 @@ output: ga_caps_income_eligible: false -- name: Case 12, larger family of 5 at 50 percent SMI threshold. +- name: Case 12, larger family of 5 at 40 percent SMI threshold. period: 2026-01 input: people: person1: age: 35 - employment_income: 64_226 + employment_income: 51_382 person2: age: 30 person3: @@ -259,8 +259,8 @@ members: [person1, person2, person3, person4, person5] state_code: GA output: - # 50% SMI family of 5 = $64,226.88 - # income 64,226 <= 64,226.88 -> eligible + # 40% SMI family of 5 rounds up to $51,382 + # income 51,382 <= 51,382 -> eligible ga_caps_income_eligible: true - name: Case 13, larger family of 5 one dollar over threshold. @@ -269,7 +269,7 @@ people: person1: age: 35 - employment_income: 64_227 + employment_income: 51_383 person2: age: 30 person3: @@ -286,8 +286,8 @@ members: [person1, person2, person3, person4, person5] state_code: GA output: - # 50% SMI family of 5 = $64,226.88 - # income 64,227 > 64,226.88 -> ineligible + # 40% SMI family of 5 rounds up to $51,382 + # income 51,383 > 51,382 -> ineligible ga_caps_income_eligible: false - name: Case 14, enrolled family of 3 at ongoing threshold. @@ -296,7 +296,7 @@ people: person1: age: 30 - employment_income: 79_065 + employment_income: 79_066 person2: age: 28 person3: @@ -310,8 +310,8 @@ members: [person1, person2, person3] state_code: GA output: - # 85% SMI family of 3 = $79,065.51 - # enrolled: income 79,065 <= 79,065.51 -> eligible + # 85% SMI family of 3 rounds up to $79,066 + # enrolled: income 79,066 <= 79,066 -> eligible ga_caps_income_eligible: true - name: Case 15, multiple income sources combined. @@ -320,7 +320,7 @@ people: person1: age: 30 - employment_income: 25_000 + employment_income: 20_000 self_employment_income: 10_000 person2: age: 5 @@ -332,5 +332,5 @@ members: [person1, person2] state_code: GA output: - # total income = 25,000 + 10,000 = 35,000 <= 37,650.24 -> eligible + # total income = 20,000 + 10,000 = 30,000 <= 30,121 -> eligible ga_caps_income_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible_by_date.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible_by_date.yaml new file mode 100644 index 00000000000..a8779737927 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible_by_date.yaml @@ -0,0 +1,1020 @@ +# GA CAPS income limits by date. +# DECAL's letters date each change. A monthly variable reads the parameter at the first day of +# the month, so a change after the first applies from the next month. + +- name: September 2019, 50 percent for four, at the limit. + period: 2019-09 + input: + people: + person1: + age: + 2019: 30 + person2: + age: + 2019: 5 + person3: + age: + 2019: 5 + person4: + age: + 2019: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ga_caps_countable_income: 3_050 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2019: GA + output: + # DECAL webinar, September 24, 2019: $36,601 for four before October 2019. + ga_caps_income_eligible: true + +- name: September 2019, 50 percent for four, over the limit. + period: 2019-09 + input: + people: + person1: + age: + 2019: 30 + person2: + age: + 2019: 5 + person3: + age: + 2019: 5 + person4: + age: + 2019: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ga_caps_countable_income: 3_051 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2019: GA + output: + ga_caps_income_eligible: false + +- name: October 2019, 50 percent for four on the new median income table, at the limit. + period: 2019-10 + input: + people: + person1: + age: + 2019: 30 + person2: + age: + 2019: 5 + person3: + age: + 2019: 5 + person4: + age: + 2019: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ga_caps_countable_income: 3_175.25 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2019: GA + output: + # DECAL webinar, September 24, 2019: $38,103 for four in October 2019. + ga_caps_income_eligible: true + +- name: October 2019, 50 percent for four on the new median income table, over the limit. + period: 2019-10 + input: + people: + person1: + age: + 2019: 30 + person2: + age: + 2019: 5 + person3: + age: + 2019: 5 + person4: + age: + 2019: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ga_caps_countable_income: 3_176 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2019: GA + output: + ga_caps_income_eligible: false + +- name: October 2021, 50 percent for four, at the limit. + period: 2021-10 + input: + people: + person1: + age: + 2021: 30 + person2: + age: + 2021: 5 + person3: + age: + 2021: 5 + person4: + age: + 2021: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ga_caps_countable_income: 3_535.5 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2021: GA + output: + # DECAL letter, October 21, 2021: $42,426 for four before the waiver. + ga_caps_income_eligible: true + +- name: October 2021, 50 percent for four, over the limit. + period: 2021-10 + input: + people: + person1: + age: + 2021: 30 + person2: + age: + 2021: 5 + person3: + age: + 2021: 5 + person4: + age: + 2021: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ga_caps_countable_income: 3_536 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2021: GA + output: + ga_caps_income_eligible: false + +- name: November 2021, 85 percent for four, at the limit. + period: 2021-11 + input: + people: + person1: + age: + 2021: 30 + person2: + age: + 2021: 5 + person3: + age: + 2021: 5 + person4: + age: + 2021: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ga_caps_countable_income: 6_010.33 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2021: GA + output: + # DECAL letter, October 21, 2021: $72,124 for four from November 1, 2021. + ga_caps_income_eligible: true + +- name: November 2021, 85 percent for four, over the limit. + period: 2021-11 + input: + people: + person1: + age: + 2021: 30 + person2: + age: + 2021: 5 + person3: + age: + 2021: 5 + person4: + age: + 2021: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ga_caps_countable_income: 6_011 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2021: GA + output: + ga_caps_income_eligible: false + +- name: October 2021, 50 percent for three, at the limit. + period: 2021-10 + input: + people: + person1: + age: + 2021: 30 + person2: + age: + 2021: 5 + person3: + age: + 2021: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_969 + households: + household: + members: [person1, person2, person3] + state_code: + 2021: GA + output: + # Urban Institute CCDF tables print $2,969 for three in October 2021. + ga_caps_income_eligible: true + +- name: October 2021, 50 percent for three, over the limit. + period: 2021-10 + input: + people: + person1: + age: + 2021: 30 + person2: + age: + 2021: 5 + person3: + age: + 2021: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_970 + households: + household: + members: [person1, person2, person3] + state_code: + 2021: GA + output: + ga_caps_income_eligible: false + +- name: November 2021, 85 percent for three, at the limit. + period: 2021-11 + input: + people: + person1: + age: + 2021: 30 + person2: + age: + 2021: 5 + person3: + age: + 2021: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 5_048 + households: + household: + members: [person1, person2, person3] + state_code: + 2021: GA + output: + ga_caps_income_eligible: true + +- name: November 2021, 85 percent for three, over the limit. + period: 2021-11 + input: + people: + person1: + age: + 2021: 30 + person2: + age: + 2021: 5 + person3: + age: + 2021: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 5_049 + households: + household: + members: [person1, person2, person3] + state_code: + 2021: GA + output: + ga_caps_income_eligible: false + +- name: October 2022, 85 percent for three, at the limit. + period: 2022-10 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 5_351 + households: + household: + members: [person1, person2, person3] + state_code: + 2022: GA + output: + # Urban Institute CCDF tables print $5,351 for three in October 2022. + ga_caps_income_eligible: true + +- name: October 2022, 85 percent for three, over the limit. + period: 2022-10 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 5_352 + households: + household: + members: [person1, person2, person3] + state_code: + 2022: GA + output: + ga_caps_income_eligible: false + +- name: December 2022 reads December 1, so 85 percent still applies. + period: 2022-12 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 5_351 + households: + household: + members: [person1, person2, person3] + state_code: + 2022: GA + output: + # DECAL letter, December 19, 2022: the waiver ended December 15, 2022. + ga_caps_income_eligible: true + +- name: January 2023, back to 50 percent for three, at the limit. + period: 2023-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_147 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_income_eligible: true + +- name: January 2023, back to 50 percent for three, over the limit. + period: 2023-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_148 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_income_eligible: false + +- name: August 2024, 50 percent for three, at the limit. + period: 2024-08 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_333.33 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + ga_caps_income_eligible: true + +- name: August 2024, 50 percent for three, over the limit. + period: 2024-08 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_334 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + ga_caps_income_eligible: false + +- name: September 2024, 30 percent for three, at the limit. + period: 2024-09 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + # DECAL letter, September 3, 2024: 50% to 30% from September 1, 2024. + ga_caps_income_eligible: true + +- name: September 2024, 30 percent for three, over the limit. + period: 2024-09 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000.5 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + ga_caps_income_eligible: false + +- name: October 2024, 30 percent for three on the new median income table, at the limit. + period: 2024-10 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_223 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + ga_caps_income_eligible: true + +- name: October 2024, 30 percent for three on the new median income table, over the limit. + period: 2024-10 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_224 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + ga_caps_income_eligible: false + +- name: October 2025 reads October 1, so 30 percent still applies, at the limit. + period: 2025-10 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + person3: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_325 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: GA + output: + ga_caps_income_eligible: true + +- name: October 2025 reads October 1, so 30 percent still applies, over the limit. + period: 2025-10 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + person3: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_326 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: GA + output: + ga_caps_income_eligible: false + +- name: November 2025, 40 percent for three, at the limit. + period: 2025-11 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + person3: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_100.6 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: GA + output: + # DECAL letter, October 6, 2025: 30% to 40%. The CCDF plan prints $3,101 a month for three, + # which rounds $37,208 a year divided by 12. Manual 8.8.4 compares income times 12 with the + # annual chart, so $3,101 a month fails. + ga_caps_income_eligible: true + +- name: November 2025, 40 percent for three, over the limit. + period: 2025-11 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + person3: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_101 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: GA + output: + ga_caps_income_eligible: false + +- name: A family of three earning $40,000 fails in January 2026. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_333.33 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_income_eligible: false + +- name: March 2026 reads March 1, so 40 percent still applies. + period: 2026-03 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_101 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + ga_caps_income_eligible: false + +- name: April 2026, 50 percent for three, at the limit. + period: 2026-04 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_875 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + # DECAL letter, March 2, 2026: 40% to 50% from March 2, 2026. + ga_caps_income_eligible: true + +- name: April 2026, 50 percent for three, over the limit. + period: 2026-04 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_876 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + ga_caps_income_eligible: false + +- name: October 2026, 50 percent for three, at the limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 4_029.16 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + # Appendix A, effective October 5, 2026, prints $48,350 for three. + ga_caps_income_eligible: true + +- name: October 2026, 50 percent for three, over the limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 4_029.25 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + ga_caps_income_eligible: false + +- name: October 2026, 50 percent for two, at the limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2] + ga_caps_countable_income: 3_261.75 + households: + household: + members: [person1, person2] + state_code: + 2026: GA + output: + # Appendix A prints $39,141 for two. + ga_caps_income_eligible: true + +- name: October 2026, 50 percent for two, over the limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2] + ga_caps_countable_income: 3_262 + households: + household: + members: [person1, person2] + state_code: + 2026: GA + output: + ga_caps_income_eligible: false + +- name: October 2026, 50 percent for six, at the limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + person4: + age: + 2026: 5 + person5: + age: + 2026: 5 + person6: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6] + ga_caps_countable_income: 6_331.5 + households: + household: + members: [person1, person2, person3, person4, person5, person6] + state_code: + 2026: GA + output: + # Appendix A prints $75,978 for six. + ga_caps_income_eligible: true + +- name: October 2026, 50 percent for six, over the limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + person4: + age: + 2026: 5 + person5: + age: + 2026: 5 + person6: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6] + ga_caps_countable_income: 6_332 + households: + household: + members: [person1, person2, person3, person4, person5, person6] + state_code: + 2026: GA + output: + ga_caps_income_eligible: false + +- name: October 2026, 85 percent for an enrolled family of three, at the limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 6_849.58 + ga_caps_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + # Appendix A prints $82,195 for three. + ga_caps_income_eligible: true + +- name: October 2026, 85 percent for an enrolled family of three, over the limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 6_850 + ga_caps_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + ga_caps_income_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.yaml new file mode 100644 index 00000000000..d7575c14715 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.yaml @@ -0,0 +1,1296 @@ +# GA CAPS priority groups (CAPS/00-7). +# New applicants must belong to one. The very low income group tests income against a dated +# share of the poverty guideline. + +- name: Family with income over the very low income limit and no group. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_priority_group_eligible: false + +- name: Child under court-ordered supervision. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_under_court_supervision: true + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.4. + ga_caps_priority_group_eligible: true + +- name: Child receiving or needing protective services. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + receives_or_needs_protective_services: true + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.4 and 7.15. + ga_caps_priority_group_eligible: true + +- name: Child in DFCS custody. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_in_foster_care: true + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.5. + ga_caps_priority_group_eligible: true + +- name: Child with a disability. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_disabled: true + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.7. + ga_caps_priority_group_eligible: true + +- name: Child with a developmental delay. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + has_developmental_delay: true + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.7. + ga_caps_priority_group_eligible: true + +- name: A parent's disability does not form a group. + period: 2026-01 + input: + people: + person1: + age: 30 + is_disabled: true + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_priority_group_eligible: false + +- name: A 25-year-old with a disability is not an eligible child, so forms no group. + period: 2026-01 + input: + people: + person1: + age: 50 + person2: + age: 25 + is_disabled: true + spm_units: + spm_unit: + members: [person1, person2] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2] + state_code: GA + output: + ga_caps_priority_group_eligible: false + +- name: Child enrolled in Georgia's Pre-K. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + ga_caps_pre_k_enrolled: true + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.8. + ga_caps_priority_group_eligible: true + +- name: Parent aged 20. + period: 2026-01 + input: + people: + person1: + age: 20 + person2: + age: 2 + person3: + age: 1 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.14: minor parents aged 20 and younger. + ga_caps_priority_group_eligible: true + +- name: Parent aged 21. + period: 2026-01 + input: + people: + person1: + age: 21 + person2: + age: 2 + person3: + age: 1 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_priority_group_eligible: false + +- name: Full-time student parent. + period: 2026-01 + input: + people: + person1: + age: 30 + is_full_time_student: true + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.16. + ga_caps_priority_group_eligible: true + +- name: Student parent before the group began. + period: 2022-04 + input: + people: + person1: + age: + 2022: 30 + is_full_time_student: + 2022: true + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2022: GA + output: + ga_caps_priority_group_eligible: false + +- name: Student parent from the month the group began. + period: 2022-05 + input: + people: + person1: + age: + 2022: 30 + is_full_time_student: + 2022: true + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2022: GA + output: + # CAPS/00-7 revision history: added May 1, 2022. + ga_caps_priority_group_eligible: true + +- name: Family in TANF. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + is_tanf_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.9. + ga_caps_priority_group_eligible: true + +- name: Family without fixed, regular and adequate housing. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + is_homeless: true + output: + # CAPS/00-7, 7.11. + ga_caps_priority_group_eligible: true + +- name: Family experiencing domestic violence. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + ga_caps_domestic_violence: true + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.6. + ga_caps_priority_group_eligible: true + +- name: Family after a natural disaster. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + ga_caps_natural_disaster: true + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.10. + ga_caps_priority_group_eligible: true + +- name: Grandparents raising grandchildren. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 3_000 + ga_caps_grandparents_raising_grandchildren: true + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # CAPS/00-7, 7.13. + ga_caps_priority_group_eligible: true + +- name: Before August 2016 Georgia required no group. + period: 2016-07 + input: + people: + person1: + age: + 2016: 30 + person2: + age: + 2016: 5 + person3: + age: + 2016: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2016: GA + output: + ga_caps_priority_group_eligible: true + +- name: From August 2016 Georgia required a group. + period: 2016-08 + input: + people: + person1: + age: + 2016: 30 + person2: + age: + 2016: 5 + person3: + age: + 2016: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2016: GA + output: + # DECAL funding Q&A: new applicants from August 1, 2016 must belong to a priority group. + ga_caps_priority_group_eligible: false + +- name: Very low income, May 2018 reads May 1, so 50 percent, at the limit. + period: 2018-05 + input: + people: + person1: + age: + 2018: 30 + person2: + age: + 2018: 5 + person3: + age: + 2018: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 865 + households: + household: + members: [person1, person2, person3] + state_code: + 2018: GA + output: + ga_caps_priority_group_eligible: true + +- name: Very low income, May 2018 reads May 1, so 50 percent, over the limit. + period: 2018-05 + input: + people: + person1: + age: + 2018: 30 + person2: + age: + 2018: 5 + person3: + age: + 2018: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 866 + households: + household: + members: [person1, person2, person3] + state_code: + 2018: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, June 2018, 100 percent, at the limit. + period: 2018-06 + input: + people: + person1: + age: + 2018: 30 + person2: + age: + 2018: 5 + person3: + age: + 2018: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_731 + households: + household: + members: [person1, person2, person3] + state_code: + 2018: GA + output: + # DECAL letter, June 18, 2018: 100% from May 30, 2018. + ga_caps_priority_group_eligible: true + +- name: Very low income, June 2018, 100 percent, over the limit. + period: 2018-06 + input: + people: + person1: + age: + 2018: 30 + person2: + age: + 2018: 5 + person3: + age: + 2018: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_732 + households: + household: + members: [person1, person2, person3] + state_code: + 2018: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, June 2019, 100 percent, at the limit. + period: 2019-06 + input: + people: + person1: + age: + 2019: 30 + person2: + age: + 2019: 5 + person3: + age: + 2019: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_777 + households: + household: + members: [person1, person2, person3] + state_code: + 2019: GA + output: + ga_caps_priority_group_eligible: true + +- name: Very low income, June 2019, 100 percent, over the limit. + period: 2019-06 + input: + people: + person1: + age: + 2019: 30 + person2: + age: + 2019: 5 + person3: + age: + 2019: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_778 + households: + household: + members: [person1, person2, person3] + state_code: + 2019: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, July 2019, 50 percent, at the limit. + period: 2019-07 + input: + people: + person1: + age: + 2019: 30 + person2: + age: + 2019: 5 + person3: + age: + 2019: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 888 + households: + household: + members: [person1, person2, person3] + state_code: + 2019: GA + output: + # DECAL webinar, July 10, 2019: 50% for applications from July 1, 2019. + ga_caps_priority_group_eligible: true + +- name: Very low income, July 2019, 50 percent, over the limit. + period: 2019-07 + input: + people: + person1: + age: + 2019: 30 + person2: + age: + 2019: 5 + person3: + age: + 2019: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 889 + households: + household: + members: [person1, person2, person3] + state_code: + 2019: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, November 2021, 150 percent for four, at the limit. + period: 2021-11 + input: + people: + person1: + age: + 2021: 30 + person2: + age: + 2021: 5 + person3: + age: + 2021: 5 + person4: + age: + 2021: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ga_caps_countable_income: 3_312.5 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2021: GA + output: + # DECAL letter, October 21, 2021: $39,750 for four. + ga_caps_priority_group_eligible: true + +- name: Very low income, November 2021, 150 percent for four, over the limit. + period: 2021-11 + input: + people: + person1: + age: + 2021: 30 + person2: + age: + 2021: 5 + person3: + age: + 2021: 5 + person4: + age: + 2021: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ga_caps_countable_income: 3_313 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2021: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, October 2021, 50 percent for four, at the limit. + period: 2021-10 + input: + people: + person1: + age: + 2021: 30 + person2: + age: + 2021: 5 + person3: + age: + 2021: 5 + person4: + age: + 2021: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ga_caps_countable_income: 1_104 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2021: GA + output: + # DECAL letter, October 21, 2021: $13,250 for four. + ga_caps_priority_group_eligible: true + +- name: Very low income, October 2021, 50 percent for four, over the limit. + period: 2021-10 + input: + people: + person1: + age: + 2021: 30 + person2: + age: + 2021: 5 + person3: + age: + 2021: 5 + person4: + age: + 2021: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ga_caps_countable_income: 1_105 + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2021: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, December 2022 reads December 1, so 150 percent, at the limit. + period: 2022-12 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_878 + households: + household: + members: [person1, person2, person3] + state_code: + 2022: GA + output: + ga_caps_priority_group_eligible: true + +- name: Very low income, December 2022 reads December 1, so 150 percent, over the limit. + period: 2022-12 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_879 + households: + household: + members: [person1, person2, person3] + state_code: + 2022: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, January 2023, 50 percent, at the limit. + period: 2023-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_035 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # DECAL letter, December 19, 2022: 50% from December 16, 2022. + ga_caps_priority_group_eligible: true + +- name: Very low income, January 2023, 50 percent, over the limit. + period: 2023-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_036 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, June 2024, 50 percent, at the limit. + period: 2024-06 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_075 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + ga_caps_priority_group_eligible: true + +- name: Very low income, June 2024, 50 percent, over the limit. + period: 2024-06 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_076 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, July 2024, 10 percent, at the limit. + period: 2024-07 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 215 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + # DECAL letter, July 1, 2024: 10% from July 1, 2024. + ga_caps_priority_group_eligible: true + +- name: Very low income, July 2024, 10 percent, over the limit. + period: 2024-07 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 216 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, October 2025 reads October 1, so 10 percent, at the limit. + period: 2025-10 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + person3: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 222 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: GA + output: + ga_caps_priority_group_eligible: true + +- name: Very low income, October 2025 reads October 1, so 10 percent, over the limit. + period: 2025-10 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + person3: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 223 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, November 2025, 30 percent, at the limit. + period: 2025-11 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + person3: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 666 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: GA + output: + # DECAL letter, October 6, 2025: 10% to 30%. + ga_caps_priority_group_eligible: true + +- name: Very low income, November 2025, 30 percent, over the limit. + period: 2025-11 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + person3: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 667 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, January 2026, 30 percent, at the limit. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 683 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_priority_group_eligible: true + +- name: Very low income, January 2026, 30 percent, over the limit. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 684 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, March 2026 reads March 1, so 30 percent, at the limit. + period: 2026-03 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 683 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + ga_caps_priority_group_eligible: true + +- name: Very low income, March 2026 reads March 1, so 30 percent, over the limit. + period: 2026-03 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 684 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, April 2026, 50 percent, at the limit. + period: 2026-04 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_138 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + # DECAL letter, March 2, 2026: 30% to 50%. + ga_caps_priority_group_eligible: true + +- name: Very low income, April 2026, 50 percent, over the limit. + period: 2026-04 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_139 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, October 2026, 50 percent, at the limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_138 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + # Appendix A, effective October 5, 2026, prints $13,660 for three. + ga_caps_priority_group_eligible: true + +- name: Very low income, October 2026, 50 percent, over the limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_139 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + ga_caps_priority_group_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/ga_caps.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/ga_caps.yaml index 6cbd3ad2e3e..3144c26be7c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/ga_caps.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/ga_caps.yaml @@ -6,8 +6,11 @@ # Family of 2: 21,640 # Family of 3: 27,320 # -# GA SMI 4-person at 2026-01: $116,773.19 (uprated) -# Family of 2: 116,773.19 * 0.68 = $79,405.77 -> 50% = $39,702.88 +# GA SMI 4-person at 2026-01 (October 2025 table): $110,736 +# New applicants in January 2026 face 40% of it, rounded up to the next dollar: +# Family of 2: 110,736 * 0.68 * 0.4 -> $30,121 +# Family of 3: 110,736 * 0.84 * 0.4 -> $37,208 +# Family of 4: 110,736 * 1.00 * 0.4 -> $44,295 - name: Case 1, subsidy zero when fee exceeds expenses. period: 2026-01 @@ -32,6 +35,9 @@ spm_units: spm_unit: members: [person1, person2] + # Enrolled, so the 85% limit applies. New applicants face a lower limit in + # January 2026. + ga_caps_enrolled: true spm_unit_pre_subsidy_childcare_expenses: 2_000 households: household: @@ -75,6 +81,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 10_000 households: household: @@ -122,6 +129,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 10_000 households: household: @@ -163,6 +171,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 10_000 households: household: @@ -293,6 +302,7 @@ spm_units: spm_unit: members: [person1, person2, person3] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 12_000 households: household: @@ -382,6 +392,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 6_000 households: household: @@ -427,6 +438,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 0 households: household: @@ -464,6 +476,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 8_000 households: household: @@ -510,6 +523,9 @@ spm_units: spm_unit: members: [person1, person2] + # Enrolled, so the 85% limit applies. New applicants face a lower limit in + # January 2026. + ga_caps_enrolled: true # Expenses far above the max rate, so the base is capped at the max. spm_unit_pre_subsidy_childcare_expenses: 60_000 households: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/integration.yaml index 2ecdbcdc222..3a38f2ffcaa 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/integration.yaml @@ -1,8 +1,10 @@ # GA CAPS Integration Tests # -# Period: tests use 2026-01 intentionally. CAPS parameters are dated -# 2026-03-02 (current Appendix C/D rates), and PolicyEngine backcasts the -# first dated value, so a 2026-01 test exercises the current rules. +# Period: tests use 2026-01 intentionally. The rate and fee parameters are +# dated 2026-03-02 (current Appendix C/D rates), and PolicyEngine backcasts the +# first dated value, so a 2026-01 test exercises the current payment rules. The +# income limit for new applicants has its own history, and it reads 40% of state +# median income in January 2026. # This avoids 2027-01 where FPG and SMI would be uprated rather than using # the published 2026 values cited in the inline calculation comments. # @@ -12,10 +14,11 @@ # Family of 3: 27,320 # Family of 4: 33,000 # -# GA SMI 4-person at 2026-01: $116,773.19 (uprated) -# Family of 2: 116,773.19 * 0.68 = $79,405.77 -> 50% = $39,702.88 -# Family of 3: 116,773.19 * 0.84 = $98,089.48 -> 50% = $49,044.74 -# Family of 4: 116,773.19 * 1.00 = $116,773.19 -> 50% = $58,386.59 +# GA SMI 4-person at 2026-01 (October 2025 table): $110,736 +# New applicants in January 2026 face 40% of it, rounded up to the next dollar: +# Family of 2: 110,736 * 0.68 * 0.4 -> $30,121 +# Family of 3: 110,736 * 0.84 * 0.4 -> $37,208 +# Family of 4: 110,736 * 1.00 * 0.4 -> $44,295 - name: Case 1, basic eligible family with Zone 1 center care. period: 2026-01 @@ -40,6 +43,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 11_000 households: household: @@ -52,7 +56,7 @@ # Citizen -> immigration eligible ga_caps_eligible_child: [false, true] - # income 30,000 <= 39,702.88 (50% SMI for family of 2) -> income eligible + # income 30,000 <= 30,121 (40% SMI for family of 2) -> income eligible ga_caps_income_eligible: true is_ccdf_asset_eligible: true ga_caps_eligible: true @@ -219,6 +223,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 12_000 households: household: @@ -226,7 +231,7 @@ state_code: GA county_str: FULTON_COUNTY_GA output: - # income 40,000 > 39,702.88 (50% SMI for family of 2) -> ineligible + # income 40,000 > 30,121 (40% SMI for family of 2) -> ineligible ga_caps_income_eligible: false ga_caps_eligible: false ga_caps: 0 @@ -261,6 +266,7 @@ spm_units: spm_unit: members: [person1, person2, person3] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 10_000 households: household: @@ -272,8 +278,8 @@ ga_caps_eligible_child: [false, true, true] # FPG family of 3: $27,320 - # 50% SMI family of 3 = $49,044.74 - # income 20,000 <= 49,044.74 -> eligible + # 40% SMI family of 3 = $37,208 + # income 20,000 <= 37,208 -> eligible ga_caps_income_eligible: true ga_caps_eligible: true @@ -325,6 +331,9 @@ spm_units: spm_unit: members: [person1, person2] + # Enrolled, so the 85% limit applies. New applicants face a lower limit in + # January 2026. Case 12 covers a disabled child as a priority group. + ga_caps_enrolled: true spm_unit_pre_subsidy_childcare_expenses: 7_000 households: household: @@ -336,7 +345,7 @@ # disabled, age 15 <= 17 -> eligible child ga_caps_eligible_child: [false, true] - # income 35,000 <= 39,702.88 (50% SMI for family of 2) -> eligible + # enrolled: income 35,000 <= 64,006 (85% SMI for family of 2) -> eligible ga_caps_income_eligible: true ga_caps_eligible: true @@ -394,7 +403,7 @@ ga_caps: 0 # 2026 FPG family of 5: 38,680; family of 6: 44,360 -# 50% SMI family of 5 = $67,728.45; family of 6 = $77,070.30 +# 40% SMI family of 5 = $51,382; family of 6 = $58,469 - name: Case 8, large family of 6 at income threshold boundary. period: 2026-01 @@ -404,7 +413,7 @@ person1: age: 40 weekly_hours_worked_before_lsr: 40 - employment_income: 73_085 + employment_income: 58_469 immigration_status: CITIZEN person2: age: 38 @@ -441,6 +450,7 @@ spm_units: spm_unit: members: [person1, person2, person3, person4, person5, person6] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 20_000 households: household: @@ -455,8 +465,8 @@ # person6 (14): age >= 13, not disabled -> ineligible ga_caps_eligible_child: [false, false, true, true, true, false] - # 50% SMI family of 6 = $77,070.30 - # income 73,085 <= 77,070.30 -> eligible + # 40% SMI family of 6 = 110,736 * 1.32 * 0.4, rounded up = $58,469 + # income 58,469 <= 58,469 -> eligible ga_caps_income_eligible: true ga_caps_eligible: true @@ -471,20 +481,20 @@ # === Family fee === # FPG family of 6: $44,360 - # FPL ratio = 73,085 / 44,360 = 1.648 -> 7% rate - # weekly fee = floor(73,085 * 0.07 / 52) = floor(98.38) = $98 - # monthly fee = 98 * 52 / 12 = $424.67 - ga_caps_family_fee: 424.67 + # FPL ratio = 58,469 / 44,360 = 1.318 -> 7% rate + # weekly fee = floor(58,469 * 0.07 / 52) = floor(78.71) = $78 + # monthly fee = 78 * 52 / 12 = $338.00 + ga_caps_family_fee: 338 # === Benefit === # sum_max_weekly = 84 + 180 + 260 = $524 # sum_max_monthly = $524 * 52/12 = $2,270.67 # expenses_monthly = 20,000 / 12 = $1,666.67 # base = min($1,666.67, $2,270.67) = $1,666.67 - # net_base = max($1,666.67 - $424.67, 0) = $1,242.00 + # net_base = max($1,666.67 - $338.00, 0) = $1,328.67 # weighted_bonus_rate = (84*0 + 180*0.05 + 260*0.05) / 524 = 0.04198 - # subsidy = $1,242.00 * 1.04198 = $1,294.14 - ga_caps: 1_294.14 + # subsidy = $1,328.67 * 1.04198 = $1,384.45 + ga_caps: 1_384.45 - name: Case 9, enrolled family between 50 and 85 percent SMI. period: 2026-01 @@ -520,7 +530,7 @@ # === Eligibility === ga_caps_eligible_child: [false, true] # enrolled: 50,000 <= 67,494.90 (85% SMI) -> eligible - # NOT eligible as new applicant: 50,000 > 39,702.88 (50% SMI) + # NOT eligible as new applicant: 50,000 > 30,121 (40% SMI) ga_caps_income_eligible: true ga_caps_eligible: true @@ -547,14 +557,14 @@ # subsidy = $784.33 * 1.10 = $862.77 ga_caps: 862.77 -- name: Case 10, non-enrolled family at 50 percent SMI plus 1 dollar is ineligible. +- name: Case 10, non-enrolled family at the 40 percent SMI limit plus 1 dollar is ineligible. period: 2026-01 absolute_error_margin: 0.01 input: people: person1: age: 35 - employment_income: 39_703 + employment_income: 30_122 immigration_status: CITIZEN person2: age: 4 @@ -569,6 +579,7 @@ spm_units: spm_unit: members: [person1, person2] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 12_000 households: household: @@ -577,7 +588,7 @@ county_str: FULTON_COUNTY_GA output: ga_caps_eligible_child: [false, true] - # 39,703 > 39,702.88 (50% SMI for family of 2) -> ineligible + # 30,122 > 30,121 (40% SMI for family of 2) -> ineligible ga_caps_income_eligible: false ga_caps_eligible: false ga_caps: 0 @@ -609,6 +620,7 @@ spm_units: spm_unit: members: [person1, person2, person3] + ga_caps_priority_group_eligible: true spm_unit_pre_subsidy_childcare_expenses: 10_000 households: household: diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_activity_eligible.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_activity_eligible.py index 3f8b4e4f790..7df872e514c 100644 --- a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_activity_eligible.py +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_activity_eligible.py @@ -7,7 +7,11 @@ class ga_caps_activity_eligible(Variable): label = "Eligible for Georgia CAPS based on activity requirements" definition_period = MONTH defined_for = StateCode.GA - reference = "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=33" + reference = ( + "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=33", + "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=2", + "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=8", + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ga.decal.caps.activity_requirements @@ -33,4 +37,17 @@ def formula(spm_unit, period, parameters): individually_eligible = meets_work_requirement | is_student | is_disabled all_heads_meet = ~spm_unit.any(is_head_or_spouse & ~individually_eligible) meets_ccdf = spm_unit("meets_ccdf_activity_test", period.this_year) - return all_heads_meet | meets_ccdf + # CAPS/00-7 waives the requirement for foster parents of children in DFCS + # custody (7.5) and for parents in Grandparents Raising Grandchildren + # (7.13). The Child Protective Services waiver in 7.4 is discretionary + # ("may be waived"), so meets_ccdf_activity_test carries it as an input. + has_dfcs_custody_child = add(spm_unit, period, ["is_in_foster_care"]) > 0 + grandparents_raising_grandchildren = spm_unit( + "ga_caps_grandparents_raising_grandchildren", period + ) + return ( + all_heads_meet + | meets_ccdf + | has_dfcs_custody_child + | grandparents_raising_grandchildren + ) diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_eligible.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_eligible.py index 113bc8e6911..253c690f6e4 100644 --- a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_eligible.py +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_eligible.py @@ -7,11 +7,26 @@ class ga_caps_eligible(Variable): label = "Eligible for Georgia CAPS" definition_period = MONTH defined_for = StateCode.GA - reference = "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=29" + reference = ( + "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=29", + "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=1", + ) def formula(spm_unit, period, parameters): has_eligible_child = add(spm_unit, period, ["ga_caps_eligible_child"]) > 0 income_eligible = spm_unit("ga_caps_income_eligible", period) asset_eligible = spm_unit("is_ccdf_asset_eligible", period.this_year) activity_eligible = spm_unit("ga_caps_activity_eligible", period) - return has_eligible_child & income_eligible & asset_eligible & activity_eligible + # CAPS/00-7, 7.3.1: new applicants outside a priority group are denied even + # when they meet every other requirement. 7.3.1.3 drops the requirement at + # annual redetermination. + priority_group_met = spm_unit( + "ga_caps_priority_group_eligible", period + ) | spm_unit("ga_caps_enrolled", period) + return ( + has_eligible_child + & income_eligible + & asset_eligible + & activity_eligible + & priority_group_met + ) diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.py index c3e8213fc7a..26ddbdf513c 100644 --- a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.py +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.py @@ -1,4 +1,5 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import smi class ga_caps_income_eligible(Variable): @@ -9,15 +10,29 @@ class ga_caps_income_eligible(Variable): defined_for = StateCode.GA reference = ( "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=49", - "https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf", + "https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1", + "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=52", + "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=2", ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ga.decal.caps.income.smi_rate - countable_income = spm_unit("ga_caps_countable_income", period) - smi = spm_unit("hhs_smi", period) + # Appendix A takes up the state median income table each October (October + # 5 in 2026), so read the table at the month. hhs_smi keeps one table + # through the calendar year. The chart prints annual limits rounded up to + # the next dollar, and Manual 8.8.4 multiplies monthly income by 12 to + # compare with it. Round to cents first so floating-point noise can't push + # a whole-dollar limit up by one or move a family at the limit. + size = spm_unit("spm_unit_size", period.this_year) + state = spm_unit.household("state_code_str", period.this_year) + annual_smi = smi(size, state, period, parameters) enrolled = spm_unit("ga_caps_enrolled", period) - initial_limit = smi * p.initial_eligibility - ongoing_limit = smi * p.ongoing_eligibility - income_limit = where(enrolled, ongoing_limit, initial_limit) - return countable_income <= income_limit + rate = where(enrolled, p.ongoing_eligibility, p.initial_eligibility) + income_limit = np.ceil(np.round(annual_smi * rate, 2)) + annual_income = np.round( + spm_unit("ga_caps_countable_income", period) * MONTHS_IN_YEAR, 2 + ) + # CAPS/00-7, 7.5: foster parents of children in DFCS custody need not meet + # the income requirement. The family fee applies the same family-wide test. + has_dfcs_custody_child = add(spm_unit, period, ["is_in_foster_care"]) > 0 + return (annual_income <= income_limit) | has_dfcs_custody_child diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_domestic_violence.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_domestic_violence.py new file mode 100644 index 00000000000..0f2a26dc845 --- /dev/null +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_domestic_violence.py @@ -0,0 +1,10 @@ +from policyengine_us.model_api import * + + +class ga_caps_domestic_violence(Variable): + value_type = bool + entity = SPMUnit + definition_period = MONTH + label = "Family experiences domestic violence, for the Georgia CAPS priority group" + defined_for = StateCode.GA + reference = "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=3" diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_grandparents_raising_grandchildren.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_grandparents_raising_grandchildren.py new file mode 100644 index 00000000000..de7d12110cf --- /dev/null +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_grandparents_raising_grandchildren.py @@ -0,0 +1,10 @@ +from policyengine_us.model_api import * + + +class ga_caps_grandparents_raising_grandchildren(Variable): + value_type = bool + entity = SPMUnit + definition_period = MONTH + label = "Family participates in the Georgia Grandparents Raising Grandchildren program, for the Georgia CAPS priority group" + defined_for = StateCode.GA + reference = "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=8" diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_natural_disaster.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_natural_disaster.py new file mode 100644 index 00000000000..b8b16fdfcc4 --- /dev/null +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_natural_disaster.py @@ -0,0 +1,10 @@ +from policyengine_us.model_api import * + + +class ga_caps_natural_disaster(Variable): + value_type = bool + entity = SPMUnit + definition_period = MONTH + label = "Family was harmed by a declared natural disaster in the previous 24 months, for the Georgia CAPS priority group" + defined_for = StateCode.GA + reference = "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=6" diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_pre_k_enrolled.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_pre_k_enrolled.py new file mode 100644 index 00000000000..7fa1c77087d --- /dev/null +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_pre_k_enrolled.py @@ -0,0 +1,10 @@ +from policyengine_us.model_api import * + + +class ga_caps_pre_k_enrolled(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Child attends Georgia's Pre-K Program, for the Georgia CAPS priority group" + defined_for = StateCode.GA + reference = "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=5" diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.py new file mode 100644 index 00000000000..04826c75a09 --- /dev/null +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.py @@ -0,0 +1,70 @@ +from policyengine_us.model_api import * + + +class ga_caps_priority_group_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Belongs to a Georgia CAPS priority group" + definition_period = MONTH + defined_for = StateCode.GA + reference = ( + "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=1", + "https://www.decal.ga.gov/documents/attachments/fundingrestrictionsqa.pdf#page=1", + "https://www.decal.ga.gov/documents/attachments/CCDFStatePlan25-27.pdf#page=25", + "https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ga.decal.caps.priority_groups + if not p.in_effect: + return np.ones_like(spm_unit("spm_unit_size", period.this_year), dtype=bool) + person = spm_unit.members + # Groups that turn on a child: Child Protective Services and court-ordered + # supervision (CAPS/00-7, 7.4), need to protect (7.15), DFCS custody (7.5), + # disabilities (7.7) and Georgia's Pre-K (7.8). + protective_care = person( + "receives_or_needs_protective_services", period.this_year + ) | person("is_under_court_supervision", period.this_year) + dfcs_custody = person("is_in_foster_care", period) + disability = person("is_disabled", period.this_year) | person( + "has_developmental_delay", period.this_year + ) + pre_k = person("ga_caps_pre_k_enrolled", period) + child_group = spm_unit.any( + person("ga_caps_eligible_child", period) + & (protective_care | dfcs_custody | disability | pre_k) + ) + # Groups that turn on a parent: minor parents (7.14) and student parents + # (7.16). is_full_time_student stands in for enrollment in the listed + # programs, as it does in ga_caps_activity_eligible. + minor_parent = person("age", period.this_year) <= p.minor_parent_age + student_parent = ( + person("is_full_time_student", period.this_year) + & p.student_parent_in_effect + ) + parent_group = spm_unit.any( + person("is_tax_unit_head_or_spouse", period.this_year) + & (minor_parent | student_parent) + ) + # 7.12 and Appendix A: gross applicable income against an annual chart. + # Round to cents so floating-point noise can't move a family at the limit. + annual_income = np.round( + spm_unit("ga_caps_countable_income", period) * MONTHS_IN_YEAR, 2 + ) + very_low_income_limit = np.round( + spm_unit("spm_unit_fpg", period.this_year) * p.very_low_income_fpg_rate, 2 + ) + very_low_income = annual_income <= very_low_income_limit + # is_tanf_enrolled stands in for families in TANF employment services + # (7.9); the group excludes payees outside those services, and the model + # can't tell them apart. + return ( + child_group + | parent_group + | very_low_income + | spm_unit("is_tanf_enrolled", period) + | spm_unit.household("is_homeless", period.this_year) + | spm_unit("ga_caps_domestic_violence", period) + | spm_unit("ga_caps_natural_disaster", period) + | spm_unit("ga_caps_grandparents_raising_grandchildren", period) + ) From 692414a47e198a47a9db8c638fe0fbcbdd77ed44 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 6 Nov 2026 18:29:39 -0500 Subject: [PATCH 06/13] Date Idaho's earlier limit, record the conflicts and test the invariants - Idaho: IDAPA 16.06.12.070 set 130% of the guideline until April 6, 2023, so the model no longer backdates 175% to 2015. New cases pin both sides of the 2022 and 2023 limits for a family of three. - Montana: cite the Legislative Fiscal Division's overview, which dates HB 648's 185% to July 2023, and say why the model keeps 150% for the pandemic months that overview also lists at 185%. - candidates.yaml records five source conflicts: Idaho's intake limit, Montana's initial, graduated and pandemic limits, and West Virginia's plan against its manual. - A Hypothesis module walks every posted chart and checks the stated invariants: the top of each chart passes and a dollar over fails, each limit equals its rate times the dated guideline, enrollment never removes eligibility, Ohio's two programs stay exclusive, Nevada's 2024 copays stay within 7% of income, and Georgia's test equals its conjuncts. Co-Authored-By: Claude Opus 5.5 --- changelog.d/child-care-posted-limits.fixed.md | 2 +- .../income/fpl_rate/initial_eligibility.yaml | 26 +- .../dphhs/ccap/income/fpg_limit/initial.yaml | 16 +- .../eligibility/id_iccp_income_eligible.yaml | 96 ++ .../gov/states/id/dhw/iccp/integration.yaml | 9 +- .../test_child_care_posted_income_limits.py | 881 ++++++++++++++++++ source_conflicts/candidates.yaml | 189 ++++ 7 files changed, 1205 insertions(+), 14 deletions(-) create mode 100644 policyengine_us/tests/test_child_care_posted_income_limits.py diff --git a/changelog.d/child-care-posted-limits.fixed.md b/changelog.d/child-care-posted-limits.fixed.md index 5c075416709..b2edb06e79e 100644 --- a/changelog.d/child-care-posted-limits.fixed.md +++ b/changelog.d/child-care-posted-limits.fixed.md @@ -1 +1 @@ -Bring state child care income limits into line with what states post, starting with Alabama's June 2026 limits and Idaho's January 2025 move to 130% of the poverty guideline. +Bring state child care income limits into line with what states post: Alabama's June 2026 limits; Idaho's 130% limit for new applicants from January 2025 and before April 2023; the poverty guideline year that Idaho, Indiana, Missouri, West Virginia and Montana apply; Missouri's transitional limits; Montana's 185% limit for new applicants from July 2023 and 200% graduated limit from July 2025; Nevada's dated intake and renewal limits and copay schedules back to 2015; and Georgia's dated limits for new applicants since 2016. diff --git a/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml b/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml index 55b510f5707..f028c33f179 100644 --- a/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml +++ b/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml @@ -1,8 +1,14 @@ description: Idaho limits initial income to this share of the federal poverty guidelines under the Idaho Child Care Program. -# IDAPA 16.06.12.070.01 still prints 175%. The department moved new applicants -# to 130% when it reopened applications on January 13, 2025, and posts its -# limits at that rate. The model follows what the department applies. +# IDAPA 16.06.12.070 set the limit at 130% from at least 2013 and raised it to 175% +# on April 6, 2023. Until March 2, 2017, the rule required income below 130%; the +# model tests at or below the limit in every year. +# The department moved new applicants back to 130% when it reopened applications on +# January 13, 2025, to keep the program within its appropriation, and posts its +# limits at that rate. IDAPA 16.06.12.070.01 still prints 175%, and IDAPA +# 16.06.12.705 lets the department reduce child care benefits when it projects a +# funding shortfall. The model follows the department's 130% from that date. values: + 2015-01-01: 1.3 2023-04-06: 1.75 2025-01-13: 1.3 @@ -11,11 +17,19 @@ metadata: period: year label: Idaho Child Care Program initial income limit reference: - - title: IDAPA 16.06.12.070.01, Income at Application + - title: IDAPA 16.06.12.070, Income Limits (2014 compilation, effective April 4, 2013) + href: https://adminrules.idaho.gov/rules/2014/16/0612.pdf#page=7 + - title: IDAPA 16.06.12.070.01, Income at Application (2019 archive, effective March 2, 2017) + href: https://adminrules.idaho.gov/rules/2019%20Archive%20C2/16/160612.pdf#page=8 + - title: IDAPA 16.06.12.070.01, Income at Application (2022 archive, effective March 17, 2022) + href: https://adminrules.idaho.gov/rules/2022%20Archive/16/160612.pdf#page=7 + - title: IDAPA 16.06.12.070.01, Income at Application (current, effective April 6, 2023) href: https://adminrules.idaho.gov/rules/current/16/160612.pdf#page=7 - - title: Idaho Department of Health and Welfare, Idaho Child Care Program - href: https://healthandwelfare.idaho.gov/services-programs/children-families-older-adults/idaho-child-care-program + - title: IDAPA 16.06.12.705, Funding Restrictions + href: https://adminrules.idaho.gov/rules/current/16/160612.pdf#page=18 - title: Idaho Department of Health and Welfare, DHW will resume applications for the Idaho Child Care Program in January (November 14, 2024) href: https://healthandwelfare.idaho.gov/news/dhw-will-resume-applications-idaho-child-care-program-january - title: Idaho Department of Health and Welfare, Apply for Child Care (limits effective October 2025; page last updated September 30, 2025) href: https://healthandwelfare.idaho.gov/services-programs/children-families/apply-child-care + - title: Idaho Department of Health and Welfare, Idaho Child Care Program + href: https://healthandwelfare.idaho.gov/services-programs/children-families-older-adults/idaho-child-care-program diff --git a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml index c682812ca35..93d87a1c7b5 100644 --- a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml +++ b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml @@ -1,9 +1,13 @@ description: Montana limits gross income to this share of the federal poverty guideline for initial eligibility under the Best Beginnings Child Care Scholarship program. # ARM 37.80.202(1) still prints 150%. MCA 52-2-715, enacted by House Bill 648 in 2023, -# requires a threshold of no less than 185%, and the department's scale ends Standard -# Eligibility at 185%. The model follows the statute and the scale. This is the initial / -# first-time applicant standard; continuing recipients at annual redetermination use -# the higher graduated share (see graduated.yaml), selected via the mt_ccap_enrolled input. +# requires a threshold of no less than 185%, and the department has applied 185% since +# July 1, 2023; its scale ends Standard Eligibility there. The model follows the statute +# and the scale from that date. The Legislative Fiscal Division's timeline, adapted from +# the department's communications, also lists 185% from July 2021 through December 2022 +# under pandemic CCDF policies; the model keeps the rule's 150% for that period. This is +# the initial / first-time applicant standard; continuing recipients at annual +# redetermination use the higher graduated share (see graduated.yaml), selected via the +# mt_ccap_enrolled input. values: 2016-11-01: 1.5 2023-07-01: 1.85 @@ -17,6 +21,10 @@ metadata: href: https://archive.legmt.gov/bills/MCA/title_0520/chapter_0020/part_0070/section_0150/0520-0020-0070-0150.html - title: Best Beginnings Child Care Sliding Fee Scale (document header "Effective 07-01-2025"; URL filename says 2023) href: https://dphhs.mt.gov/assets/ecfsd/childcare/policymanual/SlidingFeeScale07012023.pdf#page=1 + - title: Montana Legislative Fiscal Division, Child Care Overview (June 2024), HB 648 in the 2023 Session + href: https://leg.mt.gov/content/Publications/fiscal/2025-Biennium/Special-Topics/Childcare/Childcare-Overview-LEG-Days-June2024.pdf#page=4 + - title: Montana Legislative Fiscal Division, Child Care Overview (June 2024), Policy Timeline + href: https://leg.mt.gov/content/Publications/fiscal/2025-Biennium/Special-Topics/Childcare/Childcare-Overview-LEG-Days-June2024.pdf#page=13 - title: Mont. Admin. R. 37.80.202(1) href: https://rules.mt.gov/gateway/ruleno.asp?RN=37.80.202 - title: Mont. Admin. R. 37.80.202(1) — Cornell LII diff --git a/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.yaml index 509b50c0fea..2193e5fea97 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.yaml @@ -214,3 +214,99 @@ id_iccp_enrolled: true output: id_iccp_income_eligible: true + +# IDAPA 16.06.12.070 set 130% before April 6, 2023 and 175% from then. +# 130% x 23,030 / 12 = 2,494.92, rounded up to 2,495 (June 2022). +# 175% x 24,860 / 12 = 3,625.42, rounded up to 3,626 (June 2023). + +- name: Case 11, in June 2022 a family of three at 130 percent of the 2022 guideline qualifies as a new applicant. + period: 2022-06 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2022: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + id_iccp_countable_income: 2_495 + id_iccp_enrolled: false + output: + id_iccp_income_eligible: true + +- name: Case 12, in June 2022 a family of three one dollar above 130 percent of the 2022 guideline doesn't qualify. + period: 2022-06 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2022: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + id_iccp_countable_income: 2_496 + id_iccp_enrolled: false + output: + id_iccp_income_eligible: false + +- name: Case 13, in June 2023 a family of three at 175 percent of the 2023 guideline qualifies as a new applicant. + period: 2023-06 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2023: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + id_iccp_countable_income: 3_626 + id_iccp_enrolled: false + output: + id_iccp_income_eligible: true + +- name: Case 14, in June 2023 a family of three one dollar above 175 percent of the 2023 guideline doesn't qualify. + period: 2023-06 + input: + people: + person1: + age: 30 + person2: + age: 30 + person3: + age: 4 + households: + household: + members: [person1, person2, person3] + state_code: + 2023: ID + spm_units: + spm_unit: + members: [person1, person2, person3] + id_iccp_countable_income: 3_627 + id_iccp_enrolled: false + output: + id_iccp_income_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/integration.yaml index 8240c8b04f6..d67f82da09f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/integration.yaml @@ -44,10 +44,11 @@ spm_unit: members: [person1, person2] spm_unit_pre_subsidy_childcare_expenses: 24_000 # 2,000/month - spm_unit_fpg: 24_000 # initial limit 1.75 x 24,000 / 12 = 3,500/month + spm_unit_fpg: 24_000 # sets the copay bands; the income limit reads id_iccp_fpg output: id_iccp_eligible: true - # countable income 2,000/month <= 3,500/month initial limit + # countable income 2,000/month <= 2,292/month initial limit + # (130% x the 2025 guideline for two, 21,150 / 12, rounded up) # max benefit: CENTER, CLUSTER_3, FULL_TIME, PRESCHOOL = 1,089/month # copay (size 2, full-time): income 2,000 in 1,940-2,116 band = 50/month # id_iccp = min(2,000, 1,089) - 50 = 1,039/month @@ -79,9 +80,11 @@ spm_unit: members: [person1, person2, person3] spm_unit_pre_subsidy_childcare_expenses: 60_000 # 5,000/month - spm_unit_fpg: 30_000 # initial limit 1.75 x 30,000 / 12 = 4,375/month + spm_unit_fpg: 30_000 # sets the copay bands; the income limit reads id_iccp_fpg output: id_iccp_eligible: true + # countable income 2,000/month <= 2,888/month initial limit + # (130% x the 2025 guideline for three, 26,650 / 12, rounded up) # size 3, full-time, countable income 2,000 in first band (< 2,222) = 20/child id_iccp_copay_per_child: [0, 20, 20] id_iccp_copay: 40 diff --git a/policyengine_us/tests/test_child_care_posted_income_limits.py b/policyengine_us/tests/test_child_care_posted_income_limits.py new file mode 100644 index 00000000000..dc7fcf3e3eb --- /dev/null +++ b/policyengine_us/tests/test_child_care_posted_income_limits.py @@ -0,0 +1,881 @@ +"""Invariants of the child care income limits that states post. + +Each chart below copies one state document, so it acts as a second implementation +of that state's limit. Each rule below states the same limit as a rate, a guideline +year and a rounding rule, written apart from the formulas. + +1. Posted charts: a family at the printed top of a chart passes the income test and + a family one dollar over fails, for every family size on the chart. Nevada prints + the nearest dollar and tests the unrounded share, so its test allows one dollar. +2. Rules: for every date in RULES and for any income, a family passes exactly when + its income is at or below the rate times that date's guideline, rounded as the + state's chart rounds. This also makes each income test monotonic in income. +3. Enrolled families: a family that passes as a new applicant passes as an enrolled + family at the same income, in every state with separate limits. +4. Ohio: the voucher pays only families over the Publicly Funded Child Care limit, + never pays more than the charge, and leaves the two programs exclusive. Together + the two income tests stay monotonic. The voucher's own test is not monotonic, and + that violation is intended, since a family under the intake limit belongs to + Publicly Funded Child Care. +5. Nevada: while the April to September 2024 percent-of-income schedule applied, no + family owed more than 7% of income, and sizes above 14 use the 14-person column. +6. Georgia: the program test equals its conjuncts, a priority group never removes + eligibility, and enrollment replaces the priority group. +7. A family of three earning $40,000 gets the result each state's chart gives. + +YAML pins single households. These tests walk whole charts and many incomes in one +simulation, which keeps them fast enough to run in CI. +""" + +import math +from dataclasses import dataclass +from typing import Callable, Optional + +import numpy as np +import pytest +from hypothesis import given, settings +from hypothesis import strategies as st + +from policyengine_us import Simulation + + +def simulate(state, month, families, income_variable, spm=None, person=None): + """Build one simulation with a separate household per (size, monthly income).""" + year = int(month[:4]) + people, tax_units, spm_units, family_units, households = {}, {}, {}, {}, {} + marital_units = {} + for index, (size, income) in enumerate(families): + members = [f"person_{index}_{slot}" for slot in range(size)] + for slot, member in enumerate(members): + people[member] = { + "age": {year: 30 if slot == 0 else 5}, + "immigration_status": {year: "CITIZEN"}, + "weekly_hours_worked_before_lsr": {year: 40 if slot == 0 else 0}, + } + people[member].update(person(index, slot) if person else {}) + # Without explicit marital units, every person would share one. + marital_units[f"marital_{index}_{slot}"] = {"members": [member]} + income_input = ( + {year: income * 12} + if income_variable == "nv_ccdp_countable_income" + else {month: income} + ) + spm_units[f"spm_{index}"] = { + "members": members, + income_variable: income_input, + **(spm(index) if spm else {}), + } + tax_units[f"tax_{index}"] = {"members": members} + family_units[f"family_{index}"] = {"members": members} + households[f"household_{index}"] = { + "members": members, + "state_code": {year: state}, + } + return Simulation( + situation={ + "people": people, + "tax_units": tax_units, + "spm_units": spm_units, + "families": family_units, + "marital_units": marital_units, + "households": households, + } + ) + + +def passes(test, month, families): + """Run an income test for (size, monthly income) families.""" + + def enrolled(_): + return {test.enrolled_variable: {month: True}} + + spm = enrolled if test.enrolled_variable and test.enrolled else None + simulation = simulate(test.state, month, families, test.income, spm=spm) + return simulation.calculate(test.eligible, month).astype(bool) + + +@dataclass(frozen=True) +class Program: + state: str + eligible: str + income: str + enrolled_variable: Optional[str] = None + enrolled: bool = False + + +AL = Program( + "AL", "al_ccsp_income_eligible", "al_ccsp_countable_income", "al_ccsp_enrolled" +) +AL_ENROLLED = Program( + "AL", + "al_ccsp_income_eligible", + "al_ccsp_countable_income", + "al_ccsp_enrolled", + True, +) +ID = Program( + "ID", "id_iccp_income_eligible", "id_iccp_countable_income", "id_iccp_enrolled" +) +IN = Program( + "IN", "in_ccdf_income_eligible", "in_ccdf_countable_income", "is_in_ccdf_enrolled" +) +MO = Program( + "MO", "mo_ccs_income_eligible", "mo_ccs_adjusted_income", "mo_ccs_enrolled" +) +MO_ENROLLED = Program( + "MO", "mo_ccs_income_eligible", "mo_ccs_adjusted_income", "mo_ccs_enrolled", True +) +WV = Program("WV", "wv_ccap_income_eligible", "wv_ccap_countable_income") +MT = Program( + "MT", "mt_ccap_income_eligible", "mt_ccap_countable_income", "mt_ccap_enrolled" +) +MT_ENROLLED = Program( + "MT", + "mt_ccap_income_eligible", + "mt_ccap_countable_income", + "mt_ccap_enrolled", + True, +) +NV = Program( + "NV", "nv_ccdp_income_eligible", "nv_ccdp_countable_income", "nv_ccdp_enrolled" +) +NV_ENROLLED = Program( + "NV", + "nv_ccdp_income_eligible", + "nv_ccdp_countable_income", + "nv_ccdp_enrolled", + True, +) +OH = Program( + "OH", "oh_ccap_income_eligible", "oh_ccap_countable_income", "oh_ccap_enrolled" +) +OH_VOUCHER = Program("OH", "oh_ccvp_eligible", "oh_ccap_countable_income") +GA = Program( + "GA", "ga_caps_income_eligible", "ga_caps_countable_income", "ga_caps_enrolled" +) +GA_ENROLLED = Program( + "GA", + "ga_caps_income_eligible", + "ga_caps_countable_income", + "ga_caps_enrolled", + True, +) +GA_VERY_LOW = Program( + "GA", "ga_caps_priority_group_eligible", "ga_caps_countable_income" +) + + +@dataclass(frozen=True) +class Chart: + source: str + program: Program + month: str + tops: dict + annual: bool = False + + +CHARTS = [ + Chart( + "Alabama fact sheet, June 1, 2026, initial", + AL, + "2026-06", + {2: 2_644, 3: 3_331, 4: 4_019, 5: 4_706, 6: 5_394, 7: 6_081, 8: 6_769}, + ), + Chart( + "Alabama fact sheet, June 1, 2026, continuing", + AL_ENROLLED, + "2026-06", + {2: 2_996, 3: 3_775, 4: 4_555, 5: 5_334, 6: 6_113, 7: 6_892, 8: 7_671}, + ), + Chart( + "Idaho Department of Health and Welfare, October 2025", + ID, + "2026-01", + {2: 2_292, 3: 2_888, 4: 3_483, 5: 4_079, 6: 4_675, 7: 5_271, 8: 5_867}, + ), + Chart( + "Indiana FSSA, April 5, 2026", + IN, + "2026-05", + {2: 2_435, 3: 3_074, 4: 3_713, 5: 4_352, 6: 4_991, 7: 5_630, 8: 6_269}, + ), + Chart( + "Indiana CCDF plan, March 31, 2024", + IN, + "2024-06", + {1: 1_883, 2: 2_555, 3: 3_228, 4: 3_900, 5: 4_573}, + ), + Chart( + "Missouri DESE, July 1, 2026, traditional", + MO, + "2026-07", + { + 1: 1_956, + 2: 2_644, + 3: 3_331, + 4: 4_019, + 5: 4_706, + 6: 5_394, + 7: 6_081, + 8: 6_769, + }, + ), + Chart( + "Missouri DESE, July 1, 2026, Transitional Level 2", + MO_ENROLLED, + "2026-07", + {1: 2_804, 2: 3_789, 3: 4_775, 4: 5_760, 5: 6_746, 6: 7_731, 7: 8_716}, + ), + Chart( + "West Virginia Appendix A, FY 2024", + WV, + "2026-01", + { + 1: 2_322, + 2: 3_151, + 3: 3_981, + 4: 4_810, + 5: 5_639, + 6: 6_469, + 7: 7_298, + 8: 8_128, + 9: 8_957, + }, + ), + Chart( + "Montana Sliding Fee Scale, July 1, 2025, Standard", + MT, + "2026-01", + {2: 3_261, 3: 4_109, 4: 4_956, 5: 5_804, 6: 6_652, 7: 7_500, 8: 8_348}, + ), + Chart( + "Montana Sliding Fee Scale, July 1, 2025, Graduated", + MT_ENROLLED, + "2026-01", + {2: 3_525, 3: 4_442, 4: 5_358, 5: 6_275, 6: 7_192, 7: 8_108, 8: 9_025}, + ), + Chart( + "Ohio Procedure Letter 21, Publicly Funded Child Care", + OH, + "2026-01", + {2: 2_556, 3: 3_221, 4: 3_885, 5: 4_550, 6: 5_214, 7: 5_879, 8: 6_544}, + ), + Chart( + "Ohio Procedure Letter 45, Publicly Funded Child Care", + OH, + "2026-10", + {2: 2_615, 3: 3_302, 4: 3_988, 5: 4_674, 6: 5_361, 7: 6_047, 8: 6_733}, + ), + Chart( + "Ohio Procedure Letter 21, Child Care Choice Voucher", + OH_VOUCHER, + "2026-01", + {2: 3_525, 3: 4_442, 4: 5_359, 5: 6_275, 6: 7_192, 7: 8_109, 8: 9_025}, + ), + Chart( + "Ohio Procedure Letter 45, Child Care Choice Voucher", + OH_VOUCHER, + "2026-10", + {2: 3_607, 3: 4_554, 4: 5_500, 5: 6_447, 6: 7_394, 7: 8_340, 8: 9_287}, + ), + Chart( + "Georgia Appendix A, October 5, 2026, initial", + GA, + "2026-10", + dict( + zip( + range(1, 15), + [ + 29_931, + 39_141, + 48_350, + 57_559, + 66_769, + 75_978, + 77_705, + 79_432, + 81_159, + 82_885, + 84_612, + 86_339, + 88_066, + 89_793, + ], + ) + ), + annual=True, + ), + Chart( + "Georgia Appendix A, October 5, 2026, ongoing", + GA_ENROLLED, + "2026-10", + dict( + zip( + range(1, 15), + [ + 50_883, + 66_539, + 82_195, + 97_851, + 113_507, + 129_163, + 132_098, + 135_034, + 137_969, + 140_905, + 143_840, + 146_776, + 149_711, + 152_647, + ], + ) + ), + annual=True, + ), + Chart( + "Georgia Appendix A, October 5, 2026, very low income", + GA_VERY_LOW, + "2026-10", + dict( + zip( + range(1, 15), + [ + 7_980, + 10_820, + 13_660, + 16_500, + 19_340, + 22_180, + 25_020, + 27_860, + 30_700, + 33_540, + 36_380, + 39_220, + 42_060, + 44_900, + ], + ) + ), + annual=True, + ), +] + +NEVADA_CHARTS = [ + Chart( + "Nevada transmittal, October 1, 2026, intake", + NV, + "2026-10", + { + 1: 1_866, + 2: 2_440, + 3: 3_014, + 4: 3_588, + 5: 4_163, + 6: 4_737, + 7: 4_844, + 8: 4_952, + 9: 5_060, + }, + ), + Chart( + "Nevada transmittal, October 1, 2026, renewal", + NV_ENROLLED, + "2026-10", + { + 1: 2_230, + 2: 2_916, + 3: 3_602, + 4: 4_289, + 5: 4_975, + 6: 5_661, + 7: 5_790, + 8: 5_918, + 9: 6_047, + }, + ), +] + + +def monthly(annual_amount): + """An annual amount as monthly income, rounded down to the cent. + + The model stores income as float32, which near $150,000 a year resolves only + to about 1.6 cents. Rounding the at-limit family down a cent keeps it at or + below the annual limit after the model multiplies by 12. + """ + return math.floor(annual_amount * 100 / 12) / 100 + + +@pytest.mark.parametrize("chart", CHARTS, ids=lambda chart: chart.source) +def test_family_at_the_posted_top_passes_and_one_dollar_over_fails(chart): + families = [] + for size, top in chart.tops.items(): + if chart.annual: + families += [(size, monthly(top)), (size, (top + 1) / 12)] + else: + families += [(size, top), (size, top + 1)] + result = passes(chart.program, chart.month, families) + assert result.tolist() == [True, False] * len(chart.tops) + + +@pytest.mark.parametrize("chart", NEVADA_CHARTS, ids=lambda chart: chart.source) +def test_nevada_tests_the_unrounded_share_within_a_dollar_of_the_chart(chart): + families = [] + for size, top in chart.tops.items(): + families += [(size, top - 1), (size, top + 1)] + result = passes(chart.program, chart.month, families) + assert result.tolist() == [True, False] * len(chart.tops) + + +# HHS poverty guidelines for the contiguous states, as (first person, each additional). +GUIDELINES = { + 2022: (13_590, 4_720), + 2023: (14_580, 5_140), + 2024: (15_060, 5_380), + 2025: (15_650, 5_500), + 2026: (15_960, 5_680), +} + + +def guideline(year, size): + first, additional = GUIDELINES[year] + return first + additional * (size - 1) + + +def nearest_dollar(amount): + """Half a dollar goes up, as Alabama, Indiana, Missouri, West Virginia and Montana print.""" + return math.floor(round(amount, 2) + 0.5) + + +def next_dollar(amount): + """Any cents go up, as Idaho and Ohio print.""" + return math.ceil(round(amount, 2)) + + +@dataclass(frozen=True) +class Rule: + program: Program + month: str + guideline_year: int + rate: float + rounding: Callable + + def top(self, size): + return self.rounding(guideline(self.guideline_year, size) * self.rate / 12) + + +RULES = [ + # Alabama's fact sheets apply the prior year's guideline. + Rule(AL, "2026-01", 2025, 1.8, nearest_dollar), + Rule(AL, "2026-05", 2025, 1.8, nearest_dollar), + Rule(AL, "2026-06", 2025, 1.5, nearest_dollar), + Rule(AL_ENROLLED, "2026-01", 2025, 2, nearest_dollar), + Rule(AL_ENROLLED, "2026-06", 2025, 1.7, nearest_dollar), + # Idaho's rule set 130% until April 6, 2023, and 175% from then. The department + # reopened at 130% on January 13, 2025, and kept the 2024 guideline until its + # October 2025 table. + Rule(ID, "2022-06", 2022, 1.3, next_dollar), + Rule(ID, "2023-06", 2023, 1.75, next_dollar), + Rule(ID, "2025-02", 2024, 1.3, next_dollar), + Rule(ID, "2025-09", 2024, 1.3, next_dollar), + Rule(ID, "2025-10", 2025, 1.3, next_dollar), + Rule(ID, "2026-06", 2025, 1.3, next_dollar), + # Indiana's charts move partway through each year. + Rule(IN, "2024-06", 2024, 1.5, nearest_dollar), + Rule(IN, "2025-03", 2024, 1.5, nearest_dollar), + Rule(IN, "2025-06", 2025, 1.5, nearest_dollar), + Rule(IN, "2026-01", 2025, 1.5, nearest_dollar), + Rule(IN, "2026-04", 2025, 1.5, nearest_dollar), + Rule(IN, "2026-05", 2026, 1.35, nearest_dollar), + # Missouri holds the 2025 guideline through 2026. + Rule(MO, "2025-11", 2025, 1.5, nearest_dollar), + Rule(MO, "2026-01", 2025, 1.5, nearest_dollar), + Rule(MO, "2026-07", 2025, 1.5, nearest_dollar), + Rule(MO_ENROLLED, "2026-06", 2025, 2.42, nearest_dollar), + Rule(MO_ENROLLED, "2026-07", 2025, 2.15, nearest_dollar), + # West Virginia's Appendix A still prints the 2024 guideline. + Rule(WV, "2024-06", 2024, 1.85, nearest_dollar), + Rule(WV, "2025-03", 2024, 1.85, nearest_dollar), + Rule(WV, "2026-03", 2024, 1.85, nearest_dollar), + # Montana's scale moves each July. + Rule(MT, "2024-03", 2024, 1.85, nearest_dollar), + Rule(MT, "2025-03", 2024, 1.85, nearest_dollar), + Rule(MT, "2025-07", 2025, 1.85, nearest_dollar), + Rule(MT, "2026-03", 2025, 1.85, nearest_dollar), + Rule(MT_ENROLLED, "2025-07", 2025, 2, nearest_dollar), + Rule(MT_ENROLLED, "2026-03", 2025, 2, nearest_dollar), + # Ohio moves each October. + Rule(OH, "2026-01", 2025, 1.45, next_dollar), + Rule(OH, "2026-09", 2025, 1.45, next_dollar), + Rule(OH, "2026-10", 2026, 1.45, next_dollar), +] + +SMALL_FAMILIES = st.lists( + st.tuples( + st.integers(min_value=1, max_value=6), + st.integers(min_value=0, max_value=12_000), + ), + min_size=20, + max_size=20, +) + + +@pytest.mark.parametrize( + "rule", + RULES, + ids=lambda rule: ( + f"{rule.program.state}-{rule.month}" + + ("-enrolled" if rule.program.enrolled else "") + ), +) +def test_limit_equals_rate_times_dated_guideline(rule): + @settings(max_examples=2, deadline=None) + @given(families=SMALL_FAMILIES) + def check(families): + # Each family also sits at its top and one dollar over, the two cases a + # random income almost never lands on. + sizes = sorted({size for size, _ in families}) + edges = [ + (size, income) + for size in sizes + for income in (rule.top(size), rule.top(size) + 1) + ] + cases = families + edges + result = passes(rule.program, rule.month, cases) + expected = [income <= rule.top(size) for size, income in cases] + assert result.tolist() == expected + + check() + + +# Nevada's four-person state median income, by the October that starts each table. +NEVADA_SMI = { + "2017-10": 69_361, + "2018-10": 71_593, + "2021-10": 82_509, + "2023-10": 89_325, + "2024-10": 96_026, + "2026-10": 105_027, +} +SMI_SIZE_FACTOR = {1: 0.52, 2: 0.68, 3: 0.84, 4: 1.0, 5: 1.16, 6: 1.32} + +NEVADA_RULES = [ + (NV, "2018-09", "2017-10", 0.85), + (NV, "2018-10", "2018-10", 0.41), + (NV, "2022-06", "2021-10", 0.41), + (NV, "2022-07", "2021-10", 0.85), + (NV, "2024-09", "2023-10", 0.85), + (NV, "2024-10", "2024-10", 0.41), + (NV_ENROLLED, "2024-09", "2023-10", 0.85), + (NV_ENROLLED, "2024-10", "2024-10", 0.49), + (NV, "2026-10", "2026-10", 0.41), + (NV_ENROLLED, "2026-10", "2026-10", 0.49), +] + + +@pytest.mark.parametrize( + "program, month, table, rate", + NEVADA_RULES, + ids=lambda value: value.eligible if isinstance(value, Program) else str(value), +) +def test_nevada_limit_equals_rate_times_dated_median_income( + program, month, table, rate +): + sizes = list(SMI_SIZE_FACTOR) + tops = { + size: NEVADA_SMI[table] * SMI_SIZE_FACTOR[size] * rate / 12 for size in sizes + } + families = [] + for size in sizes: + families += [(size, tops[size] - 1), (size, tops[size] + 1)] + result = passes(program, month, families) + assert result.tolist() == [True, False] * len(sizes) + + +ENROLLMENT_PAIRS = [ + (AL, AL_ENROLLED, "2026-06"), + (AL, AL_ENROLLED, "2026-01"), + ( + ID, + Program( + "ID", + "id_iccp_income_eligible", + "id_iccp_countable_income", + "id_iccp_enrolled", + True, + ), + "2026-01", + ), + ( + IN, + Program( + "IN", + "in_ccdf_income_eligible", + "in_ccdf_countable_income", + "is_in_ccdf_enrolled", + True, + ), + "2026-05", + ), + (MO, MO_ENROLLED, "2026-07"), + (MT, MT_ENROLLED, "2026-03"), + (NV, NV_ENROLLED, "2024-10"), + (NV, NV_ENROLLED, "2022-07"), + ( + OH, + Program( + "OH", + "oh_ccap_income_eligible", + "oh_ccap_countable_income", + "oh_ccap_enrolled", + True, + ), + "2026-10", + ), + (GA, GA_ENROLLED, "2026-01"), + (GA, GA_ENROLLED, "2026-10"), +] + + +@pytest.mark.parametrize( + "new, enrolled, month", + ENROLLMENT_PAIRS, + ids=lambda value: value.state if isinstance(value, Program) else str(value), +) +def test_new_applicant_who_passes_also_passes_when_enrolled(new, enrolled, month): + @settings(max_examples=2, deadline=None) + @given(families=SMALL_FAMILIES) + def check(families): + passes_new = passes(new, month, families) + passes_enrolled = passes(enrolled, month, families) + assert not (passes_new & ~passes_enrolled).any() + + check() + + +OHIO_MONTHS = ["2025-11", "2026-01", "2026-10", "2026-11"] + + +def ohio_family_results(month, cases): + """Run Ohio for a family with one 2-year-old in center care at a set charge.""" + year = int(month[:4]) + + def person(_, slot): + if slot == 0: + return {} + return { + "age": {year: 2}, + "childcare_hours_per_week": {year: 40}, + "oh_ccap_provider_type": {month: "CENTER"}, + "pre_subsidy_childcare_expenses": {year: 24_000}, + } + + simulation = simulate("OH", month, cases, "oh_ccap_countable_income", person=person) + return { + variable: simulation.calculate(variable, month) + for variable in [ + "oh_ccap", + "oh_ccvp", + "oh_ccap_income_eligible", + "oh_ccvp_eligible", + ] + } + + +@pytest.mark.parametrize("month", OHIO_MONTHS) +def test_ohio_voucher_stays_apart_from_publicly_funded_child_care(month): + cases = [ + (size, income) for size in (2, 3, 4) for income in range(1_500, 9_500, 250) + ] + results = ohio_family_results(month, cases) + voucher = results["oh_ccvp"] + # Exclusive: a family drawing the voucher draws nothing from the other program. + assert not ((voucher > 0) & (results["oh_ccap"] > 0)).any() + # The voucher never pays more than the family's charge, $2,000 a month a child. + charge = np.array([(size - 1) * 2_000 for size, _ in cases]) + assert (voucher <= charge + 0.01).all() + # The voucher pays in some months of this range, so the checks above bind. + assert (voucher > 0).any() + # Only families over the intake limit qualify. + assert not ( + results["oh_ccvp_eligible"].astype(bool) + & results["oh_ccap_income_eligible"].astype(bool) + ).any() + + +@pytest.mark.parametrize("month", ["2026-01", "2026-10"]) +def test_ohio_income_tests_together_are_monotonic(month): + incomes = list(range(0, 12_000, 150)) + cases = [(3, income) for income in incomes] + results = ohio_family_results(month, cases) + either = results["oh_ccap_income_eligible"].astype(bool) | results[ + "oh_ccvp_eligible" + ].astype(bool) + # Once a family fails both tests, every higher income fails both. + assert (np.diff(either.astype(int)) <= 0).all() + + +def test_ohio_voucher_test_alone_is_not_monotonic_by_design(): + # Intended violation, minimized: the same family fails the voucher at $3,221 (it + # belongs to Publicly Funded Child Care) and passes at $3,222. + results = ohio_family_results("2026-01", [(3, 3_221), (3, 3_222)]) + assert results["oh_ccvp_eligible"].astype(bool).tolist() == [False, True] + + +def test_nevada_copay_stays_within_seven_percent_of_income(): + month = "2024-06" + cases = [ + (size, income) + for size in (1, 2, 3, 4, 5, 8, 14) + for income in range(0, 9_000, 300) + ] + simulation = simulate("NV", month, cases, "nv_ccdp_countable_income") + copay = simulation.calculate("nv_ccdp_copay", month) + income = np.array([income for _, income in cases], dtype=float) + assert (copay <= income * 0.07 + 0.01).all() + # The schedule charges something in this range, so the bound binds. + assert (copay > 0).any() + + +def test_nevada_copay_uses_the_fourteen_person_column_above_fourteen(): + month = "2024-06" + cases = [ + (size, income) for income in range(0, 12_000, 400) for size in (14, 15, 18) + ] + simulation = simulate("NV", month, cases, "nv_ccdp_countable_income") + copay = simulation.calculate("nv_ccdp_copay", month).reshape(-1, 3) + # The copay depends on income and the column, so equal incomes give equal copays. + assert (copay[:, 1] == copay[:, 0]).all() + assert (copay[:, 2] == copay[:, 0]).all() + + +GEORGIA_FLAGS = st.fixed_dictionaries( + { + "size": st.integers(min_value=2, max_value=5), + "income": st.integers(min_value=0, max_value=8_000), + "hours": st.sampled_from([0, 20, 40]), + "enrolled": st.booleans(), + "pre_k": st.booleans(), + "domestic_violence": st.booleans(), + } +) + + +def georgia_results(month, families, **overrides): + year = int(month[:4]) + enrolled = overrides.get("enrolled") + pre_k = overrides.get("pre_k") + + def spm(index): + family = families[index] + return { + "ga_caps_enrolled": { + month: family["enrolled"] if enrolled is None else enrolled + }, + "ga_caps_domestic_violence": {month: family["domestic_violence"]}, + } + + def person(index, slot): + family = families[index] + if slot == 0: + return {"weekly_hours_worked_before_lsr": {year: family["hours"]}} + return { + "ga_caps_pre_k_enrolled": { + month: family["pre_k"] if pre_k is None else pre_k + } + } + + simulation = simulate( + "GA", + month, + [(family["size"], family["income"]) for family in families], + "ga_caps_countable_income", + spm=spm, + person=person, + ) + return { + variable: simulation.calculate(variable, month).astype(bool) + for variable in [ + "ga_caps_eligible", + "ga_caps_income_eligible", + "ga_caps_activity_eligible", + "ga_caps_priority_group_eligible", + "ga_caps_enrolled", + ] + } + + +@pytest.mark.parametrize( + "month", ["2015-06", "2022-11", "2024-08", "2026-01", "2026-10"] +) +def test_georgia_eligibility_is_the_product_of_its_tests(month): + @settings(max_examples=2, deadline=None) + @given(families=st.lists(GEORGIA_FLAGS, min_size=20, max_size=20)) + def check(families): + results = georgia_results(month, families) + # Every family has a citizen child under 13 and assets under the limit, so + # those two conjuncts hold for all of them. + expected = ( + results["ga_caps_income_eligible"] + & results["ga_caps_activity_eligible"] + & (results["ga_caps_priority_group_eligible"] | results["ga_caps_enrolled"]) + ) + assert (results["ga_caps_eligible"] == expected).all() + + check() + + +def test_georgia_priority_group_never_removes_eligibility(): + @settings(max_examples=2, deadline=None) + @given(families=st.lists(GEORGIA_FLAGS, min_size=20, max_size=20)) + def check(families): + without = georgia_results("2026-10", families, enrolled=False, pre_k=False) + with_group = georgia_results("2026-10", families, enrolled=False, pre_k=True) + assert not (without["ga_caps_eligible"] & ~with_group["ga_caps_eligible"]).any() + assert with_group["ga_caps_priority_group_eligible"].all() + + check() + + +def test_georgia_enrollment_replaces_the_priority_group(): + @settings(max_examples=2, deadline=None) + @given(families=st.lists(GEORGIA_FLAGS, min_size=20, max_size=20)) + def check(families): + results = georgia_results("2026-10", families, enrolled=True, pre_k=False) + expected = ( + results["ga_caps_income_eligible"] & results["ga_caps_activity_eligible"] + ) + assert (results["ga_caps_eligible"] == expected).all() + + check() + + +FORTY_THOUSAND_A_YEAR = 40_000 / 12 + +FAMILY_OF_THREE_AT_40000 = [ + # Each row gives the result the state's chart gives for three people at $40,000. + (AL, "2026-01", True), # Fact sheet, January 2026: up to $3,998. + (AL, "2026-06", False), # Fact sheet, June 2026: up to $3,331. + (ID, "2026-01", False), # Department table: up to $2,888. + (IN, "2026-01", False), # 150% of the 2025 guideline: up to $3,331. + (IN, "2026-05", False), # FSSA chart, April 5, 2026: up to $3,074. + (MO, "2026-01", False), # DESE chart: up to $3,331. + (WV, "2026-01", True), # Appendix A: up to $3,981. + (MT, "2026-01", True), # Sliding Fee Scale: up to $4,109. + (NV, "2026-01", False), # Transmittal CC PT 06-25, 41% of median income. + (OH, "2026-01", False), # Procedure Letter 21: up to $3,221. + (OH_VOUCHER, "2026-01", True), # Procedure Letter 21: voucher up to $4,442. + (GA, "2026-01", False), # 40% of median income: $37,208 a year. + (GA, "2026-10", True), # Appendix A: $48,350 a year. +] + + +@pytest.mark.parametrize( + "program, month, expected", + FAMILY_OF_THREE_AT_40000, + ids=lambda value: value.eligible if isinstance(value, Program) else str(value), +) +def test_family_of_three_earning_40000(program, month, expected): + result = passes(program, month, [(3, FORTY_THOUSAND_A_YEAR)]) + assert result.tolist() == [expected] diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index f254eb0fbd8..db445ab45b2 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -2875,6 +2875,52 @@ candidates: state: ruled note: 'Ruled statute-first in October 2026; confirm line 12(c)''s scope against the per-person statute and worksheet. Code not yet on main: id_grocery_credit.' +- id: us-id:iccp-initial-income-limit + program: child-care-assistance + years: + from: 2025 + type: calendar + question: Does a new Idaho Child Care Program applicant face the 175% of poverty limit in IDAPA 16.06.12.070.01, + or the 130% limit that the Department of Health and Welfare has applied since it reopened applications on January + 13, 2025? + sources: + - kind: regulation + citation: IDAPA 16.06.12.070.01, Income at Application (effective April 6, 2023) + url: https://adminrules.idaho.gov/rules/current/16/160612.pdf#page=7 + - kind: regulation + citation: IDAPA 16.06.12.705, Funding Restrictions + url: https://adminrules.idaho.gov/rules/current/16/160612.pdf#page=18 + - kind: agency-practice + citation: Idaho Department of Health and Welfare, DHW will resume applications to Idaho Child Care Program in + January (November 14, 2024) + url: https://healthandwelfare.idaho.gov/news/dhw-will-resume-applications-idaho-child-care-program-january + - kind: guidance + citation: Idaho Department of Health and Welfare, Apply for Child Care, maximum monthly income limits effective + October 2025 + url: https://healthandwelfare.idaho.gov/services-programs/children-families/apply-child-care + readings: + statute: No statute supplied. Under IDAPA 16.06.12.070.01, "When applying, a family's income cannot exceed one + hundred seventy-five percent (175%) of FPG for a family of the same size." + other: The department applies 130% to new applicants from January 13, 2025, to stay within its appropriation, + and posts $2,888 a month for a family of three from October 2025. IDAPA 16.06.12.705 lets it reduce child + care benefits when it projects a funding shortfall. + example: A family of three that applies in June 2026 with $3,000 a month of countable income qualifies under the + rule's 175% (limit $3,887) but not under the department's 130% (limit $2,888). + pe_us: + follows: conflicting-source + code: + - policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10670 + state: ruled + note: On 2026-11-06, PolicyEngine took the department's 130%. Rule 070 lists conditions a family must meet to + be eligible, and rule 705 lets the department reduce child care benefits when it projects a funding shortfall; + the department tied the change to its appropriation. The rules' text doesn't settle whether 705 reaches the + intake limit, so the agency's reading breaks the tie. PolicyEngine has not settled whether a state rule binds + like a Treasury regulation; if it does and 070.01 reads as clear text, new applicants return to 175%. The 2026 + Legislature enacted none of S1374 (155% at application), S1419 (135%) and H0958 (175%). The department also + applies 130% at recertification, with a phase-out; the model keeps enrolled families on the 85% of state median + income limit. - id: us-il:2022-rebate-claimed-vs-claimable program: income-tax years: @@ -5375,6 +5421,113 @@ candidates: state: unreviewed note: PE-US follows the manual from October 1, 2025; verify the checklist's meaning and the manual's administrative-code status. +- id: us-mt:best-beginnings-graduated-income-limit + program: child-care-assistance + years: + from: 2025 + type: calendar + question: Does a Best Beginnings family at annual redetermination keep graduated eligibility only with income + below 185% of poverty, as ARM 37.80.202(2) says, or up to 200%, as the department's sliding fee scale effective + July 1, 2025 prints? + sources: + - kind: statute + citation: MCA 52-2-715(2) (En. Sec. 2, Ch. 773, L. 2023) + url: https://archive.legmt.gov/bills/MCA/title_0520/chapter_0020/part_0070/section_0150/0520-0020-0070-0150.html + - kind: regulation + citation: ARM 37.80.202(2) + url: https://rules.mt.gov/gateway/ruleno.asp?RN=37.80.202 + - kind: guidance + citation: DPHHS, Best Beginnings Child Care Sliding Fee Scale, effective July 1, 2025 + url: https://dphhs.mt.gov/assets/ecfsd/childcare/policymanual/SlidingFeeScale07012023.pdf#page=1 + readings: + statute: MCA 52-2-715(2) has the department set a maximum qualifying income level no higher than the federal + child care and development block grant allows, and sets no graduated level. ARM 37.80.202(2) gives graduated + eligibility at redetermination to a non-TANF household with income above 150% and below 185% of the poverty + guideline. + other: The department's scale runs Graduated Eligibility from 185% to 200% of the poverty guideline for families + already on the program. + example: A family of three at redetermination in March 2026 with $4,300 a month keeps graduated eligibility under + the scale (limit $4,442) but has income above the rule's 185% (limit $4,109). + pe_us: + follows: conflicting-source + code: + - policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/graduated.yaml + - policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_income_eligible.py + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10670 + state: ruled + note: On 2026-11-06, PolicyEngine took the department's 200% from July 1, 2025, the date of the earliest scale + it found that prints it. Once the statute moved initial eligibility to 185%, the rule's graduated band, 150% + to 185%, covers no one above the initial limit; the statute leaves the maximum qualifying income level to the + department within the federal limit, and its scale sets it. If PolicyEngine decides that a state rule binds + like a Treasury regulation, enrolled families could return to 185%. +- id: us-mt:best-beginnings-initial-income-limit + program: child-care-assistance + years: + from: 2023 + type: calendar + question: From July 1, 2023, does a new Best Beginnings applicant face ARM 37.80.202(1)'s limit of income below + 150% of poverty, or the threshold of no less than 185% that MCA 52-2-715(1) requires and the department's sliding + fee scale applies? + sources: + - kind: statute + citation: MCA 52-2-715(1) (En. Sec. 2, Ch. 773, L. 2023) + url: https://archive.legmt.gov/bills/MCA/title_0520/chapter_0020/part_0070/section_0150/0520-0020-0070-0150.html + - kind: regulation + citation: ARM 37.80.202(1) + url: https://rules.mt.gov/gateway/ruleno.asp?RN=37.80.202 + - kind: guidance + citation: DPHHS, Best Beginnings Child Care Sliding Fee Scale, effective July 1, 2025 + url: https://dphhs.mt.gov/assets/ecfsd/childcare/policymanual/SlidingFeeScale07012023.pdf#page=1 + readings: + statute: Under MCA 52-2-715(1), the department shall "set a qualifying income threshold at no less than 185% + of the federal poverty level for each family size". + other: ARM 37.80.202(1) still makes a household with income below 150% of the poverty guideline eligible. + example: A family of three that applies in March 2026 with $3,500 a month qualifies at 185% (limit $4,109) but + not under the rule's 150% (limit $3,331). + pe_us: + follows: statute + code: + - policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml + - policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_income_eligible.py + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10670 + state: ruled + note: 'On 2026-11-06, PolicyEngine took the statute''s floor, which the department''s scale applies: its Standard + Eligibility ends at 185%. The rule''s 150% predates the 2023 statute. If PolicyEngine decides that a state rule + binds like a Treasury regulation, a rule that contradicts its statute goes to the project lead case by case.' +- id: us-mt:best-beginnings-pandemic-income-limit + program: child-care-assistance + years: + from: 2021 + to: 2022 + type: calendar + question: From July 2021 through December 2022, did a new Best Beginnings applicant face ARM 37.80.202(1)'s limit + of income below 150% of poverty, or the 185% the department applied under its pandemic CCDF policies? + sources: + - kind: regulation + citation: ARM 37.80.202(1) + url: https://rules.mt.gov/gateway/ruleno.asp?RN=37.80.202 + - kind: agency-practice + citation: Montana Legislative Fiscal Division, Child Care Overview (June 2024), Policy Timeline, adapted from + DPHHS communications + url: https://leg.mt.gov/content/Publications/fiscal/2025-Biennium/Special-Topics/Childcare/Childcare-Overview-LEG-Days-June2024.pdf#page=13 + readings: + statute: No statute supplied; ARM 37.80.202(1) makes a household with income below 150% of the poverty guideline + eligible. + other: The timeline lists 185% under the department's pandemic CCDF policies from July 2021 to December 2022, + then 150% from January to June 2023. + example: A family of three that applied in June 2022 with $3,300 a month qualified at 185% (limit $3,550) but + not under the rule's 150% ($2,878.75). + pe_us: + follows: statute + code: + - policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10670 + state: unreviewed + note: PE-US keeps the rule's 150% for these months, and the PR leaves them unchanged. The question turns on whether + a state rule binds like a Treasury regulation, which PolicyEngine has not settled. - id: us-mt:elderly-credit-homestead-costs program: income-tax years: @@ -10558,6 +10711,42 @@ candidates: note: 'PE-US follows the handbook: only liquid assets are tested against the limit, and the comment says the statutory home-value and vehicle-equity limits are not part of the operational test (wi_shares_asset_eligible.py). The statute-first rule requires implementing the omitted home-value and vehicle-equity limits.' +- id: us-wv:ccap-initial-income-limit + program: child-care-assistance + years: + from: 2025 + to: 2027 + type: federal-fiscal + question: Does a new West Virginia Child Care Assistance applicant face 85% of state median income, which the + FFY 2025-2027 CCDF State Plan lists as its maximum initial eligibility limit, or 185% of the poverty guideline, + which the Child Care Subsidy Policy manual and Appendix A's sliding fee scale print? + sources: + - kind: plan + citation: West Virginia CCDF State Plan FFY 2025-2027, 2.2.4(a)(i) (p. 20) + url: https://bfa.wv.gov/media/39915/download?inline#page=20 + - kind: manual + citation: West Virginia Child Care Subsidy Policy and Procedures Manual, 3.2.1, Eligibility Guidelines + url: https://bfa.wv.gov/media/6766/download?inline#page=25 + - kind: guidance + citation: West Virginia Child Care Subsidy Appendix A, Sliding Fee Scale (October 1, 2024) + url: https://bfa.wv.gov/media/6826/download?inline#page=1 + readings: + statute: No statute or rule supplied. The plan's table lists a maximum initial eligibility limit of 85% of state + median income, $5,394 a month for a family of three. + other: The manual's eligibility guidelines point to Appendix A, whose scale ends at 185% of the 2024 poverty + guideline, $3,981 a month for a family of three. + example: A family of three that applies in January 2026 with $4,500 a month qualifies under the plan's 85% of + state median income ($5,394) but not under Appendix A's 185% ($3,981). + pe_us: + follows: gap-fill + code: + - policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/fpl_limit.yaml + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10670 + state: unreviewed + note: PE-US follows the manual and Appendix A, which the Bureau for Family Assistance links from its Child Care + Policy page; the PR changes only the guideline year. Check whether the plan's 85% states a limit the Bureau + applies or the federal ceiling. - id: us-wv:claim-of-right-subtraction-authority program: income-tax years: From f1332d9734068e17c8a9affda727ee1fc030a9a8 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 6 Nov 2026 22:00:37 -0500 Subject: [PATCH 07/13] Make the Ohio voucher property test able to fail The cap check set each child's charge at $2,000 a month, above every payment in the voucher chart ($375 to $900), so a voucher that ignored the charge still passed. The test now also runs families whose provider charges $300 a month and checks that the charge binds for some of them. It also adds homeless families, whom Publicly Funded Child Care serves without its income test, and checks that the two programs stay exclusive for them too. Co-Authored-By: Claude Opus 5.5 --- .../test_child_care_posted_income_limits.py | 73 +++++++++++++++---- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/policyengine_us/tests/test_child_care_posted_income_limits.py b/policyengine_us/tests/test_child_care_posted_income_limits.py index dc7fcf3e3eb..1982137dd73 100644 --- a/policyengine_us/tests/test_child_care_posted_income_limits.py +++ b/policyengine_us/tests/test_child_care_posted_income_limits.py @@ -13,9 +13,10 @@ 3. Enrolled families: a family that passes as a new applicant passes as an enrolled family at the same income, in every state with separate limits. 4. Ohio: the voucher pays only families over the Publicly Funded Child Care limit, - never pays more than the charge, and leaves the two programs exclusive. Together - the two income tests stay monotonic. The voucher's own test is not monotonic, and - that violation is intended, since a family under the intake limit belongs to + never pays more than the charge, and leaves the two programs exclusive, including + for homeless families, whom Publicly Funded Child Care serves without its income + test. Together the two income tests stay monotonic. The voucher's own test breaks + monotonicity on purpose, since a family under the intake limit belongs to Publicly Funded Child Care. 5. Nevada: while the April to September 2024 percent-of-income schedule applied, no family owed more than 7% of income, and sizes above 14 use the 14-person column. @@ -39,7 +40,9 @@ from policyengine_us import Simulation -def simulate(state, month, families, income_variable, spm=None, person=None): +def simulate( + state, month, families, income_variable, spm=None, person=None, household=None +): """Build one simulation with a separate household per (size, monthly income).""" year = int(month[:4]) people, tax_units, spm_units, family_units, households = {}, {}, {}, {}, {} @@ -70,6 +73,7 @@ def simulate(state, month, families, income_variable, spm=None, person=None): households[f"household_{index}"] = { "members": members, "state_code": {year: state}, + **(household(index) if household else {}), } return Simulation( situation={ @@ -657,21 +661,37 @@ def check(families): OHIO_MONTHS = ["2025-11", "2026-01", "2026-10", "2026-11"] -def ohio_family_results(month, cases): - """Run Ohio for a family with one 2-year-old in center care at a set charge.""" +def ohio_family_results(month, cases, charges=None, homeless=None): + """Run Ohio for families whose children are 2 and in center care. + + Each child's provider charges charges[index] a year ($24,000 unless given), and + homeless[index] marks a homeless household. + """ year = int(month[:4]) - def person(_, slot): + def person(index, slot): if slot == 0: return {} return { "age": {year: 2}, "childcare_hours_per_week": {year: 40}, "oh_ccap_provider_type": {month: "CENTER"}, - "pre_subsidy_childcare_expenses": {year: 24_000}, + "pre_subsidy_childcare_expenses": { + year: charges[index] if charges else 24_000 + }, } - simulation = simulate("OH", month, cases, "oh_ccap_countable_income", person=person) + def household(index): + return {"is_homeless": {year: homeless[index]}} if homeless else {} + + simulation = simulate( + "OH", + month, + cases, + "oh_ccap_countable_income", + person=person, + household=household, + ) return { variable: simulation.calculate(variable, month) for variable in [ @@ -685,16 +705,39 @@ def person(_, slot): @pytest.mark.parametrize("month", OHIO_MONTHS) def test_ohio_voucher_stays_apart_from_publicly_funded_child_care(month): - cases = [ - (size, income) for size in (2, 3, 4) for income in range(1_500, 9_500, 250) + # Each child's provider charges $300 a month, under every voucher rate, or + # $2,000, over them. Homeless families qualify for Publicly Funded Child Care + # without its income test. + families = [ + (size, income, annual_charge, homeless) + for size in (2, 3, 4) + for income in range(1_500, 9_500, 250) + for annual_charge in (3_600, 24_000) + for homeless in (False, True) ] - results = ohio_family_results(month, cases) + results = ohio_family_results( + month, + [(size, income) for size, income, _, _ in families], + charges=[annual_charge for _, _, annual_charge, _ in families], + homeless=[homeless for _, _, _, homeless in families], + ) voucher = results["oh_ccvp"] + publicly_funded = results["oh_ccap"] + charge = np.array( + [(size - 1) * annual_charge / 12 for size, _, annual_charge, _ in families] + ) + homeless = np.array([homeless for _, _, _, homeless in families]) # Exclusive: a family drawing the voucher draws nothing from the other program. - assert not ((voucher > 0) & (results["oh_ccap"] > 0)).any() - # The voucher never pays more than the family's charge, $2,000 a month a child. - charge = np.array([(size - 1) * 2_000 for size, _ in cases]) + assert not ((voucher > 0) & (publicly_funded > 0)).any() + # The voucher never pays more than the family's charge... assert (voucher <= charge + 0.01).all() + # ...and the charge sets the payment for some families, so the bound binds. + assert ((voucher > 0) & (np.abs(voucher - charge) < 0.01)).any() + # Homeless families draw Publicly Funded Child Care at any income, so none draws + # the voucher, and some over that program's intake limit draw it. + assert not (voucher[homeless] > 0).any() + over_intake_limit = ~results["oh_ccap_income_eligible"].astype(bool) + assert ((publicly_funded > 0) & homeless & over_intake_limit).any() # The voucher pays in some months of this range, so the checks above bind. assert (voucher > 0).any() # Only families over the intake limit qualify. From 91fad5607da2c4bfee1d0f8094cf181c87731938 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 6 Nov 2026 22:06:40 -0500 Subject: [PATCH 08/13] Stop three comments from stating limits this PR changed Alabama's and Montana's enrollment flags named the old limits (180% and 200%; 150% and 185%). They now point to the limit parameters instead. Montana's SMI cap note said the cap binds only from 13 people under a 185% graduated limit. With the 200% graduated limit on the scale's 2025 guideline, the model's January 2026 limits show the cap binding from 11 people for enrolled families and from 12 for new applicants. Co-Authored-By: Claude Opus 5.5 --- .../mt/dphhs/ccap/income/income_limit_smi_rate.yaml | 8 ++++---- .../variables/gov/states/al/dhr/ccsp/al_ccsp_enrolled.py | 9 +++++---- .../states/mt/dphhs/ccap/eligibility/mt_ccap_enrolled.py | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/income_limit_smi_rate.yaml b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/income_limit_smi_rate.yaml index e13e649ce79..150b9d891c6 100644 --- a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/income_limit_smi_rate.yaml +++ b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/income_limit_smi_rate.yaml @@ -5,10 +5,10 @@ description: Montana limits gross income to this share of state median income un # Fee Scale and mirrors the federal CCDF maximum at 45 CFR 98.20(a)(2) (no child care # subsidy above 85% of State median income). It is NOT in ARM 37.80.202. # -# (S3) Binding behavior: with the 185% FPG graduated limit (ARM 37.80.202(2)), the FPG -# limit binds before this 85% SMI cap for all but the largest households. It only binds -# (0.85*SMI < 1.85*FPG) at very large household sizes, e.g. size 13+ in 2026 once HHS -# SMI uprating is applied. For typical sizes the cap is non-binding. +# (S3) Binding behavior: the FPG limits in fpg_limit bind before this 85% SMI cap for +# all but the largest households. In 2026 the cap binds from 11 people for enrolled +# families (the 200% graduated limit) and from 12 people for new applicants (the 185% +# initial limit). For typical sizes the cap does not bind. # # (S6) The SMI ceiling STRUCTURE dates to 2016-11-01, while the 0.85 share reflects the # 2025 Sliding Fee Scale (2025 Federal Register poverty guidelines context). The diff --git a/policyengine_us/variables/gov/states/al/dhr/ccsp/al_ccsp_enrolled.py b/policyengine_us/variables/gov/states/al/dhr/ccsp/al_ccsp_enrolled.py index 55f21e6be47..dcb0f8e5f24 100644 --- a/policyengine_us/variables/gov/states/al/dhr/ccsp/al_ccsp_enrolled.py +++ b/policyengine_us/variables/gov/states/al/dhr/ccsp/al_ccsp_enrolled.py @@ -5,10 +5,11 @@ class al_ccsp_enrolled(Variable): value_type = bool entity = SPMUnit definition_period = MONTH - # Distinguishes new applicants (180% FPL initial cap) from continuing - # recipients (200% FPL continuing cap, §2.5.2(c)(iii)). Defaults to - # False, so every household is treated as a new applicant unless this - # input is explicitly set. + # Distinguishes new applicants, who face the initial limit, from continuing + # recipients, who face the higher continuing limit (§2.5.2(c)(iii)); both + # limits live in gov.states.al.dhr.ccsp.income.limit. Defaults to False, + # so the model treats every household as a new applicant unless the user + # sets this input. label = "Whether the family is currently enrolled in Alabama CCSP" defined_for = StateCode.AL reference = "https://dhr.alabama.gov/wp-content/uploads/2023/04/2025-2027-CCDF-State-Plan-with-Approval-Letter.pdf#page=39" diff --git a/policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_enrolled.py b/policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_enrolled.py index 87bc4fa548d..bf4ed8d6d00 100644 --- a/policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_enrolled.py +++ b/policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_enrolled.py @@ -8,6 +8,6 @@ class mt_ccap_enrolled(Variable): definition_period = MONTH defined_for = StateCode.MT reference = "https://www.law.cornell.edu/regulations/montana/Mont-Admin-r-37.80.202" - # Distinguishes a continuing recipient (at annual redetermination, eligible - # under the ARM 37.80.202(2) graduated 185% FPG limit) from a first-time - # applicant (the default, held to the 150% initial limit in 37.80.202(1)). + # Distinguishes a continuing recipient at annual redetermination, who faces + # the graduated limit, from a first-time applicant (the default), who faces + # the initial limit; gov.states.mt.dphhs.ccap.income.fpg_limit holds both. From b07d2f5aca4fef9dafd32dee10e9a77dfa33b042 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 6 Nov 2026 22:43:21 -0500 Subject: [PATCH 09/13] Pin Indiana's limit before August 2023 No test covered Indiana before its 2024 guideline-year switch or its August 2023 rate change, so moving either change back to 2015 left every test passing. Three June 2023 cases now pin the 2023 guideline and the 127% limit: a family of three qualifies at $2,631 and not at $2,632. Co-Authored-By: Claude Opus 5.5 --- .../in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml | 25 ++++++++- .../eligibility/in_ccdf_income_eligible.yaml | 52 +++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml index 21e5cd4729f..9e3bcaadd13 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml @@ -1,5 +1,28 @@ # Tests for in_ccdf_fpg (SPMUnit, MONTH). Indiana moves to a new year's guideline when it -# posts a new eligibility package: March 31, 2024, May 1, 2025 and April 5, 2026. +# posts a new eligibility package: March 31, 2024, May 1, 2025 and April 5, 2026. No source +# dates the guideline year before 2024, so the model reads the current year's until then. +- name: 2023-06 uses the 2023 guideline. + period: 2023-06 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2023: IN + output: + in_ccdf_fpg: 2_071.67 + - name: 2024-03 uses the 2023 guideline. period: 2024-03 absolute_error_margin: 0.01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml index 29fdc356ae0..d4ab033daf6 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml @@ -348,6 +348,58 @@ # the 2024 guideline ($3,228, state plan section 2.2.4) until May 1, 2025; of the 2025 # guideline ($3,331) until April 5, 2026; then 135% of the 2026 guideline ($3,074, FSSA's # chart). A monthly period reads each change from the next month's first day. +# +# Before August 2023 the limit was 127% (OECOSL bulletin). No source dates Indiana's +# guideline year before the March 31, 2024 plan, so the model reads the current year's +# guideline until 2024, and these two cases pin that choice: 127% of the 2023 guideline +# gives $2,631 for three in June 2023. The 2022 guideline would give $2,437, and 150% +# would give $3,108. + +- name: New applicant of 3 at 2,631 dollars qualifies in 2023-06. + period: 2023-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 2_631 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2023: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 3 at 2,632 dollars doesn't qualify in 2023-06. + period: 2023-06 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 2_632 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2023: IN + output: + in_ccdf_income_eligible: false - name: New applicant of 3 at 3,108 dollars qualifies in 2024-03. period: 2024-03 From 7295789d3dc1dedd21596bf81ab2c0dbcb0ccb96 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 7 Nov 2026 00:08:24 -0500 Subject: [PATCH 10/13] Run the child care property tests on fixed families Hypothesis drew two examples from a random seed, so whether a property test caught a broken rule changed from run to run: Alabama's June 2026 rate and Georgia's enrollment term each slipped past some runs. The draws now use a fixed seed. The enrollment property also checks each family size at the highest income that passes as a new applicant, and the Georgia properties run on a fixed grid of 504 families and check that the grid holds families that fail only one test. Co-Authored-By: Claude Opus 5.5 --- .../test_child_care_posted_income_limits.py | 151 +++++++++++++++--- 1 file changed, 127 insertions(+), 24 deletions(-) diff --git a/policyengine_us/tests/test_child_care_posted_income_limits.py b/policyengine_us/tests/test_child_care_posted_income_limits.py index 1982137dd73..72d387f1e24 100644 --- a/policyengine_us/tests/test_child_care_posted_income_limits.py +++ b/policyengine_us/tests/test_child_care_posted_income_limits.py @@ -25,9 +25,13 @@ 7. A family of three earning $40,000 gets the result each state's chart gives. YAML pins single households. These tests walk whole charts and many incomes in one -simulation, which keeps them fast enough to run in CI. +simulation, which keeps them fast enough to run in CI. Hypothesis draws families +from a fixed seed, so every run checks the same ones. The properties also check fixed +families: each size at its limit, and a grid of Georgia families, some failing only +one test. """ +import itertools import math from dataclasses import dataclass from typing import Callable, Optional @@ -534,7 +538,7 @@ def top(self, size): ), ) def test_limit_equals_rate_times_dated_guideline(rule): - @settings(max_examples=2, deadline=None) + @settings(max_examples=2, deadline=None, derandomize=True) @given(families=SMALL_FAMILIES) def check(families): # Each family also sits at its top and one dollar over, the two cases a @@ -642,13 +646,52 @@ def test_nevada_limit_equals_rate_times_dated_median_income( ] +def highest_passing_incomes(program, month, high=15_000): + """The highest monthly income at which a family of each size from 1 to 6 passes. + + Scans $100 steps up to `high`, then each dollar after the last step that passes. + """ + sizes = range(1, 7) + steps = range(0, high + 1, 100) + coarse = passes( + program, month, [(size, income) for size in sizes for income in steps] + ).reshape(len(sizes), len(steps)) + starts = { + size: steps[np.flatnonzero(row)[-1]] + for size, row in zip(sizes, coarse) + if row.any() + } + if not starts: + return {} + fine = passes( + program, + month, + [ + (size, start + extra) + for size, start in starts.items() + for extra in range(100) + ], + ).reshape(len(starts), 100) + return { + size: start + int(np.flatnonzero(row)[-1]) + for (size, start), row in zip(starts.items(), fine) + } + + @pytest.mark.parametrize( "new, enrolled, month", ENROLLMENT_PAIRS, ids=lambda value: value.state if isinstance(value, Program) else str(value), ) def test_new_applicant_who_passes_also_passes_when_enrolled(new, enrolled, month): - @settings(max_examples=2, deadline=None) + # A family at the highest income that passes as a new applicant must pass when + # enrolled. If the enrolled test is monotonic in income, passing there means + # passing at every lower income too. + tops = highest_passing_incomes(new, month) + assert sorted(tops) == [1, 2, 3, 4, 5, 6] + assert passes(enrolled, month, list(tops.items())).all(), tops + + @settings(max_examples=2, deadline=None, derandomize=True) @given(families=SMALL_FAMILIES) def check(families): passes_new = passes(new, month, families) @@ -849,47 +892,107 @@ def person(index, slot): } +# Every combination of the drawn flags at seven incomes. The tests below check that +# the grid holds families on each side of every test they cover. +GEORGIA_GRID = [ + { + "size": size, + "income": income, + "hours": hours, + "enrolled": enrolled, + "pre_k": pre_k, + "domestic_violence": domestic_violence, + } + for size, income, hours, enrolled, pre_k, domestic_violence in itertools.product( + [2, 3, 5], + [100, 1_000, 2_000, 3_000, 4_500, 6_000, 7_500], + [0, 20, 40], + [False, True], + [False, True], + [False, True], + ) +] + + +def check_georgia_product(month, families): + results = georgia_results(month, families) + # Every family has a citizen child under 13 and assets under the limit, so + # those two conjuncts hold for all of them. + expected = ( + results["ga_caps_income_eligible"] + & results["ga_caps_activity_eligible"] + & (results["ga_caps_priority_group_eligible"] | results["ga_caps_enrolled"]) + ) + assert (results["ga_caps_eligible"] == expected).all() + return results + + @pytest.mark.parametrize( "month", ["2015-06", "2022-11", "2024-08", "2026-01", "2026-10"] ) def test_georgia_eligibility_is_the_product_of_its_tests(month): - @settings(max_examples=2, deadline=None) + results = check_georgia_product(month, GEORGIA_GRID) + income = results["ga_caps_income_eligible"] + activity = results["ga_caps_activity_eligible"] + group = results["ga_caps_priority_group_eligible"] + enrolled = results["ga_caps_enrolled"] + # Some grid family fails each test while passing the others, and some enrolled + # family passes outside every priority group, so dropping any term changes a + # result. Georgia has required new applicants to belong to a priority group since + # August 2016. + assert (~income & activity & (group | enrolled)).any() + assert (income & ~activity & (group | enrolled)).any() + if month >= "2016-08": + assert (income & activity & ~group & ~enrolled).any() + assert (income & activity & ~group & enrolled).any() + + @settings(max_examples=2, deadline=None, derandomize=True) @given(families=st.lists(GEORGIA_FLAGS, min_size=20, max_size=20)) def check(families): - results = georgia_results(month, families) - # Every family has a citizen child under 13 and assets under the limit, so - # those two conjuncts hold for all of them. - expected = ( - results["ga_caps_income_eligible"] - & results["ga_caps_activity_eligible"] - & (results["ga_caps_priority_group_eligible"] | results["ga_caps_enrolled"]) - ) - assert (results["ga_caps_eligible"] == expected).all() + check_georgia_product(month, families) check() +def check_priority_group_never_removes_eligibility(families): + without = georgia_results("2026-10", families, enrolled=False, pre_k=False) + with_group = georgia_results("2026-10", families, enrolled=False, pre_k=True) + assert not (without["ga_caps_eligible"] & ~with_group["ga_caps_eligible"]).any() + assert with_group["ga_caps_priority_group_eligible"].all() + return without, with_group + + def test_georgia_priority_group_never_removes_eligibility(): - @settings(max_examples=2, deadline=None) + without, with_group = check_priority_group_never_removes_eligibility(GEORGIA_GRID) + # Pre-K admits some grid families that no other group admits. + assert (~without["ga_caps_eligible"] & with_group["ga_caps_eligible"]).any() + + @settings(max_examples=2, deadline=None, derandomize=True) @given(families=st.lists(GEORGIA_FLAGS, min_size=20, max_size=20)) def check(families): - without = georgia_results("2026-10", families, enrolled=False, pre_k=False) - with_group = georgia_results("2026-10", families, enrolled=False, pre_k=True) - assert not (without["ga_caps_eligible"] & ~with_group["ga_caps_eligible"]).any() - assert with_group["ga_caps_priority_group_eligible"].all() + check_priority_group_never_removes_eligibility(families) check() +def check_enrollment_replaces_the_priority_group(families): + results = georgia_results("2026-10", families, enrolled=True, pre_k=False) + expected = results["ga_caps_income_eligible"] & results["ga_caps_activity_eligible"] + assert (results["ga_caps_eligible"] == expected).all() + return results + + def test_georgia_enrollment_replaces_the_priority_group(): - @settings(max_examples=2, deadline=None) + results = check_enrollment_replaces_the_priority_group(GEORGIA_GRID) + # Some enrolled grid families pass outside every priority group. + assert ( + results["ga_caps_eligible"] & ~results["ga_caps_priority_group_eligible"] + ).any() + + @settings(max_examples=2, deadline=None, derandomize=True) @given(families=st.lists(GEORGIA_FLAGS, min_size=20, max_size=20)) def check(families): - results = georgia_results("2026-10", families, enrolled=True, pre_k=False) - expected = ( - results["ga_caps_income_eligible"] & results["ga_caps_activity_eligible"] - ) - assert (results["ga_caps_eligible"] == expected).all() + check_enrollment_replaces_the_priority_group(families) check() From d81efc32dc74dd463b93e7084c9a096aafb5c929 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 7 Nov 2026 14:42:40 -0500 Subject: [PATCH 11/13] Address the review of the posted child care limits - Georgia: serve a child in DFCS custody as a family unit of one, so the foster family's own children still face the income, activity and priority tests; read the very-low-income guideline from the date CAPS takes it up; read each Appendix A chart's median year; and apply the Pre-K group's redetermination requirement from July 2024 to October 2025. - Nevada: test new applicants against 130% of the poverty guideline from October 2018 through June 2022, read the median each chart uses, and round as each chart prints. - Maryland: give new applicants and continuing families the scales MSDE posts, on the federal fiscal 2025 median. - Ohio: keep the accreditation, non-traditional-hours and special-needs add-ons in the voucher's November 2026 rates, and give the voucher its own age groups. - Indiana: date each guideline year by the effective date its schedule prints. - Missouri and Nevada: round each tier and band top as the chart prints it. - Alabama: put families of eight or more on the chart's last row. - Move the posted-chart cases into the state YAML files and keep the cross-state invariants in Python. - Record the Alabama, Maryland and Missouri source conflicts. Co-Authored-By: Claude Opus 5.5 --- changelog.d/child-care-posted-limits.fixed.md | 2 +- .../dhr/ccsp/income/limit/fpl_continuing.yaml | 2 +- .../al/dhr/ccsp/income/limit/fpl_initial.yaml | 2 +- .../al/dhr/ccsp/income/max_family_size.yaml | 15 + .../ga/decal/caps/income/smi_year_lag.yaml | 40 + .../domestic_violence_in_effect.yaml | 15 + .../priority_groups/homeless_in_effect.yaml | 15 + .../decal/caps/priority_groups/in_effect.yaml | 2 +- .../pre_k_redetermination_in_effect.yaml | 20 + .../student_parent_in_effect.yaml | 4 +- .../very_low_income_fpg_year_lag.yaml | 43 + .../very_low_income_in_effect.yaml | 15 + .../income/fpl_rate/initial_eligibility.yaml | 4 +- .../in/fssa/ccdf/income/fpg_year_lag.yaml | 29 +- .../continuation_smi_freeze_in_effect.yaml | 17 + .../income/continuation_smi_frozen_year.yaml | 17 + .../msde/ccs/income/smi_freeze_in_effect.yaml | 9 +- .../md/msde/ccs/income/smi_frozen_year.yaml | 7 +- .../mo/dese/ccs/income/fpg_year_lag.yaml | 5 +- .../dese/ccs/transitional/funding_rate.yaml | 10 +- .../dphhs/ccap/income/fpg_limit/initial.yaml | 4 +- .../ccdp/chart_rounds_to_nearest_dollar.yaml | 22 + .../gov/states/nv/dwss/ccdp/copay/amount.yaml | 14 +- .../ccdp/income/fpg_intake/in_effect.yaml | 27 + .../nv/dwss/ccdp/income/fpg_intake/rate.yaml | 19 + .../nv/dwss/ccdp/income/smi_intake.yaml | 30 +- .../nv/dwss/ccdp/income/smi_renewal.yaml | 4 +- .../nv/dwss/ccdp/income/smi_year_lag.yaml | 17 + .../gov/states/oh/dcy/ccap/ccvp/payment.yaml | 13 +- .../wv/dhhr/ccap/income/fpg_year_lag.yaml | 3 +- policyengine_us/programs.yaml | 1 + .../code_health/test_source_conflicts.py | 1 - .../gov/states/al/dhr/ccsp/al_ccsp_fpg.yaml | 108 ++ .../al/dhr/ccsp/al_ccsp_income_eligible.yaml | 558 ++++++ .../ccsp/al_ccsp_weekly_copay_per_child.yaml | 43 + .../decal/caps/copay/ga_caps_family_fee.yaml | 15 +- .../states/ga/decal/caps/dfcs_custody.yaml | 202 +++ .../ga_caps_eligible_priority_groups.yaml | 239 ++- .../eligibility/ga_caps_income_eligible.yaml | 756 ++++++++ .../ga_caps_income_eligible_by_date.yaml | 196 ++- .../ga_caps_priority_group_eligible.yaml | 721 +++++++- .../eligibility/id_iccp_income_eligible.yaml | 196 +++ .../in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml | 81 +- .../eligibility/in_ccdf_income_eligible.yaml | 414 ++++- .../md/msde/ccs/md_ccs_income_eligible.yaml | 224 +++ .../eligibility/mo_ccs_income_eligible.yaml | 1067 +++++++++++ .../gov/states/mo/dese/ccs/mo_ccs.yaml | 73 + .../mo/dese/ccs/mo_ccs_funding_rate.yaml | 199 +++ .../dphhs/ccap/mt_ccap_income_eligible.yaml | 518 ++++++ .../nv/dwss/ccdp/copay/nv_ccdp_copay.yaml | 297 +++- .../eligibility/nv_ccdp_income_eligible.yaml | 1561 ++++++++++++++++- .../gov/states/oh/dcy/ccap/ccvp/oh_ccvp.yaml | 53 +- .../oh/dcy/ccap/ccvp/oh_ccvp_eligible.yaml | 1373 +++++++++++++++ .../states/oh/dcy/ccap/ccvp/oh_ccvp_rate.yaml | 360 +++- .../oh/dcy/ccap/oh_ccap_income_eligible.yaml | 388 ++++ .../wv/dhhr/ccap/wv_ccap_income_eligible.yaml | 230 +++ .../test_child_care_posted_income_limits.py | 395 +---- .../gov/states/al/dhr/ccsp/al_ccsp_fpg.py | 29 + .../copay/al_ccsp_weekly_copay_per_child.py | 4 +- .../eligibility/al_ccsp_income_eligible.py | 6 +- .../ga/decal/caps/copay/ga_caps_family_fee.py | 20 +- .../eligibility/ga_caps_activity_eligible.py | 20 +- .../eligibility/ga_caps_dfcs_custody_child.py | 21 + .../caps/eligibility/ga_caps_eligible.py | 27 +- .../eligibility/ga_caps_family_eligible.py | 51 + .../caps/eligibility/ga_caps_family_size.py | 16 + .../eligibility/ga_caps_income_eligible.py | 27 +- ...ga_caps_pre_k_at_previous_determination.py | 10 + .../ga_caps_priority_group_eligible.py | 50 +- .../gov/states/ga/decal/caps/ga_caps.py | 59 +- .../dhw/iccp/copay/id_iccp_copay_per_child.py | 2 + .../md/msde/ccs/md_ccs_income_eligible.py | 38 +- .../ccs/eligibility/mo_ccs_income_eligible.py | 7 +- .../gov/states/mo/dese/ccs/mo_ccs.py | 6 +- .../states/mo/dese/ccs/mo_ccs_funding_rate.py | 30 + .../nv/dwss/ccdp/copay/nv_ccdp_copay.py | 32 +- .../eligibility/nv_ccdp_income_eligible.py | 55 +- .../nv_ccdp_monthly_countable_income.py | 20 + .../gov/states/nv/dwss/ccdp/nv_ccdp_smi.py | 19 +- .../gov/states/oh/dcy/ccap/ccvp/oh_ccvp.py | 6 +- .../dcy/ccap/ccvp/oh_ccvp_child_age_group.py | 42 + .../oh/dcy/ccap/ccvp/oh_ccvp_eligible.py | 8 +- .../states/oh/dcy/ccap/ccvp/oh_ccvp_rate.py | 14 +- .../oh/dcy/ccap/oh_ccap_rate_with_addons.py | 117 +- source_conflicts/candidates.yaml | 179 +- 85 files changed, 10845 insertions(+), 765 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/al/dhr/ccsp/income/max_family_size.yaml create mode 100644 policyengine_us/parameters/gov/states/ga/decal/caps/income/smi_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/domestic_violence_in_effect.yaml create mode 100644 policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/homeless_in_effect.yaml create mode 100644 policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/pre_k_redetermination_in_effect.yaml create mode 100644 policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/very_low_income_fpg_year_lag.yaml create mode 100644 policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/very_low_income_in_effect.yaml create mode 100644 policyengine_us/parameters/gov/states/md/msde/ccs/income/continuation_smi_freeze_in_effect.yaml create mode 100644 policyengine_us/parameters/gov/states/md/msde/ccs/income/continuation_smi_frozen_year.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/chart_rounds_to_nearest_dollar.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/fpg_intake/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/fpg_intake/rate.yaml create mode 100644 policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_year_lag.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_fpg.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/dfcs_custody.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/mo_ccs_funding_rate.yaml create mode 100644 policyengine_us/variables/gov/states/al/dhr/ccsp/al_ccsp_fpg.py create mode 100644 policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_dfcs_custody_child.py create mode 100644 policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_family_eligible.py create mode 100644 policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_family_size.py create mode 100644 policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_pre_k_at_previous_determination.py create mode 100644 policyengine_us/variables/gov/states/mo/dese/ccs/mo_ccs_funding_rate.py create mode 100644 policyengine_us/variables/gov/states/nv/dwss/ccdp/income/nv_ccdp_monthly_countable_income.py create mode 100644 policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_child_age_group.py diff --git a/changelog.d/child-care-posted-limits.fixed.md b/changelog.d/child-care-posted-limits.fixed.md index b2edb06e79e..a840718e248 100644 --- a/changelog.d/child-care-posted-limits.fixed.md +++ b/changelog.d/child-care-posted-limits.fixed.md @@ -1 +1 @@ -Bring state child care income limits into line with what states post: Alabama's June 2026 limits; Idaho's 130% limit for new applicants from January 2025 and before April 2023; the poverty guideline year that Idaho, Indiana, Missouri, West Virginia and Montana apply; Missouri's transitional limits; Montana's 185% limit for new applicants from July 2023 and 200% graduated limit from July 2025; Nevada's dated intake and renewal limits and copay schedules back to 2015; and Georgia's dated limits for new applicants since 2016. +Bring state child care income limits into line with what states post: Alabama's June 2026 limits, with families of eight or more on the chart's last row; Idaho's 130% limit for new applicants from January 2025 and before April 2023; the poverty guideline year that Idaho, Indiana, Missouri, West Virginia and Montana apply; Maryland's initial and continuation scales on the federal fiscal 2025 median that MSDE posts; Missouri's transitional limits; Montana's 185% limit for new applicants from July 2023 and 200% graduated limit from July 2025; Nevada's dated intake and renewal limits, including 130% of the poverty guideline for new applicants from October 2018 through June 2022, and its copay schedules back to 2015; and Georgia's dated limits for new applicants since 2016. diff --git a/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_continuing.yaml b/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_continuing.yaml index 0fae90df52e..8312f3fb52a 100644 --- a/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_continuing.yaml +++ b/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_continuing.yaml @@ -12,7 +12,7 @@ metadata: - title: Alabama CCDF State Plan 2025-2027, Section 2.5.2(c)(iii) href: https://dhr.alabama.gov/wp-content/uploads/2023/04/2025-2027-CCDF-State-Plan-with-Approval-Letter.pdf#page=39 - title: Alabama Child Care Fact Sheet, January 1, 2024 - href: https://dhr.alabama.gov/wp-content/uploads/2024/01/Child-Care-Fact-Sheet-2024.pdf + href: https://dhr.alabama.gov/wp-content/uploads/2024/01/Child-Care-Fact-Sheet-2024.pdf#page=1 - title: Alabama Child Care Fact Sheet, January 1, 2026 (Continuing Eligibility Monthly Income Scale, top column 191-200% FPL) href: https://dhr.alabama.gov/wp-content/uploads/2025/12/CHILD-CARE-FACT-SHEET-Jan2026.pdf#page=1 - title: Alabama Child Care Fact Sheet, June 1, 2026 (Continuing Eligibility Monthly Income Scale, top column 161-170% FPL) diff --git a/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_initial.yaml b/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_initial.yaml index 027842a21ab..4607f29d834 100644 --- a/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_initial.yaml +++ b/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_initial.yaml @@ -12,7 +12,7 @@ metadata: - title: Alabama CCDF State Plan 2025-2027, Section 2.2.4 href: https://dhr.alabama.gov/wp-content/uploads/2023/04/2025-2027-CCDF-State-Plan-with-Approval-Letter.pdf#page=26 - title: Alabama Child Care Fact Sheet, January 1, 2024 (Initial Eligibility Monthly Income Scale) - href: https://dhr.alabama.gov/wp-content/uploads/2024/01/Child-Care-Fact-Sheet-2024.pdf + href: https://dhr.alabama.gov/wp-content/uploads/2024/01/Child-Care-Fact-Sheet-2024.pdf#page=1 - title: Alabama Child Care Fact Sheet, January 1, 2026 (Initial Eligibility Monthly Income Scale, top column 171-180% FPL) href: https://dhr.alabama.gov/wp-content/uploads/2025/12/CHILD-CARE-FACT-SHEET-Jan2026.pdf#page=1 - title: Alabama Child Care Fact Sheet, June 1, 2026 (Initial Eligibility Monthly Income Scale, top column 141-150% FPL) diff --git a/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/max_family_size.yaml b/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/max_family_size.yaml new file mode 100644 index 00000000000..d54b016f1c8 --- /dev/null +++ b/policyengine_us/parameters/gov/states/al/dhr/ccsp/income/max_family_size.yaml @@ -0,0 +1,15 @@ +description: Alabama applies the income scale row for this family size to larger families under the Child Care Subsidy Program. +# Each fact sheet's income scales and fee charts end with one row for families of +# eight or more. +values: + 2024-01-01: 8 + +metadata: + unit: person + period: year + label: Alabama CCSP largest family size on the income scales + reference: + - title: Alabama Child Care Fact Sheet, January 1, 2024 (family size row ">=8") + href: https://dhr.alabama.gov/wp-content/uploads/2024/01/Child-Care-Fact-Sheet-2024.pdf#page=1 + - title: Alabama Child Care Fact Sheet, June 1, 2026 (family size row ">=8") + href: https://dhr.alabama.gov/wp-content/uploads/2026/06/CHILD-CARE-FACT-SHEET-Jun2026-1.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/income/smi_year_lag.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/income/smi_year_lag.yaml new file mode 100644 index 00000000000..96b3949d2fd --- /dev/null +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/income/smi_year_lag.yaml @@ -0,0 +1,40 @@ +description: Georgia reads the state median income table from this many federal fiscal years before the one in effect for the month under the Childcare and Parent Services program. + +# Each Appendix A chart prints the date its state median income data took effect: +# - The charts from October 2020 through October 2023 take up each federal table on +# its October 1 start. +# - The September 1, 2024 chart takes up the fiscal year 2025 table a month early, +# at 30% ($26,686 a year for three), so September 2024 reads one year ahead. +# - The CCDF plan prints the 40% limits that took effect October 6, 2025 on the +# fiscal year 2026 table ($3,101 a month for three). The chart effective October 5, +# 2026 takes up the fiscal year 2027 table. The first days of each October keep the +# prior table. +# The model applies each date at the first month that starts on or after it, so the +# fiscal year 2026 and 2027 tables take effect in November 2025 and November 2026. No +# chart before October 2020 survives, so earlier months take each table on October 1. +values: + 2015-10-01: 0 + 2024-09-01: -1 + 2024-10-01: 0 + 2025-10-01: 1 + 2025-10-06: 0 + 2026-10-01: 1 + 2026-10-05: 0 + +metadata: + unit: year + period: month + label: Georgia CAPS state median income table year lag + reference: + - title: Georgia CAPS Appendix A, Maximum Income Limits (effective October 1, 2020), state median income effective October 1, 2020 + href: https://web.archive.org/web/20201124060600id_/https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 + - title: Georgia CAPS Appendix A, Maximum Income Limits (archived December 8, 2023), state median income effective October 1, 2023 + href: https://web.archive.org/web/20231208060145id_/https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 + - title: Georgia CAPS Appendix A, Maximum Income Limits (archived March 1, 2025), state median income effective September 1, 2024 + href: https://web.archive.org/web/20250301224420id_/https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 + - title: Georgia CCDF Plan FFY 2025-2027, Section 2.2.4, 40% of state median income effective October 6, 2025 + href: https://www.decal.ga.gov/documents/attachments/CCDFStatePlan25-27.pdf#page=22 + - title: Georgia DECAL, Letter to CAPS Families (October 6, 2025), 30% to 40% from October 6, 2025 + href: https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_to_Families_Policy_Revisions_10.06.25.pdf#page=1 + - title: Georgia CAPS Appendix A, Maximum Income Limits (effective October 5, 2026), state median income effective October 5, 2026 + href: https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/domestic_violence_in_effect.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/domestic_violence_in_effect.yaml new file mode 100644 index 00000000000..67b080de8ee --- /dev/null +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/domestic_violence_in_effect.yaml @@ -0,0 +1,15 @@ +description: Georgia uses this indicator to determine whether families experiencing domestic violence form a priority group under the Childcare and Parent Services program. + +# The funding restriction started August 1, 2016 with seven groups. The funding Q&A +# adds the homeless, domestic violence and very low income groups on October 1, 2016. +values: + 2015-01-01: false + 2016-10-01: true + +metadata: + unit: bool + period: month + label: Georgia CAPS domestic violence priority group in effect + reference: + - title: Georgia DECAL, Questions about CAPS Funding Restrictions (2016), three groups added October 1, 2016 + href: https://www.decal.ga.gov/documents/attachments/fundingrestrictionsqa.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/homeless_in_effect.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/homeless_in_effect.yaml new file mode 100644 index 00000000000..b3aaa4bc3ee --- /dev/null +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/homeless_in_effect.yaml @@ -0,0 +1,15 @@ +description: Georgia uses this indicator to determine whether families without fixed, regular and adequate housing form a priority group under the Childcare and Parent Services program. + +# The funding restriction started August 1, 2016 with seven groups. The funding Q&A +# adds the homeless, domestic violence and very low income groups on October 1, 2016. +values: + 2015-01-01: false + 2016-10-01: true + +metadata: + unit: bool + period: month + label: Georgia CAPS homeless priority group in effect + reference: + - title: Georgia DECAL, Questions about CAPS Funding Restrictions (2016), three groups added October 1, 2016 + href: https://www.decal.ga.gov/documents/attachments/fundingrestrictionsqa.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/in_effect.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/in_effect.yaml index 21f9beb997e..d22e90c3a44 100644 --- a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/in_effect.yaml +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/in_effect.yaml @@ -2,7 +2,7 @@ description: Georgia uses this indicator to determine whether the Childcare and # DECAL restricted funding to priority groups for new applicants from August 1, # 2016. The funding Q&A adds the homeless, domestic violence and very low income -# groups on October 1, 2016, and the model counts them from August 1. +# groups on October 1, 2016, and each of those groups has its own indicator. values: 2015-01-01: false 2016-08-01: true diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/pre_k_redetermination_in_effect.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/pre_k_redetermination_in_effect.yaml new file mode 100644 index 00000000000..2eee2643fbd --- /dev/null +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/pre_k_redetermination_in_effect.yaml @@ -0,0 +1,20 @@ +description: Georgia uses this indicator to determine whether families of children enrolled in Georgia's Pre-K Program at initial application or the previous eligibility determination must belong to a priority group at redetermination under the Childcare and Parent Services program. + +# DECAL's July 1, 2024 letter adds the requirement to CAPS/00-7 and CAPS/00-14, and +# its October 6, 2025 letter removes it. The model applies each date at the first +# month that starts on or after it, so the requirement covers July 2024 through +# October 2025. +values: + 2015-01-01: false + 2024-07-01: true + 2025-10-06: false + +metadata: + unit: bool + period: month + label: Georgia CAPS Pre-K redetermination requirement in effect + reference: + - title: Georgia DECAL, Letter to CAPS Families (July 1, 2024), requirement added July 1, 2024 + href: https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_from_Elisabetta_Kasfir_Families_07.01.2024.pdf#page=1 + - title: Georgia DECAL, Letter to CAPS Families (October 6, 2025), requirement removed October 6, 2025 + href: https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_to_Families_Policy_Revisions_10.06.25.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/student_parent_in_effect.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/student_parent_in_effect.yaml index 25ed8b4ca73..ff698200374 100644 --- a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/student_parent_in_effect.yaml +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/student_parent_in_effect.yaml @@ -8,7 +8,5 @@ metadata: period: month label: Georgia CAPS student parent priority group in effect reference: - - title: Georgia CAPS Policy CAPS/00-7, revision history (May 1, 2022) - href: https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=10 - - title: Georgia CAPS Policy CAPS/00-7, Section 7.16 (revised October 5, 2026) + - title: "Georgia CAPS Policy CAPS/00-7, Section 7.16 (revised October 5, 2026) and revision history (May 1, 2022) #page 9-10" href: https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=9 diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/very_low_income_fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/very_low_income_fpg_year_lag.yaml new file mode 100644 index 00000000000..0bfaba6d626 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/very_low_income_fpg_year_lag.yaml @@ -0,0 +1,43 @@ +description: Georgia uses the federal poverty guideline from this many years before the current date for the very low income priority group under the Childcare and Parent Services program. + +# Each Appendix A chart prints the date CAPS took up that year's guideline: March 1 +# in 2020 through 2025 and March 2 in 2026. The prior year's guideline holds until +# then. The model applies each date at the first month that starts on or after it, +# so the 2026 guideline takes effect in April 2026. No chart before 2020 survives, so +# earlier years read the current year's guideline. +values: + 2015-01-01: 0 + 2020-01-01: 1 + 2020-03-01: 0 + 2021-01-01: 1 + 2021-03-01: 0 + 2022-01-01: 1 + 2022-03-01: 0 + 2023-01-01: 1 + 2023-03-01: 0 + 2024-01-01: 1 + 2024-03-01: 0 + 2025-01-01: 1 + 2025-03-01: 0 + 2026-01-01: 1 + 2026-03-02: 0 + +metadata: + unit: year + period: month + label: Georgia CAPS very low income poverty guideline year lag + reference: + - title: Georgia CAPS Appendix A, Maximum Income Limits (effective October 1, 2020), guidelines effective for CAPS March 1, 2020 + href: https://web.archive.org/web/20201124060600id_/https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 + - title: Georgia CAPS Appendix A, Maximum Income Limits (effective October 1, 2021), guidelines effective for CAPS March 1, 2021 + href: https://web.archive.org/web/20211026013823id_/https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 + - title: Georgia CAPS Appendix A, Maximum Income Limits (archived March 1, 2022), guidelines effective for CAPS March 1, 2022 + href: https://web.archive.org/web/20220301180356id_/https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 + - title: Georgia CAPS Appendix A, Maximum Income Limits (archived March 4, 2023), guidelines effective for CAPS March 1, 2023 + href: https://web.archive.org/web/20230304133123id_/https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 + - title: Georgia CAPS Appendix A, Maximum Income Limits (archived May 20, 2024), guidelines effective for CAPS March 1, 2024 + href: https://web.archive.org/web/20240520214500id_/https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 + - title: Georgia CAPS Appendix A, Maximum Income Limits (archived March 8, 2025), guidelines effective for CAPS March 1, 2025 + href: https://web.archive.org/web/20250308021446id_/https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 + - title: Georgia CAPS Appendix A, Maximum Income Limits (archived March 8, 2026), guidelines effective for CAPS March 2, 2026 + href: https://web.archive.org/web/20260308171215id_/https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/very_low_income_in_effect.yaml b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/very_low_income_in_effect.yaml new file mode 100644 index 00000000000..ffab1319889 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ga/decal/caps/priority_groups/very_low_income_in_effect.yaml @@ -0,0 +1,15 @@ +description: Georgia uses this indicator to determine whether families with very low income form a priority group under the Childcare and Parent Services program. + +# The funding restriction started August 1, 2016 with seven groups. The funding Q&A +# adds the homeless, domestic violence and very low income groups on October 1, 2016. +values: + 2015-01-01: false + 2016-10-01: true + +metadata: + unit: bool + period: month + label: Georgia CAPS very low income priority group in effect + reference: + - title: Georgia DECAL, Questions about CAPS Funding Restrictions (2016), three groups added October 1, 2016 + href: https://www.decal.ga.gov/documents/attachments/fundingrestrictionsqa.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml b/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml index f028c33f179..005e86d73c7 100644 --- a/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml +++ b/policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml @@ -23,10 +23,8 @@ metadata: href: https://adminrules.idaho.gov/rules/2019%20Archive%20C2/16/160612.pdf#page=8 - title: IDAPA 16.06.12.070.01, Income at Application (2022 archive, effective March 17, 2022) href: https://adminrules.idaho.gov/rules/2022%20Archive/16/160612.pdf#page=7 - - title: IDAPA 16.06.12.070.01, Income at Application (current, effective April 6, 2023) + - title: "IDAPA 16.06.12.070.01, Income at Application (current, effective April 6, 2023), and 16.06.12.705, Funding Restrictions #page 7,18" href: https://adminrules.idaho.gov/rules/current/16/160612.pdf#page=7 - - title: IDAPA 16.06.12.705, Funding Restrictions - href: https://adminrules.idaho.gov/rules/current/16/160612.pdf#page=18 - title: Idaho Department of Health and Welfare, DHW will resume applications for the Idaho Child Care Program in January (November 14, 2024) href: https://healthandwelfare.idaho.gov/news/dhw-will-resume-applications-idaho-child-care-program-january - title: Idaho Department of Health and Welfare, Apply for Child Care (limits effective October 2025; page last updated September 30, 2025) diff --git a/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/fpg_year_lag.yaml index ae3fbc9f65d..f2ae776ce37 100644 --- a/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/fpg_year_lag.yaml +++ b/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/fpg_year_lag.yaml @@ -1,17 +1,22 @@ description: Indiana uses the federal poverty guideline from this many years before the current date under the Child Care and Development Fund program. -# Indiana moves to a new year's guideline when it posts a new eligibility package, -# months into that year, and the old guideline holds until then: -# - March 31, 2024: the state plan prints 150% limits on the 2024 guideline ($3,228 for three). -# - May 1, 2025: FSSA's 2025 sliding fee schedule carries that date in its file name -# (CCDFSlidingFeeSchedule_w-Copays_2025_050125.pdf). -# - April 5, 2026: FSSA's chart prints 135% of the 2026 guideline ($3,074 for three). -# So a family of three faces 150% of the 2025 guideline ($3,331) through April 4, 2026. +# Indiana moves to a new year's guideline when FSSA posts that year's income eligibility +# and fee schedule, and the old guideline holds until then. Each schedule prints its +# effective date: +# - March 12, 2023: 127% of the 2023 guideline ($2,631 a month for three). +# - March 31, 2024: 150% of the 2024 guideline ($3,228 for three). +# - March 23, 2025: 150% of the 2025 guideline ($3,331 for three). +# - April 5, 2026: 135% of the 2026 guideline ($3,074 for three). +# Before March 12, 2023 the model reads the 2022 guideline, and before 2023 the current +# year's, since no earlier dated schedule is available. From 2027 a lag of 1 extrapolates: +# the model keeps the prior year's guideline because no 2027 schedule exists yet. values: 2015-01-01: 0 + 2023-01-01: 1 + 2023-03-12: 0 2024-01-01: 1 2024-03-31: 0 2025-01-01: 1 - 2025-05-01: 0 + 2025-03-23: 0 2026-01-01: 1 2026-04-05: 0 2027-01-01: 1 @@ -23,8 +28,12 @@ metadata: reference: - title: Indiana CCDF State Plan FFY 2025-2027, Amendment 2, Section 2.2.4 (limits effective March 31, 2024) href: https://www.in.gov/dA/6307709ae5/ACF-118CCDFFFY2025-2027IndianaAmendment.pdf?language_id=1 - - title: Indiana FSSA, CCDF Sliding Fee Schedule with copays, 2025, file dated May 1, 2025 - href: https://secure.in.gov/fssa/carefinder/files/CCDFSlidingFeeSchedule_w-Copays_2025_050125.pdf + - title: Indiana FSSA, Child Care Income Eligibility Determination and Fee Schedule 2023 (effective March 12, 2023), archived May 1, 2023 + href: https://web.archive.org/web/20230501122705/https://www.in.gov/fssa/carefinder/files/CCDFSlidingFeeSchedule_withCopays.pdf#page=1 + - title: Indiana FSSA, Child Care Income Eligibility Determination and Fee Schedule 2024 (effective March 31, 2024), archived April 13, 2024 + href: https://web.archive.org/web/20240413093550/https://www.in.gov/fssa/carefinder/files/CCDFSlidingFeeSchedule_withCopays.pdf#page=1 + - title: Indiana FSSA, Child Care Income Eligibility Determination and Fee Schedule 2025 (effective March 23, 2025), archived April 3, 2025 + href: https://web.archive.org/web/20250403065234/https://www.in.gov/fssa/carefinder/files/CCDFSlidingFeeSchedule_withCopays.pdf#page=1 - title: Indiana FSSA, Income to Get on CCDF (effective April 5, 2026) href: https://www.in.gov/dA/3271c7180e/Income-Get-on-CCDF.pdf - title: Indiana FSSA, CCDF Sliding Fee Schedule with copays, 2026 (effective April 5, 2026) diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/income/continuation_smi_freeze_in_effect.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/income/continuation_smi_freeze_in_effect.yaml new file mode 100644 index 00000000000..42809ea6f04 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/income/continuation_smi_freeze_in_effect.yaml @@ -0,0 +1,17 @@ +description: Maryland uses this indicator to determine whether the State Median Income base year is frozen for the Child Care Scholarship continuation income scale. +# The model gives continuing families the initial scale's frozen base years until MSDE's +# Continuation Income Scale took effect on April 22, 2024: 85% of the federal fiscal 2025 +# median, $106,563 a year for three. MSDE's page still posts that scale in October 2026. +values: + 2016-01-01: false + 2018-07-01: true + +metadata: + unit: bool + period: year + label: Maryland CCS continuation SMI freeze in effect + reference: + - title: MSDE Child Care Scholarship Program Briefing (Feb 4, 2026), slide 21 - fiscal-year freeze schedule + href: https://mgaleg.maryland.gov/meeting_material/2026/w&m%20-%20134146885147130127%20-%20Briefing%20materials.pdf#page=21 + - title: MSDE, Child Care Scholarship Program, Continuation Income Scale effective April 22, 2024 (captured October 9, 2026) + href: https://web.archive.org/web/20261009215322/https://earlychildhood.marylandpublicschools.org/child-care-providers/child-care-scholarship-program diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/income/continuation_smi_frozen_year.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/income/continuation_smi_frozen_year.yaml new file mode 100644 index 00000000000..748f36e1036 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/income/continuation_smi_frozen_year.yaml @@ -0,0 +1,17 @@ +description: Maryland pins the State Median Income (SMI) base year used for the Child Care Scholarship continuation income scale when continuation_smi_freeze_in_effect is true. Maryland's fiscal year starts July 1. +values: + 2018-07-01: 2018 + 2022-07-01: 2021 + # The posted Continuation Income Scale effective April 22, 2024 uses the median HHS + # published for federal fiscal 2025, which starts October 1, 2024. + 2024-04-22: 2024 + +metadata: + unit: year + period: year + label: Maryland CCS continuation SMI frozen year + reference: + - title: MSDE Child Care Scholarship Program Briefing (Feb 4, 2026), slide 21 - fiscal-year base years + href: https://mgaleg.maryland.gov/meeting_material/2026/w&m%20-%20134146885147130127%20-%20Briefing%20materials.pdf#page=21 + - title: MSDE, Child Care Scholarship Program, Continuation Income Scale effective April 22, 2024 (captured October 9, 2026) + href: https://web.archive.org/web/20261009215322/https://earlychildhood.marylandpublicschools.org/child-care-providers/child-care-scholarship-program diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_freeze_in_effect.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_freeze_in_effect.yaml index a8cbe7a2fe8..ba8a6edb55d 100644 --- a/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_freeze_in_effect.yaml +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_freeze_in_effect.yaml @@ -1,8 +1,13 @@ -description: Maryland uses this indicator to determine whether the State Median Income base year is frozen for Child Care Scholarship income eligibility. +description: Maryland uses this indicator to determine whether the State Median Income base year is frozen for the Child Care Scholarship initial income scale. +# MSDE's scholarship page, captured October 9, 2026, still posts the Initial Income Scale +# effective December 15, 2024 as the table for new applications: 75% of the federal +# fiscal 2025 median, $94,026 a year for three. The model holds that median from October +# 1, 2025, when HHS's fiscal 2026 estimates took effect; a new posted table adds a date here. values: 2016-01-01: false 2018-07-01: true 2024-12-15: false + 2025-10-01: true metadata: unit: bool @@ -13,3 +18,5 @@ metadata: href: https://mgaleg.maryland.gov/meeting_material/2026/w&m%20-%20134146885147130127%20-%20Briefing%20materials.pdf#page=21 - title: MSDE Jan 23, 2025 OCC Info Session - Dec 15, 2024 SMI unfreeze href: https://earlychildhood.marylandpublicschools.org/system/files/filedepot/3/january_2025_occ_info_session.pdf#page=7 + - title: MSDE, Child Care Scholarship Program, Initial Income Scale effective December 15, 2024 (captured October 9, 2026) + href: https://web.archive.org/web/20261009215322/https://earlychildhood.marylandpublicschools.org/child-care-providers/child-care-scholarship-program diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_frozen_year.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_frozen_year.yaml index c3c1ab7017a..f6dc1f4c629 100644 --- a/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_frozen_year.yaml +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_frozen_year.yaml @@ -1,7 +1,10 @@ -description: Maryland pins the State Median Income (SMI) base year used for Child Care Scholarship income eligibility when smi_freeze_in_effect is true. Maryland's fiscal year starts July 1. +description: Maryland pins the State Median Income (SMI) base year used for the Child Care Scholarship initial income scale when smi_freeze_in_effect is true. Maryland's fiscal year starts July 1. values: 2018-07-01: 2018 2022-07-01: 2021 + # The posted Initial Income Scale effective December 15, 2024 uses the median HHS + # published for federal fiscal 2025, which starts October 1, 2024. + 2025-10-01: 2024 metadata: unit: year @@ -10,3 +13,5 @@ metadata: reference: - title: MSDE Child Care Scholarship Program Briefing (Feb 4, 2026), slide 21 - fiscal-year base years href: https://mgaleg.maryland.gov/meeting_material/2026/w&m%20-%20134146885147130127%20-%20Briefing%20materials.pdf#page=21 + - title: MSDE, Child Care Scholarship Program, Initial Income Scale effective December 15, 2024 (captured October 9, 2026) + href: https://web.archive.org/web/20261009215322/https://earlychildhood.marylandpublicschools.org/child-care-providers/child-care-scholarship-program diff --git a/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpg_year_lag.yaml index 77dfcb94282..cf0524c4d3d 100644 --- a/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpg_year_lag.yaml +++ b/policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpg_year_lag.yaml @@ -1,8 +1,9 @@ description: Missouri uses the federal poverty guideline from this many years before the current date under the Child Care Subsidy program. # DESE's chart headed November 2025 and updated July 1, 2026 prints 150% of the 2025 # guideline ($3,331 a month for three). A lag of one holds the 2025 guideline through -# 2026; a new chart adds a date here. No source dates the guideline year before the -# October 2025 chart, so the list keeps the current year until then. +# 2026; a new chart adds a date here. From 2027 the lag of one extrapolates, since no +# chart prints a 2027 limit. No source dates the guideline year before the October +# 2025 chart, so the list keeps the current year until then. values: 2015-01-01: 0 2026-01-01: 1 diff --git a/policyengine_us/parameters/gov/states/mo/dese/ccs/transitional/funding_rate.yaml b/policyengine_us/parameters/gov/states/mo/dese/ccs/transitional/funding_rate.yaml index 789d082af59..fc218d52b07 100644 --- a/policyengine_us/parameters/gov/states/mo/dese/ccs/transitional/funding_rate.yaml +++ b/policyengine_us/parameters/gov/states/mo/dese/ccs/transitional/funding_rate.yaml @@ -4,6 +4,10 @@ description: Missouri funds this share of the base reimbursement rate by federal # Level 1 (above 150% up to 185%) = 80%, Level 2 (above 185% up to 215%) = 60%, # Level 3 (above 215% up to 242%) = 50%. DESE removed Level 3 on July 1, 2026, so no # eligible family reaches the 50% share from that date. +# Each threshold gives, as a multiple of the guideline, the top of the level below +# it. DESE's chart prints each top as the nearest dollar ($3,331, $4,109 and $4,775 +# a month for three from July 2026), and mo_ccs_funding_rate rounds them the same +# way. metadata: type: single_amount threshold_unit: /1 @@ -28,14 +32,14 @@ brackets: amount: 2025-10-01: 1 - threshold: - 2025-10-01: 1.5001 + 2025-10-01: 1.5 amount: 2025-10-01: 0.8 - threshold: - 2025-10-01: 1.8501 + 2025-10-01: 1.85 amount: 2025-10-01: 0.6 - threshold: - 2025-10-01: 2.1501 + 2025-10-01: 2.15 amount: 2025-10-01: 0.5 diff --git a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml index 93d87a1c7b5..3dd39be6ab0 100644 --- a/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml +++ b/policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/initial.yaml @@ -21,10 +21,8 @@ metadata: href: https://archive.legmt.gov/bills/MCA/title_0520/chapter_0020/part_0070/section_0150/0520-0020-0070-0150.html - title: Best Beginnings Child Care Sliding Fee Scale (document header "Effective 07-01-2025"; URL filename says 2023) href: https://dphhs.mt.gov/assets/ecfsd/childcare/policymanual/SlidingFeeScale07012023.pdf#page=1 - - title: Montana Legislative Fiscal Division, Child Care Overview (June 2024), HB 648 in the 2023 Session + - title: "Montana Legislative Fiscal Division, Child Care Overview (June 2024), HB 648 in the 2023 Session and Policy Timeline #page 4,13" href: https://leg.mt.gov/content/Publications/fiscal/2025-Biennium/Special-Topics/Childcare/Childcare-Overview-LEG-Days-June2024.pdf#page=4 - - title: Montana Legislative Fiscal Division, Child Care Overview (June 2024), Policy Timeline - href: https://leg.mt.gov/content/Publications/fiscal/2025-Biennium/Special-Topics/Childcare/Childcare-Overview-LEG-Days-June2024.pdf#page=13 - title: Mont. Admin. R. 37.80.202(1) href: https://rules.mt.gov/gateway/ruleno.asp?RN=37.80.202 - title: Mont. Admin. R. 37.80.202(1) — Cornell LII diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/chart_rounds_to_nearest_dollar.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/chart_rounds_to_nearest_dollar.yaml new file mode 100644 index 00000000000..49271560d85 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/chart_rounds_to_nearest_dollar.yaml @@ -0,0 +1,22 @@ +description: Nevada uses this indicator to determine whether its income chart rounds each income limit and copayment band to the nearest dollar under the Child Care and Development Program. + +# The charts effective October 1, 2025 and October 1, 2026 print every limit and band +# top as the nearest dollar of its share of state median income ($1,789 a month for one +# at 41% in 2025, from $1,788.77). CC PT 07-23 prints the 85% tops of the October 2023 +# chart in cents ($5,314.84 for three). The model treats the flat schedule's charts, +# from October 1, 2024, as rounded and earlier charts as unrounded. +values: + 2015-01-01: false + 2024-10-01: true + +metadata: + unit: bool + period: month + label: Nevada CCDP chart rounds to the nearest dollar + reference: + - title: Nevada DWSS Policy Transmittal CC PT 06-25 (October 2, 2025), Household Size and Monthly Income Charts + href: https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/CC_PT_06-25_ANNUAL_INCOME_CHANGES_10.02.2025.pdf#page=2 + - title: Nevada DSS Policy Transmittal, Annual Changes to the CCDP Household Size and Monthly Income Limits (October 1, 2026) + href: https://prod.dss.nv.gov/siteassets/dwss.nv.gov/ccdp-annual-income-changes-2026_1.pdf#page=2 + - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/amount.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/amount.yaml index d6bb3cb7bba..a16f06095e0 100644 --- a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/amount.yaml +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/copay/amount.yaml @@ -19,12 +19,12 @@ metadata: # The flat $0/$90/$150 copay and two-tier copay structure took effect # Oct 1, 2024 (State Plan Section 2.4.v); CC PT 06-25 is the Oct 1, 2025 annual # income-chart refresh that restates the same percentages and bands. -# Income up to 32.99% SMI -> $0; 33%-42% SMI -> $90; above 42% SMI -> $150. -# The State Plan summary prose ("33%-42% -> $90, 43%-49% -> $150") leaves an -# undefined 42%-43% gap; the operational CC PT 06-25 fee chart resolves it, with -# the $90 band topping out at 42% SMI and the $150 band beginning just above it. -# The scale is at-or-above, so 0.33 belongs to the $90 band and 0.4201 to the -# $150 band (a family at exactly 42% SMI stays in the $90 band, per the chart). +# Each threshold gives, as a share of SMI, the top of the band below it: income up to +# 33% SMI pays $0, up to 42% SMI pays $90, and above 42% SMI pays $150. The charts +# print each top as the nearest dollar ($2,326 and $2,890 a month for three in October +# 2025), and nv_ccdp_copay rounds them the same way. The State Plan summary prose +# ("33%-42% -> $90, 43%-49% -> $150") leaves an undefined 42%-43% gap; the operational +# fee charts resolve it, with the $90 band topping out at 42% SMI. brackets: - threshold: 2024-10-01: 0 @@ -35,6 +35,6 @@ brackets: amount: 2024-10-01: 90 - threshold: - 2024-10-01: 0.4201 + 2024-10-01: 0.42 amount: 2024-10-01: 150 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/fpg_intake/in_effect.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/fpg_intake/in_effect.yaml new file mode 100644 index 00000000000..e3c114214ed --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/fpg_intake/in_effect.yaml @@ -0,0 +1,27 @@ +description: Nevada uses this indicator to determine whether new applicants face a limit set as a share of the federal poverty guideline under the Child Care and Development Program. + +# Urban's CCDF Policies Database prints 85% of state median income for new applicants +# in October 2017 and a lower limit by October 2018, so the start date falls between +# those two snapshots. The state's own figures from February 2019 through October 2021 +# all equal 130% of the poverty guideline. The FFY 2022-2024 plan moves new applicants +# to 85% of state median income on July 1, 2022. +values: + 2015-01-01: false + 2018-10-01: true + 2022-07-01: false + +metadata: + unit: bool + period: month + label: Nevada CCDP poverty-guideline intake limit in effect + reference: + - title: Urban Institute, CCDF Policies Database Book of Tables 2018, Changes in Financial Eligibility Tests from 2017 to 2018 + href: https://ccdf.urban.org/sites/default/files/CrossStateVariationCCDFPolicies2018%20%28final%2011%2021%202019%29.pdf#page=41 + - title: "National Women's Law Center, State Child Care Assistance Policies: Nevada (February 2020) #page 1-2" + href: https://nwlc.org/wp-content/uploads/2020/02/nevada-childcare-subsidy2019_v1.pdf#page=1 + - title: Nevada draft CCDF State Plan FFY 2022-2024, Section 3.1.3 (limits effective October 1, 2020) + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Home/Features/2022-2024%20Child%20Care%20PrePrint%20Draft(1).pdf#page=45 + - title: Urban Institute, CCDF Policies Database Book of Tables 2021, Table B-1 (thresholds reported for October 1, 2021) + href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202021%20Book%20of%20Tables%20%28final%29_1.pdf#page=393 + - title: "Nevada CCDF State Plan FFY 2022-2024, Amendment approved May 16, 2023, Section 3.1.3 (85% of SMI effective July 1, 2022) #page 50-51" + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/Amended%20State%20Plan.pdf#page=50 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/fpg_intake/rate.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/fpg_intake/rate.yaml new file mode 100644 index 00000000000..06e998751d0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/fpg_intake/rate.yaml @@ -0,0 +1,19 @@ +description: Nevada limits new applicants to income at or below this multiple of the federal poverty guideline under the Child Care and Development Program, while the poverty-guideline intake limit applies. + +# The state's figures for a family of three all equal 130% of the guideline Nevada had +# taken up that October: $27,012 a year in February 2019 (2018 guideline), $27,729 from +# October 2019, $2,353 a month from October 1, 2020 and $2,379 on October 1, 2021. +values: + 2018-10-01: 1.3 + +metadata: + unit: /1 + period: month + label: Nevada CCDP poverty-guideline intake rate + reference: + - title: "National Women's Law Center, State Child Care Assistance Policies: Nevada (February 2020) #page 1-2" + href: https://nwlc.org/wp-content/uploads/2020/02/nevada-childcare-subsidy2019_v1.pdf#page=1 + - title: Nevada draft CCDF State Plan FFY 2022-2024, Section 3.1.3 (limits effective October 1, 2020) + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Home/Features/2022-2024%20Child%20Care%20PrePrint%20Draft(1).pdf#page=45 + - title: Urban Institute, CCDF Policies Database Book of Tables 2021, Table B-1 (thresholds reported for October 1, 2021) + href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202021%20Book%20of%20Tables%20%28final%29_1.pdf#page=393 diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_intake.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_intake.yaml index 9ab3aedf4b6..698c5c8c060 100644 --- a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_intake.yaml +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_intake.yaml @@ -3,20 +3,16 @@ description: Nevada limits new applicants to income at or below this share of st # - Through 2017 Urban's CCDF Policies Database prints 85% of SMI each October ($3,954, # $4,104 and $4,127 a month for three in 2015, 2016 and 2017). No Nevada document # from those years survives on its site. -# - By October 2018 Urban shows a lower first tier with 85% kept for families already -# enrolled. The state's plan documents and NWLC print 130% of the poverty guideline -# ($27,012 a year for three in February 2019; $2,353 a month from October 2020; $2,379 -# in October 2021, which the FFY 2022-2024 plan reports as 41% of SMI). 41% stands in -# for that guideline-based limit, which ran up to about four points higher for three -# in earlier years (NWLC prints 45% for February 2019). -# - The FFY 2022-2024 plan moves new applicants to 85% of SMI effective July 1, 2022 -# ($5,066 for three), and CC PT 07-23 keeps 85% for October 2023 ($5,314.84). +# - From October 2018 through June 2022 most new applicants faced 130% of the poverty +# guideline instead (fpg_intake). NWLC reports that families with a child in foster +# care or protective services and homeless families still qualified at 85% of SMI, +# which this parameter keeps for them. +# - The FFY 2022-2024 plan moves every new applicant to 85% of SMI effective July 1, +# 2022 ($5,066 for three), and CC PT 07-23 keeps 85% for October 2023 ($5,314.84). # - From October 1, 2024 new applicants face 41% and renewals 49%. The chart effective # October 1, 2026 keeps both shares. values: 2015-01-01: 0.85 - 2018-10-01: 0.41 - 2022-07-01: 0.85 2024-10-01: 0.41 metadata: @@ -28,16 +24,10 @@ metadata: href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202015%20Book%20of%20Tables%20%28final%2011%2023%2016%29.pdf#page=124 - title: Urban Institute, CCDF Policies Database Book of Tables 2017, Table 14 href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202017%20Book%20of%20Tables%20%28final%2010%2009%2018%29.pdf#page=122 - - title: Urban Institute, CCDF Policies Database Book of Tables 2018, Table 14 - href: https://ccdf.urban.org/sites/default/files/CrossStateVariationCCDFPolicies2018%20%28final%2011%2021%202019%29.pdf#page=123 - - title: National Women's Law Center, Nevada child care subsidy profile 2019 - href: https://nwlc.org/wp-content/uploads/2020/02/nevada-childcare-subsidy2019_v1.pdf#page=1 - - title: Nevada draft CCDF State Plan FFY 2022-2024, Section 3.1.3 (limits effective October 1, 2020) - href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Home/Features/2022-2024%20Child%20Care%20PrePrint%20Draft(1).pdf#page=45 - - title: Urban Institute, CCDF Policies Database Book of Tables 2021, Table B-1 - href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202021%20Book%20of%20Tables%20%28final%29_1.pdf#page=393 - - title: Nevada CCDF State Plan FFY 2022-2024, Amendment approved May 16, 2023, Section 3.1.3 (85% of SMI effective July 1, 2022) - href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/Amended%20State%20Plan.pdf#page=51 + - title: "National Women's Law Center, State Child Care Assistance Policies: Nevada (February 2020), note 1" + href: https://nwlc.org/wp-content/uploads/2020/02/nevada-childcare-subsidy2019_v1.pdf#page=2 + - title: "Nevada CCDF State Plan FFY 2022-2024, Amendment approved May 16, 2023, Section 3.1.3 (85% of SMI effective July 1, 2022) #page 50-51" + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/Amended%20State%20Plan.pdf#page=50 - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=1 - title: Nevada DWSS Policy Transmittal CC PT 06-25 (Oct 2, 2025) — Annual Income Changes diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_renewal.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_renewal.yaml index 2443371d12b..bb7470c99f0 100644 --- a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_renewal.yaml +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_renewal.yaml @@ -18,8 +18,8 @@ metadata: href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202017%20Book%20of%20Tables%20%28final%2010%2009%2018%29.pdf#page=122 - title: Urban Institute, CCDF Policies Database Book of Tables 2022, Table F-3 (initial and continuing limits, 2018-2022) href: https://ccdf.urban.org/sites/default/files/CCDF%20Policies%20Database%202022%20Book%20of%20Tables%20%28final%29.pdf#page=428 - - title: Nevada CCDF State Plan FFY 2022-2024, Amendment approved May 16, 2023, Section 3.1.3 - href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/Amended%20State%20Plan.pdf#page=51 + - title: "Nevada CCDF State Plan FFY 2022-2024, Amendment approved May 16, 2023, Section 3.1.3 #page 50-51" + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/Amended%20State%20Plan.pdf#page=50 - title: Nevada DWSS Policy Transmittal CC PT 07-23 (October 9, 2023), Household Size Monthly Income Chart href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=1 - title: Nevada DWSS, Copayment Webinar Questions and Answers (November 2024) diff --git a/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_year_lag.yaml b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_year_lag.yaml new file mode 100644 index 00000000000..86ee72b475d --- /dev/null +++ b/policyengine_us/parameters/gov/states/nv/dwss/ccdp/income/smi_year_lag.yaml @@ -0,0 +1,17 @@ +description: Nevada reads the state median income table from this many federal fiscal years before the program year in effect under the Child Care and Development Program. + +# Nevada takes up each federal table on its October 1 start, with one exception: the +# FFY 2022-2024 plan dates its 85% limits ($5,066 a month for three) to July 1, 2022, +# and builds them on the LIHEAP fiscal year 2023 table, which starts October 1, 2022. +values: + 2015-01-01: 0 + 2022-07-01: -1 + 2022-10-01: 0 + +metadata: + unit: year + period: month + label: Nevada CCDP state median income table year lag + reference: + - title: "Nevada CCDF State Plan FFY 2022-2024, Amendment approved May 16, 2023, Section 3.1.3(b), (d) and (f), 85% of the LIHEAP FFY23 state median income from July 1, 2022 #page 50-51" + href: https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/Amended%20State%20Plan.pdf#page=50 diff --git a/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/payment.yaml b/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/payment.yaml index 13c1b18739b..ac9b8079249 100644 --- a/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/payment.yaml +++ b/policyengine_us/parameters/gov/states/oh/dcy/ccap/ccvp/payment.yaml @@ -6,15 +6,18 @@ metadata: label: Ohio CCVP monthly voucher payment breakdown: - oh_ccap_provider_type - - oh_ccap_child_age_group + - oh_ccvp_child_age_group reference: - - title: DCY Procedure Letter 36, voucher payment rates for enrollment and attendance on or after November 1, 2025 + - title: "DCY Procedure Letter 36, voucher payment rates for enrollment and attendance on or after November 1, 2025 #page 2-3" href: https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=2 # Procedure Letter 36 charts centers and school-based programs apart from -# type A and type B family child care homes, with one school-age row, so the -# school-age summer group takes the school-age amount. It prices enrollment and -# attendance from November 1, 2025; the model carries no earlier chart. +# type A and type B family child care homes, with one school-age row for children +# enrolled in or eligible to enroll in kindergarten, so the school-age summer group +# takes the school-age amount. It prices enrollment and attendance from November 1, +# 2025; the model carries no earlier chart. The letter also pays programs an initial +# enrollment payment on authorization, at most three per child in an eligibility +# year; the model pays only the monthly amounts. CENTER: INFANT: 2025-11-01: 900 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/fpg_year_lag.yaml index ade29af2827..b024caf55c0 100644 --- a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/fpg_year_lag.yaml +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/fpg_year_lag.yaml @@ -2,7 +2,8 @@ description: West Virginia uses the federal poverty guideline from this many yea # Appendix A's sliding fee scale, created October 1, 2024, prints the 2024 guideline # (headed "FY 2024 Federal Poverty Level"; $3,981 a month for three at 185%). The # Bureau's Child Care Policy page still linked that scale on November 5, 2026, so the -# lag grows to keep the 2024 guideline. A new scale adds a date here. +# lag grows to keep the 2024 guideline. A new scale adds a date here. From 2027 the +# lag of two extrapolates: it reads the 2025 guideline, which no scale prints. values: 2015-01-01: 0 2025-01-01: 1 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index e8da11432e9..34c399b9e28 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -856,6 +856,7 @@ programs: full_name: Ohio Child Care Assistance Program (Publicly Funded Child Care and Child Care Choice Voucher Program) variable: oh_child_care_subsidies parameter_prefix: gov.states.oh.dcy.ccap + notes: The Child Care Choice Voucher Program starts in November 2025 with Procedure Letter 36's monthly payment chart; the model leaves out the voucher from its April 2024 launch until then and the initial enrollment payment the letter adds on top of the monthly payments. - state: PA status: complete name: Pennsylvania CCW diff --git a/policyengine_us/tests/code_health/test_source_conflicts.py b/policyengine_us/tests/code_health/test_source_conflicts.py index 9ceab10c355..4ba8bd3027f 100644 --- a/policyengine_us/tests/code_health/test_source_conflicts.py +++ b/policyengine_us/tests/code_health/test_source_conflicts.py @@ -177,7 +177,6 @@ "policyengine_us/variables/gov/states/ky/dcbs/liheap/ky_liheap.py": 1, "policyengine_us/variables/gov/states/mn/dcyf/mfip/income/earned/mn_mfip_dependent_care_deduction.py": 1, "policyengine_us/variables/gov/states/mn/tax/income/deductions/mn_itemized_deductions.py": 1, - "policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.py": 1, "policyengine_us/variables/gov/states/sc/tax/income/subtractions/retirement/sc_retirement_deduction_survivors.py": 1, "policyengine_us/variables/gov/states/vt/tax/income/credits/cdcc/vt_low_income_cdcc_eligible.py": 1, "policyengine_us/variables/gov/states/wa/dor/property_tax_exemption/senior_disabled/wa_pte_categorical_eligible.py": 1, diff --git a/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_fpg.yaml b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_fpg.yaml new file mode 100644 index 00000000000..351ef19a391 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_fpg.yaml @@ -0,0 +1,108 @@ +# Alabama CCSP monthly federal poverty guideline (SPMUnit, MONTH). +# The fact sheets use the prior calendar year's guideline and one row for families +# of eight or more. + +- name: A family of nine uses the eight-person guideline in June 2026. + period: 2026-06 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 15 + is_tax_unit_dependent: true + person4: + age: 13 + is_tax_unit_dependent: true + person5: + age: 11 + is_tax_unit_dependent: true + person6: + age: 9 + is_tax_unit_dependent: true + person7: + age: 7 + is_tax_unit_dependent: true + person8: + age: 5 + is_tax_unit_dependent: true + person9: + age: 3 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + # (15,650 + 7 x 5,500) / 12 = 4,512.50; the June 2026 fact sheet's >=8 row prints 0-4,513 dollars at 0-100% FPL. + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + state_code: + 2026: AL + output: + al_ccsp_fpg: 4_512.50 + +- name: A family of three uses the prior year's guideline in June 2026. + period: 2026-06 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 15 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + # 26,650 / 12 = 2,220.83; the June 2026 fact sheet prints 0-2,221 dollars at 0-100% FPL. + households: + household: + members: [person1, person2, person3] + state_code: + 2026: AL + output: + al_ccsp_fpg: 2_220.83 + +- name: A family of eight uses the 2023 guideline in January 2024. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 15 + is_tax_unit_dependent: true + person4: + age: 13 + is_tax_unit_dependent: true + person5: + age: 11 + is_tax_unit_dependent: true + person6: + age: 9 + is_tax_unit_dependent: true + person7: + age: 7 + is_tax_unit_dependent: true + person8: + age: 5 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + # (14,580 + 7 x 5,140) / 12 = 4,213.33; the January 2024 fact sheet's >=8 row prints 0-4,213 dollars at 0-100% FPL. + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: + 2024: AL + output: + al_ccsp_fpg: 4_213.33 diff --git a/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_income_eligible.yaml index 0eaadd11d9b..bc522840c33 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_income_eligible.yaml @@ -426,3 +426,561 @@ 2026: AL output: al_ccsp_income_eligible: true + +- name: A new applicant family of nine uses the eight-or-more row, so 6,769 dollars qualifies in June 2026. + period: 2026-06 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 15 + is_tax_unit_dependent: true + person4: + age: 13 + is_tax_unit_dependent: true + person5: + age: 11 + is_tax_unit_dependent: true + person6: + age: 9 + is_tax_unit_dependent: true + person7: + age: 7 + is_tax_unit_dependent: true + person8: + age: 5 + is_tax_unit_dependent: true + person9: + age: 3 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + # The June 2026 fact sheet's >=8 row tops out at 6,769 dollars (141-150% FPL). + al_ccsp_countable_income: 6_769 + al_ccsp_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + state_code: + 2026: AL + output: + al_ccsp_income_eligible: true + +- name: A new applicant family of nine at 6,770 dollars doesn't qualify in June 2026. + period: 2026-06 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 15 + is_tax_unit_dependent: true + person4: + age: 13 + is_tax_unit_dependent: true + person5: + age: 11 + is_tax_unit_dependent: true + person6: + age: 9 + is_tax_unit_dependent: true + person7: + age: 7 + is_tax_unit_dependent: true + person8: + age: 5 + is_tax_unit_dependent: true + person9: + age: 3 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + al_ccsp_countable_income: 6_770 + al_ccsp_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + state_code: + 2026: AL + output: + al_ccsp_income_eligible: false + +- name: A continuing family of nine at the eight-or-more top of 8,427 dollars stays eligible in January 2024. + period: 2024-01 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 15 + is_tax_unit_dependent: true + person4: + age: 13 + is_tax_unit_dependent: true + person5: + age: 11 + is_tax_unit_dependent: true + person6: + age: 9 + is_tax_unit_dependent: true + person7: + age: 7 + is_tax_unit_dependent: true + person8: + age: 5 + is_tax_unit_dependent: true + person9: + age: 3 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + # The January 2024 fact sheet's >=8 row tops out at 8,427 dollars (191-200% FPL). + al_ccsp_countable_income: 8_427 + al_ccsp_enrolled: true + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + state_code: + 2024: AL + output: + al_ccsp_income_eligible: true + +- name: A continuing family of nine at 8,428 dollars loses eligibility in January 2024. + period: 2024-01 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 15 + is_tax_unit_dependent: true + person4: + age: 13 + is_tax_unit_dependent: true + person5: + age: 11 + is_tax_unit_dependent: true + person6: + age: 9 + is_tax_unit_dependent: true + person7: + age: 7 + is_tax_unit_dependent: true + person8: + age: 5 + is_tax_unit_dependent: true + person9: + age: 3 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + al_ccsp_countable_income: 8_428 + al_ccsp_enrolled: true + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + state_code: + 2024: AL + output: + al_ccsp_income_eligible: false + +# Posted charts: each printed family size at its top passes and a dollar more +# fails. Each case sets the unit's size directly and lists the outcomes in size +# order, the top first. + +- name: The June 1, 2026 fact sheet's initial scale holds at every family size. + period: 2026-06 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 2 + al_ccsp_countable_income: 2_644 + al_ccsp_enrolled: false + u2: + members: [p2] + spm_unit_size: + 2026: 2 + al_ccsp_countable_income: 2_645 + al_ccsp_enrolled: false + u3: + members: [p3] + spm_unit_size: + 2026: 3 + al_ccsp_countable_income: 3_331 + al_ccsp_enrolled: false + u4: + members: [p4] + spm_unit_size: + 2026: 3 + al_ccsp_countable_income: 3_332 + al_ccsp_enrolled: false + u5: + members: [p5] + spm_unit_size: + 2026: 4 + al_ccsp_countable_income: 4_019 + al_ccsp_enrolled: false + u6: + members: [p6] + spm_unit_size: + 2026: 4 + al_ccsp_countable_income: 4_020 + al_ccsp_enrolled: false + u7: + members: [p7] + spm_unit_size: + 2026: 5 + al_ccsp_countable_income: 4_706 + al_ccsp_enrolled: false + u8: + members: [p8] + spm_unit_size: + 2026: 5 + al_ccsp_countable_income: 4_707 + al_ccsp_enrolled: false + u9: + members: [p9] + spm_unit_size: + 2026: 6 + al_ccsp_countable_income: 5_394 + al_ccsp_enrolled: false + u10: + members: [p10] + spm_unit_size: + 2026: 6 + al_ccsp_countable_income: 5_395 + al_ccsp_enrolled: false + u11: + members: [p11] + spm_unit_size: + 2026: 7 + al_ccsp_countable_income: 6_081 + al_ccsp_enrolled: false + u12: + members: [p12] + spm_unit_size: + 2026: 7 + al_ccsp_countable_income: 6_082 + al_ccsp_enrolled: false + u13: + members: [p13] + spm_unit_size: + 2026: 8 + al_ccsp_countable_income: 6_769 + al_ccsp_enrolled: false + u14: + members: [p14] + spm_unit_size: + 2026: 8 + al_ccsp_countable_income: 6_770 + al_ccsp_enrolled: false + households: + h1: + members: [p1] + state_code: + 2026: AL + h2: + members: [p2] + state_code: + 2026: AL + h3: + members: [p3] + state_code: + 2026: AL + h4: + members: [p4] + state_code: + 2026: AL + h5: + members: [p5] + state_code: + 2026: AL + h6: + members: [p6] + state_code: + 2026: AL + h7: + members: [p7] + state_code: + 2026: AL + h8: + members: [p8] + state_code: + 2026: AL + h9: + members: [p9] + state_code: + 2026: AL + h10: + members: [p10] + state_code: + 2026: AL + h11: + members: [p11] + state_code: + 2026: AL + h12: + members: [p12] + state_code: + 2026: AL + h13: + members: [p13] + state_code: + 2026: AL + h14: + members: [p14] + state_code: + 2026: AL + output: + # Initial Eligibility Monthly Income Scale, 141-150% FPL column, sizes 2 to 8. + al_ccsp_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: The June 1, 2026 fact sheet's continuing scale holds at every family size. + period: 2026-06 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 2 + al_ccsp_countable_income: 2_996 + al_ccsp_enrolled: true + u2: + members: [p2] + spm_unit_size: + 2026: 2 + al_ccsp_countable_income: 2_997 + al_ccsp_enrolled: true + u3: + members: [p3] + spm_unit_size: + 2026: 3 + al_ccsp_countable_income: 3_775 + al_ccsp_enrolled: true + u4: + members: [p4] + spm_unit_size: + 2026: 3 + al_ccsp_countable_income: 3_776 + al_ccsp_enrolled: true + u5: + members: [p5] + spm_unit_size: + 2026: 4 + al_ccsp_countable_income: 4_555 + al_ccsp_enrolled: true + u6: + members: [p6] + spm_unit_size: + 2026: 4 + al_ccsp_countable_income: 4_556 + al_ccsp_enrolled: true + u7: + members: [p7] + spm_unit_size: + 2026: 5 + al_ccsp_countable_income: 5_334 + al_ccsp_enrolled: true + u8: + members: [p8] + spm_unit_size: + 2026: 5 + al_ccsp_countable_income: 5_335 + al_ccsp_enrolled: true + u9: + members: [p9] + spm_unit_size: + 2026: 6 + al_ccsp_countable_income: 6_113 + al_ccsp_enrolled: true + u10: + members: [p10] + spm_unit_size: + 2026: 6 + al_ccsp_countable_income: 6_114 + al_ccsp_enrolled: true + u11: + members: [p11] + spm_unit_size: + 2026: 7 + al_ccsp_countable_income: 6_892 + al_ccsp_enrolled: true + u12: + members: [p12] + spm_unit_size: + 2026: 7 + al_ccsp_countable_income: 6_893 + al_ccsp_enrolled: true + u13: + members: [p13] + spm_unit_size: + 2026: 8 + al_ccsp_countable_income: 7_671 + al_ccsp_enrolled: true + u14: + members: [p14] + spm_unit_size: + 2026: 8 + al_ccsp_countable_income: 7_672 + al_ccsp_enrolled: true + households: + h1: + members: [p1] + state_code: + 2026: AL + h2: + members: [p2] + state_code: + 2026: AL + h3: + members: [p3] + state_code: + 2026: AL + h4: + members: [p4] + state_code: + 2026: AL + h5: + members: [p5] + state_code: + 2026: AL + h6: + members: [p6] + state_code: + 2026: AL + h7: + members: [p7] + state_code: + 2026: AL + h8: + members: [p8] + state_code: + 2026: AL + h9: + members: [p9] + state_code: + 2026: AL + h10: + members: [p10] + state_code: + 2026: AL + h11: + members: [p11] + state_code: + 2026: AL + h12: + members: [p12] + state_code: + 2026: AL + h13: + members: [p13] + state_code: + 2026: AL + h14: + members: [p14] + state_code: + 2026: AL + output: + # Continuing Eligibility Monthly Income Scale, 161-170% FPL column, sizes 2 to 8. + al_ccsp_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_weekly_copay_per_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_weekly_copay_per_child.yaml index 665a5ed724b..1631f695217 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_weekly_copay_per_child.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ccsp/al_ccsp_weekly_copay_per_child.yaml @@ -414,3 +414,46 @@ # Homeless is NOT a §3.3.1 copay-waiver category (§3.3.1(iii) # unchecked); 105% FPL -> band [1.0001, 1.1001) -> $18/wk, not $0. al_ccsp_weekly_copay_per_child: 18 + +- name: A family of nine at 6,500 dollars pays the eight-or-more row's 30 dollars a week in June 2026. + period: 2026-06 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 15 + is_tax_unit_dependent: true + person4: + age: 13 + is_tax_unit_dependent: true + person5: + age: 11 + is_tax_unit_dependent: true + person6: + age: 9 + is_tax_unit_dependent: true + person7: + age: 7 + is_tax_unit_dependent: true + person8: + age: 5 + is_tax_unit_dependent: true + person9: + age: 3 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + # The June 2026 fact sheet's >=8 row charges 30 dollars from 6,319 to 6,769 dollars (141-150% FPL). + al_ccsp_countable_income: 6_500 + al_ccsp_enrolled: false + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9] + state_code: + 2026: AL + output: + al_ccsp_weekly_copay_per_child: 30 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/copay/ga_caps_family_fee.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/copay/ga_caps_family_fee.yaml index ba693f91c25..03a595a003f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/copay/ga_caps_family_fee.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/copay/ga_caps_family_fee.yaml @@ -8,8 +8,8 @@ # strict "above X%" semantics while single_amount brackets use "at or above". # Weekly fee = floor(annual_income * rate / 52) # Monthly fee = weekly_fee * 52 / 12 -# Fee waived (§ 9.5.1) for: minor parents (age <= 17), -# children in DFCS custody, and income <= 10% FPL. +# Fee waived (§ 9.5.1) for minor parents (age <= 17) and income <= 10% FPL. A child in +# DFCS custody forms a family unit of one that owes no fee, which ga_caps pays apart. # # 2026 FPG family of 3: 15,960 + 5,680 * 2 = $27,320 # 2026 FPG family of 2: 15,960 + 5,680 = $21,640 @@ -454,7 +454,7 @@ # monthly fee = 20 * 52 / 12 = $86.67 ga_caps_family_fee: 86.67 -- name: Case 19, child in DFCS custody waives the family fee. +- name: Case 19, a child in DFCS custody leaves the family's unit, which still owes its fee. period: 2026-01 absolute_error_margin: 0.01 input: @@ -475,6 +475,9 @@ members: [person1, person2, person3] state_code: GA output: - # Same income/family as Case 1 (fee would be $173.33), - # but child in DFCS custody triggers the § 9.5.1 waiver -> $0. - ga_caps_family_fee: 0 + # The child in DFCS custody forms a family unit of one that owes no fee (CAPS/00-5, + # 5.4.1; Manual 9.5.1), so the family's own unit has two members. + # FPL ratio = 30,000 / 21,640 = 1.386 -> 7% rate + # weekly fee = floor(30,000 * 0.07 / 52) = floor(40.38) = $40 + # monthly fee = 40 * 52 / 12 = $173.33 + ga_caps_family_fee: 173.33 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/dfcs_custody.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/dfcs_custody.yaml new file mode 100644 index 00000000000..363025d8785 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/dfcs_custody.yaml @@ -0,0 +1,202 @@ +# GA CAPS children in DFCS custody. +# CAPS/00-5, 5.4.1: the State stands as the parent of each child in DFCS custody, and the +# child forms a family unit of one. CAPS/00-7, 7.5: foster parents need not meet the income +# or activity requirements, and Manual 9.5.1 assesses no family fee for these children. The +# family's own case covers its other children on its own tests. +# +# GA SMI 4-person at 2026-01 (October 2025 table): $110,736. New applicants in January 2026 +# face 40% of it: $30,121 for two, $37,208 for three. +# Center, full time, preschool, Zone 1: $221 a week, or 221 * 52 / 12 = $957.67 a month. + +- name: Each child in DFCS custody leaves the family's own unit. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 2 + is_in_foster_care: true + person4: + age: 6 + is_in_foster_care: true + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: GA + output: + ga_caps_family_size: 2 + ga_caps_dfcs_custody_child: [false, false, true, true] + +- name: The family's income test counts a family of two beside a child in DFCS custody, at the limit. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 2 + is_in_foster_care: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_510.08 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # 2,510.08 * 12 = 30,120.96, within $30,121 for two. + ga_caps_income_eligible: true + +- name: The family's income test counts a family of two beside a child in DFCS custody, over the limit. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 2 + is_in_foster_care: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_510.09 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # 2,510.09 * 12 = 30,121.08 exceeds $30,121 for two, though it falls within $37,208 + # for three. + ga_caps_income_eligible: false + +- name: A child in DFCS custody qualifies when the family's own case does not. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 0 + immigration_status: CITIZEN + person2: + age: 2 + immigration_status: CITIZEN + is_in_foster_care: true + person3: + age: 4 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 9_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # The family of two fails its own income, activity and priority group tests. + ga_caps_income_eligible: false + ga_caps_activity_eligible: false + ga_caps_priority_group_eligible: false + ga_caps_family_eligible: false + ga_caps_dfcs_custody_child: [false, true, false] + ga_caps_eligible: true + +- name: CAPS pays only the DFCS child's care when the family's own case fails. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 0 + employment_income: 108_000 + immigration_status: CITIZEN + person2: + age: 4 + immigration_status: CITIZEN + is_in_foster_care: true + ga_caps_provider_type: CENTER + ga_caps_care_type: FULL_TIME + ga_caps_quality_rating: NONE + person3: + age: 4 + immigration_status: CITIZEN + ga_caps_provider_type: CENTER + ga_caps_care_type: FULL_TIME + ga_caps_quality_rating: NONE + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + spm_unit_pre_subsidy_childcare_expenses: 24_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + county_str: FULTON_COUNTY_GA + output: + ga_caps_family_eligible: false + ga_caps_eligible: true + # Expenses of $2,000 a month split evenly: $1,000 for each child. + # DFCS child: min(1,000, 957.67) = $957.67, with no fee. The sibling gets nothing. + ga_caps: 957.67 + +- name: The family's own case pays its fee while the DFCS child's care owes none. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + employment_income: 24_000 + immigration_status: CITIZEN + person2: + age: 4 + immigration_status: CITIZEN + is_in_foster_care: true + ga_caps_provider_type: CENTER + ga_caps_care_type: FULL_TIME + ga_caps_quality_rating: NONE + person3: + age: 4 + immigration_status: CITIZEN + ga_caps_provider_type: CENTER + ga_caps_care_type: FULL_TIME + ga_caps_quality_rating: NONE + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_enrolled: true + spm_unit_pre_subsidy_childcare_expenses: 24_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + county_str: FULTON_COUNTY_GA + output: + ga_caps_family_size: 2 + ga_caps_family_eligible: true + # FPL ratio for two = 24,000 / 21,640 = 1.109 -> 7% + # weekly fee = floor(24,000 * 0.07 / 52) = floor(32.31) = $32 + # monthly fee = 32 * 52 / 12 = $138.67 + ga_caps_family_fee: 138.67 + # Family's case: min(2,000 - 1,000, 957.67) - 138.67 = $819.00 + # DFCS child: min(1,000, 957.67) = $957.67 + ga_caps: 1_776.67 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_eligible_priority_groups.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_eligible_priority_groups.yaml index 51b4d370f2f..e3f3475d8d7 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_eligible_priority_groups.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_eligible_priority_groups.yaml @@ -201,7 +201,7 @@ output: ga_caps_eligible: false -- name: DFCS custody waives the income and activity requirements. +- name: Grandparents raising grandchildren need no qualifying activity. period: 2026-01 input: people: @@ -212,26 +212,24 @@ person2: age: 2 immigration_status: CITIZEN - is_in_foster_care: true person3: age: 4 immigration_status: CITIZEN spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 9_000 + ga_caps_countable_income: 2_000 + ga_caps_grandparents_raising_grandchildren: true households: household: members: [person1, person2, person3] state_code: GA output: - # CAPS/00-7, 7.5: foster parents need not meet income or activity requirements. - ga_caps_income_eligible: true + # CAPS/00-7, 7.13. ga_caps_activity_eligible: true - ga_caps_priority_group_eligible: true ga_caps_eligible: true -- name: Grandparents raising grandchildren need no qualifying activity. +- name: Grandparents raising grandchildren still meet the income limit. period: 2026-01 input: people: @@ -248,18 +246,18 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 2_000 + ga_caps_countable_income: 5_000 ga_caps_grandparents_raising_grandchildren: true households: household: members: [person1, person2, person3] state_code: GA output: - # CAPS/00-7, 7.13. ga_caps_activity_eligible: true - ga_caps_eligible: true + ga_caps_income_eligible: false + ga_caps_eligible: false -- name: Grandparents raising grandchildren still meet the income limit. +- name: Without the group the same family needs a qualifying activity. period: 2026-01 input: people: @@ -273,43 +271,230 @@ person3: age: 4 immigration_status: CITIZEN + ga_caps_pre_k_enrolled: true spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 5_000 - ga_caps_grandparents_raising_grandchildren: true + ga_caps_countable_income: 2_000 households: household: members: [person1, person2, person3] state_code: GA output: - ga_caps_activity_eligible: true - ga_caps_income_eligible: false + ga_caps_activity_eligible: false ga_caps_eligible: false -- name: Without the group the same family needs a qualifying activity. - period: 2026-01 +- name: June 2024, an enrolled family first admitted through Pre-K needs no priority group. + period: 2024-06 input: people: person1: - age: 30 - weekly_hours_worked_before_lsr: 0 - immigration_status: CITIZEN + age: + 2024: 30 + weekly_hours_worked_before_lsr: + 2024: 40 + immigration_status: + 2024: CITIZEN person2: - age: 2 - immigration_status: CITIZEN + age: + 2024: 2 + immigration_status: + 2024: CITIZEN person3: - age: 4 - immigration_status: CITIZEN - ga_caps_pre_k_enrolled: true + age: + 2024: 6 + immigration_status: + 2024: CITIZEN + ga_caps_pre_k_at_previous_determination: true spm_units: spm_unit: members: [person1, person2, person3] ga_caps_countable_income: 2_000 + ga_caps_enrolled: true households: household: members: [person1, person2, person3] - state_code: GA + state_code: + 2024: GA output: - ga_caps_activity_eligible: false + # CAPS/00-7, 7.3.1.3 exempts enrolled families at redetermination. + ga_caps_eligible: true + +- name: July 2024, an enrolled family first admitted through Pre-K needs a priority group. + period: 2024-07 + input: + people: + person1: + age: + 2024: 30 + weekly_hours_worked_before_lsr: + 2024: 40 + immigration_status: + 2024: CITIZEN + person2: + age: + 2024: 2 + immigration_status: + 2024: CITIZEN + person3: + age: + 2024: 6 + immigration_status: + 2024: CITIZEN + ga_caps_pre_k_at_previous_determination: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + ga_caps_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + # DECAL letter, July 1, 2024: families whose child attended Georgia's Pre-K at the + # initial application or previous determination must belong to a group at redetermination. + ga_caps_priority_group_eligible: false ga_caps_eligible: false + +- name: July 2024, an enrolled family first admitted through Pre-K keeps CAPS through another group. + period: 2024-07 + input: + people: + person1: + age: + 2024: 30 + weekly_hours_worked_before_lsr: + 2024: 40 + immigration_status: + 2024: CITIZEN + person2: + age: + 2024: 2 + immigration_status: + 2024: CITIZEN + person3: + age: + 2024: 6 + immigration_status: + 2024: CITIZEN + ga_caps_pre_k_at_previous_determination: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + ga_caps_enrolled: true + is_tanf_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + ga_caps_eligible: true + +- name: July 2024, an enrolled family with no Pre-K child needs no priority group. + period: 2024-07 + input: + people: + person1: + age: + 2024: 30 + weekly_hours_worked_before_lsr: + 2024: 40 + immigration_status: + 2024: CITIZEN + person2: + age: + 2024: 2 + immigration_status: + 2024: CITIZEN + person3: + age: + 2024: 6 + immigration_status: + 2024: CITIZEN + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + ga_caps_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2024: GA + output: + ga_caps_eligible: true + +- name: October 2025 reads October 1, so an enrolled family first admitted through Pre-K still needs a group. + period: 2025-10 + input: + people: + person1: + age: + 2025: 30 + weekly_hours_worked_before_lsr: + 2025: 40 + immigration_status: + 2025: CITIZEN + person2: + age: + 2025: 2 + immigration_status: + 2025: CITIZEN + person3: + age: + 2025: 6 + immigration_status: + 2025: CITIZEN + ga_caps_pre_k_at_previous_determination: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + ga_caps_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2025: GA + output: + # DECAL letter, October 6, 2025 removes the requirement; the model applies it from November. + ga_caps_eligible: false + +- name: November 2025, an enrolled family first admitted through Pre-K needs no priority group again. + period: 2025-11 + input: + people: + person1: + age: + 2025: 30 + weekly_hours_worked_before_lsr: + 2025: 40 + immigration_status: + 2025: CITIZEN + person2: + age: + 2025: 2 + immigration_status: + 2025: CITIZEN + person3: + age: + 2025: 6 + immigration_status: + 2025: CITIZEN + ga_caps_pre_k_at_previous_determination: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + ga_caps_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2025: GA + output: + ga_caps_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.yaml index 81ded6be77f..1a96a4a5673 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.yaml @@ -334,3 +334,759 @@ output: # total income = 20,000 + 10,000 = 30,000 <= 30,121 -> eligible ga_caps_income_eligible: true + +# Posted charts: each printed family size at its top passes and a dollar more +# fails. Each case sets the unit's size directly and lists the outcomes in size +# order, the top first. + +- name: Appendix A's initial limits effective October 5, 2026 hold at sizes 1 to 14 in November 2026. + period: 2026-11 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + p23: + age: + 2026: 30 + p24: + age: + 2026: 30 + p25: + age: + 2026: 30 + p26: + age: + 2026: 30 + p27: + age: + 2026: 30 + p28: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 1 + ga_caps_countable_income: 2_494.25 + ga_caps_enrolled: false + u2: + members: [p2] + spm_unit_size: + 2026: 1 + ga_caps_countable_income: 2_494.34 + ga_caps_enrolled: false + u3: + members: [p3] + spm_unit_size: + 2026: 2 + ga_caps_countable_income: 3_261.75 + ga_caps_enrolled: false + u4: + members: [p4] + spm_unit_size: + 2026: 2 + ga_caps_countable_income: 3_261.84 + ga_caps_enrolled: false + u5: + members: [p5] + spm_unit_size: + 2026: 3 + ga_caps_countable_income: 4_029.16 + ga_caps_enrolled: false + u6: + members: [p6] + spm_unit_size: + 2026: 3 + ga_caps_countable_income: 4_029.25 + ga_caps_enrolled: false + u7: + members: [p7] + spm_unit_size: + 2026: 4 + ga_caps_countable_income: 4_796.58 + ga_caps_enrolled: false + u8: + members: [p8] + spm_unit_size: + 2026: 4 + ga_caps_countable_income: 4_796.67 + ga_caps_enrolled: false + u9: + members: [p9] + spm_unit_size: + 2026: 5 + ga_caps_countable_income: 5_564.08 + ga_caps_enrolled: false + u10: + members: [p10] + spm_unit_size: + 2026: 5 + ga_caps_countable_income: 5_564.17 + ga_caps_enrolled: false + u11: + members: [p11] + spm_unit_size: + 2026: 6 + ga_caps_countable_income: 6_331.50 + ga_caps_enrolled: false + u12: + members: [p12] + spm_unit_size: + 2026: 6 + ga_caps_countable_income: 6_331.59 + ga_caps_enrolled: false + u13: + members: [p13] + spm_unit_size: + 2026: 7 + ga_caps_countable_income: 6_475.41 + ga_caps_enrolled: false + u14: + members: [p14] + spm_unit_size: + 2026: 7 + ga_caps_countable_income: 6_475.50 + ga_caps_enrolled: false + u15: + members: [p15] + spm_unit_size: + 2026: 8 + ga_caps_countable_income: 6_619.33 + ga_caps_enrolled: false + u16: + members: [p16] + spm_unit_size: + 2026: 8 + ga_caps_countable_income: 6_619.42 + ga_caps_enrolled: false + u17: + members: [p17] + spm_unit_size: + 2026: 9 + ga_caps_countable_income: 6_763.25 + ga_caps_enrolled: false + u18: + members: [p18] + spm_unit_size: + 2026: 9 + ga_caps_countable_income: 6_763.34 + ga_caps_enrolled: false + u19: + members: [p19] + spm_unit_size: + 2026: 10 + ga_caps_countable_income: 6_907.08 + ga_caps_enrolled: false + u20: + members: [p20] + spm_unit_size: + 2026: 10 + ga_caps_countable_income: 6_907.17 + ga_caps_enrolled: false + u21: + members: [p21] + spm_unit_size: + 2026: 11 + ga_caps_countable_income: 7_051 + ga_caps_enrolled: false + u22: + members: [p22] + spm_unit_size: + 2026: 11 + ga_caps_countable_income: 7_051.09 + ga_caps_enrolled: false + u23: + members: [p23] + spm_unit_size: + 2026: 12 + ga_caps_countable_income: 7_194.91 + ga_caps_enrolled: false + u24: + members: [p24] + spm_unit_size: + 2026: 12 + ga_caps_countable_income: 7_195 + ga_caps_enrolled: false + u25: + members: [p25] + spm_unit_size: + 2026: 13 + ga_caps_countable_income: 7_338.83 + ga_caps_enrolled: false + u26: + members: [p26] + spm_unit_size: + 2026: 13 + ga_caps_countable_income: 7_338.92 + ga_caps_enrolled: false + u27: + members: [p27] + spm_unit_size: + 2026: 14 + ga_caps_countable_income: 7_482.75 + ga_caps_enrolled: false + u28: + members: [p28] + spm_unit_size: + 2026: 14 + ga_caps_countable_income: 7_482.84 + ga_caps_enrolled: false + households: + h1: + members: [p1] + state_code: + 2026: GA + h2: + members: [p2] + state_code: + 2026: GA + h3: + members: [p3] + state_code: + 2026: GA + h4: + members: [p4] + state_code: + 2026: GA + h5: + members: [p5] + state_code: + 2026: GA + h6: + members: [p6] + state_code: + 2026: GA + h7: + members: [p7] + state_code: + 2026: GA + h8: + members: [p8] + state_code: + 2026: GA + h9: + members: [p9] + state_code: + 2026: GA + h10: + members: [p10] + state_code: + 2026: GA + h11: + members: [p11] + state_code: + 2026: GA + h12: + members: [p12] + state_code: + 2026: GA + h13: + members: [p13] + state_code: + 2026: GA + h14: + members: [p14] + state_code: + 2026: GA + h15: + members: [p15] + state_code: + 2026: GA + h16: + members: [p16] + state_code: + 2026: GA + h17: + members: [p17] + state_code: + 2026: GA + h18: + members: [p18] + state_code: + 2026: GA + h19: + members: [p19] + state_code: + 2026: GA + h20: + members: [p20] + state_code: + 2026: GA + h21: + members: [p21] + state_code: + 2026: GA + h22: + members: [p22] + state_code: + 2026: GA + h23: + members: [p23] + state_code: + 2026: GA + h24: + members: [p24] + state_code: + 2026: GA + h25: + members: [p25] + state_code: + 2026: GA + h26: + members: [p26] + state_code: + 2026: GA + h27: + members: [p27] + state_code: + 2026: GA + h28: + members: [p28] + state_code: + 2026: GA + output: + # Annual tops as monthly income: the top rounded down to the cent, then a + # dollar more a year rounded up to the cent. The chart takes effect October 5, + # 2026, so the model applies it from November 2026. + ga_caps_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: Appendix A's ongoing limits effective October 5, 2026 hold at sizes 1 to 14 in November 2026. + period: 2026-11 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + p23: + age: + 2026: 30 + p24: + age: + 2026: 30 + p25: + age: + 2026: 30 + p26: + age: + 2026: 30 + p27: + age: + 2026: 30 + p28: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 1 + ga_caps_countable_income: 4_240.25 + ga_caps_enrolled: true + u2: + members: [p2] + spm_unit_size: + 2026: 1 + ga_caps_countable_income: 4_240.34 + ga_caps_enrolled: true + u3: + members: [p3] + spm_unit_size: + 2026: 2 + ga_caps_countable_income: 5_544.91 + ga_caps_enrolled: true + u4: + members: [p4] + spm_unit_size: + 2026: 2 + ga_caps_countable_income: 5_545 + ga_caps_enrolled: true + u5: + members: [p5] + spm_unit_size: + 2026: 3 + ga_caps_countable_income: 6_849.58 + ga_caps_enrolled: true + u6: + members: [p6] + spm_unit_size: + 2026: 3 + ga_caps_countable_income: 6_849.67 + ga_caps_enrolled: true + u7: + members: [p7] + spm_unit_size: + 2026: 4 + ga_caps_countable_income: 8_154.25 + ga_caps_enrolled: true + u8: + members: [p8] + spm_unit_size: + 2026: 4 + ga_caps_countable_income: 8_154.34 + ga_caps_enrolled: true + u9: + members: [p9] + spm_unit_size: + 2026: 5 + ga_caps_countable_income: 9_458.91 + ga_caps_enrolled: true + u10: + members: [p10] + spm_unit_size: + 2026: 5 + ga_caps_countable_income: 9_459 + ga_caps_enrolled: true + u11: + members: [p11] + spm_unit_size: + 2026: 6 + ga_caps_countable_income: 10_763.58 + ga_caps_enrolled: true + u12: + members: [p12] + spm_unit_size: + 2026: 6 + ga_caps_countable_income: 10_763.67 + ga_caps_enrolled: true + u13: + members: [p13] + spm_unit_size: + 2026: 7 + ga_caps_countable_income: 11_008.16 + ga_caps_enrolled: true + u14: + members: [p14] + spm_unit_size: + 2026: 7 + ga_caps_countable_income: 11_008.25 + ga_caps_enrolled: true + u15: + members: [p15] + spm_unit_size: + 2026: 8 + ga_caps_countable_income: 11_252.83 + ga_caps_enrolled: true + u16: + members: [p16] + spm_unit_size: + 2026: 8 + ga_caps_countable_income: 11_252.92 + ga_caps_enrolled: true + u17: + members: [p17] + spm_unit_size: + 2026: 9 + ga_caps_countable_income: 11_497.41 + ga_caps_enrolled: true + u18: + members: [p18] + spm_unit_size: + 2026: 9 + ga_caps_countable_income: 11_497.50 + ga_caps_enrolled: true + u19: + members: [p19] + spm_unit_size: + 2026: 10 + ga_caps_countable_income: 11_742.08 + ga_caps_enrolled: true + u20: + members: [p20] + spm_unit_size: + 2026: 10 + ga_caps_countable_income: 11_742.17 + ga_caps_enrolled: true + u21: + members: [p21] + spm_unit_size: + 2026: 11 + ga_caps_countable_income: 11_986.66 + ga_caps_enrolled: true + u22: + members: [p22] + spm_unit_size: + 2026: 11 + ga_caps_countable_income: 11_986.75 + ga_caps_enrolled: true + u23: + members: [p23] + spm_unit_size: + 2026: 12 + ga_caps_countable_income: 12_231.33 + ga_caps_enrolled: true + u24: + members: [p24] + spm_unit_size: + 2026: 12 + ga_caps_countable_income: 12_231.42 + ga_caps_enrolled: true + u25: + members: [p25] + spm_unit_size: + 2026: 13 + ga_caps_countable_income: 12_475.91 + ga_caps_enrolled: true + u26: + members: [p26] + spm_unit_size: + 2026: 13 + ga_caps_countable_income: 12_476 + ga_caps_enrolled: true + u27: + members: [p27] + spm_unit_size: + 2026: 14 + ga_caps_countable_income: 12_720.58 + ga_caps_enrolled: true + u28: + members: [p28] + spm_unit_size: + 2026: 14 + ga_caps_countable_income: 12_720.67 + ga_caps_enrolled: true + households: + h1: + members: [p1] + state_code: + 2026: GA + h2: + members: [p2] + state_code: + 2026: GA + h3: + members: [p3] + state_code: + 2026: GA + h4: + members: [p4] + state_code: + 2026: GA + h5: + members: [p5] + state_code: + 2026: GA + h6: + members: [p6] + state_code: + 2026: GA + h7: + members: [p7] + state_code: + 2026: GA + h8: + members: [p8] + state_code: + 2026: GA + h9: + members: [p9] + state_code: + 2026: GA + h10: + members: [p10] + state_code: + 2026: GA + h11: + members: [p11] + state_code: + 2026: GA + h12: + members: [p12] + state_code: + 2026: GA + h13: + members: [p13] + state_code: + 2026: GA + h14: + members: [p14] + state_code: + 2026: GA + h15: + members: [p15] + state_code: + 2026: GA + h16: + members: [p16] + state_code: + 2026: GA + h17: + members: [p17] + state_code: + 2026: GA + h18: + members: [p18] + state_code: + 2026: GA + h19: + members: [p19] + state_code: + 2026: GA + h20: + members: [p20] + state_code: + 2026: GA + h21: + members: [p21] + state_code: + 2026: GA + h22: + members: [p22] + state_code: + 2026: GA + h23: + members: [p23] + state_code: + 2026: GA + h24: + members: [p24] + state_code: + 2026: GA + h25: + members: [p25] + state_code: + 2026: GA + h26: + members: [p26] + state_code: + 2026: GA + h27: + members: [p27] + state_code: + 2026: GA + h28: + members: [p28] + state_code: + 2026: GA + output: + # Annual tops as monthly income: the top rounded down to the cent, then a + # dollar more a year rounded up to the cent. The chart takes effect October 5, + # 2026, so the model applies it from November 2026. + ga_caps_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible_by_date.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible_by_date.yaml index a8779737927..b932fb94a6c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible_by_date.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible_by_date.yaml @@ -1,6 +1,7 @@ # GA CAPS income limits by date. # DECAL's letters date each change. A monthly variable reads the parameter at the first day of -# the month, so a change after the first applies from the next month. +# the month, so a change after the first applies from the next month. Each chart also dates +# the median income table it takes up, which smi_year_lag carries. - name: September 2019, 50 percent for four, at the limit. period: 2019-09 @@ -30,7 +31,6 @@ output: # DECAL webinar, September 24, 2019: $36,601 for four before October 2019. ga_caps_income_eligible: true - - name: September 2019, 50 percent for four, over the limit. period: 2019-09 input: @@ -58,7 +58,6 @@ 2019: GA output: ga_caps_income_eligible: false - - name: October 2019, 50 percent for four on the new median income table, at the limit. period: 2019-10 input: @@ -87,7 +86,6 @@ output: # DECAL webinar, September 24, 2019: $38,103 for four in October 2019. ga_caps_income_eligible: true - - name: October 2019, 50 percent for four on the new median income table, over the limit. period: 2019-10 input: @@ -115,7 +113,6 @@ 2019: GA output: ga_caps_income_eligible: false - - name: October 2021, 50 percent for four, at the limit. period: 2021-10 input: @@ -144,7 +141,6 @@ output: # DECAL letter, October 21, 2021: $42,426 for four before the waiver. ga_caps_income_eligible: true - - name: October 2021, 50 percent for four, over the limit. period: 2021-10 input: @@ -172,7 +168,6 @@ 2021: GA output: ga_caps_income_eligible: false - - name: November 2021, 85 percent for four, at the limit. period: 2021-11 input: @@ -201,7 +196,6 @@ output: # DECAL letter, October 21, 2021: $72,124 for four from November 1, 2021. ga_caps_income_eligible: true - - name: November 2021, 85 percent for four, over the limit. period: 2021-11 input: @@ -229,7 +223,6 @@ 2021: GA output: ga_caps_income_eligible: false - - name: October 2021, 50 percent for three, at the limit. period: 2021-10 input: @@ -255,7 +248,6 @@ output: # Urban Institute CCDF tables print $2,969 for three in October 2021. ga_caps_income_eligible: true - - name: October 2021, 50 percent for three, over the limit. period: 2021-10 input: @@ -280,7 +272,6 @@ 2021: GA output: ga_caps_income_eligible: false - - name: November 2021, 85 percent for three, at the limit. period: 2021-11 input: @@ -305,7 +296,6 @@ 2021: GA output: ga_caps_income_eligible: true - - name: November 2021, 85 percent for three, over the limit. period: 2021-11 input: @@ -330,7 +320,6 @@ 2021: GA output: ga_caps_income_eligible: false - - name: October 2022, 85 percent for three, at the limit. period: 2022-10 input: @@ -356,7 +345,6 @@ output: # Urban Institute CCDF tables print $5,351 for three in October 2022. ga_caps_income_eligible: true - - name: October 2022, 85 percent for three, over the limit. period: 2022-10 input: @@ -381,7 +369,6 @@ 2022: GA output: ga_caps_income_eligible: false - - name: December 2022 reads December 1, so 85 percent still applies. period: 2022-12 input: @@ -407,7 +394,6 @@ output: # DECAL letter, December 19, 2022: the waiver ended December 15, 2022. ga_caps_income_eligible: true - - name: January 2023, back to 50 percent for three, at the limit. period: 2023-01 input: @@ -428,7 +414,6 @@ state_code: GA output: ga_caps_income_eligible: true - - name: January 2023, back to 50 percent for three, over the limit. period: 2023-01 input: @@ -449,7 +434,6 @@ state_code: GA output: ga_caps_income_eligible: false - - name: August 2024, 50 percent for three, at the limit. period: 2024-08 input: @@ -474,7 +458,6 @@ 2024: GA output: ga_caps_income_eligible: true - - name: August 2024, 50 percent for three, over the limit. period: 2024-08 input: @@ -499,8 +482,7 @@ 2024: GA output: ga_caps_income_eligible: false - -- name: September 2024, 30 percent for three, at the limit. +- name: September 2024, 30 percent for three on the fiscal year 2025 median income table, at the limit. period: 2024-09 input: people: @@ -516,17 +498,18 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 2_000 + ga_caps_countable_income: 2_223.83 households: household: members: [person1, person2, person3] state_code: 2024: GA output: - # DECAL letter, September 3, 2024: 50% to 30% from September 1, 2024. + # DECAL letter, September 3, 2024: 50% to 30% from September 1, 2024. Appendix A, + # effective September 1, 2024, prints $26,686 for three on the fiscal year 2025 + # median income table. ga_caps_income_eligible: true - -- name: September 2024, 30 percent for three, over the limit. +- name: September 2024, 30 percent for three on the fiscal year 2025 median income table, over the limit. period: 2024-09 input: people: @@ -542,7 +525,7 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 2_000.5 + ga_caps_countable_income: 2_223.84 households: household: members: [person1, person2, person3] @@ -550,7 +533,6 @@ 2024: GA output: ga_caps_income_eligible: false - - name: October 2024, 30 percent for three on the new median income table, at the limit. period: 2024-10 input: @@ -575,7 +557,6 @@ 2024: GA output: ga_caps_income_eligible: true - - name: October 2024, 30 percent for three on the new median income table, over the limit. period: 2024-10 input: @@ -600,8 +581,7 @@ 2024: GA output: ga_caps_income_eligible: false - -- name: October 2025 reads October 1, so 30 percent still applies, at the limit. +- name: October 2025 reads October 1, so the September 2024 chart still applies, at the limit. period: 2025-10 input: people: @@ -617,16 +597,16 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 2_325 + ga_caps_countable_income: 2_223.83 households: household: members: [person1, person2, person3] state_code: 2025: GA output: + # The chart effective March 1, 2025 still prints $26,686 for three until October 6. ga_caps_income_eligible: true - -- name: October 2025 reads October 1, so 30 percent still applies, over the limit. +- name: October 2025 reads October 1, so the September 2024 chart still applies, over the limit. period: 2025-10 input: people: @@ -642,7 +622,7 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 2_326 + ga_caps_countable_income: 2_223.84 households: household: members: [person1, person2, person3] @@ -650,7 +630,6 @@ 2025: GA output: ga_caps_income_eligible: false - - name: November 2025, 40 percent for three, at the limit. period: 2025-11 input: @@ -678,7 +657,6 @@ # which rounds $37,208 a year divided by 12. Manual 8.8.4 compares income times 12 with the # annual chart, so $3,101 a month fails. ga_caps_income_eligible: true - - name: November 2025, 40 percent for three, over the limit. period: 2025-11 input: @@ -703,7 +681,6 @@ 2025: GA output: ga_caps_income_eligible: false - - name: A family of three earning $40,000 fails in January 2026. period: 2026-01 input: @@ -724,7 +701,6 @@ state_code: GA output: ga_caps_income_eligible: false - - name: March 2026 reads March 1, so 40 percent still applies. period: 2026-03 input: @@ -749,7 +725,6 @@ 2026: GA output: ga_caps_income_eligible: false - - name: April 2026, 50 percent for three, at the limit. period: 2026-04 input: @@ -775,7 +750,6 @@ output: # DECAL letter, March 2, 2026: 40% to 50% from March 2, 2026. ga_caps_income_eligible: true - - name: April 2026, 50 percent for three, over the limit. period: 2026-04 input: @@ -800,8 +774,7 @@ 2026: GA output: ga_caps_income_eligible: false - -- name: October 2026, 50 percent for three, at the limit. +- name: October 2026 reads October 1, so the March 2026 chart still applies, at the limit. period: 2026-10 input: people: @@ -817,17 +790,18 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 4_029.16 + ga_caps_countable_income: 3_875 households: household: members: [person1, person2, person3] state_code: 2026: GA output: - # Appendix A, effective October 5, 2026, prints $48,350 for three. + # The chart effective March 2, 2026 prints $46,510 for three on the fiscal year 2026 + # median income table until October 5. ga_caps_income_eligible: true -- name: October 2026, 50 percent for three, over the limit. +- name: October 2026 reads October 1, so the March 2026 chart still applies, over the limit. period: 2026-10 input: people: @@ -843,7 +817,7 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 4_029.25 + ga_caps_countable_income: 3_876 households: household: members: [person1, person2, person3] @@ -852,8 +826,111 @@ output: ga_caps_income_eligible: false -- name: October 2026, 50 percent for two, at the limit. +- name: October 2026, 85 percent for an enrolled family of three on the March 2026 chart, at the limit. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 6_588.83 + ga_caps_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + # The chart effective March 2, 2026 prints $79,066 for three. + ga_caps_income_eligible: true + +- name: October 2026, 85 percent for an enrolled family of three on the March 2026 chart, over the limit. period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 6_588.84 + ga_caps_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + ga_caps_income_eligible: false + +- name: November 2026, 50 percent for three, at the limit. + period: 2026-11 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 4_029.16 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + # Appendix A, effective October 5, 2026, prints $48,350 for three. The model + # applies it at the first month that starts after October 5. + ga_caps_income_eligible: true +- name: November 2026, 50 percent for three, over the limit. + period: 2026-11 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 4_029.25 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: GA + output: + ga_caps_income_eligible: false +- name: November 2026, 50 percent for two, at the limit. + period: 2026-11 input: people: person1: @@ -874,9 +951,8 @@ output: # Appendix A prints $39,141 for two. ga_caps_income_eligible: true - -- name: October 2026, 50 percent for two, over the limit. - period: 2026-10 +- name: November 2026, 50 percent for two, over the limit. + period: 2026-11 input: people: person1: @@ -896,9 +972,8 @@ 2026: GA output: ga_caps_income_eligible: false - -- name: October 2026, 50 percent for six, at the limit. - period: 2026-10 +- name: November 2026, 50 percent for six, at the limit. + period: 2026-11 input: people: person1: @@ -931,9 +1006,8 @@ output: # Appendix A prints $75,978 for six. ga_caps_income_eligible: true - -- name: October 2026, 50 percent for six, over the limit. - period: 2026-10 +- name: November 2026, 50 percent for six, over the limit. + period: 2026-11 input: people: person1: @@ -965,9 +1039,8 @@ 2026: GA output: ga_caps_income_eligible: false - -- name: October 2026, 85 percent for an enrolled family of three, at the limit. - period: 2026-10 +- name: November 2026, 85 percent for an enrolled family of three, at the limit. + period: 2026-11 input: people: person1: @@ -992,9 +1065,8 @@ output: # Appendix A prints $82,195 for three. ga_caps_income_eligible: true - -- name: October 2026, 85 percent for an enrolled family of three, over the limit. - period: 2026-10 +- name: November 2026, 85 percent for an enrolled family of three, over the limit. + period: 2026-11 input: people: person1: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.yaml index d7575c14715..7fc11f279a1 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.yaml @@ -69,7 +69,7 @@ # CAPS/00-7, 7.4 and 7.15. ga_caps_priority_group_eligible: true -- name: Child in DFCS custody. +- name: A child in DFCS custody doesn't place the rest of the family in a priority group. period: 2026-01 input: people: @@ -89,8 +89,10 @@ members: [person1, person2, person3] state_code: GA output: - # CAPS/00-7, 7.5. - ga_caps_priority_group_eligible: true + # CAPS/00-5, 5.4.1: the child forms a family unit of one, which + # ga_caps_dfcs_custody_child serves (CAPS/00-7, 7.5). + ga_caps_priority_group_eligible: false + ga_caps_dfcs_custody_child: [false, true, false] - name: Child with a disability. period: 2026-01 @@ -490,6 +492,193 @@ # DECAL funding Q&A: new applicants from August 1, 2016 must belong to a priority group. ga_caps_priority_group_eligible: false +- name: Family after a natural disaster, August 2016, in a group from the start. + period: 2016-08 + input: + people: + person1: + age: + 2016: 30 + person2: + age: + 2016: 5 + person3: + age: + 2016: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + ga_caps_natural_disaster: true + households: + household: + members: [person1, person2, person3] + state_code: + 2016: GA + output: + # DECAL funding Q&A: natural disaster victims form a group from August 1, 2016. + ga_caps_priority_group_eligible: true + +- name: Homeless family, September 2016, before the group began. + period: 2016-09 + input: + people: + person1: + age: + 2016: 30 + person2: + age: + 2016: 5 + person3: + age: + 2016: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2016: GA + is_homeless: + 2016: true + output: + # DECAL funding Q&A: the homeless, domestic violence and very low income groups start October 1, 2016. + ga_caps_priority_group_eligible: false + +- name: Homeless family, October 2016, from the month the group began. + period: 2016-10 + input: + people: + person1: + age: + 2016: 30 + person2: + age: + 2016: 5 + person3: + age: + 2016: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2016: GA + is_homeless: + 2016: true + output: + ga_caps_priority_group_eligible: true + +- name: Family experiencing domestic violence, September 2016, before the group began. + period: 2016-09 + input: + people: + person1: + age: + 2016: 30 + person2: + age: + 2016: 5 + person3: + age: + 2016: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + ga_caps_domestic_violence: true + households: + household: + members: [person1, person2, person3] + state_code: + 2016: GA + output: + # DECAL funding Q&A: the homeless, domestic violence and very low income groups start October 1, 2016. + ga_caps_priority_group_eligible: false + +- name: Family experiencing domestic violence, October 2016, from the month the group began. + period: 2016-10 + input: + people: + person1: + age: + 2016: 30 + person2: + age: + 2016: 5 + person3: + age: + 2016: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 2_000 + ga_caps_domestic_violence: true + households: + household: + members: [person1, person2, person3] + state_code: + 2016: GA + output: + ga_caps_priority_group_eligible: true + +- name: Very low income, September 2016, before the group began. + period: 2016-09 + input: + people: + person1: + age: + 2016: 30 + person2: + age: + 2016: 5 + person3: + age: + 2016: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 500 + households: + household: + members: [person1, person2, person3] + state_code: + 2016: GA + output: + # DECAL funding Q&A: the homeless, domestic violence and very low income groups start October 1, 2016. + # 50% of the 2016 guideline is $10,100 for three. + ga_caps_priority_group_eligible: false + +- name: Very low income, October 2016, from the month the group began. + period: 2016-10 + input: + people: + person1: + age: + 2016: 30 + person2: + age: + 2016: 5 + person3: + age: + 2016: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 500 + households: + household: + members: [person1, person2, person3] + state_code: + 2016: GA + output: + ga_caps_priority_group_eligible: true + - name: Very low income, May 2018 reads May 1, so 50 percent, at the limit. period: 2018-05 input: @@ -856,7 +1045,7 @@ output: ga_caps_priority_group_eligible: false -- name: Very low income, January 2023, 50 percent, at the limit. +- name: Very low income, January 2023, 50 percent of the 2022 guideline, at the limit. period: 2023-01 input: people: @@ -869,16 +1058,18 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 1_035 + ga_caps_countable_income: 959.58 households: household: members: [person1, person2, person3] state_code: GA output: - # DECAL letter, December 19, 2022: 50% from December 16, 2022. + # DECAL letter, December 19, 2022: 50% from December 16, 2022. The chart takes up + # the 2023 guideline on March 1, 2023, so 50% of the 2022 guideline, $11,515 for + # three, applies until then. ga_caps_priority_group_eligible: true -- name: Very low income, January 2023, 50 percent, over the limit. +- name: Very low income, January 2023, 50 percent of the 2022 guideline, over the limit. period: 2023-01 input: people: @@ -891,7 +1082,7 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 1_036 + ga_caps_countable_income: 959.59 households: household: members: [person1, person2, person3] @@ -899,6 +1090,57 @@ output: ga_caps_priority_group_eligible: false +- name: Very low income, March 2023, 50 percent of the 2023 guideline, at the limit. + period: 2023-03 + input: + people: + person1: + age: + 2023: 30 + person2: + age: + 2023: 5 + person3: + age: + 2023: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_035 + households: + household: + members: [person1, person2, person3] + state_code: + 2023: GA + output: + # Appendix A, guidelines effective for CAPS March 1, 2023: $12,430 for three. + ga_caps_priority_group_eligible: true + +- name: Very low income, March 2023, 50 percent of the 2023 guideline, over the limit. + period: 2023-03 + input: + people: + person1: + age: + 2023: 30 + person2: + age: + 2023: 5 + person3: + age: + 2023: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 1_036 + households: + household: + members: [person1, person2, person3] + state_code: + 2023: GA + output: + ga_caps_priority_group_eligible: false + - name: Very low income, June 2024, 50 percent, at the limit. period: 2024-06 input: @@ -1000,6 +1242,100 @@ output: ga_caps_priority_group_eligible: false +- name: Very low income, January 2025, 10 percent of the 2024 guideline, at the limit. + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 215.16 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + # The chart effective July 1, 2024 holds until March 1, 2025: $2,582 for three. + ga_caps_priority_group_eligible: true + +- name: Very low income, January 2025, 10 percent of the 2024 guideline, over the limit. + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 215.17 + households: + household: + members: [person1, person2, person3] + state_code: GA + output: + ga_caps_priority_group_eligible: false + +- name: Very low income, March 2025, 10 percent of the 2025 guideline, at the limit. + period: 2025-03 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + person3: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 222.08 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: GA + output: + # Appendix A, guidelines effective for CAPS March 1, 2025: $2,665 for three. + ga_caps_priority_group_eligible: true + +- name: Very low income, March 2025, 10 percent of the 2025 guideline, over the limit. + period: 2025-03 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + person3: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_countable_income: 222.09 + households: + household: + members: [person1, person2, person3] + state_code: + 2025: GA + output: + ga_caps_priority_group_eligible: false + - name: Very low income, October 2025 reads October 1, so 10 percent, at the limit. period: 2025-10 input: @@ -1101,7 +1437,7 @@ output: ga_caps_priority_group_eligible: false -- name: Very low income, January 2026, 30 percent, at the limit. +- name: Very low income, January 2026, 30 percent of the 2025 guideline, at the limit. period: 2026-01 input: people: @@ -1114,15 +1450,16 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 683 + ga_caps_countable_income: 666.25 households: household: members: [person1, person2, person3] state_code: GA output: + # The chart takes up the 2026 guideline on March 2, 2026: $7,995 for three until then. ga_caps_priority_group_eligible: true -- name: Very low income, January 2026, 30 percent, over the limit. +- name: Very low income, January 2026, 30 percent of the 2025 guideline, over the limit. period: 2026-01 input: people: @@ -1135,7 +1472,7 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 684 + ga_caps_countable_income: 666.26 households: household: members: [person1, person2, person3] @@ -1143,7 +1480,7 @@ output: ga_caps_priority_group_eligible: false -- name: Very low income, March 2026 reads March 1, so 30 percent, at the limit. +- name: Very low income, March 2026 reads March 1, so 30 percent of the 2025 guideline, at the limit. period: 2026-03 input: people: @@ -1159,7 +1496,7 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 683 + ga_caps_countable_income: 666.25 households: household: members: [person1, person2, person3] @@ -1168,7 +1505,7 @@ output: ga_caps_priority_group_eligible: true -- name: Very low income, March 2026 reads March 1, so 30 percent, over the limit. +- name: Very low income, March 2026 reads March 1, so 30 percent of the 2025 guideline, over the limit. period: 2026-03 input: people: @@ -1184,7 +1521,7 @@ spm_units: spm_unit: members: [person1, person2, person3] - ga_caps_countable_income: 684 + ga_caps_countable_income: 666.26 households: household: members: [person1, person2, person3] @@ -1294,3 +1631,355 @@ 2026: GA output: ga_caps_priority_group_eligible: false + +# Posted charts: each printed family size at its top passes and a dollar more +# fails. Each case sets the unit's size directly and lists the outcomes in size +# order, the top first. + +- name: Appendix A's very low income limits hold at sizes 1 to 14 in November 2026. + period: 2026-11 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + p23: + age: + 2026: 30 + p24: + age: + 2026: 30 + p25: + age: + 2026: 30 + p26: + age: + 2026: 30 + p27: + age: + 2026: 30 + p28: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 1 + ga_caps_countable_income: 665 + u2: + members: [p2] + spm_unit_size: + 2026: 1 + ga_caps_countable_income: 665.09 + u3: + members: [p3] + spm_unit_size: + 2026: 2 + ga_caps_countable_income: 901.66 + u4: + members: [p4] + spm_unit_size: + 2026: 2 + ga_caps_countable_income: 901.75 + u5: + members: [p5] + spm_unit_size: + 2026: 3 + ga_caps_countable_income: 1_138.33 + u6: + members: [p6] + spm_unit_size: + 2026: 3 + ga_caps_countable_income: 1_138.42 + u7: + members: [p7] + spm_unit_size: + 2026: 4 + ga_caps_countable_income: 1_375 + u8: + members: [p8] + spm_unit_size: + 2026: 4 + ga_caps_countable_income: 1_375.09 + u9: + members: [p9] + spm_unit_size: + 2026: 5 + ga_caps_countable_income: 1_611.66 + u10: + members: [p10] + spm_unit_size: + 2026: 5 + ga_caps_countable_income: 1_611.75 + u11: + members: [p11] + spm_unit_size: + 2026: 6 + ga_caps_countable_income: 1_848.33 + u12: + members: [p12] + spm_unit_size: + 2026: 6 + ga_caps_countable_income: 1_848.42 + u13: + members: [p13] + spm_unit_size: + 2026: 7 + ga_caps_countable_income: 2_085 + u14: + members: [p14] + spm_unit_size: + 2026: 7 + ga_caps_countable_income: 2_085.09 + u15: + members: [p15] + spm_unit_size: + 2026: 8 + ga_caps_countable_income: 2_321.66 + u16: + members: [p16] + spm_unit_size: + 2026: 8 + ga_caps_countable_income: 2_321.75 + u17: + members: [p17] + spm_unit_size: + 2026: 9 + ga_caps_countable_income: 2_558.33 + u18: + members: [p18] + spm_unit_size: + 2026: 9 + ga_caps_countable_income: 2_558.42 + u19: + members: [p19] + spm_unit_size: + 2026: 10 + ga_caps_countable_income: 2_795 + u20: + members: [p20] + spm_unit_size: + 2026: 10 + ga_caps_countable_income: 2_795.09 + u21: + members: [p21] + spm_unit_size: + 2026: 11 + ga_caps_countable_income: 3_031.66 + u22: + members: [p22] + spm_unit_size: + 2026: 11 + ga_caps_countable_income: 3_031.75 + u23: + members: [p23] + spm_unit_size: + 2026: 12 + ga_caps_countable_income: 3_268.33 + u24: + members: [p24] + spm_unit_size: + 2026: 12 + ga_caps_countable_income: 3_268.42 + u25: + members: [p25] + spm_unit_size: + 2026: 13 + ga_caps_countable_income: 3_505 + u26: + members: [p26] + spm_unit_size: + 2026: 13 + ga_caps_countable_income: 3_505.09 + u27: + members: [p27] + spm_unit_size: + 2026: 14 + ga_caps_countable_income: 3_741.66 + u28: + members: [p28] + spm_unit_size: + 2026: 14 + ga_caps_countable_income: 3_741.75 + households: + h1: + members: [p1] + state_code: + 2026: GA + h2: + members: [p2] + state_code: + 2026: GA + h3: + members: [p3] + state_code: + 2026: GA + h4: + members: [p4] + state_code: + 2026: GA + h5: + members: [p5] + state_code: + 2026: GA + h6: + members: [p6] + state_code: + 2026: GA + h7: + members: [p7] + state_code: + 2026: GA + h8: + members: [p8] + state_code: + 2026: GA + h9: + members: [p9] + state_code: + 2026: GA + h10: + members: [p10] + state_code: + 2026: GA + h11: + members: [p11] + state_code: + 2026: GA + h12: + members: [p12] + state_code: + 2026: GA + h13: + members: [p13] + state_code: + 2026: GA + h14: + members: [p14] + state_code: + 2026: GA + h15: + members: [p15] + state_code: + 2026: GA + h16: + members: [p16] + state_code: + 2026: GA + h17: + members: [p17] + state_code: + 2026: GA + h18: + members: [p18] + state_code: + 2026: GA + h19: + members: [p19] + state_code: + 2026: GA + h20: + members: [p20] + state_code: + 2026: GA + h21: + members: [p21] + state_code: + 2026: GA + h22: + members: [p22] + state_code: + 2026: GA + h23: + members: [p23] + state_code: + 2026: GA + h24: + members: [p24] + state_code: + 2026: GA + h25: + members: [p25] + state_code: + 2026: GA + h26: + members: [p26] + state_code: + 2026: GA + h27: + members: [p27] + state_code: + 2026: GA + h28: + members: [p28] + state_code: + 2026: GA + output: + # 50% of the 2026 guideline, which CAPS took up on March 2, 2026. + # Annual tops as monthly income: the top rounded down to the cent, then a + # dollar more a year rounded up to the cent. + ga_caps_priority_group_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.yaml index 2193e5fea97..8222afdd482 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/id/dhw/iccp/eligibility/id_iccp_income_eligible.yaml @@ -310,3 +310,199 @@ id_iccp_enrolled: false output: id_iccp_income_eligible: false + +# Posted charts: each printed family size at its top passes and a dollar more +# fails. Each case sets the unit's size directly and lists the outcomes in size +# order, the top first. + +- name: The department's table effective October 2025 holds at every family size in January 2026. + period: 2026-01 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 2 + id_iccp_countable_income: 2_292 + id_iccp_enrolled: false + u2: + members: [p2] + spm_unit_size: + 2026: 2 + id_iccp_countable_income: 2_293 + id_iccp_enrolled: false + u3: + members: [p3] + spm_unit_size: + 2026: 3 + id_iccp_countable_income: 2_888 + id_iccp_enrolled: false + u4: + members: [p4] + spm_unit_size: + 2026: 3 + id_iccp_countable_income: 2_889 + id_iccp_enrolled: false + u5: + members: [p5] + spm_unit_size: + 2026: 4 + id_iccp_countable_income: 3_483 + id_iccp_enrolled: false + u6: + members: [p6] + spm_unit_size: + 2026: 4 + id_iccp_countable_income: 3_484 + id_iccp_enrolled: false + u7: + members: [p7] + spm_unit_size: + 2026: 5 + id_iccp_countable_income: 4_079 + id_iccp_enrolled: false + u8: + members: [p8] + spm_unit_size: + 2026: 5 + id_iccp_countable_income: 4_080 + id_iccp_enrolled: false + u9: + members: [p9] + spm_unit_size: + 2026: 6 + id_iccp_countable_income: 4_675 + id_iccp_enrolled: false + u10: + members: [p10] + spm_unit_size: + 2026: 6 + id_iccp_countable_income: 4_676 + id_iccp_enrolled: false + u11: + members: [p11] + spm_unit_size: + 2026: 7 + id_iccp_countable_income: 5_271 + id_iccp_enrolled: false + u12: + members: [p12] + spm_unit_size: + 2026: 7 + id_iccp_countable_income: 5_272 + id_iccp_enrolled: false + u13: + members: [p13] + spm_unit_size: + 2026: 8 + id_iccp_countable_income: 5_867 + id_iccp_enrolled: false + u14: + members: [p14] + spm_unit_size: + 2026: 8 + id_iccp_countable_income: 5_868 + id_iccp_enrolled: false + households: + h1: + members: [p1] + state_code: + 2026: ID + h2: + members: [p2] + state_code: + 2026: ID + h3: + members: [p3] + state_code: + 2026: ID + h4: + members: [p4] + state_code: + 2026: ID + h5: + members: [p5] + state_code: + 2026: ID + h6: + members: [p6] + state_code: + 2026: ID + h7: + members: [p7] + state_code: + 2026: ID + h8: + members: [p8] + state_code: + 2026: ID + h9: + members: [p9] + state_code: + 2026: ID + h10: + members: [p10] + state_code: + 2026: ID + h11: + members: [p11] + state_code: + 2026: ID + h12: + members: [p12] + state_code: + 2026: ID + h13: + members: [p13] + state_code: + 2026: ID + h14: + members: [p14] + state_code: + 2026: ID + output: + # Apply for Child Care, 130% of the 2025 guideline, sizes 2 to 8. + id_iccp_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml index 9e3bcaadd13..e3905698e5d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_fpg.yaml @@ -1,6 +1,73 @@ -# Tests for in_ccdf_fpg (SPMUnit, MONTH). Indiana moves to a new year's guideline when it -# posts a new eligibility package: March 31, 2024, May 1, 2025 and April 5, 2026. No source -# dates the guideline year before 2024, so the model reads the current year's until then. +# Tests for in_ccdf_fpg (SPMUnit, MONTH). Indiana moves to a new year's guideline on each +# fee schedule's effective date: March 12, 2023, March 31, 2024, March 23, 2025 and April 5, +# 2026. A monthly period reads the parameter at its first day, so each switch shows in the +# next month. Before 2023 the model reads the current year's guideline. +- name: 2022-12 uses the 2022 guideline. + period: 2022-12 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2022: IN + output: + in_ccdf_fpg: 1_919.17 + +- name: 2023-03 still uses the 2022 guideline. + period: 2023-03 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2023: IN + output: + in_ccdf_fpg: 1_919.17 + +- name: 2023-04 uses the 2023 guideline. + period: 2023-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: + 2023: IN + output: + in_ccdf_fpg: 2_071.67 + - name: 2023-06 uses the 2023 guideline. period: 2023-06 absolute_error_margin: 0.01 @@ -67,8 +134,8 @@ output: in_ccdf_fpg: 2_151.67 -- name: 2025-04 uses the 2024 guideline. - period: 2025-04 +- name: 2025-03 uses the 2024 guideline. + period: 2025-03 absolute_error_margin: 0.01 input: people: @@ -89,8 +156,8 @@ output: in_ccdf_fpg: 2_151.67 -- name: 2025-05 uses the 2025 guideline. - period: 2025-05 +- name: 2025-04 uses the 2025 guideline. + period: 2025-04 absolute_error_margin: 0.01 input: people: diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml index d4ab033daf6..fc820eaa0f0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml @@ -344,16 +344,58 @@ # 3,333/mo < 4,835/mo -> eligible. A 2-person unit at this income fails. in_ccdf_income_eligible: true -# Tops by family of three: 150% of the 2023 guideline ($3,108) until March 31, 2024; of -# the 2024 guideline ($3,228, state plan section 2.2.4) until May 1, 2025; of the 2025 -# guideline ($3,331) until April 5, 2026; then 135% of the 2026 guideline ($3,074, FSSA's -# chart). A monthly period reads each change from the next month's first day. -# -# Before August 2023 the limit was 127% (OECOSL bulletin). No source dates Indiana's -# guideline year before the March 31, 2024 plan, so the model reads the current year's -# guideline until 2024, and these two cases pin that choice: 127% of the 2023 guideline -# gives $2,631 for three in June 2023. The 2022 guideline would give $2,437, and 150% -# would give $3,108. +# Tops by family of three, from FSSA's fee schedules: 127% of the 2022 guideline ($2,437) +# until March 12, 2023; 127% of the 2023 guideline ($2,631) until August 1, 2023, when the +# rate rises to 150% ($3,108, OECOSL bulletin); 150% of the 2024 guideline ($3,228) from +# March 31, 2024; of the 2025 guideline ($3,331) from March 23, 2025; then 135% of the +# 2026 guideline ($3,074) from April 5, 2026. A monthly period reads each change from the +# next month's first day. + +- name: New applicant of 3 at 2,437 dollars qualifies in 2023-03. + period: 2023-03 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 2_437 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2023: IN + output: + in_ccdf_income_eligible: true + +- name: New applicant of 3 at 2,438 dollars doesn't qualify in 2023-03. + period: 2023-03 + input: + people: + person1: + age: 30 + person2: + age: 4 + person3: + age: 7 + spm_units: + spm_unit: + members: [person1, person2, person3] + in_ccdf_countable_income: 2_438 + is_in_ccdf_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2023: IN + output: + in_ccdf_income_eligible: false - name: New applicant of 3 at 2,631 dollars qualifies in 2023-06. period: 2023-06 @@ -493,8 +535,8 @@ output: in_ccdf_income_eligible: false -- name: New applicant of 3 at 3,228 dollars qualifies in 2025-04. - period: 2025-04 +- name: New applicant of 3 at 3,228 dollars qualifies in 2025-03. + period: 2025-03 input: people: person1: @@ -516,8 +558,8 @@ output: in_ccdf_income_eligible: true -- name: New applicant of 3 at 3,229 dollars doesn't qualify in 2025-04. - period: 2025-04 +- name: New applicant of 3 at 3,229 dollars doesn't qualify in 2025-03. + period: 2025-03 input: people: person1: @@ -539,8 +581,8 @@ output: in_ccdf_income_eligible: false -- name: New applicant of 3 at 3,331 dollars qualifies in 2025-05. - period: 2025-05 +- name: New applicant of 3 at 3,331 dollars qualifies in 2025-04. + period: 2025-04 input: people: person1: @@ -562,8 +604,8 @@ output: in_ccdf_income_eligible: true -- name: New applicant of 3 at 3,332 dollars doesn't qualify in 2025-05. - period: 2025-05 +- name: New applicant of 3 at 3,332 dollars doesn't qualify in 2025-04. + period: 2025-04 input: people: person1: @@ -1008,3 +1050,339 @@ 2026: IN output: in_ccdf_income_eligible: false + +# Posted charts: each printed family size at its top passes and a dollar more +# fails. Each case sets the unit's size directly and lists the outcomes in size +# order, the top first. + +- name: FSSA's chart effective April 5, 2026 holds at every family size in May 2026. + period: 2026-05 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 2 + in_ccdf_countable_income: 2_435 + is_in_ccdf_enrolled: false + u2: + members: [p2] + spm_unit_size: + 2026: 2 + in_ccdf_countable_income: 2_436 + is_in_ccdf_enrolled: false + u3: + members: [p3] + spm_unit_size: + 2026: 3 + in_ccdf_countable_income: 3_074 + is_in_ccdf_enrolled: false + u4: + members: [p4] + spm_unit_size: + 2026: 3 + in_ccdf_countable_income: 3_075 + is_in_ccdf_enrolled: false + u5: + members: [p5] + spm_unit_size: + 2026: 4 + in_ccdf_countable_income: 3_713 + is_in_ccdf_enrolled: false + u6: + members: [p6] + spm_unit_size: + 2026: 4 + in_ccdf_countable_income: 3_714 + is_in_ccdf_enrolled: false + u7: + members: [p7] + spm_unit_size: + 2026: 5 + in_ccdf_countable_income: 4_352 + is_in_ccdf_enrolled: false + u8: + members: [p8] + spm_unit_size: + 2026: 5 + in_ccdf_countable_income: 4_353 + is_in_ccdf_enrolled: false + u9: + members: [p9] + spm_unit_size: + 2026: 6 + in_ccdf_countable_income: 4_991 + is_in_ccdf_enrolled: false + u10: + members: [p10] + spm_unit_size: + 2026: 6 + in_ccdf_countable_income: 4_992 + is_in_ccdf_enrolled: false + u11: + members: [p11] + spm_unit_size: + 2026: 7 + in_ccdf_countable_income: 5_630 + is_in_ccdf_enrolled: false + u12: + members: [p12] + spm_unit_size: + 2026: 7 + in_ccdf_countable_income: 5_631 + is_in_ccdf_enrolled: false + u13: + members: [p13] + spm_unit_size: + 2026: 8 + in_ccdf_countable_income: 6_269 + is_in_ccdf_enrolled: false + u14: + members: [p14] + spm_unit_size: + 2026: 8 + in_ccdf_countable_income: 6_270 + is_in_ccdf_enrolled: false + households: + h1: + members: [p1] + state_code: + 2026: IN + h2: + members: [p2] + state_code: + 2026: IN + h3: + members: [p3] + state_code: + 2026: IN + h4: + members: [p4] + state_code: + 2026: IN + h5: + members: [p5] + state_code: + 2026: IN + h6: + members: [p6] + state_code: + 2026: IN + h7: + members: [p7] + state_code: + 2026: IN + h8: + members: [p8] + state_code: + 2026: IN + h9: + members: [p9] + state_code: + 2026: IN + h10: + members: [p10] + state_code: + 2026: IN + h11: + members: [p11] + state_code: + 2026: IN + h12: + members: [p12] + state_code: + 2026: IN + h13: + members: [p13] + state_code: + 2026: IN + h14: + members: [p14] + state_code: + 2026: IN + output: + # 135% of the 2026 guideline, sizes 2 to 8. + in_ccdf_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: The CCDF plan's limits effective March 31, 2024 hold at every family size in June 2024. + period: 2024-06 + input: + people: + p1: + age: + 2024: 30 + p2: + age: + 2024: 30 + p3: + age: + 2024: 30 + p4: + age: + 2024: 30 + p5: + age: + 2024: 30 + p6: + age: + 2024: 30 + p7: + age: + 2024: 30 + p8: + age: + 2024: 30 + p9: + age: + 2024: 30 + p10: + age: + 2024: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2024: 1 + in_ccdf_countable_income: 1_883 + is_in_ccdf_enrolled: false + u2: + members: [p2] + spm_unit_size: + 2024: 1 + in_ccdf_countable_income: 1_884 + is_in_ccdf_enrolled: false + u3: + members: [p3] + spm_unit_size: + 2024: 2 + in_ccdf_countable_income: 2_555 + is_in_ccdf_enrolled: false + u4: + members: [p4] + spm_unit_size: + 2024: 2 + in_ccdf_countable_income: 2_556 + is_in_ccdf_enrolled: false + u5: + members: [p5] + spm_unit_size: + 2024: 3 + in_ccdf_countable_income: 3_228 + is_in_ccdf_enrolled: false + u6: + members: [p6] + spm_unit_size: + 2024: 3 + in_ccdf_countable_income: 3_229 + is_in_ccdf_enrolled: false + u7: + members: [p7] + spm_unit_size: + 2024: 4 + in_ccdf_countable_income: 3_900 + is_in_ccdf_enrolled: false + u8: + members: [p8] + spm_unit_size: + 2024: 4 + in_ccdf_countable_income: 3_901 + is_in_ccdf_enrolled: false + u9: + members: [p9] + spm_unit_size: + 2024: 5 + in_ccdf_countable_income: 4_573 + is_in_ccdf_enrolled: false + u10: + members: [p10] + spm_unit_size: + 2024: 5 + in_ccdf_countable_income: 4_574 + is_in_ccdf_enrolled: false + households: + h1: + members: [p1] + state_code: + 2024: IN + h2: + members: [p2] + state_code: + 2024: IN + h3: + members: [p3] + state_code: + 2024: IN + h4: + members: [p4] + state_code: + 2024: IN + h5: + members: [p5] + state_code: + 2024: IN + h6: + members: [p6] + state_code: + 2024: IN + h7: + members: [p7] + state_code: + 2024: IN + h8: + members: [p8] + state_code: + 2024: IN + h9: + members: [p9] + state_code: + 2024: IN + h10: + members: [p10] + state_code: + 2024: IN + output: + # 150% of the 2024 guideline, sizes 1 to 5. + in_ccdf_income_eligible: [true, false, true, false, true, false, true, false, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_income_eligible.yaml index ef692523db0..ed43e141ae0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_income_eligible.yaml @@ -140,3 +140,227 @@ # Monthly 75% SMI threshold: 124,807 * 0.75 / 12 = 7,800.44 # 8,333.33 > 7,800.44 -> not eligible md_ccs_income_eligible: false + +# MSDE posts an Initial Income Scale effective December 15, 2024 ($94,026 a year for three) +# and a Continuation Income Scale effective April 22, 2024 ($106,563), both at the federal +# fiscal 2025 median, and still posts them in October 2026. +- name: In November 2024 a new family of three still faced 75% of the median MSDE froze at its 2021 level. + period: 2024-11 + input: + people: + p1_1: + age: + 2024: 30 + p1_2: + age: + 2024: 8 + p1_3: + age: + 2024: 5 + p2_1: + age: + 2024: 30 + p2_2: + age: + 2024: 8 + p2_3: + age: + 2024: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + md_ccs_countable_income: 6_552 + md_ccs_enrolled: false + u2: + members: [p2_1, p2_2, p2_3] + md_ccs_countable_income: 6_553 + md_ccs_enrolled: false + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2024: MD + h2: + members: [p2_1, p2_2, p2_3] + state_code: + 2024: MD + output: + # 75% * 124_807 * 0.84 / 12 = 6_552.37 + md_ccs_income_eligible: [true, false] + +- name: In March 2026 a new family of three faces the posted Initial Income Scale of $94,026 a year. + period: 2026-03 + input: + people: + p1_1: + age: + 2026: 30 + p1_2: + age: + 2026: 8 + p1_3: + age: + 2026: 5 + p2_1: + age: + 2026: 30 + p2_2: + age: + 2026: 8 + p2_3: + age: + 2026: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + md_ccs_countable_income: 7_835 + md_ccs_enrolled: false + u2: + members: [p2_1, p2_2, p2_3] + md_ccs_countable_income: 7_836 + md_ccs_enrolled: false + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2026: MD + h2: + members: [p2_1, p2_2, p2_3] + state_code: + 2026: MD + output: + # 75% of the federal fiscal 2025 median: 0.75 * 149_249 * 0.84 / 12 = 7_835.57. + # The federal fiscal 2026 median would give 0.75 * 154_117 * 0.84 / 12 = 8_091.14 + md_ccs_income_eligible: [true, false] + +- name: In April 2024 an enrolled family of three faced 85% of the median MSDE froze at its 2021 level. + period: 2024-04 + input: + people: + p1_1: + age: + 2024: 30 + p1_2: + age: + 2024: 8 + p1_3: + age: + 2024: 5 + p2_1: + age: + 2024: 30 + p2_2: + age: + 2024: 8 + p2_3: + age: + 2024: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + md_ccs_countable_income: 7_426 + md_ccs_enrolled: true + u2: + members: [p2_1, p2_2, p2_3] + md_ccs_countable_income: 7_427 + md_ccs_enrolled: true + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2024: MD + h2: + members: [p2_1, p2_2, p2_3] + state_code: + 2024: MD + output: + # 0.85 * 124_807 * 0.84 / 12 = 7_426.02; the posted scale of April 22, 2024 shows from May + md_ccs_income_eligible: [true, false] + +- name: In May 2024 an enrolled family of three faces the posted Continuation Income Scale of $106,563 a year. + period: 2024-05 + input: + people: + p1_1: + age: + 2024: 30 + p1_2: + age: + 2024: 8 + p1_3: + age: + 2024: 5 + p2_1: + age: + 2024: 30 + p2_2: + age: + 2024: 8 + p2_3: + age: + 2024: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + md_ccs_countable_income: 8_880 + md_ccs_enrolled: true + u2: + members: [p2_1, p2_2, p2_3] + md_ccs_countable_income: 8_881 + md_ccs_enrolled: true + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2024: MD + h2: + members: [p2_1, p2_2, p2_3] + state_code: + 2024: MD + output: + # 85% of the federal fiscal 2025 median: 0.85 * 149_249 * 0.84 / 12 = 8_880.32 + md_ccs_income_eligible: [true, false] + +- name: In March 2026 an enrolled family of three still faces the posted Continuation Income Scale. + period: 2026-03 + input: + people: + p1_1: + age: + 2026: 30 + p1_2: + age: + 2026: 8 + p1_3: + age: + 2026: 5 + p2_1: + age: + 2026: 30 + p2_2: + age: + 2026: 8 + p2_3: + age: + 2026: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + md_ccs_countable_income: 8_880 + md_ccs_enrolled: true + u2: + members: [p2_1, p2_2, p2_3] + md_ccs_countable_income: 8_881 + md_ccs_enrolled: true + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2026: MD + h2: + members: [p2_1, p2_2, p2_3] + state_code: + 2026: MD + output: + # 0.85 * 149_249 * 0.84 / 12 = 8_880.32; the fiscal 2026 median would give 9_170.31 + md_ccs_income_eligible: [true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.yaml index a576d90dc12..8cc9ede938d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.yaml @@ -579,3 +579,1070 @@ 2026: MO output: mo_ccs_income_eligible: false + +# Posted charts: each printed family size at its top passes and a dollar more +# fails. Each case sets the unit's size directly and lists the outcomes in size +# order, the top first. + +- name: DESE's July 1, 2026 chart holds new applicants to the lower of its maximum and 85% of SMI at sizes 1 to 20. + period: 2026-07 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + p23: + age: + 2026: 30 + p24: + age: + 2026: 30 + p25: + age: + 2026: 30 + p26: + age: + 2026: 30 + p27: + age: + 2026: 30 + p28: + age: + 2026: 30 + p29: + age: + 2026: 30 + p30: + age: + 2026: 30 + p31: + age: + 2026: 30 + p32: + age: + 2026: 30 + p33: + age: + 2026: 30 + p34: + age: + 2026: 30 + p35: + age: + 2026: 30 + p36: + age: + 2026: 30 + p37: + age: + 2026: 30 + p38: + age: + 2026: 30 + p39: + age: + 2026: 30 + p40: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 1 + mo_ccs_adjusted_income: 1_956 + mo_ccs_enrolled: false + u2: + members: [p2] + spm_unit_size: + 2026: 1 + mo_ccs_adjusted_income: 1_957 + mo_ccs_enrolled: false + u3: + members: [p3] + spm_unit_size: + 2026: 2 + mo_ccs_adjusted_income: 2_644 + mo_ccs_enrolled: false + u4: + members: [p4] + spm_unit_size: + 2026: 2 + mo_ccs_adjusted_income: 2_645 + mo_ccs_enrolled: false + u5: + members: [p5] + spm_unit_size: + 2026: 3 + mo_ccs_adjusted_income: 3_331 + mo_ccs_enrolled: false + u6: + members: [p6] + spm_unit_size: + 2026: 3 + mo_ccs_adjusted_income: 3_332 + mo_ccs_enrolled: false + u7: + members: [p7] + spm_unit_size: + 2026: 4 + mo_ccs_adjusted_income: 4_019 + mo_ccs_enrolled: false + u8: + members: [p8] + spm_unit_size: + 2026: 4 + mo_ccs_adjusted_income: 4_020 + mo_ccs_enrolled: false + u9: + members: [p9] + spm_unit_size: + 2026: 5 + mo_ccs_adjusted_income: 4_706 + mo_ccs_enrolled: false + u10: + members: [p10] + spm_unit_size: + 2026: 5 + mo_ccs_adjusted_income: 4_707 + mo_ccs_enrolled: false + u11: + members: [p11] + spm_unit_size: + 2026: 6 + mo_ccs_adjusted_income: 5_394 + mo_ccs_enrolled: false + u12: + members: [p12] + spm_unit_size: + 2026: 6 + mo_ccs_adjusted_income: 5_395 + mo_ccs_enrolled: false + u13: + members: [p13] + spm_unit_size: + 2026: 7 + mo_ccs_adjusted_income: 6_081 + mo_ccs_enrolled: false + u14: + members: [p14] + spm_unit_size: + 2026: 7 + mo_ccs_adjusted_income: 6_082 + mo_ccs_enrolled: false + u15: + members: [p15] + spm_unit_size: + 2026: 8 + mo_ccs_adjusted_income: 6_769 + mo_ccs_enrolled: false + u16: + members: [p16] + spm_unit_size: + 2026: 8 + mo_ccs_adjusted_income: 6_770 + mo_ccs_enrolled: false + u17: + members: [p17] + spm_unit_size: + 2026: 9 + mo_ccs_adjusted_income: 7_456 + mo_ccs_enrolled: false + u18: + members: [p18] + spm_unit_size: + 2026: 9 + mo_ccs_adjusted_income: 7_457 + mo_ccs_enrolled: false + u19: + members: [p19] + spm_unit_size: + 2026: 10 + mo_ccs_adjusted_income: 8_144 + mo_ccs_enrolled: false + u20: + members: [p20] + spm_unit_size: + 2026: 10 + mo_ccs_adjusted_income: 8_145 + mo_ccs_enrolled: false + u21: + members: [p21] + spm_unit_size: + 2026: 11 + mo_ccs_adjusted_income: 8_831 + mo_ccs_enrolled: false + u22: + members: [p22] + spm_unit_size: + 2026: 11 + mo_ccs_adjusted_income: 8_832 + mo_ccs_enrolled: false + u23: + members: [p23] + spm_unit_size: + 2026: 12 + mo_ccs_adjusted_income: 9_519 + mo_ccs_enrolled: false + u24: + members: [p24] + spm_unit_size: + 2026: 12 + mo_ccs_adjusted_income: 9_520 + mo_ccs_enrolled: false + u25: + members: [p25] + spm_unit_size: + 2026: 13 + mo_ccs_adjusted_income: 10_206 + mo_ccs_enrolled: false + u26: + members: [p26] + spm_unit_size: + 2026: 13 + mo_ccs_adjusted_income: 10_207 + mo_ccs_enrolled: false + u27: + members: [p27] + spm_unit_size: + 2026: 14 + mo_ccs_adjusted_income: 10_894 + mo_ccs_enrolled: false + u28: + members: [p28] + spm_unit_size: + 2026: 14 + mo_ccs_adjusted_income: 10_895 + mo_ccs_enrolled: false + u29: + members: [p29] + spm_unit_size: + 2026: 15 + mo_ccs_adjusted_income: 11_581 + mo_ccs_enrolled: false + u30: + members: [p30] + spm_unit_size: + 2026: 15 + mo_ccs_adjusted_income: 11_582 + mo_ccs_enrolled: false + u31: + members: [p31] + spm_unit_size: + 2026: 16 + mo_ccs_adjusted_income: 12_269 + mo_ccs_enrolled: false + u32: + members: [p32] + spm_unit_size: + 2026: 16 + mo_ccs_adjusted_income: 12_270 + mo_ccs_enrolled: false + u33: + members: [p33] + spm_unit_size: + 2026: 17 + mo_ccs_adjusted_income: 12_766 + mo_ccs_enrolled: false + u34: + members: [p34] + spm_unit_size: + 2026: 17 + mo_ccs_adjusted_income: 12_767 + mo_ccs_enrolled: false + u35: + members: [p35] + spm_unit_size: + 2026: 18 + mo_ccs_adjusted_income: 12_998 + mo_ccs_enrolled: false + u36: + members: [p36] + spm_unit_size: + 2026: 18 + mo_ccs_adjusted_income: 12_999 + mo_ccs_enrolled: false + u37: + members: [p37] + spm_unit_size: + 2026: 19 + mo_ccs_adjusted_income: 13_230 + mo_ccs_enrolled: false + u38: + members: [p38] + spm_unit_size: + 2026: 19 + mo_ccs_adjusted_income: 13_231 + mo_ccs_enrolled: false + u39: + members: [p39] + spm_unit_size: + 2026: 20 + mo_ccs_adjusted_income: 13_462 + mo_ccs_enrolled: false + u40: + members: [p40] + spm_unit_size: + 2026: 20 + mo_ccs_adjusted_income: 13_463 + mo_ccs_enrolled: false + households: + h1: + members: [p1] + state_code: + 2026: MO + h2: + members: [p2] + state_code: + 2026: MO + h3: + members: [p3] + state_code: + 2026: MO + h4: + members: [p4] + state_code: + 2026: MO + h5: + members: [p5] + state_code: + 2026: MO + h6: + members: [p6] + state_code: + 2026: MO + h7: + members: [p7] + state_code: + 2026: MO + h8: + members: [p8] + state_code: + 2026: MO + h9: + members: [p9] + state_code: + 2026: MO + h10: + members: [p10] + state_code: + 2026: MO + h11: + members: [p11] + state_code: + 2026: MO + h12: + members: [p12] + state_code: + 2026: MO + h13: + members: [p13] + state_code: + 2026: MO + h14: + members: [p14] + state_code: + 2026: MO + h15: + members: [p15] + state_code: + 2026: MO + h16: + members: [p16] + state_code: + 2026: MO + h17: + members: [p17] + state_code: + 2026: MO + h18: + members: [p18] + state_code: + 2026: MO + h19: + members: [p19] + state_code: + 2026: MO + h20: + members: [p20] + state_code: + 2026: MO + h21: + members: [p21] + state_code: + 2026: MO + h22: + members: [p22] + state_code: + 2026: MO + h23: + members: [p23] + state_code: + 2026: MO + h24: + members: [p24] + state_code: + 2026: MO + h25: + members: [p25] + state_code: + 2026: MO + h26: + members: [p26] + state_code: + 2026: MO + h27: + members: [p27] + state_code: + 2026: MO + h28: + members: [p28] + state_code: + 2026: MO + h29: + members: [p29] + state_code: + 2026: MO + h30: + members: [p30] + state_code: + 2026: MO + h31: + members: [p31] + state_code: + 2026: MO + h32: + members: [p32] + state_code: + 2026: MO + h33: + members: [p33] + state_code: + 2026: MO + h34: + members: [p34] + state_code: + 2026: MO + h35: + members: [p35] + state_code: + 2026: MO + h36: + members: [p36] + state_code: + 2026: MO + h37: + members: [p37] + state_code: + 2026: MO + h38: + members: [p38] + state_code: + 2026: MO + h39: + members: [p39] + state_code: + 2026: MO + h40: + members: [p40] + state_code: + 2026: MO + output: + # The chart's $5.00 row tops for sizes 1 to 20, except that the chart's + # July 1, 2026 clarification applies the lower of that top and its 85% State + # Median Income row, which binds from size 17 ($12,766.15 for 17). + mo_ccs_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: DESE's July 1, 2026 chart holds enrolled families to the lower of Transitional Level 2 and 85% of SMI at sizes 1 to 20. + period: 2026-07 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + p23: + age: + 2026: 30 + p24: + age: + 2026: 30 + p25: + age: + 2026: 30 + p26: + age: + 2026: 30 + p27: + age: + 2026: 30 + p28: + age: + 2026: 30 + p29: + age: + 2026: 30 + p30: + age: + 2026: 30 + p31: + age: + 2026: 30 + p32: + age: + 2026: 30 + p33: + age: + 2026: 30 + p34: + age: + 2026: 30 + p35: + age: + 2026: 30 + p36: + age: + 2026: 30 + p37: + age: + 2026: 30 + p38: + age: + 2026: 30 + p39: + age: + 2026: 30 + p40: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 1 + mo_ccs_adjusted_income: 2_804 + mo_ccs_enrolled: true + u2: + members: [p2] + spm_unit_size: + 2026: 1 + mo_ccs_adjusted_income: 2_805 + mo_ccs_enrolled: true + u3: + members: [p3] + spm_unit_size: + 2026: 2 + mo_ccs_adjusted_income: 3_789 + mo_ccs_enrolled: true + u4: + members: [p4] + spm_unit_size: + 2026: 2 + mo_ccs_adjusted_income: 3_790 + mo_ccs_enrolled: true + u5: + members: [p5] + spm_unit_size: + 2026: 3 + mo_ccs_adjusted_income: 4_775 + mo_ccs_enrolled: true + u6: + members: [p6] + spm_unit_size: + 2026: 3 + mo_ccs_adjusted_income: 4_776 + mo_ccs_enrolled: true + u7: + members: [p7] + spm_unit_size: + 2026: 4 + mo_ccs_adjusted_income: 5_760 + mo_ccs_enrolled: true + u8: + members: [p8] + spm_unit_size: + 2026: 4 + mo_ccs_adjusted_income: 5_761 + mo_ccs_enrolled: true + u9: + members: [p9] + spm_unit_size: + 2026: 5 + mo_ccs_adjusted_income: 6_746 + mo_ccs_enrolled: true + u10: + members: [p10] + spm_unit_size: + 2026: 5 + mo_ccs_adjusted_income: 6_747 + mo_ccs_enrolled: true + u11: + members: [p11] + spm_unit_size: + 2026: 6 + mo_ccs_adjusted_income: 7_731 + mo_ccs_enrolled: true + u12: + members: [p12] + spm_unit_size: + 2026: 6 + mo_ccs_adjusted_income: 7_732 + mo_ccs_enrolled: true + u13: + members: [p13] + spm_unit_size: + 2026: 7 + mo_ccs_adjusted_income: 8_716 + mo_ccs_enrolled: true + u14: + members: [p14] + spm_unit_size: + 2026: 7 + mo_ccs_adjusted_income: 8_717 + mo_ccs_enrolled: true + u15: + members: [p15] + spm_unit_size: + 2026: 8 + mo_ccs_adjusted_income: 9_702 + mo_ccs_enrolled: true + u16: + members: [p16] + spm_unit_size: + 2026: 8 + mo_ccs_adjusted_income: 9_703 + mo_ccs_enrolled: true + u17: + members: [p17] + spm_unit_size: + 2026: 9 + mo_ccs_adjusted_income: 10_687 + mo_ccs_enrolled: true + u18: + members: [p18] + spm_unit_size: + 2026: 9 + mo_ccs_adjusted_income: 10_688 + mo_ccs_enrolled: true + u19: + members: [p19] + spm_unit_size: + 2026: 10 + mo_ccs_adjusted_income: 11_141 + mo_ccs_enrolled: true + u20: + members: [p20] + spm_unit_size: + 2026: 10 + mo_ccs_adjusted_income: 11_142 + mo_ccs_enrolled: true + u21: + members: [p21] + spm_unit_size: + 2026: 11 + mo_ccs_adjusted_income: 11_373 + mo_ccs_enrolled: true + u22: + members: [p22] + spm_unit_size: + 2026: 11 + mo_ccs_adjusted_income: 11_374 + mo_ccs_enrolled: true + u23: + members: [p23] + spm_unit_size: + 2026: 12 + mo_ccs_adjusted_income: 11_605 + mo_ccs_enrolled: true + u24: + members: [p24] + spm_unit_size: + 2026: 12 + mo_ccs_adjusted_income: 11_606 + mo_ccs_enrolled: true + u25: + members: [p25] + spm_unit_size: + 2026: 13 + mo_ccs_adjusted_income: 11_837 + mo_ccs_enrolled: true + u26: + members: [p26] + spm_unit_size: + 2026: 13 + mo_ccs_adjusted_income: 11_838 + mo_ccs_enrolled: true + u27: + members: [p27] + spm_unit_size: + 2026: 14 + mo_ccs_adjusted_income: 12_069 + mo_ccs_enrolled: true + u28: + members: [p28] + spm_unit_size: + 2026: 14 + mo_ccs_adjusted_income: 12_070 + mo_ccs_enrolled: true + u29: + members: [p29] + spm_unit_size: + 2026: 15 + mo_ccs_adjusted_income: 12_301 + mo_ccs_enrolled: true + u30: + members: [p30] + spm_unit_size: + 2026: 15 + mo_ccs_adjusted_income: 12_302 + mo_ccs_enrolled: true + u31: + members: [p31] + spm_unit_size: + 2026: 16 + mo_ccs_adjusted_income: 12_534 + mo_ccs_enrolled: true + u32: + members: [p32] + spm_unit_size: + 2026: 16 + mo_ccs_adjusted_income: 12_535 + mo_ccs_enrolled: true + u33: + members: [p33] + spm_unit_size: + 2026: 17 + mo_ccs_adjusted_income: 12_766 + mo_ccs_enrolled: true + u34: + members: [p34] + spm_unit_size: + 2026: 17 + mo_ccs_adjusted_income: 12_767 + mo_ccs_enrolled: true + u35: + members: [p35] + spm_unit_size: + 2026: 18 + mo_ccs_adjusted_income: 12_998 + mo_ccs_enrolled: true + u36: + members: [p36] + spm_unit_size: + 2026: 18 + mo_ccs_adjusted_income: 12_999 + mo_ccs_enrolled: true + u37: + members: [p37] + spm_unit_size: + 2026: 19 + mo_ccs_adjusted_income: 13_230 + mo_ccs_enrolled: true + u38: + members: [p38] + spm_unit_size: + 2026: 19 + mo_ccs_adjusted_income: 13_231 + mo_ccs_enrolled: true + u39: + members: [p39] + spm_unit_size: + 2026: 20 + mo_ccs_adjusted_income: 13_462 + mo_ccs_enrolled: true + u40: + members: [p40] + spm_unit_size: + 2026: 20 + mo_ccs_adjusted_income: 13_463 + mo_ccs_enrolled: true + households: + h1: + members: [p1] + state_code: + 2026: MO + h2: + members: [p2] + state_code: + 2026: MO + h3: + members: [p3] + state_code: + 2026: MO + h4: + members: [p4] + state_code: + 2026: MO + h5: + members: [p5] + state_code: + 2026: MO + h6: + members: [p6] + state_code: + 2026: MO + h7: + members: [p7] + state_code: + 2026: MO + h8: + members: [p8] + state_code: + 2026: MO + h9: + members: [p9] + state_code: + 2026: MO + h10: + members: [p10] + state_code: + 2026: MO + h11: + members: [p11] + state_code: + 2026: MO + h12: + members: [p12] + state_code: + 2026: MO + h13: + members: [p13] + state_code: + 2026: MO + h14: + members: [p14] + state_code: + 2026: MO + h15: + members: [p15] + state_code: + 2026: MO + h16: + members: [p16] + state_code: + 2026: MO + h17: + members: [p17] + state_code: + 2026: MO + h18: + members: [p18] + state_code: + 2026: MO + h19: + members: [p19] + state_code: + 2026: MO + h20: + members: [p20] + state_code: + 2026: MO + h21: + members: [p21] + state_code: + 2026: MO + h22: + members: [p22] + state_code: + 2026: MO + h23: + members: [p23] + state_code: + 2026: MO + h24: + members: [p24] + state_code: + 2026: MO + h25: + members: [p25] + state_code: + 2026: MO + h26: + members: [p26] + state_code: + 2026: MO + h27: + members: [p27] + state_code: + 2026: MO + h28: + members: [p28] + state_code: + 2026: MO + h29: + members: [p29] + state_code: + 2026: MO + h30: + members: [p30] + state_code: + 2026: MO + h31: + members: [p31] + state_code: + 2026: MO + h32: + members: [p32] + state_code: + 2026: MO + h33: + members: [p33] + state_code: + 2026: MO + h34: + members: [p34] + state_code: + 2026: MO + h35: + members: [p35] + state_code: + 2026: MO + h36: + members: [p36] + state_code: + 2026: MO + h37: + members: [p37] + state_code: + 2026: MO + h38: + members: [p38] + state_code: + 2026: MO + h39: + members: [p39] + state_code: + 2026: MO + h40: + members: [p40] + state_code: + 2026: MO + output: + # Transitional Level 2 tops for sizes 1 to 20, except that the 85% State + # Median Income row binds from size 10 ($11,141.38 for 10). + mo_ccs_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/mo_ccs.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/mo_ccs.yaml index 25fdbed64d9..41da7430fe8 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/mo_ccs.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/mo_ccs.yaml @@ -349,3 +349,76 @@ # tier 7 full fee $5/day * 20 = $100. Disabled child waived. # Benefit = max(3,709.25 - 100, 0) = $3,609.25. mo_ccs: 3_609.25 + +- name: July 2026, an enrolled family of three at the $4,109 Level 1 top gets 80 percent of the remaining rate. + period: 2026-07 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 30 + person3: + age: + 2026: 4 + childcare_attending_days_per_month: + 2026: 20 + mo_ccs_maximum_daily_benefit: 60 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_eligible: true + mo_ccs_adjusted_income: 4_109 + mo_ccs_copay: 200 + spm_unit_pre_subsidy_childcare_expenses: + 2026: 36_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + # DESE's July 2026 chart puts $4,109 for three at the top of Transitional Level 1. + # Reimbursement = min($60 * 20, $36,000 / 12) = $1,200; less the $200 fee = $1,000. + # Benefit = 80% * $1,000 = $800. + mo_ccs_funding_rate: 0.8 + mo_ccs: 800 + +- name: July 2026, an enrolled family of three at $4,110 gets 60 percent of the remaining rate. + period: 2026-07 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 30 + person3: + age: + 2026: 4 + childcare_attending_days_per_month: + 2026: 20 + mo_ccs_maximum_daily_benefit: 60 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_eligible: true + mo_ccs_adjusted_income: 4_110 + mo_ccs_copay: 200 + spm_unit_pre_subsidy_childcare_expenses: + 2026: 36_000 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + # $4,110 for three falls in Transitional Level 2 on DESE's July 2026 chart. + # Benefit = 60% * ($1,200 - $200) = $600. + mo_ccs_funding_rate: 0.6 + mo_ccs: 600 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/mo_ccs_funding_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/mo_ccs_funding_rate.yaml new file mode 100644 index 00000000000..8924200aae5 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dese/ccs/mo_ccs_funding_rate.yaml @@ -0,0 +1,199 @@ +# mo_ccs_funding_rate: SPMUnit, MONTH. +# DESE's chart updated July 1, 2026 prints, for three on the 2025 guideline ($26,650): +# traditional up to $3,331, Transitional Level 1 $3,332 to $4,109, Level 2 $4,110 to $4,775. + +- name: July 2026, a family of three at the $3,331 traditional top keeps the full rate. + period: 2026-07 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 3_331 + mo_ccs_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + mo_ccs_funding_rate: 1 + +- name: July 2026, a family of three at $3,332 enters Transitional Level 1. + period: 2026-07 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 3_332 + mo_ccs_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + mo_ccs_funding_rate: 0.8 + +- name: July 2026, a family of three at the $4,109 Level 1 top keeps 80 percent. + period: 2026-07 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 4_109 + mo_ccs_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + # 185% * 26_650 / 12 = 4_108.54, which the chart prints as $4,109. + mo_ccs_funding_rate: 0.8 + +- name: July 2026, a family of three at $4,110 enters Transitional Level 2. + period: 2026-07 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 4_110 + mo_ccs_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + mo_ccs_funding_rate: 0.6 + +- name: July 2026, a family of three at the $4,775 Level 2 top keeps 60 percent. + period: 2026-07 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + mo_ccs_adjusted_income: 4_775 + mo_ccs_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: + 2026: MO + output: + mo_ccs_funding_rate: 0.6 + +- name: July 2026, a family of one at the $2,413 Level 1 top keeps 80 percent. + period: 2026-07 + input: + people: + person1: + age: + 2026: 30 + spm_units: + spm_unit: + members: [person1] + mo_ccs_adjusted_income: 2_413 + mo_ccs_enrolled: true + households: + household: + members: [person1] + state_code: + 2026: MO + output: + # 185% * 15_650 / 12 = 2_412.71, which the chart prints as $2,413. + mo_ccs_funding_rate: 0.8 + +- name: July 2026, a family of one at $2,414 enters Transitional Level 2. + period: 2026-07 + input: + people: + person1: + age: + 2026: 30 + spm_units: + spm_unit: + members: [person1] + mo_ccs_adjusted_income: 2_414 + mo_ccs_enrolled: true + households: + household: + members: [person1] + state_code: + 2026: MO + output: + mo_ccs_funding_rate: 0.6 + +- name: January 2025, a family of two above 215 percent reaches Transitional Level 3. + period: 2025-01 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2] + mo_ccs_adjusted_income: 4_000 + mo_ccs_enrolled: true + households: + household: + members: [person1, person2] + state_code: + 2025: MO + output: + # Level 2 tops out at round(215% * 21_150 / 12) = $3,789 for two. + mo_ccs_funding_rate: 0.5 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_income_eligible.yaml index 3ce0465ebfd..002d9783542 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/mt_ccap_income_eligible.yaml @@ -1473,3 +1473,521 @@ 2023: MT output: mt_ccap_income_eligible: false + +# Posted charts: each printed family size at its top passes and a dollar more +# fails. Each case sets the unit's size directly and lists the outcomes in size +# order, the top first. + +- name: The July 1, 2025 sliding fee scale's Standard Eligibility top holds at sizes 2 to 11 in January 2026. + period: 2026-01 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 2 + mt_ccap_countable_income: 3_261 + mt_ccap_enrolled: false + u2: + members: [p2] + spm_unit_size: + 2026: 2 + mt_ccap_countable_income: 3_262 + mt_ccap_enrolled: false + u3: + members: [p3] + spm_unit_size: + 2026: 3 + mt_ccap_countable_income: 4_109 + mt_ccap_enrolled: false + u4: + members: [p4] + spm_unit_size: + 2026: 3 + mt_ccap_countable_income: 4_110 + mt_ccap_enrolled: false + u5: + members: [p5] + spm_unit_size: + 2026: 4 + mt_ccap_countable_income: 4_956 + mt_ccap_enrolled: false + u6: + members: [p6] + spm_unit_size: + 2026: 4 + mt_ccap_countable_income: 4_957 + mt_ccap_enrolled: false + u7: + members: [p7] + spm_unit_size: + 2026: 5 + mt_ccap_countable_income: 5_804 + mt_ccap_enrolled: false + u8: + members: [p8] + spm_unit_size: + 2026: 5 + mt_ccap_countable_income: 5_805 + mt_ccap_enrolled: false + u9: + members: [p9] + spm_unit_size: + 2026: 6 + mt_ccap_countable_income: 6_652 + mt_ccap_enrolled: false + u10: + members: [p10] + spm_unit_size: + 2026: 6 + mt_ccap_countable_income: 6_653 + mt_ccap_enrolled: false + u11: + members: [p11] + spm_unit_size: + 2026: 7 + mt_ccap_countable_income: 7_500 + mt_ccap_enrolled: false + u12: + members: [p12] + spm_unit_size: + 2026: 7 + mt_ccap_countable_income: 7_501 + mt_ccap_enrolled: false + u13: + members: [p13] + spm_unit_size: + 2026: 8 + mt_ccap_countable_income: 8_348 + mt_ccap_enrolled: false + u14: + members: [p14] + spm_unit_size: + 2026: 8 + mt_ccap_countable_income: 8_349 + mt_ccap_enrolled: false + u15: + members: [p15] + spm_unit_size: + 2026: 9 + mt_ccap_countable_income: 9_196 + mt_ccap_enrolled: false + u16: + members: [p16] + spm_unit_size: + 2026: 9 + mt_ccap_countable_income: 9_197 + mt_ccap_enrolled: false + u17: + members: [p17] + spm_unit_size: + 2026: 10 + mt_ccap_countable_income: 10_044 + mt_ccap_enrolled: false + u18: + members: [p18] + spm_unit_size: + 2026: 10 + mt_ccap_countable_income: 10_045 + mt_ccap_enrolled: false + u19: + members: [p19] + spm_unit_size: + 2026: 11 + mt_ccap_countable_income: 10_892 + mt_ccap_enrolled: false + u20: + members: [p20] + spm_unit_size: + 2026: 11 + mt_ccap_countable_income: 10_893 + mt_ccap_enrolled: false + households: + h1: + members: [p1] + state_code: + 2026: MT + h2: + members: [p2] + state_code: + 2026: MT + h3: + members: [p3] + state_code: + 2026: MT + h4: + members: [p4] + state_code: + 2026: MT + h5: + members: [p5] + state_code: + 2026: MT + h6: + members: [p6] + state_code: + 2026: MT + h7: + members: [p7] + state_code: + 2026: MT + h8: + members: [p8] + state_code: + 2026: MT + h9: + members: [p9] + state_code: + 2026: MT + h10: + members: [p10] + state_code: + 2026: MT + h11: + members: [p11] + state_code: + 2026: MT + h12: + members: [p12] + state_code: + 2026: MT + h13: + members: [p13] + state_code: + 2026: MT + h14: + members: [p14] + state_code: + 2026: MT + h15: + members: [p15] + state_code: + 2026: MT + h16: + members: [p16] + state_code: + 2026: MT + h17: + members: [p17] + state_code: + 2026: MT + h18: + members: [p18] + state_code: + 2026: MT + h19: + members: [p19] + state_code: + 2026: MT + h20: + members: [p20] + state_code: + 2026: MT + output: + # 185% FPG GMI row, sizes 2 to 11. + mt_ccap_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: The July 1, 2025 sliding fee scale's Graduated Eligibility top holds at sizes 2 to 10 in January 2026. + period: 2026-01 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 2 + mt_ccap_countable_income: 3_525 + mt_ccap_enrolled: true + u2: + members: [p2] + spm_unit_size: + 2026: 2 + mt_ccap_countable_income: 3_526 + mt_ccap_enrolled: true + u3: + members: [p3] + spm_unit_size: + 2026: 3 + mt_ccap_countable_income: 4_442 + mt_ccap_enrolled: true + u4: + members: [p4] + spm_unit_size: + 2026: 3 + mt_ccap_countable_income: 4_443 + mt_ccap_enrolled: true + u5: + members: [p5] + spm_unit_size: + 2026: 4 + mt_ccap_countable_income: 5_358 + mt_ccap_enrolled: true + u6: + members: [p6] + spm_unit_size: + 2026: 4 + mt_ccap_countable_income: 5_359 + mt_ccap_enrolled: true + u7: + members: [p7] + spm_unit_size: + 2026: 5 + mt_ccap_countable_income: 6_275 + mt_ccap_enrolled: true + u8: + members: [p8] + spm_unit_size: + 2026: 5 + mt_ccap_countable_income: 6_276 + mt_ccap_enrolled: true + u9: + members: [p9] + spm_unit_size: + 2026: 6 + mt_ccap_countable_income: 7_192 + mt_ccap_enrolled: true + u10: + members: [p10] + spm_unit_size: + 2026: 6 + mt_ccap_countable_income: 7_193 + mt_ccap_enrolled: true + u11: + members: [p11] + spm_unit_size: + 2026: 7 + mt_ccap_countable_income: 8_108 + mt_ccap_enrolled: true + u12: + members: [p12] + spm_unit_size: + 2026: 7 + mt_ccap_countable_income: 8_109 + mt_ccap_enrolled: true + u13: + members: [p13] + spm_unit_size: + 2026: 8 + mt_ccap_countable_income: 9_025 + mt_ccap_enrolled: true + u14: + members: [p14] + spm_unit_size: + 2026: 8 + mt_ccap_countable_income: 9_026 + mt_ccap_enrolled: true + u15: + members: [p15] + spm_unit_size: + 2026: 9 + mt_ccap_countable_income: 9_942 + mt_ccap_enrolled: true + u16: + members: [p16] + spm_unit_size: + 2026: 9 + mt_ccap_countable_income: 9_943 + mt_ccap_enrolled: true + u17: + members: [p17] + spm_unit_size: + 2026: 10 + mt_ccap_countable_income: 10_858 + mt_ccap_enrolled: true + u18: + members: [p18] + spm_unit_size: + 2026: 10 + mt_ccap_countable_income: 10_859 + mt_ccap_enrolled: true + households: + h1: + members: [p1] + state_code: + 2026: MT + h2: + members: [p2] + state_code: + 2026: MT + h3: + members: [p3] + state_code: + 2026: MT + h4: + members: [p4] + state_code: + 2026: MT + h5: + members: [p5] + state_code: + 2026: MT + h6: + members: [p6] + state_code: + 2026: MT + h7: + members: [p7] + state_code: + 2026: MT + h8: + members: [p8] + state_code: + 2026: MT + h9: + members: [p9] + state_code: + 2026: MT + h10: + members: [p10] + state_code: + 2026: MT + h11: + members: [p11] + state_code: + 2026: MT + h12: + members: [p12] + state_code: + 2026: MT + h13: + members: [p13] + state_code: + 2026: MT + h14: + members: [p14] + state_code: + 2026: MT + h15: + members: [p15] + state_code: + 2026: MT + h16: + members: [p16] + state_code: + 2026: MT + h17: + members: [p17] + state_code: + 2026: MT + h18: + members: [p18] + state_code: + 2026: MT + output: + # 200% FPG GMI row, sizes 2 to 10. + mt_ccap_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.yaml index fd7c636f715..4fa8979f4f4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.yaml @@ -4,9 +4,10 @@ # October 1, 2023, by household size. # From October 2024, and standing in before July 2022, the flat schedule below applies. # Flat copay by income as a share of SMI (eff. Oct 1, 2024; State Plan 2.4.v): -# <= 32.99% SMI -> $0; 33%-42% SMI -> $90; above 42% SMI -> $150. -# The $150 band begins just above 42% SMI (threshold 0.4201) per the operational -# CC PT 06-25 fee chart; the State Plan summary's "43%" is superseded by the chart. +# up to 33% SMI -> $0; up to 42% SMI -> $90; above 42% SMI -> $150. +# The charts print each band top as the nearest dollar, and MS 316 rounds monthly +# income to the nearest dollar before reading them. The $150 band begins above 42% +# SMI per the operational fee charts; the State Plan summary's "43%" is superseded. # Waived for TANF/NEON (is_tanf_enrolled), CPS/foster placements, and homeless. # Family of 3, period 2025-01 -> monthly SMI = 6_721.82. @@ -157,10 +158,10 @@ # Eligible child in foster care -> protective-care waiver -> $0 nv_ccdp_copay: 0 -# Edge cases: copay-band cut-points. The scale is at-or-above (single_amount), -# so the 0.33 and 0.4201 thresholds belong to the HIGHER band: -# ratio < 0.33 -> $0; 0.33 <= ratio < 0.4201 -> $90; ratio >= 0.4201 -> $150. -# Family of 3, period 2025-01: monthly SMI = 6_721.82. +# Edge cases: copay-band cut-points. Each band top is a share of SMI rounded to the +# nearest dollar, and income above a top pays the next band. +# Family of 3, period 2025-01: monthly SMI = 6_721.82, so the $0 band tops out at +# round(0.33 * 6_721.82) = $2,218 and the $90 band at round(0.42 * 6_721.82) = $2,823. - name: Income just below the 33% SMI cut-point yields a zero copay. period: 2025-01 @@ -183,7 +184,7 @@ members: [person1, person2, person3] state_code: NV output: - # 2_200/mo / 6_721.82 = 0.3273 < 0.33 -> $0 + # 2_200 stays within the $2,218 top of the $0 band -> $0 nv_ccdp_copay: 0 - name: Income just above the 33% SMI cut-point yields a $90 copay. @@ -207,7 +208,7 @@ members: [person1, person2, person3] state_code: NV output: - # 2_225/mo / 6_721.82 = 0.3310 >= 0.33 -> $90 + # 2_225 exceeds the $2,218 top of the $0 band -> $90 nv_ccdp_copay: 90 - name: Income just below the 42% SMI cut-point stays in the $90 band. @@ -231,7 +232,7 @@ members: [person1, person2, person3] state_code: NV output: - # 2_800/mo / 6_721.82 = 0.4166 in [0.33, 0.4201) -> $90 + # 2_800 stays within the $2,823 top of the $90 band -> $90 nv_ccdp_copay: 90 - name: Income just above the 42% SMI cut-point yields a $150 copay. @@ -255,7 +256,7 @@ members: [person1, person2, person3] state_code: NV output: - # 2_850/mo / 6_721.82 = 0.4240 >= 0.4201 -> $150 + # 2_850 exceeds the $2,823 top of the $90 band -> $150 nv_ccdp_copay: 150 - name: Income at 42.8% SMI (above the operational 42% break) yields a $150 copay. @@ -279,7 +280,7 @@ members: [person1, person2, person3] state_code: NV output: - # 2_875/mo / 6_721.82 = 0.4277 >= 0.4201 -> $150. The State Plan summary + # 2_875 is 42.8% of SMI, above the $2,823 top -> $150. The State Plan summary # text ("43%-49% -> $150") would wrongly bucket this 42-43% SMI income as # $90; the operational chart (42% break) correctly makes it $150. nv_ccdp_copay: 150 @@ -834,7 +835,7 @@ output: nv_ccdp_copay: 344.05 -- name: Under the April 2024 chart a family of 3 at $5,314.84 pays $372.04. +- name: Under the April 2024 chart a family of 3 at $5,314 pays $371.98. period: 2024-04 absolute_error_margin: 0.01 input: @@ -852,14 +853,15 @@ spm_unit: members: [person1, person2, person3] nv_ccdp_countable_income: - 2024: 63_778.08 + 2024: 63_768 households: household: members: [person1, person2, person3] state_code: 2024: NV output: - nv_ccdp_copay: 372.04 + # The top band charges 7%: 0.07 * 5_314 = 371.98. + nv_ccdp_copay: 371.98 - name: Under the April 2024 chart a family of 4 at $2,979 pays $0. period: 2024-04 @@ -1029,7 +1031,7 @@ output: nv_ccdp_copay: 43.82 -- name: Under the April 2024 chart a family of 7 at $8,541.7 pays $597.92. +- name: Under the April 2024 chart a family of 7 at $8,541 pays $597.87. period: 2024-04 absolute_error_margin: 0.01 input: @@ -1059,14 +1061,15 @@ spm_unit: members: [person1, person2, person3, person4, person5, person6, person7] nv_ccdp_countable_income: - 2024: 102_500.4 + 2024: 102_492 households: household: members: [person1, person2, person3, person4, person5, person6, person7] state_code: 2024: NV output: - nv_ccdp_copay: 597.92 + # The top band charges 7%: 0.07 * 8_541 = 597.87. + nv_ccdp_copay: 597.87 - name: Under the April 2024 chart a family of 14 at $7,170 pays $0. period: 2024-04 @@ -1188,7 +1191,7 @@ output: nv_ccdp_copay: 71.71 -- name: Under the April 2024 chart a family of 14 at $9,870.41 pays $690.93. +- name: Under the April 2024 chart a family of 14 at $9,870 pays $690.90. period: 2024-04 absolute_error_margin: 0.01 input: @@ -1239,14 +1242,15 @@ spm_unit: members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] nv_ccdp_countable_income: - 2024: 118_444.92 + 2024: 118_440 households: household: members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] state_code: 2024: NV output: - nv_ccdp_copay: 690.93 + # The top band charges 7%: 0.07 * 9_870 = 690.90. + nv_ccdp_copay: 690.9 - name: Copayments stay a share of income through September 2024. period: 2024-09 @@ -1360,3 +1364,254 @@ 2024: NV output: nv_ccdp_copay: 0 + +- name: Under the April 2024 chart a family of 3 at $2,478.25 rounds to $2,478 and pays $0. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 29_739 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + # MS 316 rounds monthly income to the nearest dollar before reading the chart. + nv_ccdp_copay: 0 + +- name: Under the April 2024 chart a family of 3 at $2,478.50 rounds to $2,479 and pays $24.79. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + person3: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2024: 29_742 + households: + household: + members: [person1, person2, person3] + state_code: + 2024: NV + output: + # 1% of the rounded $2,479. + nv_ccdp_copay: 24.79 + +- name: Under the April 2024 chart a family of 2 at $1,976 pays $0. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2] + nv_ccdp_countable_income: + 2024: 23_712 + households: + household: + members: [person1, person2] + state_code: + 2024: NV + output: + nv_ccdp_copay: 0 + +- name: Under the April 2024 chart a family of 2 at $1,977 pays $19.77. + period: 2024-04 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2024: 30 + person2: + age: + 2024: 5 + spm_units: + spm_unit: + members: [person1, person2] + nv_ccdp_countable_income: + 2024: 23_724 + households: + household: + members: [person1, person2] + state_code: + 2024: NV + output: + nv_ccdp_copay: 19.77 + +- name: Under the October 2026 chart a new applicant of 1 at $1,502 pays $0. + period: 2026-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2026: 18_024 + nv_ccdp_enrolled: false + households: + household: + members: [person1] + state_code: + 2026: NV + output: + # The chart prints $1,502 as the top of the $0 band: 33% * 105_027 * 0.52 / 12 = 1_501.89. + nv_ccdp_copay: 0 + +- name: Under the October 2026 chart a new applicant of 1 at $1,503 pays $90. + period: 2026-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2026: 18_036 + nv_ccdp_enrolled: false + households: + household: + members: [person1] + state_code: + 2026: NV + output: + nv_ccdp_copay: 90 + +- name: Under the October 2026 chart a renewing family of 1 at $1,911 pays $90. + period: 2026-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2026: 22_932 + nv_ccdp_enrolled: true + households: + household: + members: [person1] + state_code: + 2026: NV + output: + # The renewal chart prints $1,911 as the top of the $90 band: 42% * 105_027 * 0.52 / 12 = 1_911.49. + nv_ccdp_copay: 90 + +- name: Under the October 2026 chart a renewing family of 1 at $1,912 pays $150. + period: 2026-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2026: 22_944 + nv_ccdp_enrolled: true + households: + household: + members: [person1] + state_code: + 2026: NV + output: + nv_ccdp_copay: 150 + +- name: Under the October 2026 chart a family of 3 at $2,426.49 rounds to $2,426 and pays $0. + period: 2026-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2026: 29_117.88 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: NV + output: + # The chart prints $2,426 as the top of the $0 band for three. + nv_ccdp_copay: 0 + +- name: Under the October 2026 chart a family of 3 at $2,426.50 rounds to $2,427 and pays $90. + period: 2026-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2026: 29_118 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2026: NV + output: + nv_ccdp_copay: 90 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.yaml index 70d18739d7e..545e44d56cc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.yaml @@ -366,7 +366,7 @@ output: nv_ccdp_income_eligible: false -- name: In October 2018 a new applicant of three at $4,000 fails the lower first tier. +- name: In October 2018 a new applicant of three at $4,000 fails the poverty-guideline limit. period: 2018-10 input: people: @@ -391,7 +391,7 @@ state_code: 2018: NV output: - # 41% * 71_593 * 0.84 / 12 = 2_054.72. + # 1.3 * 20_780 / 12 = 2_251.17, so the limit is $2,251. nv_ccdp_income_eligible: false - name: In October 2018 an enrolled family of three at $4,000 stays within 85% of SMI. @@ -447,7 +447,7 @@ state_code: 2022: NV output: - # 41% * 82_509 * 0.84 / 12 = 2_368.01. + # 1.3 * 21_960 / 12 = 2_379. nv_ccdp_income_eligible: false - name: In July 2022 a new applicant of three at $4,000 qualifies under 85% of SMI. @@ -475,7 +475,8 @@ state_code: 2022: NV output: - # 85% * 82_509 * 0.84 / 12 = 4_909.29, the top of the October 2021 sliding fee scale. + # The plan builds the July 2022 limits on the fiscal year 2023 table: + # 85% * 85_150 * 0.84 / 12 = 5_066.43, printed as $5,066 for three. nv_ccdp_income_eligible: true - name: Under the October 2023 chart a new applicant of 1 at $3,290 qualifies. @@ -1148,3 +1149,1555 @@ 2026: NV output: nv_ccdp_income_eligible: false + +- name: In September 2018 a new applicant of three at $4,000 still qualifies under 85% of SMI. + period: 2018-09 + input: + people: + p1_1: + age: + 2018: 30 + p1_2: + age: + 2018: 5 + p1_3: + age: + 2018: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + nv_ccdp_countable_income: + 2018: 48_000 + nv_ccdp_enrolled: false + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2018: NV + output: + # The poverty-guideline limit starts in October 2018. Urban prints $4,127 a month, + # 85% of SMI for three, in October 2017. + nv_ccdp_income_eligible: [true] + +- name: In October 2018 new applicants of three face 130% of the 2018 guideline unless a protective or homeless exception applies. + period: 2018-10 + input: + people: + p1_1: + age: + 2018: 30 + p1_2: + age: + 2018: 5 + p1_3: + age: + 2018: 5 + p2_1: + age: + 2018: 30 + p2_2: + age: + 2018: 5 + p2_3: + age: + 2018: 5 + p3_1: + age: + 2018: 30 + p3_2: + age: + 2018: 5 + is_in_foster_care: true + p3_3: + age: + 2018: 5 + p4_1: + age: + 2018: 30 + p4_2: + age: + 2018: 5 + p4_3: + age: + 2018: 5 + receives_or_needs_protective_services: + 2018: true + p5_1: + age: + 2018: 30 + p5_2: + age: + 2018: 5 + p5_3: + age: + 2018: 5 + p6_1: + age: + 2018: 30 + p6_2: + age: + 2018: 15 + is_in_foster_care: true + p6_3: + age: + 2018: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + nv_ccdp_countable_income: + 2018: 27_012 + nv_ccdp_enrolled: false + u2: + members: [p2_1, p2_2, p2_3] + nv_ccdp_countable_income: + 2018: 27_024 + nv_ccdp_enrolled: false + u3: + members: [p3_1, p3_2, p3_3] + nv_ccdp_countable_income: + 2018: 48_000 + nv_ccdp_enrolled: false + u4: + members: [p4_1, p4_2, p4_3] + nv_ccdp_countable_income: + 2018: 48_000 + nv_ccdp_enrolled: false + u5: + members: [p5_1, p5_2, p5_3] + nv_ccdp_countable_income: + 2018: 48_000 + nv_ccdp_enrolled: false + u6: + members: [p6_1, p6_2, p6_3] + nv_ccdp_countable_income: + 2018: 48_000 + nv_ccdp_enrolled: false + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2018: NV + h2: + members: [p2_1, p2_2, p2_3] + state_code: + 2018: NV + h3: + members: [p3_1, p3_2, p3_3] + state_code: + 2018: NV + h4: + members: [p4_1, p4_2, p4_3] + state_code: + 2018: NV + h5: + members: [p5_1, p5_2, p5_3] + state_code: + 2018: NV + is_homeless: + 2018: true + h6: + members: [p6_1, p6_2, p6_3] + state_code: + 2018: NV + output: + # 1.3 * 20_780 / 12 = 2_251.17, which rounds to $2,251. + # Units 3-5 keep 85% of SMI ($4,259.78) for a foster child, a child in protective + # services and a homeless family. Unit 6's 15-year-old in foster care is too old + # for CCDP, so the family faces the poverty-guideline limit. + nv_ccdp_income_eligible: [true, false, true, true, true, false] + +- name: In February 2019 a new applicant of three qualifies up to NWLC's $27,012 a year. + period: 2019-02 + input: + people: + p1_1: + age: + 2019: 30 + p1_2: + age: + 2019: 5 + p1_3: + age: + 2019: 5 + p2_1: + age: + 2019: 30 + p2_2: + age: + 2019: 5 + p2_3: + age: + 2019: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + nv_ccdp_countable_income: + 2019: 27_012 + nv_ccdp_enrolled: false + u2: + members: [p2_1, p2_2, p2_3] + nv_ccdp_countable_income: + 2019: 27_024 + nv_ccdp_enrolled: false + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2019: NV + h2: + members: [p2_1, p2_2, p2_3] + state_code: + 2019: NV + output: + # NWLC prints $27,012 a year for three, or $2,251 a month: 130% of the 2018 guideline. + nv_ccdp_income_eligible: [true, false] + +- name: In September 2019 a new applicant of three still faces the 2018 guideline. + period: 2019-09 + input: + people: + p1_1: + age: + 2019: 30 + p1_2: + age: + 2019: 5 + p1_3: + age: + 2019: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + nv_ccdp_countable_income: + 2019: 27_024 + nv_ccdp_enrolled: false + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2019: NV + output: + # The 2019 guideline would allow $2,311; Nevada takes it up on October 1. + nv_ccdp_income_eligible: [false] + +- name: In October 2019 a new applicant of three faces 130% of the 2019 guideline. + period: 2019-10 + input: + people: + p1_1: + age: + 2019: 30 + p1_2: + age: + 2019: 5 + p1_3: + age: + 2019: 5 + p2_1: + age: + 2019: 30 + p2_2: + age: + 2019: 5 + p2_3: + age: + 2019: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + nv_ccdp_countable_income: + 2019: 27_732 + nv_ccdp_enrolled: false + u2: + members: [p2_1, p2_2, p2_3] + nv_ccdp_countable_income: + 2019: 27_744 + nv_ccdp_enrolled: false + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2019: NV + h2: + members: [p2_1, p2_2, p2_3] + state_code: + 2019: NV + output: + # NWLC prints $27,729 a year from October 2019: 1.3 * 21_330 / 12 = 2_310.75, which rounds to $2,311. + nv_ccdp_income_eligible: [true, false] + +- name: Under the October 2020 chart new applicants of one to five qualify up to each printed limit. + period: 2020-10 + input: + people: + p1_1: + age: + 2020: 30 + p2_1: + age: + 2020: 30 + p3_1: + age: + 2020: 30 + p3_2: + age: + 2020: 5 + p4_1: + age: + 2020: 30 + p4_2: + age: + 2020: 5 + p5_1: + age: + 2020: 30 + p5_2: + age: + 2020: 5 + p5_3: + age: + 2020: 5 + p6_1: + age: + 2020: 30 + p6_2: + age: + 2020: 5 + p6_3: + age: + 2020: 5 + p7_1: + age: + 2020: 30 + p7_2: + age: + 2020: 5 + p7_3: + age: + 2020: 5 + p7_4: + age: + 2020: 5 + p8_1: + age: + 2020: 30 + p8_2: + age: + 2020: 5 + p8_3: + age: + 2020: 5 + p8_4: + age: + 2020: 5 + p9_1: + age: + 2020: 30 + p9_2: + age: + 2020: 5 + p9_3: + age: + 2020: 5 + p9_4: + age: + 2020: 5 + p9_5: + age: + 2020: 5 + p10_1: + age: + 2020: 30 + p10_2: + age: + 2020: 5 + p10_3: + age: + 2020: 5 + p10_4: + age: + 2020: 5 + p10_5: + age: + 2020: 5 + spm_units: + u1: + members: [p1_1] + nv_ccdp_countable_income: + 2020: 16_584 + nv_ccdp_enrolled: false + u2: + members: [p2_1] + nv_ccdp_countable_income: + 2020: 16_596 + nv_ccdp_enrolled: false + u3: + members: [p3_1, p3_2] + nv_ccdp_countable_income: + 2020: 22_416 + nv_ccdp_enrolled: false + u4: + members: [p4_1, p4_2] + nv_ccdp_countable_income: + 2020: 22_428 + nv_ccdp_enrolled: false + u5: + members: [p5_1, p5_2, p5_3] + nv_ccdp_countable_income: + 2020: 28_236 + nv_ccdp_enrolled: false + u6: + members: [p6_1, p6_2, p6_3] + nv_ccdp_countable_income: + 2020: 28_248 + nv_ccdp_enrolled: false + u7: + members: [p7_1, p7_2, p7_3, p7_4] + nv_ccdp_countable_income: + 2020: 34_056 + nv_ccdp_enrolled: false + u8: + members: [p8_1, p8_2, p8_3, p8_4] + nv_ccdp_countable_income: + 2020: 34_068 + nv_ccdp_enrolled: false + u9: + members: [p9_1, p9_2, p9_3, p9_4, p9_5] + nv_ccdp_countable_income: + 2020: 39_888 + nv_ccdp_enrolled: false + u10: + members: [p10_1, p10_2, p10_3, p10_4, p10_5] + nv_ccdp_countable_income: + 2020: 39_900 + nv_ccdp_enrolled: false + households: + h1: + members: [p1_1] + state_code: + 2020: NV + h2: + members: [p2_1] + state_code: + 2020: NV + h3: + members: [p3_1, p3_2] + state_code: + 2020: NV + h4: + members: [p4_1, p4_2] + state_code: + 2020: NV + h5: + members: [p5_1, p5_2, p5_3] + state_code: + 2020: NV + h6: + members: [p6_1, p6_2, p6_3] + state_code: + 2020: NV + h7: + members: [p7_1, p7_2, p7_3, p7_4] + state_code: + 2020: NV + h8: + members: [p8_1, p8_2, p8_3, p8_4] + state_code: + 2020: NV + h9: + members: [p9_1, p9_2, p9_3, p9_4, p9_5] + state_code: + 2020: NV + h10: + members: [p10_1, p10_2, p10_3, p10_4, p10_5] + state_code: + 2020: NV + output: + # The draft FFY 2022-2024 plan prints $1,382, $1,868, $2,353, $2,838 and $3,324 for one + # to five people from October 1, 2020: 130% of the 2020 guideline to the nearest dollar. + nv_ccdp_income_eligible: [true, false, true, false, true, false, true, false, true, false] + +- name: In September 2021 a new applicant of three still faces the 2020 guideline. + period: 2021-09 + input: + people: + p1_1: + age: + 2021: 30 + p1_2: + age: + 2021: 5 + p1_3: + age: + 2021: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + nv_ccdp_countable_income: + 2021: 28_248 + nv_ccdp_enrolled: false + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2021: NV + output: + # The 2021 guideline would allow $2,379; Nevada takes it up on October 1. + nv_ccdp_income_eligible: [false] + +- name: In October 2021 a new applicant of three faces 130% of the 2021 guideline. + period: 2021-10 + input: + people: + p1_1: + age: + 2021: 30 + p1_2: + age: + 2021: 5 + p1_3: + age: + 2021: 5 + p2_1: + age: + 2021: 30 + p2_2: + age: + 2021: 5 + p2_3: + age: + 2021: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + nv_ccdp_countable_income: + 2021: 28_548 + nv_ccdp_enrolled: false + u2: + members: [p2_1, p2_2, p2_3] + nv_ccdp_countable_income: + 2021: 28_560 + nv_ccdp_enrolled: false + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2021: NV + h2: + members: [p2_1, p2_2, p2_3] + state_code: + 2021: NV + output: + # Urban's Table B-1 prints the state's $2,379 for October 1, 2021: 1.3 * 21_960 / 12 = 2_379. + nv_ccdp_income_eligible: [true, false] + +- name: In June 2022 a new applicant of three still faces 130% of the 2021 guideline. + period: 2022-06 + input: + people: + p1_1: + age: + 2022: 30 + p1_2: + age: + 2022: 5 + p1_3: + age: + 2022: 5 + p2_1: + age: + 2022: 30 + p2_2: + age: + 2022: 5 + p2_3: + age: + 2022: 5 + spm_units: + u1: + members: [p1_1, p1_2, p1_3] + nv_ccdp_countable_income: + 2022: 28_548 + nv_ccdp_enrolled: false + u2: + members: [p2_1, p2_2, p2_3] + nv_ccdp_countable_income: + 2022: 28_560 + nv_ccdp_enrolled: false + households: + h1: + members: [p1_1, p1_2, p1_3] + state_code: + 2022: NV + h2: + members: [p2_1, p2_2, p2_3] + state_code: + 2022: NV + output: + # The limit moves to 85% of SMI on July 1, 2022. + nv_ccdp_income_eligible: [true, false] + +- name: In July 2022 a new applicant of three at $5,000 qualifies on the fiscal year 2023 table. + period: 2022-07 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2022: 60_000 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2022: NV + output: + # The October 2021 table would give 4_909.29 and deny this family. + nv_ccdp_income_eligible: true + +- name: In July 2022 a new applicant of three at $5,066.49 rounds to $5,066 and qualifies. + period: 2022-07 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2022: 60_797.88 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2022: NV + output: + # MS 316 rounds monthly income to the nearest dollar. + nv_ccdp_income_eligible: true + +- name: In July 2022 a new applicant of three at $5,066.50 rounds to $5,067 and fails. + period: 2022-07 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2022: 60_798 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2022: NV + output: + nv_ccdp_income_eligible: false + +- name: In September 2022 a new applicant of three at $5,066 still qualifies on the fiscal year 2023 table. + period: 2022-09 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2022: 60_792 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2022: NV + output: + nv_ccdp_income_eligible: true + +- name: In October 2022 a new applicant of three at $5,067 fails on the fiscal year 2023 table. + period: 2022-10 + input: + people: + person1: + age: + 2022: 30 + person2: + age: + 2022: 5 + person3: + age: + 2022: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2022: 60_804 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2022: NV + output: + # The fiscal year 2023 table takes effect on its own start; the fiscal year 2024 table would give 5_314.84. + nv_ccdp_income_eligible: false + +- name: Under the October 2025 chart a new applicant of 3 at $2,890 qualifies. + period: 2025-10 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + person3: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2025: 34_680 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2025: NV + output: + # CC PT 06-25 prints $2,890 for three: 41% * 100_681 * 0.84 / 12 = 2_889.54, rounded to the nearest dollar. + nv_ccdp_income_eligible: true + +- name: Under the October 2025 chart a new applicant of 3 at $2,891 fails. + period: 2025-10 + input: + people: + person1: + age: + 2025: 30 + person2: + age: + 2025: 5 + person3: + age: + 2025: 5 + spm_units: + spm_unit: + members: [person1, person2, person3] + nv_ccdp_countable_income: + 2025: 34_692 + nv_ccdp_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: + 2025: NV + output: + nv_ccdp_income_eligible: false + +- name: Under the October 2025 chart a new applicant of 1 at $1,789 qualifies. + period: 2025-10 + input: + people: + person1: + age: + 2025: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2025: 21_468 + nv_ccdp_enrolled: false + households: + household: + members: [person1] + state_code: + 2025: NV + output: + # CC PT 06-25 prints $1,789 for one: 41% * 100_681 * 0.52 / 12 = 1_788.77. + nv_ccdp_income_eligible: true + +- name: Under the October 2025 chart a new applicant of 1 at $1,790 fails. + period: 2025-10 + input: + people: + person1: + age: + 2025: 30 + spm_units: + spm_unit: + members: [person1] + nv_ccdp_countable_income: + 2025: 21_480 + nv_ccdp_enrolled: false + households: + household: + members: [person1] + state_code: + 2025: NV + output: + nv_ccdp_income_eligible: false + +- name: Under the October 2026 chart a renewing family of 4 at $4,289 qualifies. + period: 2026-10 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 5 + person3: + age: + 2026: 5 + person4: + age: + 2026: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + nv_ccdp_countable_income: + 2026: 51_468 + nv_ccdp_enrolled: true + households: + household: + members: [person1, person2, person3, person4] + state_code: + 2026: NV + output: + # The chart prints $4,289 for four: 49% * 105_027 / 12 = 4_288.60, rounded to the nearest dollar. + nv_ccdp_income_eligible: true + +# Posted charts: each printed family size at its top passes and a dollar more +# fails. Each case sets the unit's size directly and lists the outcomes in size +# order, the top first. +# Nevada's countable income is annual, so each case gives twelve times the +# monthly amount. + +- name: The October 1, 2026 intake chart holds at sizes 1 to 12. + period: 2026-10 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + p23: + age: + 2026: 30 + p24: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 1 + nv_ccdp_countable_income: + 2026: 22_392 + nv_ccdp_enrolled: false + u2: + members: [p2] + spm_unit_size: + 2026: 1 + nv_ccdp_countable_income: + 2026: 22_404 + nv_ccdp_enrolled: false + u3: + members: [p3] + spm_unit_size: + 2026: 2 + nv_ccdp_countable_income: + 2026: 29_280 + nv_ccdp_enrolled: false + u4: + members: [p4] + spm_unit_size: + 2026: 2 + nv_ccdp_countable_income: + 2026: 29_292 + nv_ccdp_enrolled: false + u5: + members: [p5] + spm_unit_size: + 2026: 3 + nv_ccdp_countable_income: + 2026: 36_168 + nv_ccdp_enrolled: false + u6: + members: [p6] + spm_unit_size: + 2026: 3 + nv_ccdp_countable_income: + 2026: 36_180 + nv_ccdp_enrolled: false + u7: + members: [p7] + spm_unit_size: + 2026: 4 + nv_ccdp_countable_income: + 2026: 43_056 + nv_ccdp_enrolled: false + u8: + members: [p8] + spm_unit_size: + 2026: 4 + nv_ccdp_countable_income: + 2026: 43_068 + nv_ccdp_enrolled: false + u9: + members: [p9] + spm_unit_size: + 2026: 5 + nv_ccdp_countable_income: + 2026: 49_956 + nv_ccdp_enrolled: false + u10: + members: [p10] + spm_unit_size: + 2026: 5 + nv_ccdp_countable_income: + 2026: 49_968 + nv_ccdp_enrolled: false + u11: + members: [p11] + spm_unit_size: + 2026: 6 + nv_ccdp_countable_income: + 2026: 56_844 + nv_ccdp_enrolled: false + u12: + members: [p12] + spm_unit_size: + 2026: 6 + nv_ccdp_countable_income: + 2026: 56_856 + nv_ccdp_enrolled: false + u13: + members: [p13] + spm_unit_size: + 2026: 7 + nv_ccdp_countable_income: + 2026: 58_128 + nv_ccdp_enrolled: false + u14: + members: [p14] + spm_unit_size: + 2026: 7 + nv_ccdp_countable_income: + 2026: 58_140 + nv_ccdp_enrolled: false + u15: + members: [p15] + spm_unit_size: + 2026: 8 + nv_ccdp_countable_income: + 2026: 59_424 + nv_ccdp_enrolled: false + u16: + members: [p16] + spm_unit_size: + 2026: 8 + nv_ccdp_countable_income: + 2026: 59_436 + nv_ccdp_enrolled: false + u17: + members: [p17] + spm_unit_size: + 2026: 9 + nv_ccdp_countable_income: + 2026: 60_720 + nv_ccdp_enrolled: false + u18: + members: [p18] + spm_unit_size: + 2026: 9 + nv_ccdp_countable_income: + 2026: 60_732 + nv_ccdp_enrolled: false + u19: + members: [p19] + spm_unit_size: + 2026: 10 + nv_ccdp_countable_income: + 2026: 62_004 + nv_ccdp_enrolled: false + u20: + members: [p20] + spm_unit_size: + 2026: 10 + nv_ccdp_countable_income: + 2026: 62_016 + nv_ccdp_enrolled: false + u21: + members: [p21] + spm_unit_size: + 2026: 11 + nv_ccdp_countable_income: + 2026: 63_300 + nv_ccdp_enrolled: false + u22: + members: [p22] + spm_unit_size: + 2026: 11 + nv_ccdp_countable_income: + 2026: 63_312 + nv_ccdp_enrolled: false + u23: + members: [p23] + spm_unit_size: + 2026: 12 + nv_ccdp_countable_income: + 2026: 64_596 + nv_ccdp_enrolled: false + u24: + members: [p24] + spm_unit_size: + 2026: 12 + nv_ccdp_countable_income: + 2026: 64_608 + nv_ccdp_enrolled: false + households: + h1: + members: [p1] + state_code: + 2026: NV + h2: + members: [p2] + state_code: + 2026: NV + h3: + members: [p3] + state_code: + 2026: NV + h4: + members: [p4] + state_code: + 2026: NV + h5: + members: [p5] + state_code: + 2026: NV + h6: + members: [p6] + state_code: + 2026: NV + h7: + members: [p7] + state_code: + 2026: NV + h8: + members: [p8] + state_code: + 2026: NV + h9: + members: [p9] + state_code: + 2026: NV + h10: + members: [p10] + state_code: + 2026: NV + h11: + members: [p11] + state_code: + 2026: NV + h12: + members: [p12] + state_code: + 2026: NV + h13: + members: [p13] + state_code: + 2026: NV + h14: + members: [p14] + state_code: + 2026: NV + h15: + members: [p15] + state_code: + 2026: NV + h16: + members: [p16] + state_code: + 2026: NV + h17: + members: [p17] + state_code: + 2026: NV + h18: + members: [p18] + state_code: + 2026: NV + h19: + members: [p19] + state_code: + 2026: NV + h20: + members: [p20] + state_code: + 2026: NV + h21: + members: [p21] + state_code: + 2026: NV + h22: + members: [p22] + state_code: + 2026: NV + h23: + members: [p23] + state_code: + 2026: NV + h24: + members: [p24] + state_code: + 2026: NV + output: + # Household Size and Monthly Income Chart (Intake 41% SMI), sizes 1 to 12. + nv_ccdp_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: The October 1, 2026 renewal chart holds at sizes 1 to 12. + period: 2026-10 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + p23: + age: + 2026: 30 + p24: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 1 + nv_ccdp_countable_income: + 2026: 26_760 + nv_ccdp_enrolled: true + u2: + members: [p2] + spm_unit_size: + 2026: 1 + nv_ccdp_countable_income: + 2026: 26_772 + nv_ccdp_enrolled: true + u3: + members: [p3] + spm_unit_size: + 2026: 2 + nv_ccdp_countable_income: + 2026: 34_992 + nv_ccdp_enrolled: true + u4: + members: [p4] + spm_unit_size: + 2026: 2 + nv_ccdp_countable_income: + 2026: 35_004 + nv_ccdp_enrolled: true + u5: + members: [p5] + spm_unit_size: + 2026: 3 + nv_ccdp_countable_income: + 2026: 43_224 + nv_ccdp_enrolled: true + u6: + members: [p6] + spm_unit_size: + 2026: 3 + nv_ccdp_countable_income: + 2026: 43_236 + nv_ccdp_enrolled: true + u7: + members: [p7] + spm_unit_size: + 2026: 4 + nv_ccdp_countable_income: + 2026: 51_468 + nv_ccdp_enrolled: true + u8: + members: [p8] + spm_unit_size: + 2026: 4 + nv_ccdp_countable_income: + 2026: 51_480 + nv_ccdp_enrolled: true + u9: + members: [p9] + spm_unit_size: + 2026: 5 + nv_ccdp_countable_income: + 2026: 59_700 + nv_ccdp_enrolled: true + u10: + members: [p10] + spm_unit_size: + 2026: 5 + nv_ccdp_countable_income: + 2026: 59_712 + nv_ccdp_enrolled: true + u11: + members: [p11] + spm_unit_size: + 2026: 6 + nv_ccdp_countable_income: + 2026: 67_932 + nv_ccdp_enrolled: true + u12: + members: [p12] + spm_unit_size: + 2026: 6 + nv_ccdp_countable_income: + 2026: 67_944 + nv_ccdp_enrolled: true + u13: + members: [p13] + spm_unit_size: + 2026: 7 + nv_ccdp_countable_income: + 2026: 69_480 + nv_ccdp_enrolled: true + u14: + members: [p14] + spm_unit_size: + 2026: 7 + nv_ccdp_countable_income: + 2026: 69_492 + nv_ccdp_enrolled: true + u15: + members: [p15] + spm_unit_size: + 2026: 8 + nv_ccdp_countable_income: + 2026: 71_016 + nv_ccdp_enrolled: true + u16: + members: [p16] + spm_unit_size: + 2026: 8 + nv_ccdp_countable_income: + 2026: 71_028 + nv_ccdp_enrolled: true + u17: + members: [p17] + spm_unit_size: + 2026: 9 + nv_ccdp_countable_income: + 2026: 72_564 + nv_ccdp_enrolled: true + u18: + members: [p18] + spm_unit_size: + 2026: 9 + nv_ccdp_countable_income: + 2026: 72_576 + nv_ccdp_enrolled: true + u19: + members: [p19] + spm_unit_size: + 2026: 10 + nv_ccdp_countable_income: + 2026: 74_112 + nv_ccdp_enrolled: true + u20: + members: [p20] + spm_unit_size: + 2026: 10 + nv_ccdp_countable_income: + 2026: 74_124 + nv_ccdp_enrolled: true + u21: + members: [p21] + spm_unit_size: + 2026: 11 + nv_ccdp_countable_income: + 2026: 75_648 + nv_ccdp_enrolled: true + u22: + members: [p22] + spm_unit_size: + 2026: 11 + nv_ccdp_countable_income: + 2026: 75_660 + nv_ccdp_enrolled: true + u23: + members: [p23] + spm_unit_size: + 2026: 12 + nv_ccdp_countable_income: + 2026: 77_196 + nv_ccdp_enrolled: true + u24: + members: [p24] + spm_unit_size: + 2026: 12 + nv_ccdp_countable_income: + 2026: 77_208 + nv_ccdp_enrolled: true + households: + h1: + members: [p1] + state_code: + 2026: NV + h2: + members: [p2] + state_code: + 2026: NV + h3: + members: [p3] + state_code: + 2026: NV + h4: + members: [p4] + state_code: + 2026: NV + h5: + members: [p5] + state_code: + 2026: NV + h6: + members: [p6] + state_code: + 2026: NV + h7: + members: [p7] + state_code: + 2026: NV + h8: + members: [p8] + state_code: + 2026: NV + h9: + members: [p9] + state_code: + 2026: NV + h10: + members: [p10] + state_code: + 2026: NV + h11: + members: [p11] + state_code: + 2026: NV + h12: + members: [p12] + state_code: + 2026: NV + h13: + members: [p13] + state_code: + 2026: NV + h14: + members: [p14] + state_code: + 2026: NV + h15: + members: [p15] + state_code: + 2026: NV + h16: + members: [p16] + state_code: + 2026: NV + h17: + members: [p17] + state_code: + 2026: NV + h18: + members: [p18] + state_code: + 2026: NV + h19: + members: [p19] + state_code: + 2026: NV + h20: + members: [p20] + state_code: + 2026: NV + h21: + members: [p21] + state_code: + 2026: NV + h22: + members: [p22] + state_code: + 2026: NV + h23: + members: [p23] + state_code: + 2026: NV + h24: + members: [p24] + state_code: + 2026: NV + output: + # Household Size and Monthly Income Chart (Renewal 49% SMI), sizes 1 to 12. + nv_ccdp_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.yaml index 22e20c2bda4..527f15d6021 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.yaml @@ -217,7 +217,52 @@ # Category 1 center full-time: 780 + 693.33. oh_ccvp: 1_473.33 -- name: November 2026 adds no quality enhancement. +- name: November 2026 adds no Step Up to Quality bonus. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + pre_subsidy_childcare_expenses: + 2026: 24_000 + childcare_hours_per_week: + 2026: 40 + oh_ccap_quality_tier: GOLD + person3: + age: + 2026: 4 + immigration_status: + 2026: CITIZEN + pre_subsidy_childcare_expenses: + 2026: 24_000 + childcare_hours_per_week: + 2026: 40 + oh_ccap_quality_tier: GOLD + spm_units: + spm_unit: + members: [person1, person2, person3] + oh_ccap_countable_income: 3_500 + households: + household: + members: [person1, person2, person3] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # H.B. 96, Section 423.190, rules out Step Up to Quality rates: 780 + 693.33. + oh_ccvp: 1_473.33 + +- name: November 2026 adds the accreditation payment at an accredited gold-rated center. period: 2026-11 absolute_error_margin: 0.01 input: @@ -261,9 +306,9 @@ county_str: 2026: BROWN_COUNTY_OH output: - # H.B. 96, Section 423.190, rules out Step Up to Quality rates. Accreditation stays out too; - # the pull request lists this as a reading. - oh_ccvp: 1_473.33 + # H.B. 96, Section 423.190, rules out only the Step Up to Quality rates, so 5180:6-1-10(D)(1) + # adds 10%: 780 x 1.10 + 693.33 x 1.10 = 858 + 762.67. + oh_ccvp: 1_620.67 - name: November 2026 caps the payment at the charge. period: 2026-11 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.yaml index 39c21d605ba..622377ba7b9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.yaml @@ -943,3 +943,1376 @@ state_code: PA output: oh_ccvp_eligible: false + +# Posted charts: a working parent with children of five at the voucher's printed top +# qualifies and a dollar more fails, at each printed family size in size order. + +- name: Procedure Letter 21's voucher limits hold at every family size in January 2026. + period: 2026-01 + input: + people: + p1_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p1_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p2_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p2_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p3_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p3_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p3_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p4_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p4_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p4_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p5_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p5_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p5_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p5_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p6_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p6_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p6_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p6_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p7_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p7_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p7_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p7_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p7_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p8_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p8_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p8_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p8_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p8_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p9_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p9_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p9_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p9_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p9_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p9_6: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p10_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p10_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p10_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p10_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p10_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p10_6: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p11_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p11_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p11_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p11_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p11_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p11_6: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p11_7: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p12_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p12_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p12_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p12_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p12_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p12_6: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p12_7: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p13_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_6: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_7: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_8: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p14_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_6: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_7: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_8: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + spm_units: + u1: + members: [p1_1, p1_2] + oh_ccap_countable_income: 3_525 + u2: + members: [p2_1, p2_2] + oh_ccap_countable_income: 3_526 + u3: + members: [p3_1, p3_2, p3_3] + oh_ccap_countable_income: 4_442 + u4: + members: [p4_1, p4_2, p4_3] + oh_ccap_countable_income: 4_443 + u5: + members: [p5_1, p5_2, p5_3, p5_4] + oh_ccap_countable_income: 5_359 + u6: + members: [p6_1, p6_2, p6_3, p6_4] + oh_ccap_countable_income: 5_360 + u7: + members: [p7_1, p7_2, p7_3, p7_4, p7_5] + oh_ccap_countable_income: 6_275 + u8: + members: [p8_1, p8_2, p8_3, p8_4, p8_5] + oh_ccap_countable_income: 6_276 + u9: + members: [p9_1, p9_2, p9_3, p9_4, p9_5, p9_6] + oh_ccap_countable_income: 7_192 + u10: + members: [p10_1, p10_2, p10_3, p10_4, p10_5, p10_6] + oh_ccap_countable_income: 7_193 + u11: + members: [p11_1, p11_2, p11_3, p11_4, p11_5, p11_6, p11_7] + oh_ccap_countable_income: 8_109 + u12: + members: [p12_1, p12_2, p12_3, p12_4, p12_5, p12_6, p12_7] + oh_ccap_countable_income: 8_110 + u13: + members: [p13_1, p13_2, p13_3, p13_4, p13_5, p13_6, p13_7, p13_8] + oh_ccap_countable_income: 9_025 + u14: + members: [p14_1, p14_2, p14_3, p14_4, p14_5, p14_6, p14_7, p14_8] + oh_ccap_countable_income: 9_026 + tax_units: + t1: + members: [p1_1, p1_2] + t2: + members: [p2_1, p2_2] + t3: + members: [p3_1, p3_2, p3_3] + t4: + members: [p4_1, p4_2, p4_3] + t5: + members: [p5_1, p5_2, p5_3, p5_4] + t6: + members: [p6_1, p6_2, p6_3, p6_4] + t7: + members: [p7_1, p7_2, p7_3, p7_4, p7_5] + t8: + members: [p8_1, p8_2, p8_3, p8_4, p8_5] + t9: + members: [p9_1, p9_2, p9_3, p9_4, p9_5, p9_6] + t10: + members: [p10_1, p10_2, p10_3, p10_4, p10_5, p10_6] + t11: + members: [p11_1, p11_2, p11_3, p11_4, p11_5, p11_6, p11_7] + t12: + members: [p12_1, p12_2, p12_3, p12_4, p12_5, p12_6, p12_7] + t13: + members: [p13_1, p13_2, p13_3, p13_4, p13_5, p13_6, p13_7, p13_8] + t14: + members: [p14_1, p14_2, p14_3, p14_4, p14_5, p14_6, p14_7, p14_8] + families: + f1: + members: [p1_1, p1_2] + f2: + members: [p2_1, p2_2] + f3: + members: [p3_1, p3_2, p3_3] + f4: + members: [p4_1, p4_2, p4_3] + f5: + members: [p5_1, p5_2, p5_3, p5_4] + f6: + members: [p6_1, p6_2, p6_3, p6_4] + f7: + members: [p7_1, p7_2, p7_3, p7_4, p7_5] + f8: + members: [p8_1, p8_2, p8_3, p8_4, p8_5] + f9: + members: [p9_1, p9_2, p9_3, p9_4, p9_5, p9_6] + f10: + members: [p10_1, p10_2, p10_3, p10_4, p10_5, p10_6] + f11: + members: [p11_1, p11_2, p11_3, p11_4, p11_5, p11_6, p11_7] + f12: + members: [p12_1, p12_2, p12_3, p12_4, p12_5, p12_6, p12_7] + f13: + members: [p13_1, p13_2, p13_3, p13_4, p13_5, p13_6, p13_7, p13_8] + f14: + members: [p14_1, p14_2, p14_3, p14_4, p14_5, p14_6, p14_7, p14_8] + marital_units: + m1_1: + members: [p1_1] + m1_2: + members: [p1_2] + m2_1: + members: [p2_1] + m2_2: + members: [p2_2] + m3_1: + members: [p3_1] + m3_2: + members: [p3_2] + m3_3: + members: [p3_3] + m4_1: + members: [p4_1] + m4_2: + members: [p4_2] + m4_3: + members: [p4_3] + m5_1: + members: [p5_1] + m5_2: + members: [p5_2] + m5_3: + members: [p5_3] + m5_4: + members: [p5_4] + m6_1: + members: [p6_1] + m6_2: + members: [p6_2] + m6_3: + members: [p6_3] + m6_4: + members: [p6_4] + m7_1: + members: [p7_1] + m7_2: + members: [p7_2] + m7_3: + members: [p7_3] + m7_4: + members: [p7_4] + m7_5: + members: [p7_5] + m8_1: + members: [p8_1] + m8_2: + members: [p8_2] + m8_3: + members: [p8_3] + m8_4: + members: [p8_4] + m8_5: + members: [p8_5] + m9_1: + members: [p9_1] + m9_2: + members: [p9_2] + m9_3: + members: [p9_3] + m9_4: + members: [p9_4] + m9_5: + members: [p9_5] + m9_6: + members: [p9_6] + m10_1: + members: [p10_1] + m10_2: + members: [p10_2] + m10_3: + members: [p10_3] + m10_4: + members: [p10_4] + m10_5: + members: [p10_5] + m10_6: + members: [p10_6] + m11_1: + members: [p11_1] + m11_2: + members: [p11_2] + m11_3: + members: [p11_3] + m11_4: + members: [p11_4] + m11_5: + members: [p11_5] + m11_6: + members: [p11_6] + m11_7: + members: [p11_7] + m12_1: + members: [p12_1] + m12_2: + members: [p12_2] + m12_3: + members: [p12_3] + m12_4: + members: [p12_4] + m12_5: + members: [p12_5] + m12_6: + members: [p12_6] + m12_7: + members: [p12_7] + m13_1: + members: [p13_1] + m13_2: + members: [p13_2] + m13_3: + members: [p13_3] + m13_4: + members: [p13_4] + m13_5: + members: [p13_5] + m13_6: + members: [p13_6] + m13_7: + members: [p13_7] + m13_8: + members: [p13_8] + m14_1: + members: [p14_1] + m14_2: + members: [p14_2] + m14_3: + members: [p14_3] + m14_4: + members: [p14_4] + m14_5: + members: [p14_5] + m14_6: + members: [p14_6] + m14_7: + members: [p14_7] + m14_8: + members: [p14_8] + households: + h1: + members: [p1_1, p1_2] + state_code: + 2026: OH + h2: + members: [p2_1, p2_2] + state_code: + 2026: OH + h3: + members: [p3_1, p3_2, p3_3] + state_code: + 2026: OH + h4: + members: [p4_1, p4_2, p4_3] + state_code: + 2026: OH + h5: + members: [p5_1, p5_2, p5_3, p5_4] + state_code: + 2026: OH + h6: + members: [p6_1, p6_2, p6_3, p6_4] + state_code: + 2026: OH + h7: + members: [p7_1, p7_2, p7_3, p7_4, p7_5] + state_code: + 2026: OH + h8: + members: [p8_1, p8_2, p8_3, p8_4, p8_5] + state_code: + 2026: OH + h9: + members: [p9_1, p9_2, p9_3, p9_4, p9_5, p9_6] + state_code: + 2026: OH + h10: + members: [p10_1, p10_2, p10_3, p10_4, p10_5, p10_6] + state_code: + 2026: OH + h11: + members: [p11_1, p11_2, p11_3, p11_4, p11_5, p11_6, p11_7] + state_code: + 2026: OH + h12: + members: [p12_1, p12_2, p12_3, p12_4, p12_5, p12_6, p12_7] + state_code: + 2026: OH + h13: + members: [p13_1, p13_2, p13_3, p13_4, p13_5, p13_6, p13_7, p13_8] + state_code: + 2026: OH + h14: + members: [p14_1, p14_2, p14_3, p14_4, p14_5, p14_6, p14_7, p14_8] + state_code: + 2026: OH + output: + # 200% of the 2025 guideline, rounded up, sizes 2 to 8. + oh_ccvp_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: Procedure Letter 45's voucher limits hold at every family size in October 2026. + period: 2026-10 + input: + people: + p1_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p1_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p2_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p2_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p3_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p3_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p3_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p4_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p4_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p4_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p5_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p5_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p5_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p5_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p6_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p6_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p6_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p6_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p7_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p7_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p7_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p7_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p7_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p8_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p8_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p8_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p8_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p8_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p9_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p9_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p9_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p9_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p9_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p9_6: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p10_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p10_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p10_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p10_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p10_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p10_6: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p11_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p11_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p11_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p11_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p11_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p11_6: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p11_7: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p12_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p12_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p12_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p12_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p12_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p12_6: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p12_7: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p13_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_6: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_7: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p13_8: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_1: + age: + 2026: 30 + weekly_hours_worked_before_lsr: + 2026: 40 + immigration_status: + 2026: CITIZEN + p14_2: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_3: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_4: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_5: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_6: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_7: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + p14_8: + age: + 2026: 5 + immigration_status: + 2026: CITIZEN + spm_units: + u1: + members: [p1_1, p1_2] + oh_ccap_countable_income: 3_607 + u2: + members: [p2_1, p2_2] + oh_ccap_countable_income: 3_608 + u3: + members: [p3_1, p3_2, p3_3] + oh_ccap_countable_income: 4_554 + u4: + members: [p4_1, p4_2, p4_3] + oh_ccap_countable_income: 4_555 + u5: + members: [p5_1, p5_2, p5_3, p5_4] + oh_ccap_countable_income: 5_500 + u6: + members: [p6_1, p6_2, p6_3, p6_4] + oh_ccap_countable_income: 5_501 + u7: + members: [p7_1, p7_2, p7_3, p7_4, p7_5] + oh_ccap_countable_income: 6_447 + u8: + members: [p8_1, p8_2, p8_3, p8_4, p8_5] + oh_ccap_countable_income: 6_448 + u9: + members: [p9_1, p9_2, p9_3, p9_4, p9_5, p9_6] + oh_ccap_countable_income: 7_394 + u10: + members: [p10_1, p10_2, p10_3, p10_4, p10_5, p10_6] + oh_ccap_countable_income: 7_395 + u11: + members: [p11_1, p11_2, p11_3, p11_4, p11_5, p11_6, p11_7] + oh_ccap_countable_income: 8_340 + u12: + members: [p12_1, p12_2, p12_3, p12_4, p12_5, p12_6, p12_7] + oh_ccap_countable_income: 8_341 + u13: + members: [p13_1, p13_2, p13_3, p13_4, p13_5, p13_6, p13_7, p13_8] + oh_ccap_countable_income: 9_287 + u14: + members: [p14_1, p14_2, p14_3, p14_4, p14_5, p14_6, p14_7, p14_8] + oh_ccap_countable_income: 9_288 + tax_units: + t1: + members: [p1_1, p1_2] + t2: + members: [p2_1, p2_2] + t3: + members: [p3_1, p3_2, p3_3] + t4: + members: [p4_1, p4_2, p4_3] + t5: + members: [p5_1, p5_2, p5_3, p5_4] + t6: + members: [p6_1, p6_2, p6_3, p6_4] + t7: + members: [p7_1, p7_2, p7_3, p7_4, p7_5] + t8: + members: [p8_1, p8_2, p8_3, p8_4, p8_5] + t9: + members: [p9_1, p9_2, p9_3, p9_4, p9_5, p9_6] + t10: + members: [p10_1, p10_2, p10_3, p10_4, p10_5, p10_6] + t11: + members: [p11_1, p11_2, p11_3, p11_4, p11_5, p11_6, p11_7] + t12: + members: [p12_1, p12_2, p12_3, p12_4, p12_5, p12_6, p12_7] + t13: + members: [p13_1, p13_2, p13_3, p13_4, p13_5, p13_6, p13_7, p13_8] + t14: + members: [p14_1, p14_2, p14_3, p14_4, p14_5, p14_6, p14_7, p14_8] + families: + f1: + members: [p1_1, p1_2] + f2: + members: [p2_1, p2_2] + f3: + members: [p3_1, p3_2, p3_3] + f4: + members: [p4_1, p4_2, p4_3] + f5: + members: [p5_1, p5_2, p5_3, p5_4] + f6: + members: [p6_1, p6_2, p6_3, p6_4] + f7: + members: [p7_1, p7_2, p7_3, p7_4, p7_5] + f8: + members: [p8_1, p8_2, p8_3, p8_4, p8_5] + f9: + members: [p9_1, p9_2, p9_3, p9_4, p9_5, p9_6] + f10: + members: [p10_1, p10_2, p10_3, p10_4, p10_5, p10_6] + f11: + members: [p11_1, p11_2, p11_3, p11_4, p11_5, p11_6, p11_7] + f12: + members: [p12_1, p12_2, p12_3, p12_4, p12_5, p12_6, p12_7] + f13: + members: [p13_1, p13_2, p13_3, p13_4, p13_5, p13_6, p13_7, p13_8] + f14: + members: [p14_1, p14_2, p14_3, p14_4, p14_5, p14_6, p14_7, p14_8] + marital_units: + m1_1: + members: [p1_1] + m1_2: + members: [p1_2] + m2_1: + members: [p2_1] + m2_2: + members: [p2_2] + m3_1: + members: [p3_1] + m3_2: + members: [p3_2] + m3_3: + members: [p3_3] + m4_1: + members: [p4_1] + m4_2: + members: [p4_2] + m4_3: + members: [p4_3] + m5_1: + members: [p5_1] + m5_2: + members: [p5_2] + m5_3: + members: [p5_3] + m5_4: + members: [p5_4] + m6_1: + members: [p6_1] + m6_2: + members: [p6_2] + m6_3: + members: [p6_3] + m6_4: + members: [p6_4] + m7_1: + members: [p7_1] + m7_2: + members: [p7_2] + m7_3: + members: [p7_3] + m7_4: + members: [p7_4] + m7_5: + members: [p7_5] + m8_1: + members: [p8_1] + m8_2: + members: [p8_2] + m8_3: + members: [p8_3] + m8_4: + members: [p8_4] + m8_5: + members: [p8_5] + m9_1: + members: [p9_1] + m9_2: + members: [p9_2] + m9_3: + members: [p9_3] + m9_4: + members: [p9_4] + m9_5: + members: [p9_5] + m9_6: + members: [p9_6] + m10_1: + members: [p10_1] + m10_2: + members: [p10_2] + m10_3: + members: [p10_3] + m10_4: + members: [p10_4] + m10_5: + members: [p10_5] + m10_6: + members: [p10_6] + m11_1: + members: [p11_1] + m11_2: + members: [p11_2] + m11_3: + members: [p11_3] + m11_4: + members: [p11_4] + m11_5: + members: [p11_5] + m11_6: + members: [p11_6] + m11_7: + members: [p11_7] + m12_1: + members: [p12_1] + m12_2: + members: [p12_2] + m12_3: + members: [p12_3] + m12_4: + members: [p12_4] + m12_5: + members: [p12_5] + m12_6: + members: [p12_6] + m12_7: + members: [p12_7] + m13_1: + members: [p13_1] + m13_2: + members: [p13_2] + m13_3: + members: [p13_3] + m13_4: + members: [p13_4] + m13_5: + members: [p13_5] + m13_6: + members: [p13_6] + m13_7: + members: [p13_7] + m13_8: + members: [p13_8] + m14_1: + members: [p14_1] + m14_2: + members: [p14_2] + m14_3: + members: [p14_3] + m14_4: + members: [p14_4] + m14_5: + members: [p14_5] + m14_6: + members: [p14_6] + m14_7: + members: [p14_7] + m14_8: + members: [p14_8] + households: + h1: + members: [p1_1, p1_2] + state_code: + 2026: OH + h2: + members: [p2_1, p2_2] + state_code: + 2026: OH + h3: + members: [p3_1, p3_2, p3_3] + state_code: + 2026: OH + h4: + members: [p4_1, p4_2, p4_3] + state_code: + 2026: OH + h5: + members: [p5_1, p5_2, p5_3, p5_4] + state_code: + 2026: OH + h6: + members: [p6_1, p6_2, p6_3, p6_4] + state_code: + 2026: OH + h7: + members: [p7_1, p7_2, p7_3, p7_4, p7_5] + state_code: + 2026: OH + h8: + members: [p8_1, p8_2, p8_3, p8_4, p8_5] + state_code: + 2026: OH + h9: + members: [p9_1, p9_2, p9_3, p9_4, p9_5, p9_6] + state_code: + 2026: OH + h10: + members: [p10_1, p10_2, p10_3, p10_4, p10_5, p10_6] + state_code: + 2026: OH + h11: + members: [p11_1, p11_2, p11_3, p11_4, p11_5, p11_6, p11_7] + state_code: + 2026: OH + h12: + members: [p12_1, p12_2, p12_3, p12_4, p12_5, p12_6, p12_7] + state_code: + 2026: OH + h13: + members: [p13_1, p13_2, p13_3, p13_4, p13_5, p13_6, p13_7, p13_8] + state_code: + 2026: OH + h14: + members: [p14_1, p14_2, p14_3, p14_4, p14_5, p14_6, p14_7, p14_8] + state_code: + 2026: OH + output: + # 200% of the 2026 guideline, rounded up, sizes 2 to 8. + oh_ccvp_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.yaml index 15a90ea1e1e..e1ebb821702 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.yaml @@ -1,6 +1,8 @@ # Procedure Letter 36, pages 2-3: monthly voucher payment by provider type and age from November 1, 2025. # H.B. 96, Section 423.190: Publicly Funded Child Care payment rates by November 1, 2026, without the -# Step Up to Quality enhancement. +# Step Up to Quality enhancement. OAC 5180:6-1-10(B)(1) caps the base at the provider's customary +# charge, and its (D), (F) and (G) add-ons for accreditation, non-traditional hours and special needs +# apply. - name: January 2026 center rate for an infant. period: 2026-01 @@ -318,6 +320,8 @@ 2026: CITIZEN childcare_hours_per_week: 2026: 40 + pre_subsidy_childcare_expenses: + 2026: 24_000 spm_units: spm_unit: members: [person1, person2] @@ -347,6 +351,8 @@ 2026: CITIZEN childcare_hours_per_week: 2026: 40 + pre_subsidy_childcare_expenses: + 2026: 24_000 oh_ccap_provider_type: HOME spm_units: spm_unit: @@ -377,6 +383,8 @@ 2026: CITIZEN childcare_hours_per_week: 2026: 40 + pre_subsidy_childcare_expenses: + 2026: 24_000 spm_units: spm_unit: members: [person1, person2] @@ -405,6 +413,8 @@ 2026: CITIZEN childcare_hours_per_week: 2026: 0 + pre_subsidy_childcare_expenses: + 2026: 24_000 spm_units: spm_unit: members: [person1, person2] @@ -417,3 +427,351 @@ 2026: BROWN_COUNTY_OH output: oh_ccvp_rate: [0, 0] + +- name: A six-year-old outside school takes the school-age center rate. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 6 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + is_in_k12_school: false + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + # Procedure Letter 36, page 3: the school-age row covers children eligible to enroll in kindergarten. + oh_ccvp_rate: [0, 375] + +- name: A six-year-old outside school takes the school-age home rate. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 6 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + is_in_k12_school: false + oh_ccap_provider_type: HOME + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 300] + +- name: A four-year-old already in kindergarten takes the school-age center rate. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + is_in_k12_school: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 375] + +- name: A four-year-old outside school keeps the preschool center rate. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + immigration_status: CITIZEN + childcare_hours_per_week: 40 + is_in_k12_school: false + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_ccvp_rate: [0, 750] + +- name: November 2026 adds no Step Up to Quality bonus at a gold-rated center. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + pre_subsidy_childcare_expenses: + 2026: 24_000 + oh_ccap_quality_tier: GOLD + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # Publicly Funded Child Care would pay 780 x 1.25 = 975; H.B. 96 leaves the 25% out. + oh_ccvp_rate: [0, 780] + +- name: November 2026 adds the accreditation payment. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + pre_subsidy_childcare_expenses: + 2026: 24_000 + oh_ccap_is_accredited: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # 5180:6-1-10(D)(1): 780 x 1.10 = 858. + oh_ccvp_rate: [0, 858] + +- name: November 2026 adds the accreditation payment, not the larger gold bonus, at an accredited gold-rated center. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + pre_subsidy_childcare_expenses: + 2026: 24_000 + oh_ccap_quality_tier: GOLD + oh_ccap_is_accredited: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # Without (C), (D)(2)'s higher of the two leaves the accreditation payment: 780 x 1.10 = 858. + oh_ccvp_rate: [0, 858] + +- name: November 2026 adds the special needs payment. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + pre_subsidy_childcare_expenses: + 2026: 24_000 + is_disabled: + 2026: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # 5180:6-1-10(G)(1): 780 + 5% x 780 = 819. + oh_ccvp_rate: [0, 819] + +- name: November 2026 adds the non-traditional hours payment. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + pre_subsidy_childcare_expenses: + 2026: 24_000 + oh_ccap_non_traditional_hours: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # 5180:6-1-10(F)(1): 780 + 5% x 780 = 819. + oh_ccvp_rate: [0, 819] + +- name: November 2026 doubles the rate for approved special accommodations. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + pre_subsidy_childcare_expenses: + 2026: 24_000 + is_disabled: + 2026: true + oh_ccap_has_special_accommodations: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # 5180:6-1-10(G)(2): 2 x 780 = 1,560. + oh_ccvp_rate: [0, 1560] + +- name: November 2026 takes a customary charge below the county rate as the base. + period: 2026-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + pre_subsidy_childcare_expenses: + 2026: 6_000 + oh_ccap_is_accredited: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # 5180:6-1-10(B)(1): min(780, 6,000 / 12) = 500; (D)(1) adds 10%: 550. + oh_ccvp_rate: [0, 550] + +- name: October 2026 adds nothing for special needs under the flat chart. + period: 2026-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 30 + person2: + age: + 2026: 2 + immigration_status: + 2026: CITIZEN + childcare_hours_per_week: + 2026: 40 + pre_subsidy_childcare_expenses: + 2026: 24_000 + is_disabled: + 2026: true + oh_ccap_is_accredited: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: OH + county_str: + 2026: BROWN_COUNTY_OH + output: + # Procedure Letter 36 pays a center toddler 800 a month with no add-ons. + oh_ccvp_rate: [0, 800] diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/oh_ccap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/oh_ccap_income_eligible.yaml index 6de9ab82f9d..c9805a46fe7 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/oh_ccap_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/dcy/ccap/oh_ccap_income_eligible.yaml @@ -475,3 +475,391 @@ state_code: OH output: oh_ccap_income_eligible: true + +# Posted charts: each printed family size at its top passes and a dollar more +# fails. Each case sets the unit's size directly and lists the outcomes in size +# order, the top first. + +- name: Procedure Letter 21's initial limits hold at every family size in January 2026. + period: 2026-01 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 2 + oh_ccap_countable_income: 2_556 + oh_ccap_enrolled: false + u2: + members: [p2] + spm_unit_size: + 2026: 2 + oh_ccap_countable_income: 2_557 + oh_ccap_enrolled: false + u3: + members: [p3] + spm_unit_size: + 2026: 3 + oh_ccap_countable_income: 3_221 + oh_ccap_enrolled: false + u4: + members: [p4] + spm_unit_size: + 2026: 3 + oh_ccap_countable_income: 3_222 + oh_ccap_enrolled: false + u5: + members: [p5] + spm_unit_size: + 2026: 4 + oh_ccap_countable_income: 3_885 + oh_ccap_enrolled: false + u6: + members: [p6] + spm_unit_size: + 2026: 4 + oh_ccap_countable_income: 3_886 + oh_ccap_enrolled: false + u7: + members: [p7] + spm_unit_size: + 2026: 5 + oh_ccap_countable_income: 4_550 + oh_ccap_enrolled: false + u8: + members: [p8] + spm_unit_size: + 2026: 5 + oh_ccap_countable_income: 4_551 + oh_ccap_enrolled: false + u9: + members: [p9] + spm_unit_size: + 2026: 6 + oh_ccap_countable_income: 5_214 + oh_ccap_enrolled: false + u10: + members: [p10] + spm_unit_size: + 2026: 6 + oh_ccap_countable_income: 5_215 + oh_ccap_enrolled: false + u11: + members: [p11] + spm_unit_size: + 2026: 7 + oh_ccap_countable_income: 5_879 + oh_ccap_enrolled: false + u12: + members: [p12] + spm_unit_size: + 2026: 7 + oh_ccap_countable_income: 5_880 + oh_ccap_enrolled: false + u13: + members: [p13] + spm_unit_size: + 2026: 8 + oh_ccap_countable_income: 6_544 + oh_ccap_enrolled: false + u14: + members: [p14] + spm_unit_size: + 2026: 8 + oh_ccap_countable_income: 6_545 + oh_ccap_enrolled: false + households: + h1: + members: [p1] + state_code: + 2026: OH + h2: + members: [p2] + state_code: + 2026: OH + h3: + members: [p3] + state_code: + 2026: OH + h4: + members: [p4] + state_code: + 2026: OH + h5: + members: [p5] + state_code: + 2026: OH + h6: + members: [p6] + state_code: + 2026: OH + h7: + members: [p7] + state_code: + 2026: OH + h8: + members: [p8] + state_code: + 2026: OH + h9: + members: [p9] + state_code: + 2026: OH + h10: + members: [p10] + state_code: + 2026: OH + h11: + members: [p11] + state_code: + 2026: OH + h12: + members: [p12] + state_code: + 2026: OH + h13: + members: [p13] + state_code: + 2026: OH + h14: + members: [p14] + state_code: + 2026: OH + output: + # 145% of the 2025 guideline, sizes 2 to 8. + oh_ccap_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: Procedure Letter 45's initial limits hold at every family size in October 2026. + period: 2026-10 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 2 + oh_ccap_countable_income: 2_615 + oh_ccap_enrolled: false + u2: + members: [p2] + spm_unit_size: + 2026: 2 + oh_ccap_countable_income: 2_616 + oh_ccap_enrolled: false + u3: + members: [p3] + spm_unit_size: + 2026: 3 + oh_ccap_countable_income: 3_302 + oh_ccap_enrolled: false + u4: + members: [p4] + spm_unit_size: + 2026: 3 + oh_ccap_countable_income: 3_303 + oh_ccap_enrolled: false + u5: + members: [p5] + spm_unit_size: + 2026: 4 + oh_ccap_countable_income: 3_988 + oh_ccap_enrolled: false + u6: + members: [p6] + spm_unit_size: + 2026: 4 + oh_ccap_countable_income: 3_989 + oh_ccap_enrolled: false + u7: + members: [p7] + spm_unit_size: + 2026: 5 + oh_ccap_countable_income: 4_674 + oh_ccap_enrolled: false + u8: + members: [p8] + spm_unit_size: + 2026: 5 + oh_ccap_countable_income: 4_675 + oh_ccap_enrolled: false + u9: + members: [p9] + spm_unit_size: + 2026: 6 + oh_ccap_countable_income: 5_361 + oh_ccap_enrolled: false + u10: + members: [p10] + spm_unit_size: + 2026: 6 + oh_ccap_countable_income: 5_362 + oh_ccap_enrolled: false + u11: + members: [p11] + spm_unit_size: + 2026: 7 + oh_ccap_countable_income: 6_047 + oh_ccap_enrolled: false + u12: + members: [p12] + spm_unit_size: + 2026: 7 + oh_ccap_countable_income: 6_048 + oh_ccap_enrolled: false + u13: + members: [p13] + spm_unit_size: + 2026: 8 + oh_ccap_countable_income: 6_733 + oh_ccap_enrolled: false + u14: + members: [p14] + spm_unit_size: + 2026: 8 + oh_ccap_countable_income: 6_734 + oh_ccap_enrolled: false + households: + h1: + members: [p1] + state_code: + 2026: OH + h2: + members: [p2] + state_code: + 2026: OH + h3: + members: [p3] + state_code: + 2026: OH + h4: + members: [p4] + state_code: + 2026: OH + h5: + members: [p5] + state_code: + 2026: OH + h6: + members: [p6] + state_code: + 2026: OH + h7: + members: [p7] + state_code: + 2026: OH + h8: + members: [p8] + state_code: + 2026: OH + h9: + members: [p9] + state_code: + 2026: OH + h10: + members: [p10] + state_code: + 2026: OH + h11: + members: [p11] + state_code: + 2026: OH + h12: + members: [p12] + state_code: + 2026: OH + h13: + members: [p13] + state_code: + 2026: OH + h14: + members: [p14] + state_code: + 2026: OH + output: + # 145% of the 2026 guideline, sizes 2 to 8. + oh_ccap_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml index 51bf833065f..2ab78bf2295 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml @@ -652,3 +652,233 @@ 2026: WV output: wv_ccap_income_eligible: false + +# Posted charts: each printed family size at its top passes and a dollar more +# fails. Each case sets the unit's size directly and lists the outcomes in size +# order, the top first. + +- name: Appendix A's FY 2024 scale holds at every family size in January 2026. + period: 2026-01 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 1 + wv_ccap_countable_income: 2_322 + u2: + members: [p2] + spm_unit_size: + 2026: 1 + wv_ccap_countable_income: 2_323 + u3: + members: [p3] + spm_unit_size: + 2026: 2 + wv_ccap_countable_income: 3_151 + u4: + members: [p4] + spm_unit_size: + 2026: 2 + wv_ccap_countable_income: 3_152 + u5: + members: [p5] + spm_unit_size: + 2026: 3 + wv_ccap_countable_income: 3_981 + u6: + members: [p6] + spm_unit_size: + 2026: 3 + wv_ccap_countable_income: 3_982 + u7: + members: [p7] + spm_unit_size: + 2026: 4 + wv_ccap_countable_income: 4_810 + u8: + members: [p8] + spm_unit_size: + 2026: 4 + wv_ccap_countable_income: 4_811 + u9: + members: [p9] + spm_unit_size: + 2026: 5 + wv_ccap_countable_income: 5_639 + u10: + members: [p10] + spm_unit_size: + 2026: 5 + wv_ccap_countable_income: 5_640 + u11: + members: [p11] + spm_unit_size: + 2026: 6 + wv_ccap_countable_income: 6_469 + u12: + members: [p12] + spm_unit_size: + 2026: 6 + wv_ccap_countable_income: 6_470 + u13: + members: [p13] + spm_unit_size: + 2026: 7 + wv_ccap_countable_income: 7_298 + u14: + members: [p14] + spm_unit_size: + 2026: 7 + wv_ccap_countable_income: 7_299 + u15: + members: [p15] + spm_unit_size: + 2026: 8 + wv_ccap_countable_income: 8_128 + u16: + members: [p16] + spm_unit_size: + 2026: 8 + wv_ccap_countable_income: 8_129 + u17: + members: [p17] + spm_unit_size: + 2026: 9 + wv_ccap_countable_income: 8_957 + u18: + members: [p18] + spm_unit_size: + 2026: 9 + wv_ccap_countable_income: 8_958 + households: + h1: + members: [p1] + state_code: + 2026: WV + h2: + members: [p2] + state_code: + 2026: WV + h3: + members: [p3] + state_code: + 2026: WV + h4: + members: [p4] + state_code: + 2026: WV + h5: + members: [p5] + state_code: + 2026: WV + h6: + members: [p6] + state_code: + 2026: WV + h7: + members: [p7] + state_code: + 2026: WV + h8: + members: [p8] + state_code: + 2026: WV + h9: + members: [p9] + state_code: + 2026: WV + h10: + members: [p10] + state_code: + 2026: WV + h11: + members: [p11] + state_code: + 2026: WV + h12: + members: [p12] + state_code: + 2026: WV + h13: + members: [p13] + state_code: + 2026: WV + h14: + members: [p14] + state_code: + 2026: WV + h15: + members: [p15] + state_code: + 2026: WV + h16: + members: [p16] + state_code: + 2026: WV + h17: + members: [p17] + state_code: + 2026: WV + h18: + members: [p18] + state_code: + 2026: WV + output: + # 185% of the 2024 guideline, sizes 1 to 9. + wv_ccap_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] diff --git a/policyengine_us/tests/test_child_care_posted_income_limits.py b/policyengine_us/tests/test_child_care_posted_income_limits.py index 72d387f1e24..c6505ae4b29 100644 --- a/policyengine_us/tests/test_child_care_posted_income_limits.py +++ b/policyengine_us/tests/test_child_care_posted_income_limits.py @@ -1,34 +1,30 @@ """Invariants of the child care income limits that states post. -Each chart below copies one state document, so it acts as a second implementation -of that state's limit. Each rule below states the same limit as a rate, a guideline -year and a rounding rule, written apart from the formulas. - -1. Posted charts: a family at the printed top of a chart passes the income test and - a family one dollar over fails, for every family size on the chart. Nevada prints - the nearest dollar and tests the unrounded share, so its test allows one dollar. -2. Rules: for every date in RULES and for any income, a family passes exactly when - its income is at or below the rate times that date's guideline, rounded as the - state's chart rounds. This also makes each income test monotonic in income. -3. Enrolled families: a family that passes as a new applicant passes as an enrolled +The state YAML files pin each posted chart: every printed family size at its top +passes and a dollar more fails. These tests check properties across many incomes and +families, one simulation per case, which single YAML households can't draw: + +1. Rules: for every date in RULES and NEVADA_RULES and for any income, a family passes + exactly when its income is at or below the rate times that date's guideline or + median income, rounded as the state's chart rounds. This also makes each income + test monotonic in income. Each rule states the limit apart from the formulas, so + it acts as a second implementation. +2. Enrolled families: a family that passes as a new applicant passes as an enrolled family at the same income, in every state with separate limits. -4. Ohio: the voucher pays only families over the Publicly Funded Child Care limit, +3. Ohio: the voucher pays only families over the Publicly Funded Child Care limit, never pays more than the charge, and leaves the two programs exclusive, including for homeless families, whom Publicly Funded Child Care serves without its income test. Together the two income tests stay monotonic. The voucher's own test breaks monotonicity on purpose, since a family under the intake limit belongs to Publicly Funded Child Care. -5. Nevada: while the April to September 2024 percent-of-income schedule applied, no +4. Nevada: while the April to September 2024 percent-of-income schedule applied, no family owed more than 7% of income, and sizes above 14 use the 14-person column. -6. Georgia: the program test equals its conjuncts, a priority group never removes +5. Georgia: the program test equals its conjuncts, a priority group never removes eligibility, and enrollment replaces the priority group. -7. A family of three earning $40,000 gets the result each state's chart gives. -YAML pins single households. These tests walk whole charts and many incomes in one -simulation, which keeps them fast enough to run in CI. Hypothesis draws families -from a fixed seed, so every run checks the same ones. The properties also check fixed -families: each size at its limit, and a grid of Georgia families, some failing only -one test. +Hypothesis draws families from a fixed seed, so every run checks the same ones. The +properties also check fixed families: each size at its limit, and a grid of Georgia +families, some failing only one test. """ import itertools @@ -157,7 +153,6 @@ class Program: OH = Program( "OH", "oh_ccap_income_eligible", "oh_ccap_countable_income", "oh_ccap_enrolled" ) -OH_VOUCHER = Program("OH", "oh_ccvp_eligible", "oh_ccap_countable_income") GA = Program( "GA", "ga_caps_income_eligible", "ga_caps_countable_income", "ga_caps_enrolled" ) @@ -168,276 +163,24 @@ class Program: "ga_caps_enrolled", True, ) -GA_VERY_LOW = Program( - "GA", "ga_caps_priority_group_eligible", "ga_caps_countable_income" +MD = Program( + "MD", "md_ccs_income_eligible", "md_ccs_countable_income", "md_ccs_enrolled" +) +MD_ENROLLED = Program( + "MD", + "md_ccs_income_eligible", + "md_ccs_countable_income", + "md_ccs_enrolled", + True, ) - - -@dataclass(frozen=True) -class Chart: - source: str - program: Program - month: str - tops: dict - annual: bool = False - - -CHARTS = [ - Chart( - "Alabama fact sheet, June 1, 2026, initial", - AL, - "2026-06", - {2: 2_644, 3: 3_331, 4: 4_019, 5: 4_706, 6: 5_394, 7: 6_081, 8: 6_769}, - ), - Chart( - "Alabama fact sheet, June 1, 2026, continuing", - AL_ENROLLED, - "2026-06", - {2: 2_996, 3: 3_775, 4: 4_555, 5: 5_334, 6: 6_113, 7: 6_892, 8: 7_671}, - ), - Chart( - "Idaho Department of Health and Welfare, October 2025", - ID, - "2026-01", - {2: 2_292, 3: 2_888, 4: 3_483, 5: 4_079, 6: 4_675, 7: 5_271, 8: 5_867}, - ), - Chart( - "Indiana FSSA, April 5, 2026", - IN, - "2026-05", - {2: 2_435, 3: 3_074, 4: 3_713, 5: 4_352, 6: 4_991, 7: 5_630, 8: 6_269}, - ), - Chart( - "Indiana CCDF plan, March 31, 2024", - IN, - "2024-06", - {1: 1_883, 2: 2_555, 3: 3_228, 4: 3_900, 5: 4_573}, - ), - Chart( - "Missouri DESE, July 1, 2026, traditional", - MO, - "2026-07", - { - 1: 1_956, - 2: 2_644, - 3: 3_331, - 4: 4_019, - 5: 4_706, - 6: 5_394, - 7: 6_081, - 8: 6_769, - }, - ), - Chart( - "Missouri DESE, July 1, 2026, Transitional Level 2", - MO_ENROLLED, - "2026-07", - {1: 2_804, 2: 3_789, 3: 4_775, 4: 5_760, 5: 6_746, 6: 7_731, 7: 8_716}, - ), - Chart( - "West Virginia Appendix A, FY 2024", - WV, - "2026-01", - { - 1: 2_322, - 2: 3_151, - 3: 3_981, - 4: 4_810, - 5: 5_639, - 6: 6_469, - 7: 7_298, - 8: 8_128, - 9: 8_957, - }, - ), - Chart( - "Montana Sliding Fee Scale, July 1, 2025, Standard", - MT, - "2026-01", - {2: 3_261, 3: 4_109, 4: 4_956, 5: 5_804, 6: 6_652, 7: 7_500, 8: 8_348}, - ), - Chart( - "Montana Sliding Fee Scale, July 1, 2025, Graduated", - MT_ENROLLED, - "2026-01", - {2: 3_525, 3: 4_442, 4: 5_358, 5: 6_275, 6: 7_192, 7: 8_108, 8: 9_025}, - ), - Chart( - "Ohio Procedure Letter 21, Publicly Funded Child Care", - OH, - "2026-01", - {2: 2_556, 3: 3_221, 4: 3_885, 5: 4_550, 6: 5_214, 7: 5_879, 8: 6_544}, - ), - Chart( - "Ohio Procedure Letter 45, Publicly Funded Child Care", - OH, - "2026-10", - {2: 2_615, 3: 3_302, 4: 3_988, 5: 4_674, 6: 5_361, 7: 6_047, 8: 6_733}, - ), - Chart( - "Ohio Procedure Letter 21, Child Care Choice Voucher", - OH_VOUCHER, - "2026-01", - {2: 3_525, 3: 4_442, 4: 5_359, 5: 6_275, 6: 7_192, 7: 8_109, 8: 9_025}, - ), - Chart( - "Ohio Procedure Letter 45, Child Care Choice Voucher", - OH_VOUCHER, - "2026-10", - {2: 3_607, 3: 4_554, 4: 5_500, 5: 6_447, 6: 7_394, 7: 8_340, 8: 9_287}, - ), - Chart( - "Georgia Appendix A, October 5, 2026, initial", - GA, - "2026-10", - dict( - zip( - range(1, 15), - [ - 29_931, - 39_141, - 48_350, - 57_559, - 66_769, - 75_978, - 77_705, - 79_432, - 81_159, - 82_885, - 84_612, - 86_339, - 88_066, - 89_793, - ], - ) - ), - annual=True, - ), - Chart( - "Georgia Appendix A, October 5, 2026, ongoing", - GA_ENROLLED, - "2026-10", - dict( - zip( - range(1, 15), - [ - 50_883, - 66_539, - 82_195, - 97_851, - 113_507, - 129_163, - 132_098, - 135_034, - 137_969, - 140_905, - 143_840, - 146_776, - 149_711, - 152_647, - ], - ) - ), - annual=True, - ), - Chart( - "Georgia Appendix A, October 5, 2026, very low income", - GA_VERY_LOW, - "2026-10", - dict( - zip( - range(1, 15), - [ - 7_980, - 10_820, - 13_660, - 16_500, - 19_340, - 22_180, - 25_020, - 27_860, - 30_700, - 33_540, - 36_380, - 39_220, - 42_060, - 44_900, - ], - ) - ), - annual=True, - ), -] - -NEVADA_CHARTS = [ - Chart( - "Nevada transmittal, October 1, 2026, intake", - NV, - "2026-10", - { - 1: 1_866, - 2: 2_440, - 3: 3_014, - 4: 3_588, - 5: 4_163, - 6: 4_737, - 7: 4_844, - 8: 4_952, - 9: 5_060, - }, - ), - Chart( - "Nevada transmittal, October 1, 2026, renewal", - NV_ENROLLED, - "2026-10", - { - 1: 2_230, - 2: 2_916, - 3: 3_602, - 4: 4_289, - 5: 4_975, - 6: 5_661, - 7: 5_790, - 8: 5_918, - 9: 6_047, - }, - ), -] - - -def monthly(annual_amount): - """An annual amount as monthly income, rounded down to the cent. - - The model stores income as float32, which near $150,000 a year resolves only - to about 1.6 cents. Rounding the at-limit family down a cent keeps it at or - below the annual limit after the model multiplies by 12. - """ - return math.floor(annual_amount * 100 / 12) / 100 - - -@pytest.mark.parametrize("chart", CHARTS, ids=lambda chart: chart.source) -def test_family_at_the_posted_top_passes_and_one_dollar_over_fails(chart): - families = [] - for size, top in chart.tops.items(): - if chart.annual: - families += [(size, monthly(top)), (size, (top + 1) / 12)] - else: - families += [(size, top), (size, top + 1)] - result = passes(chart.program, chart.month, families) - assert result.tolist() == [True, False] * len(chart.tops) - - -@pytest.mark.parametrize("chart", NEVADA_CHARTS, ids=lambda chart: chart.source) -def test_nevada_tests_the_unrounded_share_within_a_dollar_of_the_chart(chart): - families = [] - for size, top in chart.tops.items(): - families += [(size, top - 1), (size, top + 1)] - result = passes(chart.program, chart.month, families) - assert result.tolist() == [True, False] * len(chart.tops) # HHS poverty guidelines for the contiguous states, as (first person, each additional). GUIDELINES = { + 2018: (12_140, 4_320), + 2019: (12_490, 4_420), + 2020: (12_760, 4_480), + 2021: (12_880, 4_540), 2022: (13_590, 4_720), 2023: (14_580, 5_140), 2024: (15_060, 5_380), @@ -452,7 +195,8 @@ def guideline(year, size): def nearest_dollar(amount): - """Half a dollar goes up, as Alabama, Indiana, Missouri, West Virginia and Montana print.""" + """Half a dollar goes up, as Alabama, Indiana, Missouri, West Virginia, Montana and + Nevada print.""" return math.floor(round(amount, 2) + 0.5) @@ -517,6 +261,13 @@ def top(self, size): Rule(OH, "2026-01", 2025, 1.45, next_dollar), Rule(OH, "2026-09", 2025, 1.45, next_dollar), Rule(OH, "2026-10", 2026, 1.45, next_dollar), + # From October 2018 through June 2022 most new applicants in Nevada faced 130% of + # the guideline, which Nevada took up each October. + Rule(NV, "2018-10", 2018, 1.3, nearest_dollar), + Rule(NV, "2019-09", 2018, 1.3, nearest_dollar), + Rule(NV, "2019-10", 2019, 1.3, nearest_dollar), + Rule(NV, "2020-10", 2020, 1.3, nearest_dollar), + Rule(NV, "2022-06", 2021, 1.3, nearest_dollar), ] SMALL_FAMILIES = st.lists( @@ -561,7 +312,7 @@ def check(families): NEVADA_SMI = { "2017-10": 69_361, "2018-10": 71_593, - "2021-10": 82_509, + "2022-10": 85_150, "2023-10": 89_325, "2024-10": 96_026, "2026-10": 105_027, @@ -570,18 +321,36 @@ def check(families): NEVADA_RULES = [ (NV, "2018-09", "2017-10", 0.85), - (NV, "2018-10", "2018-10", 0.41), - (NV, "2022-06", "2021-10", 0.41), - (NV, "2022-07", "2021-10", 0.85), + # From October 2018 through June 2022 enrolled families kept 85% of the median, + # while most new applicants faced the guideline (RULES). + (NV_ENROLLED, "2019-06", "2018-10", 0.85), + # The FFY 2022-2024 plan dates its 85% limits to July 1, 2022, on the table that + # starts October 1, 2022. + (NV, "2022-07", "2022-10", 0.85), + (NV, "2022-09", "2022-10", 0.85), + (NV, "2022-10", "2022-10", 0.85), (NV, "2024-09", "2023-10", 0.85), - (NV, "2024-10", "2024-10", 0.41), (NV_ENROLLED, "2024-09", "2023-10", 0.85), + (NV, "2024-10", "2024-10", 0.41), (NV_ENROLLED, "2024-10", "2024-10", 0.49), (NV, "2026-10", "2026-10", 0.41), (NV_ENROLLED, "2026-10", "2026-10", 0.49), ] +def nevada_top(table, size, rate, month): + """The highest whole-dollar monthly income that passes. + + From October 2024 the charts print each limit as the nearest dollar. Earlier + limits keep their cents, and MS 316 rounds income to the nearest dollar, so the + highest passing income is the limit rounded down. + """ + limit = NEVADA_SMI[table] * SMI_SIZE_FACTOR[size] * rate / 12 + if month >= "2024-10": + return nearest_dollar(limit) + return math.floor(round(limit, 2)) + + @pytest.mark.parametrize( "program, month, table, rate", NEVADA_RULES, @@ -591,12 +360,10 @@ def test_nevada_limit_equals_rate_times_dated_median_income( program, month, table, rate ): sizes = list(SMI_SIZE_FACTOR) - tops = { - size: NEVADA_SMI[table] * SMI_SIZE_FACTOR[size] * rate / 12 for size in sizes - } families = [] for size in sizes: - families += [(size, tops[size] - 1), (size, tops[size] + 1)] + top = nevada_top(table, size, rate, month) + families += [(size, top), (size, top + 1)] result = passes(program, month, families) assert result.tolist() == [True, False] * len(sizes) @@ -630,6 +397,7 @@ def test_nevada_limit_equals_rate_times_dated_median_income( (MT, MT_ENROLLED, "2026-03"), (NV, NV_ENROLLED, "2024-10"), (NV, NV_ENROLLED, "2022-07"), + (NV, NV_ENROLLED, "2019-06"), ( OH, Program( @@ -643,6 +411,11 @@ def test_nevada_limit_equals_rate_times_dated_median_income( ), (GA, GA_ENROLLED, "2026-01"), (GA, GA_ENROLLED, "2026-10"), + # Maryland's continuation scale moved to the federal fiscal 2025 median eight + # months before the initial scale did. + (MD, MD_ENROLLED, "2024-05"), + (MD, MD_ENROLLED, "2024-11"), + (MD, MD_ENROLLED, "2026-03"), ] @@ -995,33 +768,3 @@ def check(families): check_enrollment_replaces_the_priority_group(families) check() - - -FORTY_THOUSAND_A_YEAR = 40_000 / 12 - -FAMILY_OF_THREE_AT_40000 = [ - # Each row gives the result the state's chart gives for three people at $40,000. - (AL, "2026-01", True), # Fact sheet, January 2026: up to $3,998. - (AL, "2026-06", False), # Fact sheet, June 2026: up to $3,331. - (ID, "2026-01", False), # Department table: up to $2,888. - (IN, "2026-01", False), # 150% of the 2025 guideline: up to $3,331. - (IN, "2026-05", False), # FSSA chart, April 5, 2026: up to $3,074. - (MO, "2026-01", False), # DESE chart: up to $3,331. - (WV, "2026-01", True), # Appendix A: up to $3,981. - (MT, "2026-01", True), # Sliding Fee Scale: up to $4,109. - (NV, "2026-01", False), # Transmittal CC PT 06-25, 41% of median income. - (OH, "2026-01", False), # Procedure Letter 21: up to $3,221. - (OH_VOUCHER, "2026-01", True), # Procedure Letter 21: voucher up to $4,442. - (GA, "2026-01", False), # 40% of median income: $37,208 a year. - (GA, "2026-10", True), # Appendix A: $48,350 a year. -] - - -@pytest.mark.parametrize( - "program, month, expected", - FAMILY_OF_THREE_AT_40000, - ids=lambda value: value.eligible if isinstance(value, Program) else str(value), -) -def test_family_of_three_earning_40000(program, month, expected): - result = passes(program, month, [(3, FORTY_THOUSAND_A_YEAR)]) - assert result.tolist() == [expected] diff --git a/policyengine_us/variables/gov/states/al/dhr/ccsp/al_ccsp_fpg.py b/policyengine_us/variables/gov/states/al/dhr/ccsp/al_ccsp_fpg.py new file mode 100644 index 00000000000..a181aeb0c48 --- /dev/null +++ b/policyengine_us/variables/gov/states/al/dhr/ccsp/al_ccsp_fpg.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class al_ccsp_fpg(Variable): + value_type = float + entity = SPMUnit + label = "Alabama CCSP monthly federal poverty guideline" + definition_period = MONTH + unit = USD + defined_for = StateCode.AL + reference = ( + "https://dhr.alabama.gov/wp-content/uploads/2024/01/Child-Care-Fact-Sheet-2024.pdf#page=1", + "https://dhr.alabama.gov/wp-content/uploads/2026/06/CHILD-CARE-FACT-SHEET-Jun2026-1.pdf#page=1", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.al.dhr.ccsp.income + size = spm_unit("spm_unit_size", period.this_year) + # The fact sheets print one row for families of eight or more. + capped_size = min_(size, p.max_family_size) + state_group = spm_unit.household("state_group_str", period.this_year) + # Alabama's fact sheets use the prior calendar year's HHS poverty + # guidelines throughout the benefit year, since HHS publishes the new + # guidelines in mid-January. + p_fpg = parameters(period.last_year).gov.hhs.fpg + annual_fpg = p_fpg.first_person[state_group] + p_fpg.additional_person[ + state_group + ] * (capped_size - 1) + return annual_fpg / MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/al/dhr/ccsp/copay/al_ccsp_weekly_copay_per_child.py b/policyengine_us/variables/gov/states/al/dhr/ccsp/copay/al_ccsp_weekly_copay_per_child.py index 6913e1b1f31..26596ec36fc 100644 --- a/policyengine_us/variables/gov/states/al/dhr/ccsp/copay/al_ccsp_weekly_copay_per_child.py +++ b/policyengine_us/variables/gov/states/al/dhr/ccsp/copay/al_ccsp_weekly_copay_per_child.py @@ -15,9 +15,7 @@ def formula(spm_unit, period, parameters): # Floor income at 0 so self-employment / farm losses land in the # $0 copay band rather than producing a negative FPL ratio. monthly_income = max_(spm_unit("al_ccsp_countable_income", period), 0) - # Use the prior calendar year's HHS poverty guidelines to match - # Alabama's Child Care Fact Sheet operational thresholds. - monthly_fpg = spm_unit("spm_unit_fpg", period.last_year) / MONTHS_IN_YEAR + monthly_fpg = spm_unit("al_ccsp_fpg", period) fpl_ratio = where(monthly_fpg > 0, monthly_income / monthly_fpg, 0) fee = p.fee_by_fpl.calc(fpl_ratio) copay_waived = spm_unit("al_ccsp_copay_waived", period) diff --git a/policyengine_us/variables/gov/states/al/dhr/ccsp/eligibility/al_ccsp_income_eligible.py b/policyengine_us/variables/gov/states/al/dhr/ccsp/eligibility/al_ccsp_income_eligible.py index 854240be9a1..06aab57366d 100644 --- a/policyengine_us/variables/gov/states/al/dhr/ccsp/eligibility/al_ccsp_income_eligible.py +++ b/policyengine_us/variables/gov/states/al/dhr/ccsp/eligibility/al_ccsp_income_eligible.py @@ -16,11 +16,7 @@ def formula(spm_unit, period, parameters): p = parameters(period).gov.states.al.dhr.ccsp.income.limit monthly_income = spm_unit("al_ccsp_countable_income", period) - # Alabama's published income tables (Child Care Fact Sheet) use the - # prior calendar year's HHS poverty guidelines throughout the - # benefit year, since HHS publishes the new guidelines mid-January. - annual_fpg = spm_unit("spm_unit_fpg", period.last_year) - monthly_fpg = annual_fpg / MONTHS_IN_YEAR + monthly_fpg = spm_unit("al_ccsp_fpg", period) enrolled = spm_unit("al_ccsp_enrolled", period) fpl_limit_ratio = where( enrolled, diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/copay/ga_caps_family_fee.py b/policyengine_us/variables/gov/states/ga/decal/caps/copay/ga_caps_family_fee.py index 874681a02a9..4e5d59e8e24 100644 --- a/policyengine_us/variables/gov/states/ga/decal/caps/copay/ga_caps_family_fee.py +++ b/policyengine_us/variables/gov/states/ga/decal/caps/copay/ga_caps_family_fee.py @@ -1,4 +1,5 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg class ga_caps_family_fee(Variable): @@ -21,16 +22,19 @@ def formula(spm_unit, period, parameters): is_head_or_spouse = person("is_tax_unit_head_or_spouse", period.this_year) age = person("age", period.this_year) has_minor_parent = spm_unit.any(is_head_or_spouse & (age <= p.minor_parent_age)) - # DFCS custody fee waiver: any child in DFCS custody waives the fee. - has_dfcs_custody_child = add(spm_unit, period, ["is_in_foster_care"]) > 0 - fee_waived = has_minor_parent | has_dfcs_custody_child - # Compute fee from FPL-ratio scale bracket. + # Each child in DFCS custody forms a family unit of one that owes no fee + # (CAPS/00-5, 5.4.1; CAPS/00-7, 7.5), which ga_caps pays apart from this + # fee. The family's own unit leaves those children out of its size. countable_income = spm_unit("ga_caps_countable_income", period) - fpg = spm_unit("spm_unit_fpg", period) - mask = fpg > 0 + size = spm_unit("ga_caps_family_size", period) + state_group = spm_unit.household("state_group_str", period.this_year) + monthly_fpg = fpg(size, state_group, period.this_year, parameters) / ( + MONTHS_IN_YEAR + ) + mask = monthly_fpg > 0 fpl_ratio = np.divide( countable_income, - fpg, + monthly_fpg, out=np.zeros_like(countable_income), where=mask, ) @@ -39,4 +43,4 @@ def formula(spm_unit, period, parameters): annual_income = countable_income * MONTHS_IN_YEAR weekly_fee = np.floor(annual_income * fee_rate / WEEKS_IN_YEAR) monthly_fee = weekly_fee * (WEEKS_IN_YEAR / MONTHS_IN_YEAR) - return where(fee_waived, 0, monthly_fee) + return where(has_minor_parent, 0, monthly_fee) diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_activity_eligible.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_activity_eligible.py index 7df872e514c..4849f8a6e43 100644 --- a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_activity_eligible.py +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_activity_eligible.py @@ -9,8 +9,8 @@ class ga_caps_activity_eligible(Variable): defined_for = StateCode.GA reference = ( "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=33", + # PDF pages 2, 8 "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=2", - "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=8", ) def formula(spm_unit, period, parameters): @@ -37,17 +37,13 @@ def formula(spm_unit, period, parameters): individually_eligible = meets_work_requirement | is_student | is_disabled all_heads_meet = ~spm_unit.any(is_head_or_spouse & ~individually_eligible) meets_ccdf = spm_unit("meets_ccdf_activity_test", period.this_year) - # CAPS/00-7 waives the requirement for foster parents of children in DFCS - # custody (7.5) and for parents in Grandparents Raising Grandchildren - # (7.13). The Child Protective Services waiver in 7.4 is discretionary - # ("may be waived"), so meets_ccdf_activity_test carries it as an input. - has_dfcs_custody_child = add(spm_unit, period, ["is_in_foster_care"]) > 0 + # CAPS/00-7, 7.13 waives the requirement for parents in Grandparents Raising + # Grandchildren. Foster parents of children in DFCS custody need not meet it + # either (7.5), but those children form family units of one, which + # ga_caps_eligible serves apart from this test. The Child Protective + # Services waiver in 7.4 is discretionary ("may be waived"), so + # meets_ccdf_activity_test carries it as an input. grandparents_raising_grandchildren = spm_unit( "ga_caps_grandparents_raising_grandchildren", period ) - return ( - all_heads_meet - | meets_ccdf - | has_dfcs_custody_child - | grandparents_raising_grandchildren - ) + return all_heads_meet | meets_ccdf | grandparents_raising_grandchildren diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_dfcs_custody_child.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_dfcs_custody_child.py new file mode 100644 index 00000000000..bfefeb77823 --- /dev/null +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_dfcs_custody_child.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class ga_caps_dfcs_custody_child(Variable): + value_type = bool + entity = Person + label = "Child in DFCS custody, served by Georgia CAPS as a family unit of one" + definition_period = MONTH + defined_for = StateCode.GA + reference = ( + "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=27", + "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=2", + ) + + def formula(person, period, parameters): + # CAPS/00-5, 5.4.1: the State stands as the parent of each child in DFCS + # custody, and the child forms a family unit of one. CAPS/00-7, 7.5: foster + # parents need not meet the income or activity requirements, and the child + # owes no family fee. + eligible_child = person("ga_caps_eligible_child", period) + return eligible_child & person("is_in_foster_care", period) diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_eligible.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_eligible.py index 253c690f6e4..57544d66ab9 100644 --- a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_eligible.py +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_eligible.py @@ -8,25 +8,16 @@ class ga_caps_eligible(Variable): definition_period = MONTH defined_for = StateCode.GA reference = ( - "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=29", - "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=1", + # PDF pages 27, 29 + "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=27", + "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=2", ) def formula(spm_unit, period, parameters): - has_eligible_child = add(spm_unit, period, ["ga_caps_eligible_child"]) > 0 - income_eligible = spm_unit("ga_caps_income_eligible", period) - asset_eligible = spm_unit("is_ccdf_asset_eligible", period.this_year) - activity_eligible = spm_unit("ga_caps_activity_eligible", period) - # CAPS/00-7, 7.3.1: new applicants outside a priority group are denied even - # when they meet every other requirement. 7.3.1.3 drops the requirement at - # annual redetermination. - priority_group_met = spm_unit( - "ga_caps_priority_group_eligible", period - ) | spm_unit("ga_caps_enrolled", period) - return ( - has_eligible_child - & income_eligible - & asset_eligible - & activity_eligible - & priority_group_met + # CAPS serves each child in DFCS custody as a family unit of one (CAPS/00-5, + # 5.4.1; CAPS/00-7, 7.5) and the family's other children when the family + # qualifies on its own. + has_dfcs_custody_child = ( + add(spm_unit, period, ["ga_caps_dfcs_custody_child"]) > 0 ) + return spm_unit("ga_caps_family_eligible", period) | has_dfcs_custody_child diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_family_eligible.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_family_eligible.py new file mode 100644 index 00000000000..a01ee97c9bc --- /dev/null +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_family_eligible.py @@ -0,0 +1,51 @@ +from policyengine_us.model_api import * + + +class ga_caps_family_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Georgia CAPS as a family, apart from children in DFCS custody" + definition_period = MONTH + defined_for = StateCode.GA + reference = ( + # PDF pages 27, 29 + "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=27", + "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=1", + "https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_from_Elisabetta_Kasfir_Families_07.01.2024.pdf#page=1", + "https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_to_Families_Policy_Revisions_10.06.25.pdf#page=1", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ga.decal.caps.priority_groups + person = spm_unit.members + # CAPS/00-5, 5.4.1: a child in DFCS custody forms a family unit of one, so + # the family's own case covers its other children. + family_child = person("ga_caps_eligible_child", period) & ~person( + "is_in_foster_care", period + ) + has_eligible_child = spm_unit.any(family_child) + income_eligible = spm_unit("ga_caps_income_eligible", period) + asset_eligible = spm_unit("is_ccdf_asset_eligible", period.this_year) + activity_eligible = spm_unit("ga_caps_activity_eligible", period) + # CAPS/00-7, 7.3.1: new applicants outside a priority group are denied even + # when they meet every other requirement. 7.3.1.3 drops the requirement at + # annual redetermination. From July 1, 2024 to October 6, 2025, a family whose + # child attended Georgia's Pre-K at the initial application or the previous + # determination had to belong to a group at redetermination. + pre_k_family = spm_unit.any( + person("ga_caps_pre_k_at_previous_determination", period) + ) + exempt_at_redetermination = spm_unit("ga_caps_enrolled", period) & ~( + pre_k_family & p.pre_k_redetermination_in_effect + ) + priority_group_met = ( + spm_unit("ga_caps_priority_group_eligible", period) + | exempt_at_redetermination + ) + return ( + has_eligible_child + & income_eligible + & asset_eligible + & activity_eligible + & priority_group_met + ) diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_family_size.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_family_size.py new file mode 100644 index 00000000000..18c5abd1a79 --- /dev/null +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_family_size.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class ga_caps_family_size(Variable): + value_type = int + entity = SPMUnit + label = "Georgia CAPS family unit size" + definition_period = MONTH + defined_for = StateCode.GA + reference = "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=27" + + def formula(spm_unit, period, parameters): + # CAPS/00-5, 5.4.1: each child in DFCS custody forms a family unit of one, so + # the foster family's own unit leaves those children out. + size = spm_unit("spm_unit_size", period.this_year) + return size - add(spm_unit, period, ["is_in_foster_care"]) diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.py index 26ddbdf513c..bf40ce17559 100644 --- a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.py +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_income_eligible.py @@ -1,3 +1,4 @@ +from policyengine_core.periods import instant from policyengine_us.model_api import * from policyengine_us.variables.gov.hhs.hhs_smi import smi @@ -9,30 +10,28 @@ class ga_caps_income_eligible(Variable): definition_period = MONTH defined_for = StateCode.GA reference = ( - "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=49", + # PDF pages 27, 49, 52 + "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=27", "https://caps.decal.ga.gov/assets/downloads/CAPS/AppendixA-CAPS%20Maximum%20Income%20Limits%20by%20Family%20Size.pdf#page=1", - "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=52", - "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=2", ) def formula(spm_unit, period, parameters): - p = parameters(period).gov.states.ga.decal.caps.income.smi_rate - # Appendix A takes up the state median income table each October (October - # 5 in 2026), so read the table at the month. hhs_smi keeps one table - # through the calendar year. The chart prints annual limits rounded up to + p = parameters(period).gov.states.ga.decal.caps.income + # Each Appendix A chart dates the state median income table it takes up, + # which smi_year_lag carries. The chart prints annual limits rounded up to # the next dollar, and Manual 8.8.4 multiplies monthly income by 12 to # compare with it. Round to cents first so floating-point noise can't push # a whole-dollar limit up by one or move a family at the limit. - size = spm_unit("spm_unit_size", period.this_year) + size = spm_unit("ga_caps_family_size", period) state = spm_unit.household("state_code_str", period.this_year) - annual_smi = smi(size, state, period, parameters) + table_date = instant(period).offset(-int(p.smi_year_lag), "year") + annual_smi = smi(size, state, table_date, parameters) enrolled = spm_unit("ga_caps_enrolled", period) - rate = where(enrolled, p.ongoing_eligibility, p.initial_eligibility) + rate = where( + enrolled, p.smi_rate.ongoing_eligibility, p.smi_rate.initial_eligibility + ) income_limit = np.ceil(np.round(annual_smi * rate, 2)) annual_income = np.round( spm_unit("ga_caps_countable_income", period) * MONTHS_IN_YEAR, 2 ) - # CAPS/00-7, 7.5: foster parents of children in DFCS custody need not meet - # the income requirement. The family fee applies the same family-wide test. - has_dfcs_custody_child = add(spm_unit, period, ["is_in_foster_care"]) > 0 - return (annual_income <= income_limit) | has_dfcs_custody_child + return annual_income <= income_limit diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_pre_k_at_previous_determination.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_pre_k_at_previous_determination.py new file mode 100644 index 00000000000..7440c91062f --- /dev/null +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_pre_k_at_previous_determination.py @@ -0,0 +1,10 @@ +from policyengine_us.model_api import * + + +class ga_caps_pre_k_at_previous_determination(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Child attended Georgia's Pre-K Program at the family's initial Georgia CAPS application or previous eligibility determination" + defined_for = StateCode.GA + reference = "https://caps.decal.ga.gov/Assets/downloads/CAPS_Letter_from_Elisabetta_Kasfir_Families_07.01.2024.pdf#page=1" diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.py b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.py index 04826c75a09..b31841239ec 100644 --- a/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.py +++ b/policyengine_us/variables/gov/states/ga/decal/caps/eligibility/priority_groups/ga_caps_priority_group_eligible.py @@ -1,4 +1,5 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg class ga_caps_priority_group_eligible(Variable): @@ -19,20 +20,24 @@ def formula(spm_unit, period, parameters): if not p.in_effect: return np.ones_like(spm_unit("spm_unit_size", period.this_year), dtype=bool) person = spm_unit.members - # Groups that turn on a child: Child Protective Services and court-ordered - # supervision (CAPS/00-7, 7.4), need to protect (7.15), DFCS custody (7.5), - # disabilities (7.7) and Georgia's Pre-K (7.8). + # Groups that turn on one of the family's own children: Child Protective + # Services and court-ordered supervision (CAPS/00-7, 7.4), need to protect + # (7.15), disabilities (7.7) and Georgia's Pre-K (7.8). A child in DFCS + # custody (7.5) forms a family unit of one (CAPS/00-5, 5.4.1), which + # ga_caps_dfcs_custody_child serves, so that child doesn't place the rest of + # the family in a group. + family_child = person("ga_caps_eligible_child", period) & ~person( + "is_in_foster_care", period + ) protective_care = person( "receives_or_needs_protective_services", period.this_year ) | person("is_under_court_supervision", period.this_year) - dfcs_custody = person("is_in_foster_care", period) disability = person("is_disabled", period.this_year) | person( "has_developmental_delay", period.this_year ) pre_k = person("ga_caps_pre_k_enrolled", period) child_group = spm_unit.any( - person("ga_caps_eligible_child", period) - & (protective_care | dfcs_custody | disability | pre_k) + family_child & (protective_care | disability | pre_k) ) # Groups that turn on a parent: minor parents (7.14) and student parents # (7.16). is_full_time_student stands in for enrollment in the listed @@ -46,15 +51,34 @@ def formula(spm_unit, period, parameters): person("is_tax_unit_head_or_spouse", period.this_year) & (minor_parent | student_parent) ) - # 7.12 and Appendix A: gross applicable income against an annual chart. - # Round to cents so floating-point noise can't move a family at the limit. + # 7.12 and Appendix A: gross applicable income against an annual chart built + # on the guideline year very_low_income_fpg_year_lag carries. Round to cents + # so floating-point noise can't move a family at the limit. annual_income = np.round( spm_unit("ga_caps_countable_income", period) * MONTHS_IN_YEAR, 2 ) - very_low_income_limit = np.round( - spm_unit("spm_unit_fpg", period.this_year) * p.very_low_income_fpg_rate, 2 + size = spm_unit("ga_caps_family_size", period) + state_group = spm_unit.household("state_group_str", period.this_year) + guideline = fpg( + size, + state_group, + period, + parameters, + year_lag=p.very_low_income_fpg_year_lag, + ) + very_low_income_limit = np.round(guideline * p.very_low_income_fpg_rate, 2) + very_low_income = ( + annual_income <= very_low_income_limit + ) & p.very_low_income_in_effect + # The funding Q&A adds the homeless, domestic violence and very low income + # groups on October 1, 2016, two months after the other groups. + homeless = ( + spm_unit.household("is_homeless", period.this_year) & p.homeless_in_effect + ) + domestic_violence = ( + spm_unit("ga_caps_domestic_violence", period) + & p.domestic_violence_in_effect ) - very_low_income = annual_income <= very_low_income_limit # is_tanf_enrolled stands in for families in TANF employment services # (7.9); the group excludes payees outside those services, and the model # can't tell them apart. @@ -63,8 +87,8 @@ def formula(spm_unit, period, parameters): | parent_group | very_low_income | spm_unit("is_tanf_enrolled", period) - | spm_unit.household("is_homeless", period.this_year) - | spm_unit("ga_caps_domestic_violence", period) + | homeless + | domestic_violence | spm_unit("ga_caps_natural_disaster", period) | spm_unit("ga_caps_grandparents_raising_grandchildren", period) ) diff --git a/policyengine_us/variables/gov/states/ga/decal/caps/ga_caps.py b/policyengine_us/variables/gov/states/ga/decal/caps/ga_caps.py index d58782d2c87..7fa945c2fa4 100644 --- a/policyengine_us/variables/gov/states/ga/decal/caps/ga_caps.py +++ b/policyengine_us/variables/gov/states/ga/decal/caps/ga_caps.py @@ -12,28 +12,19 @@ class ga_caps(Variable): definition_period = MONTH defined_for = "ga_caps_eligible" reference = ( - "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=55", + # PDF pages 27, 55 + "https://caps.decal.ga.gov/assets/downloads/CAPS/0-CAPS_Policy-Manual.pdf#page=27", "https://www.decal.ga.gov/documents/attachments/CCDFStatePlan25-27.pdf#page=69", + "https://caps.decal.ga.gov/assets/downloads/CAPS/07-CAPS_Policy-Priority%20Groups.pdf#page=2", ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ga.decal.caps person = spm_unit.members - - max_weekly = person("ga_caps_maximum_weekly_benefit", period) - sum_max_weekly = spm_unit.sum(max_weekly) - sum_max_monthly = sum_max_weekly * (WEEKS_IN_YEAR / MONTHS_IN_YEAR) - - expenses_monthly = spm_unit("spm_unit_pre_subsidy_childcare_expenses", period) - base_monthly = min_(expenses_monthly, sum_max_monthly) - - family_fee = spm_unit("ga_caps_family_fee", period) - net_base = max_(base_monthly - family_fee, 0) + weekly_to_monthly = WEEKS_IN_YEAR / MONTHS_IN_YEAR # CCDF Plan §4.3.3 phrases the Quality Rated bonus as a per-provider - # add-on. We don't distinguish provider rating per child at the moment, - # so we collapse to one family-level effective bonus rate weighted by - # each child's maximum weekly benefit. + # add-on. quality_rating = person("ga_caps_quality_rating", period) star_count = select( [ @@ -45,11 +36,43 @@ def formula(spm_unit, period, parameters): default=0, ) bonus_rate = p.quality_rated.bonus_rate.calc(star_count) - weighted_bonus = spm_unit.sum(max_weekly * bonus_rate) + max_weekly = person("ga_caps_maximum_weekly_benefit", period) + + # CAPS/00-5, 5.4.1 and CAPS/00-7, 7.5: each child in DFCS custody forms a + # family unit of one and owes no family fee. The SPM unit's expenses split + # evenly across its children in pre_subsidy_childcare_expenses, which sets + # each such child's share. + dfcs_child = person("ga_caps_dfcs_custody_child", period) + child_expense = person("pre_subsidy_childcare_expenses", period) + dfcs_payment = spm_unit.sum( + min_(child_expense, max_weekly * weekly_to_monthly) + * (1 + bonus_rate) + * dfcs_child + ) + dfcs_expenses = spm_unit.sum(child_expense * dfcs_child) + + # The family's own case covers its other eligible children against the rest + # of the SPM unit's expenses, less the family fee. + family_eligible = spm_unit("ga_caps_family_eligible", period) + family_child = ( + person("ga_caps_eligible_child", period) + & ~person("is_in_foster_care", period) + & spm_unit.project(family_eligible) + ) + family_max_weekly = spm_unit.sum(max_weekly * family_child) + expenses = spm_unit("spm_unit_pre_subsidy_childcare_expenses", period) + family_expenses = max_(expenses - dfcs_expenses, 0) + family_base = min_(family_expenses, family_max_weekly * weekly_to_monthly) + family_fee = spm_unit("ga_caps_family_fee", period) + family_net = max_(family_base - family_fee, 0) + # We don't distinguish provider rating per child within the family's case at + # the moment, so we collapse to one effective bonus rate weighted by each + # child's maximum weekly benefit. + weighted_bonus = spm_unit.sum(max_weekly * bonus_rate * family_child) effective_bonus_rate = np.divide( weighted_bonus, - sum_max_weekly, + family_max_weekly, out=np.zeros_like(weighted_bonus), - where=sum_max_weekly > 0, + where=family_max_weekly > 0, ) - return net_base * (1 + effective_bonus_rate) + return family_net * (1 + effective_bonus_rate) + dfcs_payment diff --git a/policyengine_us/variables/gov/states/id/dhw/iccp/copay/id_iccp_copay_per_child.py b/policyengine_us/variables/gov/states/id/dhw/iccp/copay/id_iccp_copay_per_child.py index dc390581cd9..0cd3bd98477 100644 --- a/policyengine_us/variables/gov/states/id/dhw/iccp/copay/id_iccp_copay_per_child.py +++ b/policyengine_us/variables/gov/states/id/dhw/iccp/copay/id_iccp_copay_per_child.py @@ -77,6 +77,8 @@ def formula(person, period, parameters): # families below 100% FPG; the 503 sub-condition limiting it to TAFI # families in non-employment activities is not tracked at the moment. tafi = person.spm_unit("is_tanf_enrolled", period) + # This test reads the current year's guideline, while the income limits + # read the guideline year of the department's posted table (id_iccp_fpg). fpg = person.spm_unit("spm_unit_fpg", period) below_tafi_fpl = income < fpg * p.tafi_exemption_fpl_rate tafi_exempt = tafi & below_tafi_fpl diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_income_eligible.py b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_income_eligible.py index f24aa0123fc..f2c9e844339 100644 --- a/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_income_eligible.py +++ b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_income_eligible.py @@ -11,27 +11,37 @@ class md_ccs_income_eligible(Variable): reference = ( "https://regs.maryland.gov/us/md/exec/comar/13A.14.06.03", "https://mgaleg.maryland.gov/2022RS/Chapters_noln/CH_525_hb0995E.pdf#page=1", + "https://web.archive.org/web/20261009215322/https://earlychildhood.marylandpublicschools.org/child-care-providers/child-care-scholarship-program", ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.md.msde.ccs.income countable_income = spm_unit("md_ccs_countable_income", period) - # Maryland freezes the SMI base year on a fiscal-year schedule (MSDE - # Feb 4, 2026 W&M briefing slide 21): FY2019-2022 used 2018 SMI, - # FY2023-2024 used 2021 SMI, FY2025+ uses current SMI. - if p.smi_freeze_in_effect: - size = spm_unit("spm_unit_size", period.this_year) - state = spm_unit.household("state_code_str", period.this_year) - smi_value = ( - smi(size, state, f"{p.smi_frozen_year}-10-01", parameters) - / MONTHS_IN_YEAR - ) - else: - smi_value = spm_unit("hhs_smi", period) + size = spm_unit("spm_unit_size", period.this_year) + state = spm_unit.household("state_code_str", period.this_year) + current_smi = spm_unit("hhs_smi", period) + + # Maryland holds the SMI base year on its own schedule (MSDE Feb 4, 2026 + # W&M briefing slide 21): FY2019-2022 used 2018 SMI and FY2023-2024 used + # 2021 SMI. The scales MSDE posts moved continuing families to the + # federal fiscal 2025 median on April 22, 2024 and new applicants on + # December 15, 2024, and MSDE still posts both scales in October 2026. + def monthly_smi(freeze_in_effect, frozen_year): + if freeze_in_effect: + return ( + smi(size, state, f"{frozen_year}-10-01", parameters) + / MONTHS_IN_YEAR + ) + return current_smi + + initial_smi = monthly_smi(p.smi_freeze_in_effect, p.smi_frozen_year) + continuation_smi = monthly_smi( + p.continuation_smi_freeze_in_effect, p.continuation_smi_frozen_year + ) enrolled = spm_unit("md_ccs_enrolled", period) income_limit = where( enrolled, - smi_value * p.smi_rate.continuation, - smi_value * p.smi_rate.initial, + continuation_smi * p.smi_rate.continuation, + initial_smi * p.smi_rate.initial, ) return countable_income <= income_limit diff --git a/policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.py b/policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.py index 58ac993e8d4..892124dc03c 100644 --- a/policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.py +++ b/policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_income_eligible.py @@ -26,9 +26,8 @@ def formula(spm_unit, period, parameters): # first so floating-point noise can't move a tie. fpg_limit = np.floor(np.round(monthly_fpg * fpg_rate, 2) + 0.5) # Adjusted gross income may also not exceed 85% of the state median - # income at application (Manual sec. 4.7). In practice the FPG limit is - # the binding ceiling at all realistic household sizes; the 85% SMI cap - # is a non-binding federal backstop kept for CCDF compliance and - # robustness to future FPG/SMI ratio shifts. + # income (Manual sec. 4.7), and the July 2026 chart applies the lower of + # its maximum and that amount. On that chart 85% of the median binds for + # enrolled families from ten people and for new applicants from 17. smi_limit = spm_unit("hhs_smi", period) * p_ccdf.income_limit_smi return adjusted_income <= min_(fpg_limit, smi_limit) diff --git a/policyengine_us/variables/gov/states/mo/dese/ccs/mo_ccs.py b/policyengine_us/variables/gov/states/mo/dese/ccs/mo_ccs.py index 662a66c9a55..ee5f4ac49b8 100644 --- a/policyengine_us/variables/gov/states/mo/dese/ccs/mo_ccs.py +++ b/policyengine_us/variables/gov/states/mo/dese/ccs/mo_ccs.py @@ -11,7 +11,6 @@ class mo_ccs(Variable): reference = "https://www.law.cornell.edu/regulations/missouri/5-CSR-25-200-060" def formula(spm_unit, period, parameters): - p = parameters(period).gov.states.mo.dese.ccs # Reimbursement is paid per child at a daily rate for each day of care, # capped at the family's child care charges. person = spm_unit.members @@ -28,8 +27,5 @@ def formula(spm_unit, period, parameters): # funds the percentage "of the remaining state base rate"). Traditional # families are funded at the full rate, so the multiplier is 1 and the # order has no effect. - adjusted_income = spm_unit("mo_ccs_adjusted_income", period) - monthly_fpg = spm_unit("mo_ccs_fpg", period) - fpl_ratio = where(monthly_fpg > 0, adjusted_income / monthly_fpg, 0) - funding_rate = p.transitional.funding_rate.calc(fpl_ratio) + funding_rate = spm_unit("mo_ccs_funding_rate", period) return funding_rate * max_(total_reimbursement - copay, 0) diff --git a/policyengine_us/variables/gov/states/mo/dese/ccs/mo_ccs_funding_rate.py b/policyengine_us/variables/gov/states/mo/dese/ccs/mo_ccs_funding_rate.py new file mode 100644 index 00000000000..0e700ab6868 --- /dev/null +++ b/policyengine_us/variables/gov/states/mo/dese/ccs/mo_ccs_funding_rate.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class mo_ccs_funding_rate(Variable): + value_type = float + entity = SPMUnit + unit = "/1" + label = "Missouri Child Care Subsidy share of the remaining base rate funded" + definition_period = MONTH + defined_for = StateCode.MO + reference = ( + "https://web.archive.org/web/20250831220820id_/https://dese.mo.gov/childhood/quality-programs/child-care-subsidy/child-care-manual/2010/045/00", + "https://www.law.cornell.edu/regulations/missouri/5-CSR-25-200-060", + "https://dese.mo.gov/sites/g/files/zuston521/files/media/pdf/2026/07/Income%20Elig%20_Updated%206.29.26.pdf#page=1", + ) + + def formula(spm_unit, period, parameters): + # Manual 2010.045.00 funds traditional families at the full base rate and + # each Transitional Child Care level at a reduced share. DESE's chart prints + # each level's top as the nearest dollar of a multiple of the guideline, and + # income above a top falls in the next level. Round to cents first so + # floating-point noise can't move a tie. + scale = parameters(period).gov.states.mo.dese.ccs.transitional.funding_rate + adjusted_income = spm_unit("mo_ccs_adjusted_income", period) + monthly_fpg = spm_unit("mo_ccs_fpg", period) + funding_rate = np.full_like(adjusted_income, scale.amounts[0]) + for threshold, amount in zip(scale.thresholds[1:], scale.amounts[1:]): + level_top = np.floor(np.round(monthly_fpg * threshold, 2) + 0.5) + funding_rate = where(adjusted_income > level_top, amount, funding_rate) + return funding_rate diff --git a/policyengine_us/variables/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.py b/policyengine_us/variables/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.py index 7cbcbcd0d6a..300b5659a93 100644 --- a/policyengine_us/variables/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.py +++ b/policyengine_us/variables/gov/states/nv/dwss/ccdp/copay/nv_ccdp_copay.py @@ -12,6 +12,7 @@ class nv_ccdp_copay(Variable): "https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/CC_PT_06-25_ANNUAL_INCOME_CHANGES_10.02.2025.pdf#page=1", "https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=2", "https://nevadachildcare.netlify.app/static/200a0b5ae99f788e8c99d6f7824dc92b/Child-Care-Updates-Parents-.pdf#page=1", + "https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=75", ) def formula(spm_unit, period, parameters): @@ -22,17 +23,18 @@ def formula(spm_unit, period, parameters): # from the chart effective October 1, 2023, by household size and income. # Households above fourteen people use the fourteen-person column. # - From October 1, 2024: a flat monthly amount by income as a share of SMI - # (State Plan Section 2.4.v): <= 32.99% SMI -> $0; 33%-42% SMI -> $90; - # >42% -> $150. The flat schedule also stands in for dates before July 2022. - p = parameters(period).gov.states.nv.dwss.ccdp.copay + # (State Plan Section 2.4.v): up to 33% SMI -> $0; up to 42% SMI -> $90; + # above 42% -> $150, with each band top rounded to the nearest dollar as the + # charts print it. The flat schedule also stands in for dates before July + # 2022. + ccdp = parameters(period).gov.states.nv.dwss.ccdp + p = ccdp.copay if p.reimbursed: return spm_unit.empty_array() - # Floor income at 0 before taking the ratio: negative self-employment - # income would otherwise produce a negative ratio and the wrong band. - monthly_income = max_( - spm_unit("nv_ccdp_countable_income", period.this_year) / MONTHS_IN_YEAR, - 0, - ) + # MS 316 rounds monthly income to the nearest dollar before reading the + # chart. Countable income floors at zero, so negative self-employment + # income can't produce a negative copayment. + monthly_income = spm_unit("nv_ccdp_monthly_countable_income", period) if p.percent_of_income.in_effect: size = spm_unit("spm_unit_size", period.this_year) scales = p.percent_of_income @@ -44,9 +46,17 @@ def formula(spm_unit, period, parameters): ) copay = share * monthly_income else: + # Each threshold of the flat schedule gives, as a share of SMI, the top + # of the band below it. The charts from October 2024 print each top as + # the nearest dollar, and income above a top pays the next band. monthly_smi = spm_unit("nv_ccdp_smi", period) - smi_ratio = where(monthly_smi > 0, monthly_income / monthly_smi, 0) - copay = p.amount.calc(smi_ratio) + scale = p.amount + copay = np.full_like(monthly_income, scale.amounts[0]) + for threshold, amount in zip(scale.thresholds[1:], scale.amounts[1:]): + band_top = monthly_smi * threshold + if ccdp.chart_rounds_to_nearest_dollar: + band_top = np.floor(np.round(band_top, 2) + 0.5) + copay = where(monthly_income > band_top, amount, copay) # Manual MS 180/181 (Co-Payments) waives the copay for exactly three # categories: TANF/NEON referrals, CPS/foster placements, and homeless # households (plus a discretionary case-by-case waiver by the CCDP diff --git a/policyengine_us/variables/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.py b/policyengine_us/variables/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.py index 869b3a14d79..4e7c5309a2d 100644 --- a/policyengine_us/variables/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.py +++ b/policyengine_us/variables/gov/states/nv/dwss/ccdp/eligibility/nv_ccdp_income_eligible.py @@ -1,4 +1,5 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.tax_unit_fpg import fpg class nv_ccdp_income_eligible(Variable): @@ -10,23 +11,27 @@ class nv_ccdp_income_eligible(Variable): reference = ( "https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/CC_PT_06-25_ANNUAL_INCOME_CHANGES_10.02.2025.pdf#page=1", "https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/CC%20PT%2007-23%20Annual%20Income%20Ceiling%20Increase%20(Public%20Distribution).pdf#page=1", - "https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/Amended%20State%20Plan.pdf#page=51", + # PDF pages 50-51 + "https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/Amended%20State%20Plan.pdf#page=50", + "https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=75", + "https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Home/Features/2022-2024%20Child%20Care%20PrePrint%20Draft(1).pdf#page=45", + # PDF pages 1-2 + "https://nwlc.org/wp-content/uploads/2020/02/nevada-childcare-subsidy2019_v1.pdf#page=1", ) def formula(spm_unit, period, parameters): - p = parameters(period).gov.states.nv.dwss.ccdp.income - # Countable income is YEAR-defined; convert to a monthly figure to - # compare against the monthly SMI accessor. - countable_income = ( - spm_unit("nv_ccdp_countable_income", period.this_year) / MONTHS_IN_YEAR - ) + p = parameters(period).gov.states.nv.dwss.ccdp + # MS 316 compares monthly income, rounded to the nearest dollar, with the + # chart for the household's size. + countable_income = spm_unit("nv_ccdp_monthly_countable_income", period) monthly_smi = spm_unit("nv_ccdp_smi", period) enrolled = spm_unit("nv_ccdp_enrolled", period) # New applicants face smi_intake and enrolled families face smi_renewal, both # dated. From October 1, 2024 they are 41% and 49% of SMI, which match the # published charts (CC PT 06-25 and the October 2026 transmittal). From July 1, - # 2022 through September 2024 both were 85%, the ceiling in the state's chart - # effective October 1, 2023. Since October 2024 a separate federal protection + # 2022 through September 2024 both were 85%: the FFY 2022-2024 plan builds the + # July 2022 limits on the fiscal year 2023 table (smi_year_lag), and CC PT + # 07-23 prints the October 2023 ceiling. Since October 2024 a separate federal protection # (45 CFR 98.21(a)(1)(ii)) bars terminating a family mid-certification until # income exceeds 85% SMI, but we don't track certification periods at the # moment, so the 85% mid-period ceiling is not modeled. @@ -39,5 +44,35 @@ def formula(spm_unit, period, parameters): # by this income test even though the program would serve them at 100% # subsidy. Their copay is still waived and their need-for-care is met via # the protective-care pathway in nv_ccdp_copay / nv_ccdp_activity_eligible. - income_limit = monthly_smi * where(enrolled, p.smi_renewal, p.smi_intake) + share = where(enrolled, p.income.smi_renewal, p.income.smi_intake) + income_limit = monthly_smi * share + # The charts from October 2024 print each limit as the nearest dollar. + if p.chart_rounds_to_nearest_dollar: + income_limit = np.floor(np.round(income_limit, 2) + 0.5) + fpg_intake = p.income.fpg_intake + if fpg_intake.in_effect: + # From October 2018 through June 2022 most new applicants faced 130% of + # the poverty guideline. Nevada took up each year's guideline on October 1, + # and the draft FFY 2022-2024 plan prints the October 2020 limits as the + # nearest dollar ($1,868 a month for two, from $1,867.67). NWLC reports that families + # with a child in foster care or protective services and homeless + # families still qualified at 85% of SMI. Families in contracted slots + # or wrap-around care did too, but we don't track those at the moment. + year = period.start.year + program_year = year if period.start.month >= 10 else year - 1 + size = spm_unit("spm_unit_size", period.this_year) + state_group = spm_unit.household("state_group_str", period.this_year) + monthly_fpg = ( + fpg(size, state_group, f"{program_year}-10-01", parameters) + / MONTHS_IN_YEAR + ) + fpg_limit = np.floor(np.round(monthly_fpg * fpg_intake.rate, 2) + 0.5) + person = spm_unit.members + in_protective_care = person("nv_ccdp_eligible_child", period) & ( + person("is_in_foster_care", period) + | person("receives_or_needs_protective_services", period.this_year) + ) + is_homeless = spm_unit.household("is_homeless", period.this_year) + keeps_smi_limit = enrolled | spm_unit.any(in_protective_care) | is_homeless + income_limit = where(keeps_smi_limit, income_limit, fpg_limit) return countable_income <= income_limit diff --git a/policyengine_us/variables/gov/states/nv/dwss/ccdp/income/nv_ccdp_monthly_countable_income.py b/policyengine_us/variables/gov/states/nv/dwss/ccdp/income/nv_ccdp_monthly_countable_income.py new file mode 100644 index 00000000000..2305b950788 --- /dev/null +++ b/policyengine_us/variables/gov/states/nv/dwss/ccdp/income/nv_ccdp_monthly_countable_income.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class nv_ccdp_monthly_countable_income(Variable): + value_type = float + entity = SPMUnit + label = "Nevada CCDP monthly countable income, rounded to the nearest dollar" + definition_period = MONTH + unit = USD + defined_for = StateCode.NV + reference = "https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/Child_Care_Manual_July_2024.pdf#page=75" + + def formula(spm_unit, period, parameters): + # MS 316, second step: round gross monthly income to the nearest dollar, + # with 50 cents and up rounding up. Round to cents first so floating-point + # noise from dividing the annual amount can't move a half dollar. + monthly_income = ( + spm_unit("nv_ccdp_countable_income", period.this_year) / MONTHS_IN_YEAR + ) + return np.floor(np.round(monthly_income, 2) + 0.5) diff --git a/policyengine_us/variables/gov/states/nv/dwss/ccdp/nv_ccdp_smi.py b/policyengine_us/variables/gov/states/nv/dwss/ccdp/nv_ccdp_smi.py index 2cbf74545ee..341359dd78d 100644 --- a/policyengine_us/variables/gov/states/nv/dwss/ccdp/nv_ccdp_smi.py +++ b/policyengine_us/variables/gov/states/nv/dwss/ccdp/nv_ccdp_smi.py @@ -9,19 +9,22 @@ class nv_ccdp_smi(Variable): unit = USD definition_period = MONTH defined_for = StateCode.NV - reference = "https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/ACF-118_CCDF_FFY_2025-2027_For_Nevada__3.pdf#page=36" + reference = ( + "https://www.dss.nv.gov/siteassets/dwss.nv.gov/content/care/ACF-118_CCDF_FFY_2025-2027_For_Nevada__3.pdf#page=36", + # PDF pages 50-51 + "https://dwss.nv.gov/uploadedFiles/dwssnvgov/content/Care/Amended%20State%20Plan.pdf#page=50", + ) def formula(spm_unit, period, parameters): # Nevada keys income eligibility and copays to State Median Income (not # the federal poverty guideline). The income chart updates annually on - # October 1, so select the SMI table in effect for that program year. + # October 1, so select the SMI table in effect for that program year, + # shifted by smi_year_lag where a chart takes up a table early. + p = parameters(period).gov.states.nv.dwss.ccdp.income year = period.start.year - month = period.start.month - if month >= 10: - instant_str = f"{year}-10-01" - else: - instant_str = f"{year - 1}-10-01" + program_year = year if period.start.month >= 10 else year - 1 + table_year = program_year - int(p.smi_year_lag) size = spm_unit("spm_unit_size", period.this_year) state = spm_unit.household("state_code_str", period.this_year) - annual_smi = smi(size, state, instant_str, parameters) + annual_smi = smi(size, state, f"{table_year}-10-01", parameters) return annual_smi / MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.py b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.py index e87352c6c9e..67146f49ffd 100644 --- a/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.py +++ b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp.py @@ -9,8 +9,8 @@ class oh_ccvp(Variable): definition_period = MONTH defined_for = "oh_ccvp_eligible" reference = ( + # PDF pages 2, 4 "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=2", - "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=4", ) def formula(spm_unit, period, parameters): @@ -19,7 +19,9 @@ def formula(spm_unit, period, parameters): # provider's private rate, so the charge caps the payment. The voucher # has no Publicly Funded Child Care copayment; the letter encourages # programs to hold the family's portion to 9% of income without - # requiring it. + # requiring it. The model leaves out the letter's initial enrollment + # payment, which programs receive on authorization on top of the + # monthly payments. person = spm_unit.members rate = person("oh_ccvp_rate", period) charge = person("pre_subsidy_childcare_expenses", period) diff --git a/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_child_age_group.py b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_child_age_group.py new file mode 100644 index 00000000000..90debf99328 --- /dev/null +++ b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_child_age_group.py @@ -0,0 +1,42 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.oh.dcy.ccap.oh_ccap_child_age_group import ( + OHCCAPAgeGroup, +) + + +class oh_ccvp_child_age_group(Variable): + value_type = Enum + entity = Person + possible_values = OHCCAPAgeGroup + default_value = OHCCAPAgeGroup.PRESCHOOL + definition_period = MONTH + label = "Ohio Child Care Choice Voucher Program child age group" + defined_for = StateCode.OH + reference = "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=3" + + def formula(person, period, parameters): + # Procedure Letter 36 prices a child enrolled in, or eligible to enroll in, + # kindergarten at its school-age row, so a child past the five-year boundary + # that oh_ccap_child_age_group uses takes that row whether or not the child + # attends school, and so does a younger child already in school. The chart + # has no summer row. + p = parameters(period).gov.states.oh.dcy.ccap.age_group + age_in_months = person("age", period.this_year) * MONTHS_IN_YEAR + base_group = p.months.calc(age_in_months) + in_school = person("is_in_k12_school", period.this_year) + school_age = (base_group == OHCCAPAgeGroup.SCHOOL_AGE.index) | ( + (base_group == OHCCAPAgeGroup.PRESCHOOL.index) & in_school + ) + return select( + [ + school_age, + base_group == OHCCAPAgeGroup.INFANT.index, + base_group == OHCCAPAgeGroup.TODDLER.index, + ], + [ + OHCCAPAgeGroup.SCHOOL_AGE, + OHCCAPAgeGroup.INFANT, + OHCCAPAgeGroup.TODDLER, + ], + default=OHCCAPAgeGroup.PRESCHOOL, + ) diff --git a/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.py b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.py index 98a978826d2..f3d7f3d9bc3 100644 --- a/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.py +++ b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_eligible.py @@ -8,8 +8,8 @@ class oh_ccvp_eligible(Variable): definition_period = MONTH defined_for = StateCode.OH reference = ( + # PDF pages 3-4 "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=3", - "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=4", "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners%20and%20Providers/Rules%20and%20Resources/2026/PL_45.pdf#page=2", "https://www.lsc.ohio.gov/assets/legislation/136/hb96/en0/files/hb96-kid-bill-analysis-as-enacted-136th-general-assembly.pdf#page=10", ) @@ -25,7 +25,11 @@ def formula(spm_unit, period, parameters): # Publicly Funded Child Care and income does not exceed 200% of the # poverty line. Procedure Letters 21 and 45 print this limit rounded up # to the next whole dollar, as they print the other limits. - income_limit = np.ceil(spm_unit("oh_ccap_fpg", period) * p.fpl_rate) + # Round to cents first so floating-point noise can't push an exact + # dollar up. + income_limit = np.ceil( + np.round(spm_unit("oh_ccap_fpg", period) * p.fpl_rate, 2) + ) within_limit = spm_unit("oh_ccap_countable_income", period) <= income_limit fails_pfcc_income_test = ~spm_unit("oh_ccap_income_eligible", period) # Procedure Letter 36: families meet every other Publicly Funded Child diff --git a/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.py b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.py index 5d90124645e..be10a08ca2c 100644 --- a/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.py +++ b/policyengine_us/variables/gov/states/oh/dcy/ccap/ccvp/oh_ccvp_rate.py @@ -1,4 +1,7 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.oh.dcy.ccap.oh_ccap_rate_with_addons import ( + ohio_rate_with_addons, +) class oh_ccvp_rate(Variable): @@ -9,17 +12,22 @@ class oh_ccvp_rate(Variable): definition_period = MONTH defined_for = "oh_ccvp_eligible_child" reference = ( + # PDF pages 2-3 "https://dam.assets.ohio.gov/image/upload/childrenandyouth.ohio.gov/For%20Partners/Rules%20and%20Resources/2025/PL_36.pdf#page=2", "https://www.lsc.ohio.gov/assets/legislation/136/hb96/en0/files/hb96-kid-bill-analysis-as-enacted-136th-general-assembly.pdf#page=10", + "https://codes.ohio.gov/ohio-administrative-code/rule-5180:6-1-10", ) def formula(person, period, parameters): p = parameters(period).gov.states.oh.dcy.ccap.ccvp # H.B. 96, Section 423.190, moves the voucher to the Publicly Funded # Child Care payment rates by November 1, 2026, without the Step Up to - # Quality enhancement, so the rate before add-ons applies from then on. + # Quality enhancement. The accreditation, non-traditional hours and + # special needs add-ons of 5180:6-1-10(D), (F) and (G) still apply. if p.pfcc_rates_in_effect: - return person("oh_ccap_base_rate", period) + return ohio_rate_with_addons( + person, period, parameters, step_up_to_quality=False + ) provider_type = person("oh_ccap_provider_type", period) - age_group = person("oh_ccap_child_age_group", period) + age_group = person("oh_ccvp_child_age_group", period) return p.payment[provider_type][age_group] diff --git a/policyengine_us/variables/gov/states/oh/dcy/ccap/oh_ccap_rate_with_addons.py b/policyengine_us/variables/gov/states/oh/dcy/ccap/oh_ccap_rate_with_addons.py index d848d547033..9025054d2fd 100644 --- a/policyengine_us/variables/gov/states/oh/dcy/ccap/oh_ccap_rate_with_addons.py +++ b/policyengine_us/variables/gov/states/oh/dcy/ccap/oh_ccap_rate_with_addons.py @@ -1,6 +1,69 @@ from policyengine_us.model_api import * +def ohio_rate_with_addons(person, period, parameters, step_up_to_quality): + """The 5180:6-1-10 payment rate after its add-ons. + + The Child Care Choice Voucher passes step_up_to_quality=False: H.B. 96, + Section 423.190, pays it the Publicly Funded Child Care rates without the + Step Up To Quality enhancement, so paragraph (C) drops out and every rate + that builds on "(B)(1) or (C)" builds on (B)(1). + """ + # 5180:6-1-10(B)(1)-(2): the base rate for all add-ons is the lower + # of the Appendix A county rate and the provider's customary charge. + p = parameters(period).gov.states.oh.dcy.ccap.addons + base_rate = person("oh_ccap_base_rate", period) + customary_charge = person("pre_subsidy_childcare_expenses", period) + capped_base = min_(base_rate, customary_charge) + + # (C)/(D): the higher of the Step Up To Quality bonus and the + # accredited bonus is added on top of the (B)(1) base; this quality + # payment may exceed the customary charge. + quality_tier = person("oh_ccap_quality_tier", period) + is_sutq = (quality_tier != quality_tier.possible_values.NONE) & step_up_to_quality + sutq_pct = where(is_sutq, p.quality.sutq[quality_tier], 0) + sutq_rate = capped_base * (1 + sutq_pct) + is_accredited = person("oh_ccap_is_accredited", period) + accredited_pct = where(is_accredited, p.accredited, 0) + accredited_rate = capped_base * (1 + accredited_pct) + rate_after_quality = max_(sutq_rate, accredited_rate) + + # (F)/(G) refer only to the rate established under (B)(1) or (C). + # Accreditation under (D) is a separate payment and therefore is not + # compounded by the non-traditional-hours or special-needs percentage. + enhancement_base = where(is_sutq, sutq_rate, capped_base) + + non_traditional = person("oh_ccap_non_traditional_hours", period) + non_traditional_pct = where(non_traditional, p.non_traditional_hours, 0) + has_special_needs = person("oh_ccap_special_needs", period) + has_accommodations = person("oh_ccap_has_special_accommodations", period) + accommodations = has_special_needs & has_accommodations + + # (F)(1)/(G)(1): the non-traditional-hours and special-needs + # percentages are computed on the (B)(1)-or-(C) rate; per (F)(3) and + # (G)(1) these payments may not exceed the customary charge, and they + # never reduce the (C) rate already established. + percentage_add = non_traditional_pct + where( + has_special_needs & ~accommodations, p.special_needs, 0 + ) + percentage_payment = rate_after_quality + enhancement_base * percentage_add + capped_percentage_payment = max_( + rate_after_quality, + min_(percentage_payment, customary_charge), + ) + # (G)(2): approved special accommodations double the (B)(1)-or-(C) + # rate with no customary-charge cap (5180:2-16-09 approval). Any + # accreditation payment remains separate, and any non-traditional + # share stays additive. + separate_accreditation_payment = rate_after_quality - enhancement_base + accommodations_payment = ( + enhancement_base + * (p.special_needs_accommodations_multiplier + non_traditional_pct) + + separate_accreditation_payment + ) + return where(accommodations, accommodations_payment, capped_percentage_payment) + + class oh_ccap_rate_with_addons(Variable): value_type = float entity = Person @@ -14,56 +77,6 @@ class oh_ccap_rate_with_addons(Variable): ) def formula(person, period, parameters): - # 5180:6-1-10(B)(1)-(2): the base rate for all add-ons is the lower - # of the Appendix A county rate and the provider's customary charge. - p = parameters(period).gov.states.oh.dcy.ccap.addons - base_rate = person("oh_ccap_base_rate", period) - customary_charge = person("pre_subsidy_childcare_expenses", period) - capped_base = min_(base_rate, customary_charge) - - # (C)/(D): the higher of the Step Up To Quality bonus and the - # accredited bonus is added on top of the (B)(1) base; this quality - # payment may exceed the customary charge. - quality_tier = person("oh_ccap_quality_tier", period) - sutq_pct = p.quality.sutq[quality_tier] - sutq_rate = capped_base * (1 + sutq_pct) - is_accredited = person("oh_ccap_is_accredited", period) - accredited_pct = where(is_accredited, p.accredited, 0) - accredited_rate = capped_base * (1 + accredited_pct) - rate_after_quality = max_(sutq_rate, accredited_rate) - - # (F)/(G) refer only to the rate established under (B)(1) or (C). - # Accreditation under (D) is a separate payment and therefore is not - # compounded by the non-traditional-hours or special-needs percentage. - is_sutq = quality_tier != quality_tier.possible_values.NONE - enhancement_base = where(is_sutq, sutq_rate, capped_base) - - non_traditional = person("oh_ccap_non_traditional_hours", period) - non_traditional_pct = where(non_traditional, p.non_traditional_hours, 0) - has_special_needs = person("oh_ccap_special_needs", period) - has_accommodations = person("oh_ccap_has_special_accommodations", period) - accommodations = has_special_needs & has_accommodations - - # (F)(1)/(G)(1): the non-traditional-hours and special-needs - # percentages are computed on the (B)(1)-or-(C) rate; per (F)(3) and - # (G)(1) these payments may not exceed the customary charge, and they - # never reduce the (C) rate already established. - percentage_add = non_traditional_pct + where( - has_special_needs & ~accommodations, p.special_needs, 0 - ) - percentage_payment = rate_after_quality + enhancement_base * percentage_add - capped_percentage_payment = max_( - rate_after_quality, - min_(percentage_payment, customary_charge), - ) - # (G)(2): approved special accommodations double the (B)(1)-or-(C) - # rate with no customary-charge cap (5180:2-16-09 approval). Any - # accreditation payment remains separate, and any non-traditional - # share stays additive. - separate_accreditation_payment = rate_after_quality - enhancement_base - accommodations_payment = ( - enhancement_base - * (p.special_needs_accommodations_multiplier + non_traditional_pct) - + separate_accreditation_payment + return ohio_rate_with_addons( + person, period, parameters, step_up_to_quality=True ) - return where(accommodations, accommodations_payment, capped_percentage_payment) diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index ab0f49eba0d..289bd1fbbf7 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -300,6 +300,44 @@ candidates: and that no authority for a statewide delay before Alaska''s November 1, 2025 good-faith exemption was found (hr1_in_effect.yaml, is_snap_abawd_hr1_in_effect.py). The good-faith window is modeled separately, through the waived areas and the retained pre-HR1 exceptions.' +- id: us-al:ccdf-new-applicant-limit-june-2026 + program: child-care-assistance + years: + from: 2026 + type: calendar + question: From June 1, 2026, does a new Alabama Child Care Subsidy applicant face 180% of the poverty guideline + and a family at recertification 200%, as the FFY 2025-2027 CCDF State Plan says, or the 150% and 170% that DHR's + June 1, 2026 fact sheet prints? + sources: + - kind: plan + citation: Alabama CCDF State Plan FFY 2025-2027, 2.2.4 (initial eligibility) + url: https://dhr.alabama.gov/wp-content/uploads/2023/04/2025-2027-CCDF-State-Plan-with-Approval-Letter.pdf#page=26 + - kind: plan + citation: Alabama CCDF State Plan FFY 2025-2027, 2.5.2(c)(iii) (second tier) + url: https://dhr.alabama.gov/wp-content/uploads/2023/04/2025-2027-CCDF-State-Plan-with-Approval-Letter.pdf#page=39 + - kind: guidance + citation: Alabama Department of Human Resources, Child Care Fact Sheet (June 1, 2026) + url: https://dhr.alabama.gov/wp-content/uploads/2026/06/CHILD-CARE-FACT-SHEET-Jun2026-1.pdf#page=1 + readings: + statute: PolicyEngine found no statute or rule that sets either limit. Plan 2.2.4 states "The income eligibility + limit is 180% of Federal Poverty Line (FPL)", effective January 1, 2024, and 2.5.2(c)(iii) describes a second + tier that "caps at 200% FPL". + other: The June 1, 2026 fact sheet ends its initial scale at the 141-150% column, $3,331 a month for a family + of three, and its continuing scale at the 161-170% column, $3,775. + example: A family of three that applies in July 2026 with $3,500 a month qualifies at 180% (the January 2026 fact + sheet tops out at $3,998) but not under the June 2026 scale ($3,331). + pe_us: + follows: gap-fill + code: + - policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_initial.yaml + - policyengine_us/parameters/gov/states/al/dhr/ccsp/income/limit/fpl_continuing.yaml + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10670 + state: ruled + note: On 2026-11-06, PolicyEngine took the June 2026 fact sheet's limits from June 1, 2026. The fact sheet holds + the scales DHR posts for families, and it says "All new applicants must enter under the Initial Eligibility + Monthly Income Scale." The plan's limits carry an effective date of January 1, 2024, and DHR's January 2026 + fact sheet still printed them. - id: us-al:federal-tax-deduction-credit-list program: income-tax years: @@ -3433,7 +3471,7 @@ candidates: example: A family of three that applies in June 2026 with $3,000 a month of countable income qualifies under the rule's 175% (limit $3,887) but not under the department's 130% (limit $2,888). pe_us: - follows: conflicting-source + follows: gap-fill code: - policyengine_us/parameters/gov/states/id/dhw/iccp/income/fpl_rate/initial_eligibility.yaml prs: @@ -4629,6 +4667,48 @@ candidates: state: unreviewed note: 'The statute-first rule requires changing main''s form-based treatment; the open PR proposes following the statute and TB-58. Code not yet on main: md_net_capital_gain, md_capital_gains_surtax.' +- id: us-md:ccdf-new-applicant-limit-sources-differ + program: child-care-assistance + years: + from: 2026 + type: federal-fiscal + question: From October 2025, does a new Maryland Child Care Scholarship applicant face 75% of the federal fiscal + 2025 state median income, $94,026 a year for a family of three, as MSDE's scholarship page posts, or 75% of + the fiscal 2026 median, $97,094, as page 4 of MSDE's February 2026 briefing applies? + sources: + - kind: guidance + citation: MSDE, Child Care Scholarship Program, Initial Income Scale effective December 15, 2024 and Continuation + Income Scale effective April 22, 2024 (captured October 9, 2026) + url: https://web.archive.org/web/20261009215322/https://earlychildhood.marylandpublicschools.org/child-care-providers/child-care-scholarship-program + - kind: guidance + citation: MSDE, Child Care Scholarship Program briefing to the House Ways and Means Committee (February 4, 2026), + pages 4, 20 and 21 + url: https://mgaleg.maryland.gov/meeting_material/2026/w&m%20-%20134146885147130127%20-%20Briefing%20materials.pdf#page=4 + readings: + statute: PolicyEngine found no statute or rule that names the median income year. COMAR 13A.14.06.03(H) prints + a dollar scale, which us-md:ccs-income-scale-regulation covers. + other: 'MSDE''s scholarship page posts the Initial Income Scale effective December 15, 2024 as the "Table used + for new applications": $94,026 a year for a family of three, 75% of the federal fiscal 2025 median. Page 20 + of the briefing says the program uses the fiscal 2025 estimates ($149,249 for four); page 4 gives $115,587 + for four, 75% of the fiscal 2026 median of $154,117.' + example: A family of three that applies in March 2026 with $95,000 a year qualifies at 75% of the fiscal 2026 + median ($97,094) but not under the posted scale ($94,026). + pe_us: + follows: gap-fill + code: + - policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_freeze_in_effect.yaml + - policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_frozen_year.yaml + - policyengine_us/parameters/gov/states/md/msde/ccs/income/continuation_smi_freeze_in_effect.yaml + - policyengine_us/parameters/gov/states/md/msde/ccs/income/continuation_smi_frozen_year.yaml + - policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_income_eligible.py + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10670 + state: ruled + note: On 2026-11-07, PolicyEngine took the posted scales, which MSDE applies to applications and page 20 of its + briefing describes. The model holds the fiscal 2025 median for new applicants from October 1, 2025, and for + continuing families from April 22, 2024, when the posted Continuation Income Scale ($106,563 for three) took + effect. Before this change, the model moved new applicants to the fiscal 2026 median in January 2026 and kept + continuing families on the median MSDE froze at its 2021 level until January 2025. - id: us-md:ccs-copay-flat-schedule program: child-care-assistance years: @@ -4670,6 +4750,47 @@ candidates: 2022 to May 2024 no statute is supplied. The bulletin''s amounts are maximums and some families pay $0, while the model charges the maximum, subject to the 7 percent federal cap. The parameter starts 2022-05-01; the bulletin dates the change May 23, 2022.' +- id: us-md:ccs-income-scale-regulation + program: child-care-assistance + years: + from: 2023 + type: state-fiscal + question: Does a new Maryland Child Care Scholarship applicant face the income eligibility scale in COMAR 13A.14.06.03(H), + which tops out at $60,081 a year for a family of three, or the 75% of state median income that MSDE has applied + since July 2022? + sources: + - kind: statute + citation: Md. Code, Educ. §9.5-111(d)(2) (Chapter 732 of 2023) + url: https://mgaleg.maryland.gov/mgawebsite/Laws/StatuteText?article=ged§ion=9.5-111&enactments=false + - kind: regulation + citation: COMAR 13A.14.06.03(F)(1) and (H) + url: https://regs.maryland.gov/us/md/exec/comar/13A.14.06.03 + - kind: guidance + citation: MSDE, Child Care Scholarship Program briefing to the House Ways and Means Committee (February 4, 2026), + page 21 + url: https://mgaleg.maryland.gov/meeting_material/2026/w&m%20-%20134146885147130127%20-%20Briefing%20materials.pdf#page=21 + readings: + statute: From July 1, 2023, the Department "may not" alter the Program in effect as of January 1, 2023 to "Reduce + the income eligibility requirements", unless it first notifies four legislative committees or the Board of + Public Works approves budget reductions. + other: COMAR 13A.14.06.03(F)(1) has an applicant meet the scale in §H, which tops out at $60,081 a year for + a family of three, 65% of the federal fiscal 2018 median. Page 21 of MSDE's briefing lists 75% of the median + it froze at its 2021 level for new applicants in fiscal 2023 and 2024. + example: A family of three that applies in March 2026 with $70,000 a year qualifies under MSDE's posted scale + ($94,026) but not under COMAR's ($60,081). + pe_us: + follows: statute + code: + - policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_rate/initial.yaml + - policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_income_eligible.py + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10670 + state: ruled + note: On 2026-11-07, PolicyEngine kept MSDE's limits. On January 1, 2023, MSDE applied 75% of the median it froze + at its 2021 level, $78,628 a year for three, and a move to COMAR's scale would reduce that limit, which the + statute bars. If the Program in effect on that date means the regulation's scale, the statute doesn't reach + MSDE's higher limit, and the question turns on whether a state rule binds like a Treasury regulation, which + PolicyEngine has not settled. The model also follows MSDE from July 2022, before the statute took effect. - id: us-md:dependent-exemption-chart-10a program: income-tax years: @@ -5525,6 +5646,51 @@ candidates: prs: [] state: unreviewed note: Establish the guidance's statutory basis and reconcile M1SA with M1REF. +- id: us-mo:ccs-chart-guideline-year-2026 + program: child-care-assistance + years: + from: 2026 + type: calendar + question: Does a new Missouri Child Care Subsidy applicant in 2026 face 150% of the 2026 poverty guideline, or + 150% of the 2025 guideline, which DESE's income chart prints through 2026? + sources: + - kind: regulation + citation: 5 CSR 25-200.060(1), incorporating the Child Care Subsidy Eligibility Policy Manual revised November + 2022 + url: https://www.law.cornell.edu/regulations/missouri/5-CSR-25-200-060 + - kind: manual + citation: DESE, Child Care Subsidy Eligibility Policy Manual (revised August 2022), 4.7 (p. 7) and 11.1 (p. + 21), the copy DESE lists among its incorporated reference materials + url: https://web.archive.org/web/20250901014258/https://dese.mo.gov/sites/dese/files/media/pdf/2022/10/Manual%20CCSEPM%20FINAL_POST.pdf#page=7 + - kind: manual + citation: DESE, Child Care Manual 2010.045.00, Income Eligibility Guidelines (archived August 31, 2025) + url: https://web.archive.org/web/20250831220820id_/https://dese.mo.gov/childhood/quality-programs/child-care-subsidy/child-care-manual/2010/045/00 + - kind: guidance + citation: DESE, November 2025 Child Care Eligibility Income Guidelines and Sliding Fee Chart, updated July 1, + 2026 + url: https://dese.mo.gov/sites/g/files/zuston521/files/media/pdf/2026/07/Income%20Elig%20_Updated%206.29.26.pdf#page=1 + readings: + statute: The entry cites no statute. 5 CSR 25-200.060(1) incorporates the manual revised November 2022 and no + later amendment. In the copy DESE lists, 4.7 caps adjusted gross income at 85% of state median income at application + and says the income maximums "are listed on the Child Care Income Eligibility Guidelines and Sliding Fee Chart", + and 11.1 starts Transitional Child Care at 151% of poverty. Neither section names a guideline year. + other: Manual 2010.045.00 caps a new applicant's adjusted gross income at "150% of the federal poverty level", + and DESE's chart, headed November 2025 and updated July 1, 2026, tops the traditional scale at $3,331 a month + for a family of three, 150% of the 2025 guideline. + example: A family of three that applies in August 2026 with $3,400 a month of adjusted gross income qualifies + at 150% of the 2026 guideline ($3,415) but not under the chart ($3,331). + pe_us: + follows: gap-fill + code: + - policyengine_us/parameters/gov/states/mo/dese/ccs/income/fpg_year_lag.yaml + - policyengine_us/variables/gov/states/mo/dese/ccs/eligibility/mo_ccs_fpg.py + prs: + - https://github.com/PolicyEngine/policyengine-us/pull/10670 + state: ruled + note: On 2026-11-06, PolicyEngine took the chart's 2025 guideline through 2026. The incorporated manual leaves + the maximums to the chart, and neither manual names a guideline year, so the agency's chart fills the gap. The + model also keeps 4.7's 85% of state median income as an outer limit, which the July 2026 chart restates. From + 2027 a lag of one year extrapolates until DESE posts a new chart. - id: us-mo:claim-of-right-federal-tax-deduction program: income-tax years: @@ -6088,7 +6254,7 @@ candidates: example: A family of three at redetermination in March 2026 with $4,300 a month keeps graduated eligibility under the scale (limit $4,442) but has income above the rule's 185% (limit $4,109). pe_us: - follows: conflicting-source + follows: gap-fill code: - policyengine_us/parameters/gov/states/mt/dphhs/ccap/income/fpg_limit/graduated.yaml - policyengine_us/variables/gov/states/mt/dphhs/ccap/eligibility/mt_ccap_income_eligible.py @@ -6165,8 +6331,10 @@ candidates: prs: - https://github.com/PolicyEngine/policyengine-us/pull/10670 state: unreviewed - note: PE-US keeps the rule's 150% for these months, and the PR leaves them unchanged. The question turns on whether - a state rule binds like a Treasury regulation, which PolicyEngine has not settled. + note: 'PE-US keeps the rule''s 150% for these months, and the PR leaves them unchanged. The question turns on + whether a state rule binds like a Treasury regulation, which PolicyEngine has not settled. With no statute in + the entry, the rule fills the statute slot, as in us-ak:hap-general-relief-assistance, so follows: statute means + the model follows ARM 37.80.202(1).' - id: us-mt:elderly-credit-homestead-costs program: income-tax years: @@ -11602,7 +11770,8 @@ candidates: state: unreviewed note: PE-US follows the manual and Appendix A, which the Bureau for Family Assistance links from its Child Care Policy page; the PR changes only the guideline year. Check whether the plan's 85% states a limit the Bureau - applies or the federal ceiling. + applies or the federal ceiling. With no statute or rule in the entry, gap-fill means the code follows the manual + and Appendix A, not the plan. - id: us-wv:claim-of-right-subtraction-authority program: income-tax years: From a7558b60b8f5b208a49c853a331a5008fb6973b1 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 7 Nov 2026 16:37:37 -0500 Subject: [PATCH 12/13] Cap Indiana's and West Virginia's limits at 85% of state median income - Indiana: each FSSA schedule caps families at 85% of the state median income table that starts the October before its guideline year, rounded up to the next dollar. Enrolled families face that cap alone, and new applicants face the lower of the cap and the guideline limit, so the cap binds from 16 people on the March 2025 schedule and 19 on the April 2026 schedule. - West Virginia: Appendix A stops its ten- and eleven-person rows at 85% of the October 2024 median ($9,247 and $9,440 a month), the ceiling 45 CFR 98.20(a)(2)(i) sets, and the model keeps that table while the scale stands. - Pin every size on Indiana's 2025 and 2026 schedules for new applicants and enrolled families, and West Virginia's capped sizes from October 2024 through October 2026. - Georgia: pin a working, enrolled family that fails only the income test beside a child in DFCS custody, so CAPS pays only the foster child's care. - Draw Indiana and West Virginia families of up to 20 and 11 people in the Python rule checks, where the caps bind. Co-Authored-By: Claude Opus 5.5 --- changelog.d/child-care-posted-limits.fixed.md | 2 +- .../in/fssa/ccdf/income/fpg_year_lag.yaml | 2 + .../in/fssa/ccdf/income/stay_on_smi_rate.yaml | 12 +- .../states/wv/dhhr/ccap/income/smi_limit.yaml | 19 + .../wv/dhhr/ccap/income/smi_year_lag.yaml | 20 + .../states/ga/decal/caps/dfcs_custody.yaml | 47 + .../eligibility/in_ccdf_income_eligible.yaml | 2002 ++++++++++++++++- .../wv/dhhr/ccap/wv_ccap_income_eligible.yaml | 227 +- .../test_child_care_posted_income_limits.py | 133 +- .../eligibility/in_ccdf_income_eligible.py | 21 +- .../in/fssa/ccdf/eligibility/in_ccdf_smi.py | 29 + .../eligibility/wv_ccap_income_eligible.py | 29 +- .../wv/dhhr/ccap/eligibility/wv_ccap_smi.py | 28 + source_conflicts/candidates.yaml | 8 +- 14 files changed, 2479 insertions(+), 100 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/smi_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/smi_year_lag.yaml create mode 100644 policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_smi.py create mode 100644 policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_smi.py diff --git a/changelog.d/child-care-posted-limits.fixed.md b/changelog.d/child-care-posted-limits.fixed.md index a840718e248..51cad6af6cc 100644 --- a/changelog.d/child-care-posted-limits.fixed.md +++ b/changelog.d/child-care-posted-limits.fixed.md @@ -1 +1 @@ -Bring state child care income limits into line with what states post: Alabama's June 2026 limits, with families of eight or more on the chart's last row; Idaho's 130% limit for new applicants from January 2025 and before April 2023; the poverty guideline year that Idaho, Indiana, Missouri, West Virginia and Montana apply; Maryland's initial and continuation scales on the federal fiscal 2025 median that MSDE posts; Missouri's transitional limits; Montana's 185% limit for new applicants from July 2023 and 200% graduated limit from July 2025; Nevada's dated intake and renewal limits, including 130% of the poverty guideline for new applicants from October 2018 through June 2022, and its copay schedules back to 2015; and Georgia's dated limits for new applicants since 2016. +Bring state child care income limits into line with what states post: Alabama's June 2026 limits, with families of eight or more on the chart's last row; Idaho's 130% limit for new applicants from January 2025 and before April 2023; the poverty guideline year that Idaho, Indiana, Missouri, West Virginia and Montana apply; the caps at 85% of state median income that Indiana's and West Virginia's charts print for their largest families; Maryland's initial and continuation scales on the federal fiscal 2025 median that MSDE posts; Missouri's transitional limits; Montana's 185% limit for new applicants from July 2023 and 200% graduated limit from July 2025; Nevada's dated intake and renewal limits, including 130% of the poverty guideline for new applicants from October 2018 through June 2022, and its copay schedules back to 2015; and Georgia's dated limits for new applicants since 2016. diff --git a/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/fpg_year_lag.yaml b/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/fpg_year_lag.yaml index f2ae776ce37..a951aee1089 100644 --- a/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/fpg_year_lag.yaml +++ b/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/fpg_year_lag.yaml @@ -9,6 +9,8 @@ description: Indiana uses the federal poverty guideline from this many years bef # Before March 12, 2023 the model reads the 2022 guideline, and before 2023 the current # year's, since no earlier dated schedule is available. From 2027 a lag of 1 extrapolates: # the model keeps the prior year's guideline because no 2027 schedule exists yet. +# Each schedule caps families at 85% of the state median income table that starts the +# October before its guideline year, so in_ccdf_smi reads that table through this lag. values: 2015-01-01: 0 2023-01-01: 1 diff --git a/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/stay_on_smi_rate.yaml b/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/stay_on_smi_rate.yaml index e3c68579087..7c63613a485 100644 --- a/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/stay_on_smi_rate.yaml +++ b/policyengine_us/parameters/gov/states/in/fssa/ccdf/income/stay_on_smi_rate.yaml @@ -1,12 +1,20 @@ -description: Indiana limits continuing eligibility to families with income at or below this percentage of the state median income under the Child Care and Development Fund program. +description: Indiana limits income to this share of the state median income under the Child Care and Development Fund program. +# Enrolled families stay eligible up to this share. New applicants face the lower of +# this share and the get-on share of the guideline; on the April 5, 2026 schedule this +# share binds from 19 people ($13,028 a month). Each schedule rounds this limit up to +# the next dollar. values: 2023-08-01: 0.85 metadata: unit: /1 period: year - label: Indiana CCDF continuing income limit rate + label: Indiana CCDF state median income limit rate reference: + - title: "Indiana FSSA, CCDF Sliding Fee Schedule with copays, 2026 (effective April 5, 2026), Max SMI column #page 1-2" + href: https://www.in.gov/dA/7fc32972de/CCDFSlidingFeeSchedule_withCopays_2026.pdf#page=1 + - title: Indiana CCDF State Plan FFY 2025-2027, Amendment 2, Section 2.2.4(a)(ii) + href: https://www.in.gov/dA/6307709ae5/ACF-118CCDFFFY2025-2027IndianaAmendment.pdf?language_id=1#page=22 - title: Indiana CCDF Policy Manual, Change in Physical Custody Policy (income below 85% SMI) href: https://www.in.gov/fssa/carefinder/files/CCDF-Policy-Manual.pdf#page=10 - title: Income to Stay On CCDF diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/smi_limit.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/smi_limit.yaml new file mode 100644 index 00000000000..2e0e5f278af --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/smi_limit.yaml @@ -0,0 +1,19 @@ +description: West Virginia limits income to this share of the state median income under the Child Care Assistance Program. +# Federal rules cap child care eligibility at 85% of the state median income, and the +# CCDF plan allows no higher limit. Appendix A ends the ten- and eleven-person scales at +# that cap, below 185% of the guideline: $9,247 and $9,440 a month on the October 2024 +# state median income table. +values: + 2015-01-01: 0.85 + +metadata: + unit: /1 + period: year + label: West Virginia CCAP income limit as share of state median income + reference: + - title: 45 CFR 98.20(a)(2)(i) + href: https://www.ecfr.gov/current/title-45/section-98.20#p-98.20(a)(2)(i) + - title: West Virginia CCDF State Plan FFY 2025-2027, 2.2.4(a)(ii) + href: https://bfa.wv.gov/media/39915/download?inline#page=21 + - title: "WV Child Care Subsidy Appendix A, Sliding Fee Scale (FY 2024 Federal Poverty Level), ten- and eleven-person families #page 5-6" + href: https://bfa.wv.gov/media/6826/download?inline#page=5 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/smi_year_lag.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/smi_year_lag.yaml new file mode 100644 index 00000000000..156f0f33e90 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/smi_year_lag.yaml @@ -0,0 +1,20 @@ +description: West Virginia reads the state median income table from this many federal fiscal years before the program year under the Child Care Assistance Program. +# Appendix A's sliding fee scale, created October 1, 2024, caps the largest families at +# 85% of the October 2024 table ($9,247 a month for ten people). The Bureau's Child Care +# Policy page still linked that scale on November 5, 2026, so the lag grows to keep the +# October 2024 table. A new scale adds a date here. From October 2027 the lag of two +# extrapolates: it reads the October 2025 table, which no scale prints. +values: + 2015-01-01: 0 + 2025-10-01: 1 + 2026-10-01: 2 + +metadata: + unit: year + period: month + label: West Virginia CCAP state median income table year lag + reference: + - title: "WV Child Care Subsidy Appendix A, Sliding Fee Scale (FY 2024 Federal Poverty Level), ten- and eleven-person families #page 5-6" + href: https://bfa.wv.gov/media/6826/download?inline#page=5 + - title: WV Bureau for Family Assistance, Child Care Policy + href: https://bfa.wv.gov/bfa-policy-and-plans/child-care-policy diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/dfcs_custody.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/dfcs_custody.yaml index 363025d8785..4e6b5428787 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/dfcs_custody.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/decal/caps/dfcs_custody.yaml @@ -154,6 +154,53 @@ # DFCS child: min(1,000, 957.67) = $957.67, with no fee. The sibling gets nothing. ga_caps: 957.67 +- name: A child in DFCS custody doesn't waive the income test for a working, enrolled family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + weekly_hours_worked_before_lsr: 40 + employment_income: 108_000 + immigration_status: CITIZEN + person2: + age: 4 + immigration_status: CITIZEN + is_in_foster_care: true + ga_caps_provider_type: CENTER + ga_caps_care_type: FULL_TIME + ga_caps_quality_rating: NONE + person3: + age: 4 + immigration_status: CITIZEN + ga_caps_provider_type: CENTER + ga_caps_care_type: FULL_TIME + ga_caps_quality_rating: NONE + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + ga_caps_enrolled: true + spm_unit_pre_subsidy_childcare_expenses: 24_000 + households: + household: + members: [person1, person2, person3] + state_code: GA + county_str: FULTON_COUNTY_GA + output: + # The family of two passes the activity test and, as an enrolled family, needs no + # priority group, but $108,000 exceeds 85% of the median for two: + # 110,736 * 0.68 * 0.85 = 64,005.41, printed as $64,006. + ga_caps_income_eligible: false + ga_caps_activity_eligible: true + ga_caps_family_eligible: false + ga_caps_eligible: true + # Only the DFCS child's care: min(1,000, 957.67) = $957.67, with no fee. + ga_caps: 957.67 + - name: The family's own case pays its fee while the DFCS child's care owes none. period: 2026-01 absolute_error_margin: 0.01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml index fc820eaa0f0..05457e44410 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.yaml @@ -233,11 +233,9 @@ in_ccdf_income_eligible: false # --- 85% SMI enrolled boundary at 2026-01 --- -# 2-person IN SMI = 6,427.06/mo; 85% = 5,462.99/mo -> 65,555.88/yr. The 2026 -# SMI is uprated from the 2025-10-01 actual (107,555/yr) by the CBO AGI -# forecast, and reverts to the un-uprated base (85% = 62,166.79/yr) once an -# actual 2026-10-01 value is added, so these cases keep a comfortable margin -# below the un-uprated limit and above the uprated one. +# January 2026 still reads FSSA's schedule effective March 23, 2025, which caps a +# family of two at 85% of the October 2024 state median income (103,324 for four): +# 103,324 * 0.68 * 0.85 / 12 = 4,976.77, printed as 4,977 a month, or 59,724 a year. - name: Case 11, enrolled income below 85% SMI, eligible. period: 2026-01 @@ -245,7 +243,7 @@ people: person1: age: 35 - employment_income: 60_000 # below 85% SMI under either basis + employment_income: 59_000 # below the 59,724 limit person2: age: 5 is_tax_unit_dependent: true @@ -266,7 +264,7 @@ people: person1: age: 35 - employment_income: 70_000 # above 85% SMI (65,556) but below 100% SMI + employment_income: 70_000 # above the 59,724 limit, below 100% of SMI (70,260) person2: age: 5 is_tax_unit_dependent: true @@ -1101,91 +1099,325 @@ p14: age: 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + p23: + age: + 2026: 30 + p24: + age: + 2026: 30 + p25: + age: + 2026: 30 + p26: + age: + 2026: 30 + p27: + age: + 2026: 30 + p28: + age: + 2026: 30 + p29: + age: + 2026: 30 + p30: + age: + 2026: 30 + p31: + age: + 2026: 30 + p32: + age: + 2026: 30 + p33: + age: + 2026: 30 + p34: + age: + 2026: 30 + p35: + age: + 2026: 30 + p36: + age: + 2026: 30 + p37: + age: + 2026: 30 + p38: + age: + 2026: 30 + p39: + age: + 2026: 30 + p40: + age: + 2026: 30 spm_units: u1: members: [p1] spm_unit_size: - 2026: 2 - in_ccdf_countable_income: 2_435 + 2026: 1 + in_ccdf_countable_income: 1_796 is_in_ccdf_enrolled: false u2: members: [p2] spm_unit_size: - 2026: 2 - in_ccdf_countable_income: 2_436 + 2026: 1 + in_ccdf_countable_income: 1_797 is_in_ccdf_enrolled: false u3: members: [p3] spm_unit_size: - 2026: 3 - in_ccdf_countable_income: 3_074 + 2026: 2 + in_ccdf_countable_income: 2_435 is_in_ccdf_enrolled: false u4: members: [p4] spm_unit_size: - 2026: 3 - in_ccdf_countable_income: 3_075 + 2026: 2 + in_ccdf_countable_income: 2_436 is_in_ccdf_enrolled: false u5: members: [p5] spm_unit_size: - 2026: 4 - in_ccdf_countable_income: 3_713 + 2026: 3 + in_ccdf_countable_income: 3_074 is_in_ccdf_enrolled: false u6: members: [p6] spm_unit_size: - 2026: 4 - in_ccdf_countable_income: 3_714 + 2026: 3 + in_ccdf_countable_income: 3_075 is_in_ccdf_enrolled: false u7: members: [p7] spm_unit_size: - 2026: 5 - in_ccdf_countable_income: 4_352 + 2026: 4 + in_ccdf_countable_income: 3_713 is_in_ccdf_enrolled: false u8: members: [p8] spm_unit_size: - 2026: 5 - in_ccdf_countable_income: 4_353 + 2026: 4 + in_ccdf_countable_income: 3_714 is_in_ccdf_enrolled: false u9: members: [p9] spm_unit_size: - 2026: 6 - in_ccdf_countable_income: 4_991 + 2026: 5 + in_ccdf_countable_income: 4_352 is_in_ccdf_enrolled: false u10: members: [p10] spm_unit_size: - 2026: 6 - in_ccdf_countable_income: 4_992 + 2026: 5 + in_ccdf_countable_income: 4_353 is_in_ccdf_enrolled: false u11: members: [p11] spm_unit_size: - 2026: 7 - in_ccdf_countable_income: 5_630 + 2026: 6 + in_ccdf_countable_income: 4_991 is_in_ccdf_enrolled: false u12: members: [p12] spm_unit_size: - 2026: 7 - in_ccdf_countable_income: 5_631 + 2026: 6 + in_ccdf_countable_income: 4_992 is_in_ccdf_enrolled: false u13: members: [p13] spm_unit_size: - 2026: 8 - in_ccdf_countable_income: 6_269 + 2026: 7 + in_ccdf_countable_income: 5_630 is_in_ccdf_enrolled: false u14: members: [p14] + spm_unit_size: + 2026: 7 + in_ccdf_countable_income: 5_631 + is_in_ccdf_enrolled: false + u15: + members: [p15] + spm_unit_size: + 2026: 8 + in_ccdf_countable_income: 6_269 + is_in_ccdf_enrolled: false + u16: + members: [p16] spm_unit_size: 2026: 8 in_ccdf_countable_income: 6_270 is_in_ccdf_enrolled: false + u17: + members: [p17] + spm_unit_size: + 2026: 9 + in_ccdf_countable_income: 6_908 + is_in_ccdf_enrolled: false + u18: + members: [p18] + spm_unit_size: + 2026: 9 + in_ccdf_countable_income: 6_909 + is_in_ccdf_enrolled: false + u19: + members: [p19] + spm_unit_size: + 2026: 10 + in_ccdf_countable_income: 7_547 + is_in_ccdf_enrolled: false + u20: + members: [p20] + spm_unit_size: + 2026: 10 + in_ccdf_countable_income: 7_548 + is_in_ccdf_enrolled: false + u21: + members: [p21] + spm_unit_size: + 2026: 11 + in_ccdf_countable_income: 8_186 + is_in_ccdf_enrolled: false + u22: + members: [p22] + spm_unit_size: + 2026: 11 + in_ccdf_countable_income: 8_187 + is_in_ccdf_enrolled: false + u23: + members: [p23] + spm_unit_size: + 2026: 12 + in_ccdf_countable_income: 8_825 + is_in_ccdf_enrolled: false + u24: + members: [p24] + spm_unit_size: + 2026: 12 + in_ccdf_countable_income: 8_826 + is_in_ccdf_enrolled: false + u25: + members: [p25] + spm_unit_size: + 2026: 13 + in_ccdf_countable_income: 9_464 + is_in_ccdf_enrolled: false + u26: + members: [p26] + spm_unit_size: + 2026: 13 + in_ccdf_countable_income: 9_465 + is_in_ccdf_enrolled: false + u27: + members: [p27] + spm_unit_size: + 2026: 14 + in_ccdf_countable_income: 10_103 + is_in_ccdf_enrolled: false + u28: + members: [p28] + spm_unit_size: + 2026: 14 + in_ccdf_countable_income: 10_104 + is_in_ccdf_enrolled: false + u29: + members: [p29] + spm_unit_size: + 2026: 15 + in_ccdf_countable_income: 10_742 + is_in_ccdf_enrolled: false + u30: + members: [p30] + spm_unit_size: + 2026: 15 + in_ccdf_countable_income: 10_743 + is_in_ccdf_enrolled: false + u31: + members: [p31] + spm_unit_size: + 2026: 16 + in_ccdf_countable_income: 11_381 + is_in_ccdf_enrolled: false + u32: + members: [p32] + spm_unit_size: + 2026: 16 + in_ccdf_countable_income: 11_382 + is_in_ccdf_enrolled: false + u33: + members: [p33] + spm_unit_size: + 2026: 17 + in_ccdf_countable_income: 12_020 + is_in_ccdf_enrolled: false + u34: + members: [p34] + spm_unit_size: + 2026: 17 + in_ccdf_countable_income: 12_021 + is_in_ccdf_enrolled: false + u35: + members: [p35] + spm_unit_size: + 2026: 18 + in_ccdf_countable_income: 12_659 + is_in_ccdf_enrolled: false + u36: + members: [p36] + spm_unit_size: + 2026: 18 + in_ccdf_countable_income: 12_660 + is_in_ccdf_enrolled: false + u37: + members: [p37] + spm_unit_size: + 2026: 19 + in_ccdf_countable_income: 13_028 + is_in_ccdf_enrolled: false + u38: + members: [p38] + spm_unit_size: + 2026: 19 + in_ccdf_countable_income: 13_029 + is_in_ccdf_enrolled: false + u39: + members: [p39] + spm_unit_size: + 2026: 20 + in_ccdf_countable_income: 13_257 + is_in_ccdf_enrolled: false + u40: + members: [p40] + spm_unit_size: + 2026: 20 + in_ccdf_countable_income: 13_258 + is_in_ccdf_enrolled: false households: h1: members: [p1] @@ -1243,9 +1475,1709 @@ members: [p14] state_code: 2026: IN + h15: + members: [p15] + state_code: + 2026: IN + h16: + members: [p16] + state_code: + 2026: IN + h17: + members: [p17] + state_code: + 2026: IN + h18: + members: [p18] + state_code: + 2026: IN + h19: + members: [p19] + state_code: + 2026: IN + h20: + members: [p20] + state_code: + 2026: IN + h21: + members: [p21] + state_code: + 2026: IN + h22: + members: [p22] + state_code: + 2026: IN + h23: + members: [p23] + state_code: + 2026: IN + h24: + members: [p24] + state_code: + 2026: IN + h25: + members: [p25] + state_code: + 2026: IN + h26: + members: [p26] + state_code: + 2026: IN + h27: + members: [p27] + state_code: + 2026: IN + h28: + members: [p28] + state_code: + 2026: IN + h29: + members: [p29] + state_code: + 2026: IN + h30: + members: [p30] + state_code: + 2026: IN + h31: + members: [p31] + state_code: + 2026: IN + h32: + members: [p32] + state_code: + 2026: IN + h33: + members: [p33] + state_code: + 2026: IN + h34: + members: [p34] + state_code: + 2026: IN + h35: + members: [p35] + state_code: + 2026: IN + h36: + members: [p36] + state_code: + 2026: IN + h37: + members: [p37] + state_code: + 2026: IN + h38: + members: [p38] + state_code: + 2026: IN + h39: + members: [p39] + state_code: + 2026: IN + h40: + members: [p40] + state_code: + 2026: IN + output: + # 135% of the 2026 guideline, sizes 1 to 18. For 19 and 20 people the + # chart's cap binds instead: 85% of the October 2025 state median income, + # rounded up to the next dollar. + in_ccdf_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: FSSA's chart effective April 5, 2026 holds enrolled families at every family size in May 2026. + period: 2026-05 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + p23: + age: + 2026: 30 + p24: + age: + 2026: 30 + p25: + age: + 2026: 30 + p26: + age: + 2026: 30 + p27: + age: + 2026: 30 + p28: + age: + 2026: 30 + p29: + age: + 2026: 30 + p30: + age: + 2026: 30 + p31: + age: + 2026: 30 + p32: + age: + 2026: 30 + p33: + age: + 2026: 30 + p34: + age: + 2026: 30 + p35: + age: + 2026: 30 + p36: + age: + 2026: 30 + p37: + age: + 2026: 30 + p38: + age: + 2026: 30 + p39: + age: + 2026: 30 + p40: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 1 + in_ccdf_countable_income: 3_962 + is_in_ccdf_enrolled: true + u2: + members: [p2] + spm_unit_size: + 2026: 1 + in_ccdf_countable_income: 3_963 + is_in_ccdf_enrolled: true + u3: + members: [p3] + spm_unit_size: + 2026: 2 + in_ccdf_countable_income: 5_181 + is_in_ccdf_enrolled: true + u4: + members: [p4] + spm_unit_size: + 2026: 2 + in_ccdf_countable_income: 5_182 + is_in_ccdf_enrolled: true + u5: + members: [p5] + spm_unit_size: + 2026: 3 + in_ccdf_countable_income: 6_400 + is_in_ccdf_enrolled: true + u6: + members: [p6] + spm_unit_size: + 2026: 3 + in_ccdf_countable_income: 6_401 + is_in_ccdf_enrolled: true + u7: + members: [p7] + spm_unit_size: + 2026: 4 + in_ccdf_countable_income: 7_619 + is_in_ccdf_enrolled: true + u8: + members: [p8] + spm_unit_size: + 2026: 4 + in_ccdf_countable_income: 7_620 + is_in_ccdf_enrolled: true + u9: + members: [p9] + spm_unit_size: + 2026: 5 + in_ccdf_countable_income: 8_838 + is_in_ccdf_enrolled: true + u10: + members: [p10] + spm_unit_size: + 2026: 5 + in_ccdf_countable_income: 8_839 + is_in_ccdf_enrolled: true + u11: + members: [p11] + spm_unit_size: + 2026: 6 + in_ccdf_countable_income: 10_057 + is_in_ccdf_enrolled: true + u12: + members: [p12] + spm_unit_size: + 2026: 6 + in_ccdf_countable_income: 10_058 + is_in_ccdf_enrolled: true + u13: + members: [p13] + spm_unit_size: + 2026: 7 + in_ccdf_countable_income: 10_285 + is_in_ccdf_enrolled: true + u14: + members: [p14] + spm_unit_size: + 2026: 7 + in_ccdf_countable_income: 10_286 + is_in_ccdf_enrolled: true + u15: + members: [p15] + spm_unit_size: + 2026: 8 + in_ccdf_countable_income: 10_514 + is_in_ccdf_enrolled: true + u16: + members: [p16] + spm_unit_size: + 2026: 8 + in_ccdf_countable_income: 10_515 + is_in_ccdf_enrolled: true + u17: + members: [p17] + spm_unit_size: + 2026: 9 + in_ccdf_countable_income: 10_743 + is_in_ccdf_enrolled: true + u18: + members: [p18] + spm_unit_size: + 2026: 9 + in_ccdf_countable_income: 10_744 + is_in_ccdf_enrolled: true + u19: + members: [p19] + spm_unit_size: + 2026: 10 + in_ccdf_countable_income: 10_971 + is_in_ccdf_enrolled: true + u20: + members: [p20] + spm_unit_size: + 2026: 10 + in_ccdf_countable_income: 10_972 + is_in_ccdf_enrolled: true + u21: + members: [p21] + spm_unit_size: + 2026: 11 + in_ccdf_countable_income: 11_200 + is_in_ccdf_enrolled: true + u22: + members: [p22] + spm_unit_size: + 2026: 11 + in_ccdf_countable_income: 11_201 + is_in_ccdf_enrolled: true + u23: + members: [p23] + spm_unit_size: + 2026: 12 + in_ccdf_countable_income: 11_428 + is_in_ccdf_enrolled: true + u24: + members: [p24] + spm_unit_size: + 2026: 12 + in_ccdf_countable_income: 11_429 + is_in_ccdf_enrolled: true + u25: + members: [p25] + spm_unit_size: + 2026: 13 + in_ccdf_countable_income: 11_657 + is_in_ccdf_enrolled: true + u26: + members: [p26] + spm_unit_size: + 2026: 13 + in_ccdf_countable_income: 11_658 + is_in_ccdf_enrolled: true + u27: + members: [p27] + spm_unit_size: + 2026: 14 + in_ccdf_countable_income: 11_885 + is_in_ccdf_enrolled: true + u28: + members: [p28] + spm_unit_size: + 2026: 14 + in_ccdf_countable_income: 11_886 + is_in_ccdf_enrolled: true + u29: + members: [p29] + spm_unit_size: + 2026: 15 + in_ccdf_countable_income: 12_114 + is_in_ccdf_enrolled: true + u30: + members: [p30] + spm_unit_size: + 2026: 15 + in_ccdf_countable_income: 12_115 + is_in_ccdf_enrolled: true + u31: + members: [p31] + spm_unit_size: + 2026: 16 + in_ccdf_countable_income: 12_342 + is_in_ccdf_enrolled: true + u32: + members: [p32] + spm_unit_size: + 2026: 16 + in_ccdf_countable_income: 12_343 + is_in_ccdf_enrolled: true + u33: + members: [p33] + spm_unit_size: + 2026: 17 + in_ccdf_countable_income: 12_571 + is_in_ccdf_enrolled: true + u34: + members: [p34] + spm_unit_size: + 2026: 17 + in_ccdf_countable_income: 12_572 + is_in_ccdf_enrolled: true + u35: + members: [p35] + spm_unit_size: + 2026: 18 + in_ccdf_countable_income: 12_800 + is_in_ccdf_enrolled: true + u36: + members: [p36] + spm_unit_size: + 2026: 18 + in_ccdf_countable_income: 12_801 + is_in_ccdf_enrolled: true + u37: + members: [p37] + spm_unit_size: + 2026: 19 + in_ccdf_countable_income: 13_028 + is_in_ccdf_enrolled: true + u38: + members: [p38] + spm_unit_size: + 2026: 19 + in_ccdf_countable_income: 13_029 + is_in_ccdf_enrolled: true + u39: + members: [p39] + spm_unit_size: + 2026: 20 + in_ccdf_countable_income: 13_257 + is_in_ccdf_enrolled: true + u40: + members: [p40] + spm_unit_size: + 2026: 20 + in_ccdf_countable_income: 13_258 + is_in_ccdf_enrolled: true + households: + h1: + members: [p1] + state_code: + 2026: IN + h2: + members: [p2] + state_code: + 2026: IN + h3: + members: [p3] + state_code: + 2026: IN + h4: + members: [p4] + state_code: + 2026: IN + h5: + members: [p5] + state_code: + 2026: IN + h6: + members: [p6] + state_code: + 2026: IN + h7: + members: [p7] + state_code: + 2026: IN + h8: + members: [p8] + state_code: + 2026: IN + h9: + members: [p9] + state_code: + 2026: IN + h10: + members: [p10] + state_code: + 2026: IN + h11: + members: [p11] + state_code: + 2026: IN + h12: + members: [p12] + state_code: + 2026: IN + h13: + members: [p13] + state_code: + 2026: IN + h14: + members: [p14] + state_code: + 2026: IN + h15: + members: [p15] + state_code: + 2026: IN + h16: + members: [p16] + state_code: + 2026: IN + h17: + members: [p17] + state_code: + 2026: IN + h18: + members: [p18] + state_code: + 2026: IN + h19: + members: [p19] + state_code: + 2026: IN + h20: + members: [p20] + state_code: + 2026: IN + h21: + members: [p21] + state_code: + 2026: IN + h22: + members: [p22] + state_code: + 2026: IN + h23: + members: [p23] + state_code: + 2026: IN + h24: + members: [p24] + state_code: + 2026: IN + h25: + members: [p25] + state_code: + 2026: IN + h26: + members: [p26] + state_code: + 2026: IN + h27: + members: [p27] + state_code: + 2026: IN + h28: + members: [p28] + state_code: + 2026: IN + h29: + members: [p29] + state_code: + 2026: IN + h30: + members: [p30] + state_code: + 2026: IN + h31: + members: [p31] + state_code: + 2026: IN + h32: + members: [p32] + state_code: + 2026: IN + h33: + members: [p33] + state_code: + 2026: IN + h34: + members: [p34] + state_code: + 2026: IN + h35: + members: [p35] + state_code: + 2026: IN + h36: + members: [p36] + state_code: + 2026: IN + h37: + members: [p37] + state_code: + 2026: IN + h38: + members: [p38] + state_code: + 2026: IN + h39: + members: [p39] + state_code: + 2026: IN + h40: + members: [p40] + state_code: + 2026: IN + output: + # The Max SMI column, sizes 1 to 20: 85% of the October 2025 state median + # income, rounded up to the next dollar. + in_ccdf_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: FSSA's chart effective March 23, 2025 still holds at every family size in January 2026. + period: 2026-01 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + p23: + age: + 2026: 30 + p24: + age: + 2026: 30 + p25: + age: + 2026: 30 + p26: + age: + 2026: 30 + p27: + age: + 2026: 30 + p28: + age: + 2026: 30 + p29: + age: + 2026: 30 + p30: + age: + 2026: 30 + p31: + age: + 2026: 30 + p32: + age: + 2026: 30 + p33: + age: + 2026: 30 + p34: + age: + 2026: 30 + p35: + age: + 2026: 30 + p36: + age: + 2026: 30 + p37: + age: + 2026: 30 + p38: + age: + 2026: 30 + p39: + age: + 2026: 30 + p40: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 1 + in_ccdf_countable_income: 1_956 + is_in_ccdf_enrolled: false + u2: + members: [p2] + spm_unit_size: + 2026: 1 + in_ccdf_countable_income: 1_957 + is_in_ccdf_enrolled: false + u3: + members: [p3] + spm_unit_size: + 2026: 2 + in_ccdf_countable_income: 2_644 + is_in_ccdf_enrolled: false + u4: + members: [p4] + spm_unit_size: + 2026: 2 + in_ccdf_countable_income: 2_645 + is_in_ccdf_enrolled: false + u5: + members: [p5] + spm_unit_size: + 2026: 3 + in_ccdf_countable_income: 3_331 + is_in_ccdf_enrolled: false + u6: + members: [p6] + spm_unit_size: + 2026: 3 + in_ccdf_countable_income: 3_332 + is_in_ccdf_enrolled: false + u7: + members: [p7] + spm_unit_size: + 2026: 4 + in_ccdf_countable_income: 4_019 + is_in_ccdf_enrolled: false + u8: + members: [p8] + spm_unit_size: + 2026: 4 + in_ccdf_countable_income: 4_020 + is_in_ccdf_enrolled: false + u9: + members: [p9] + spm_unit_size: + 2026: 5 + in_ccdf_countable_income: 4_706 + is_in_ccdf_enrolled: false + u10: + members: [p10] + spm_unit_size: + 2026: 5 + in_ccdf_countable_income: 4_707 + is_in_ccdf_enrolled: false + u11: + members: [p11] + spm_unit_size: + 2026: 6 + in_ccdf_countable_income: 5_394 + is_in_ccdf_enrolled: false + u12: + members: [p12] + spm_unit_size: + 2026: 6 + in_ccdf_countable_income: 5_395 + is_in_ccdf_enrolled: false + u13: + members: [p13] + spm_unit_size: + 2026: 7 + in_ccdf_countable_income: 6_081 + is_in_ccdf_enrolled: false + u14: + members: [p14] + spm_unit_size: + 2026: 7 + in_ccdf_countable_income: 6_082 + is_in_ccdf_enrolled: false + u15: + members: [p15] + spm_unit_size: + 2026: 8 + in_ccdf_countable_income: 6_769 + is_in_ccdf_enrolled: false + u16: + members: [p16] + spm_unit_size: + 2026: 8 + in_ccdf_countable_income: 6_770 + is_in_ccdf_enrolled: false + u17: + members: [p17] + spm_unit_size: + 2026: 9 + in_ccdf_countable_income: 7_456 + is_in_ccdf_enrolled: false + u18: + members: [p18] + spm_unit_size: + 2026: 9 + in_ccdf_countable_income: 7_457 + is_in_ccdf_enrolled: false + u19: + members: [p19] + spm_unit_size: + 2026: 10 + in_ccdf_countable_income: 8_144 + is_in_ccdf_enrolled: false + u20: + members: [p20] + spm_unit_size: + 2026: 10 + in_ccdf_countable_income: 8_145 + is_in_ccdf_enrolled: false + u21: + members: [p21] + spm_unit_size: + 2026: 11 + in_ccdf_countable_income: 8_831 + is_in_ccdf_enrolled: false + u22: + members: [p22] + spm_unit_size: + 2026: 11 + in_ccdf_countable_income: 8_832 + is_in_ccdf_enrolled: false + u23: + members: [p23] + spm_unit_size: + 2026: 12 + in_ccdf_countable_income: 9_519 + is_in_ccdf_enrolled: false + u24: + members: [p24] + spm_unit_size: + 2026: 12 + in_ccdf_countable_income: 9_520 + is_in_ccdf_enrolled: false + u25: + members: [p25] + spm_unit_size: + 2026: 13 + in_ccdf_countable_income: 10_206 + is_in_ccdf_enrolled: false + u26: + members: [p26] + spm_unit_size: + 2026: 13 + in_ccdf_countable_income: 10_207 + is_in_ccdf_enrolled: false + u27: + members: [p27] + spm_unit_size: + 2026: 14 + in_ccdf_countable_income: 10_894 + is_in_ccdf_enrolled: false + u28: + members: [p28] + spm_unit_size: + 2026: 14 + in_ccdf_countable_income: 10_895 + is_in_ccdf_enrolled: false + u29: + members: [p29] + spm_unit_size: + 2026: 15 + in_ccdf_countable_income: 11_581 + is_in_ccdf_enrolled: false + u30: + members: [p30] + spm_unit_size: + 2026: 15 + in_ccdf_countable_income: 11_582 + is_in_ccdf_enrolled: false + u31: + members: [p31] + spm_unit_size: + 2026: 16 + in_ccdf_countable_income: 11_857 + is_in_ccdf_enrolled: false + u32: + members: [p32] + spm_unit_size: + 2026: 16 + in_ccdf_countable_income: 11_858 + is_in_ccdf_enrolled: false + u33: + members: [p33] + spm_unit_size: + 2026: 17 + in_ccdf_countable_income: 12_076 + is_in_ccdf_enrolled: false + u34: + members: [p34] + spm_unit_size: + 2026: 17 + in_ccdf_countable_income: 12_077 + is_in_ccdf_enrolled: false + u35: + members: [p35] + spm_unit_size: + 2026: 18 + in_ccdf_countable_income: 12_296 + is_in_ccdf_enrolled: false + u36: + members: [p36] + spm_unit_size: + 2026: 18 + in_ccdf_countable_income: 12_297 + is_in_ccdf_enrolled: false + u37: + members: [p37] + spm_unit_size: + 2026: 19 + in_ccdf_countable_income: 12_516 + is_in_ccdf_enrolled: false + u38: + members: [p38] + spm_unit_size: + 2026: 19 + in_ccdf_countable_income: 12_517 + is_in_ccdf_enrolled: false + u39: + members: [p39] + spm_unit_size: + 2026: 20 + in_ccdf_countable_income: 12_735 + is_in_ccdf_enrolled: false + u40: + members: [p40] + spm_unit_size: + 2026: 20 + in_ccdf_countable_income: 12_736 + is_in_ccdf_enrolled: false + households: + h1: + members: [p1] + state_code: + 2026: IN + h2: + members: [p2] + state_code: + 2026: IN + h3: + members: [p3] + state_code: + 2026: IN + h4: + members: [p4] + state_code: + 2026: IN + h5: + members: [p5] + state_code: + 2026: IN + h6: + members: [p6] + state_code: + 2026: IN + h7: + members: [p7] + state_code: + 2026: IN + h8: + members: [p8] + state_code: + 2026: IN + h9: + members: [p9] + state_code: + 2026: IN + h10: + members: [p10] + state_code: + 2026: IN + h11: + members: [p11] + state_code: + 2026: IN + h12: + members: [p12] + state_code: + 2026: IN + h13: + members: [p13] + state_code: + 2026: IN + h14: + members: [p14] + state_code: + 2026: IN + h15: + members: [p15] + state_code: + 2026: IN + h16: + members: [p16] + state_code: + 2026: IN + h17: + members: [p17] + state_code: + 2026: IN + h18: + members: [p18] + state_code: + 2026: IN + h19: + members: [p19] + state_code: + 2026: IN + h20: + members: [p20] + state_code: + 2026: IN + h21: + members: [p21] + state_code: + 2026: IN + h22: + members: [p22] + state_code: + 2026: IN + h23: + members: [p23] + state_code: + 2026: IN + h24: + members: [p24] + state_code: + 2026: IN + h25: + members: [p25] + state_code: + 2026: IN + h26: + members: [p26] + state_code: + 2026: IN + h27: + members: [p27] + state_code: + 2026: IN + h28: + members: [p28] + state_code: + 2026: IN + h29: + members: [p29] + state_code: + 2026: IN + h30: + members: [p30] + state_code: + 2026: IN + h31: + members: [p31] + state_code: + 2026: IN + h32: + members: [p32] + state_code: + 2026: IN + h33: + members: [p33] + state_code: + 2026: IN + h34: + members: [p34] + state_code: + 2026: IN + h35: + members: [p35] + state_code: + 2026: IN + h36: + members: [p36] + state_code: + 2026: IN + h37: + members: [p37] + state_code: + 2026: IN + h38: + members: [p38] + state_code: + 2026: IN + h39: + members: [p39] + state_code: + 2026: IN + h40: + members: [p40] + state_code: + 2026: IN + output: + # 150% of the 2025 guideline, sizes 1 to 15. From 16 people the chart's cap + # binds instead: 85% of the October 2024 state median income, rounded up + # to the next dollar. + in_ccdf_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: FSSA's chart effective March 23, 2025 still holds enrolled families at every family size in January 2026. + period: 2026-01 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + p23: + age: + 2026: 30 + p24: + age: + 2026: 30 + p25: + age: + 2026: 30 + p26: + age: + 2026: 30 + p27: + age: + 2026: 30 + p28: + age: + 2026: 30 + p29: + age: + 2026: 30 + p30: + age: + 2026: 30 + p31: + age: + 2026: 30 + p32: + age: + 2026: 30 + p33: + age: + 2026: 30 + p34: + age: + 2026: 30 + p35: + age: + 2026: 30 + p36: + age: + 2026: 30 + p37: + age: + 2026: 30 + p38: + age: + 2026: 30 + p39: + age: + 2026: 30 + p40: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 1 + in_ccdf_countable_income: 3_806 + is_in_ccdf_enrolled: true + u2: + members: [p2] + spm_unit_size: + 2026: 1 + in_ccdf_countable_income: 3_807 + is_in_ccdf_enrolled: true + u3: + members: [p3] + spm_unit_size: + 2026: 2 + in_ccdf_countable_income: 4_977 + is_in_ccdf_enrolled: true + u4: + members: [p4] + spm_unit_size: + 2026: 2 + in_ccdf_countable_income: 4_978 + is_in_ccdf_enrolled: true + u5: + members: [p5] + spm_unit_size: + 2026: 3 + in_ccdf_countable_income: 6_148 + is_in_ccdf_enrolled: true + u6: + members: [p6] + spm_unit_size: + 2026: 3 + in_ccdf_countable_income: 6_149 + is_in_ccdf_enrolled: true + u7: + members: [p7] + spm_unit_size: + 2026: 4 + in_ccdf_countable_income: 7_319 + is_in_ccdf_enrolled: true + u8: + members: [p8] + spm_unit_size: + 2026: 4 + in_ccdf_countable_income: 7_320 + is_in_ccdf_enrolled: true + u9: + members: [p9] + spm_unit_size: + 2026: 5 + in_ccdf_countable_income: 8_490 + is_in_ccdf_enrolled: true + u10: + members: [p10] + spm_unit_size: + 2026: 5 + in_ccdf_countable_income: 8_491 + is_in_ccdf_enrolled: true + u11: + members: [p11] + spm_unit_size: + 2026: 6 + in_ccdf_countable_income: 9_661 + is_in_ccdf_enrolled: true + u12: + members: [p12] + spm_unit_size: + 2026: 6 + in_ccdf_countable_income: 9_662 + is_in_ccdf_enrolled: true + u13: + members: [p13] + spm_unit_size: + 2026: 7 + in_ccdf_countable_income: 9_881 + is_in_ccdf_enrolled: true + u14: + members: [p14] + spm_unit_size: + 2026: 7 + in_ccdf_countable_income: 9_882 + is_in_ccdf_enrolled: true + u15: + members: [p15] + spm_unit_size: + 2026: 8 + in_ccdf_countable_income: 10_100 + is_in_ccdf_enrolled: true + u16: + members: [p16] + spm_unit_size: + 2026: 8 + in_ccdf_countable_income: 10_101 + is_in_ccdf_enrolled: true + u17: + members: [p17] + spm_unit_size: + 2026: 9 + in_ccdf_countable_income: 10_320 + is_in_ccdf_enrolled: true + u18: + members: [p18] + spm_unit_size: + 2026: 9 + in_ccdf_countable_income: 10_321 + is_in_ccdf_enrolled: true + u19: + members: [p19] + spm_unit_size: + 2026: 10 + in_ccdf_countable_income: 10_540 + is_in_ccdf_enrolled: true + u20: + members: [p20] + spm_unit_size: + 2026: 10 + in_ccdf_countable_income: 10_541 + is_in_ccdf_enrolled: true + u21: + members: [p21] + spm_unit_size: + 2026: 11 + in_ccdf_countable_income: 10_759 + is_in_ccdf_enrolled: true + u22: + members: [p22] + spm_unit_size: + 2026: 11 + in_ccdf_countable_income: 10_760 + is_in_ccdf_enrolled: true + u23: + members: [p23] + spm_unit_size: + 2026: 12 + in_ccdf_countable_income: 10_979 + is_in_ccdf_enrolled: true + u24: + members: [p24] + spm_unit_size: + 2026: 12 + in_ccdf_countable_income: 10_980 + is_in_ccdf_enrolled: true + u25: + members: [p25] + spm_unit_size: + 2026: 13 + in_ccdf_countable_income: 11_198 + is_in_ccdf_enrolled: true + u26: + members: [p26] + spm_unit_size: + 2026: 13 + in_ccdf_countable_income: 11_199 + is_in_ccdf_enrolled: true + u27: + members: [p27] + spm_unit_size: + 2026: 14 + in_ccdf_countable_income: 11_418 + is_in_ccdf_enrolled: true + u28: + members: [p28] + spm_unit_size: + 2026: 14 + in_ccdf_countable_income: 11_419 + is_in_ccdf_enrolled: true + u29: + members: [p29] + spm_unit_size: + 2026: 15 + in_ccdf_countable_income: 11_637 + is_in_ccdf_enrolled: true + u30: + members: [p30] + spm_unit_size: + 2026: 15 + in_ccdf_countable_income: 11_638 + is_in_ccdf_enrolled: true + u31: + members: [p31] + spm_unit_size: + 2026: 16 + in_ccdf_countable_income: 11_857 + is_in_ccdf_enrolled: true + u32: + members: [p32] + spm_unit_size: + 2026: 16 + in_ccdf_countable_income: 11_858 + is_in_ccdf_enrolled: true + u33: + members: [p33] + spm_unit_size: + 2026: 17 + in_ccdf_countable_income: 12_076 + is_in_ccdf_enrolled: true + u34: + members: [p34] + spm_unit_size: + 2026: 17 + in_ccdf_countable_income: 12_077 + is_in_ccdf_enrolled: true + u35: + members: [p35] + spm_unit_size: + 2026: 18 + in_ccdf_countable_income: 12_296 + is_in_ccdf_enrolled: true + u36: + members: [p36] + spm_unit_size: + 2026: 18 + in_ccdf_countable_income: 12_297 + is_in_ccdf_enrolled: true + u37: + members: [p37] + spm_unit_size: + 2026: 19 + in_ccdf_countable_income: 12_516 + is_in_ccdf_enrolled: true + u38: + members: [p38] + spm_unit_size: + 2026: 19 + in_ccdf_countable_income: 12_517 + is_in_ccdf_enrolled: true + u39: + members: [p39] + spm_unit_size: + 2026: 20 + in_ccdf_countable_income: 12_735 + is_in_ccdf_enrolled: true + u40: + members: [p40] + spm_unit_size: + 2026: 20 + in_ccdf_countable_income: 12_736 + is_in_ccdf_enrolled: true + households: + h1: + members: [p1] + state_code: + 2026: IN + h2: + members: [p2] + state_code: + 2026: IN + h3: + members: [p3] + state_code: + 2026: IN + h4: + members: [p4] + state_code: + 2026: IN + h5: + members: [p5] + state_code: + 2026: IN + h6: + members: [p6] + state_code: + 2026: IN + h7: + members: [p7] + state_code: + 2026: IN + h8: + members: [p8] + state_code: + 2026: IN + h9: + members: [p9] + state_code: + 2026: IN + h10: + members: [p10] + state_code: + 2026: IN + h11: + members: [p11] + state_code: + 2026: IN + h12: + members: [p12] + state_code: + 2026: IN + h13: + members: [p13] + state_code: + 2026: IN + h14: + members: [p14] + state_code: + 2026: IN + h15: + members: [p15] + state_code: + 2026: IN + h16: + members: [p16] + state_code: + 2026: IN + h17: + members: [p17] + state_code: + 2026: IN + h18: + members: [p18] + state_code: + 2026: IN + h19: + members: [p19] + state_code: + 2026: IN + h20: + members: [p20] + state_code: + 2026: IN + h21: + members: [p21] + state_code: + 2026: IN + h22: + members: [p22] + state_code: + 2026: IN + h23: + members: [p23] + state_code: + 2026: IN + h24: + members: [p24] + state_code: + 2026: IN + h25: + members: [p25] + state_code: + 2026: IN + h26: + members: [p26] + state_code: + 2026: IN + h27: + members: [p27] + state_code: + 2026: IN + h28: + members: [p28] + state_code: + 2026: IN + h29: + members: [p29] + state_code: + 2026: IN + h30: + members: [p30] + state_code: + 2026: IN + h31: + members: [p31] + state_code: + 2026: IN + h32: + members: [p32] + state_code: + 2026: IN + h33: + members: [p33] + state_code: + 2026: IN + h34: + members: [p34] + state_code: + 2026: IN + h35: + members: [p35] + state_code: + 2026: IN + h36: + members: [p36] + state_code: + 2026: IN + h37: + members: [p37] + state_code: + 2026: IN + h38: + members: [p38] + state_code: + 2026: IN + h39: + members: [p39] + state_code: + 2026: IN + h40: + members: [p40] + state_code: + 2026: IN output: - # 135% of the 2026 guideline, sizes 2 to 8. - in_ccdf_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false] + # The Max SMI column, sizes 1 to 20: 85% of the October 2024 state median + # income, rounded up to the next dollar. + in_ccdf_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] - name: The CCDF plan's limits effective March 31, 2024 hold at every family size in June 2024. period: 2024-06 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml index 2ab78bf2295..d7e14f14bdd 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml @@ -715,6 +715,18 @@ p18: age: 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 spm_units: u1: members: [p1] @@ -806,6 +818,26 @@ spm_unit_size: 2026: 9 wv_ccap_countable_income: 8_958 + u19: + members: [p19] + spm_unit_size: + 2026: 10 + wv_ccap_countable_income: 9_247 + u20: + members: [p20] + spm_unit_size: + 2026: 10 + wv_ccap_countable_income: 9_248 + u21: + members: [p21] + spm_unit_size: + 2026: 11 + wv_ccap_countable_income: 9_440 + u22: + members: [p22] + spm_unit_size: + 2026: 11 + wv_ccap_countable_income: 9_441 households: h1: members: [p1] @@ -879,6 +911,197 @@ members: [p18] state_code: 2026: WV + h19: + members: [p19] + state_code: + 2026: WV + h20: + members: [p20] + state_code: + 2026: WV + h21: + members: [p21] + state_code: + 2026: WV + h22: + members: [p22] + state_code: + 2026: WV + output: + # 185% of the 2024 guideline, sizes 1 to 9. For ten and eleven people the + # scale stops at 85% of the October 2024 state median income. + wv_ccap_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: Appendix A caps ten and eleven people at 85% of the October 2024 state median income in October 2024, when the scale starts. + period: 2024-10 + input: + people: + p1: + age: + 2024: 30 + p2: + age: + 2024: 30 + p3: + age: + 2024: 30 + p4: + age: + 2024: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2024: 10 + wv_ccap_countable_income: 9_247 + u2: + members: [p2] + spm_unit_size: + 2024: 10 + wv_ccap_countable_income: 9_248 + u3: + members: [p3] + spm_unit_size: + 2024: 11 + wv_ccap_countable_income: 9_440 + u4: + members: [p4] + spm_unit_size: + 2024: 11 + wv_ccap_countable_income: 9_441 + households: + h1: + members: [p1] + state_code: + 2024: WV + h2: + members: [p2] + state_code: + 2024: WV + h3: + members: [p3] + state_code: + 2024: WV + h4: + members: [p4] + state_code: + 2024: WV + output: + # $9,247 for ten people and $9,440 for eleven. + wv_ccap_income_eligible: [true, false, true, false] + +- name: Appendix A caps ten and eleven people at 85% of the October 2024 state median income in October 2025, after the next table starts. + period: 2025-10 + input: + people: + p1: + age: + 2025: 30 + p2: + age: + 2025: 30 + p3: + age: + 2025: 30 + p4: + age: + 2025: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2025: 10 + wv_ccap_countable_income: 9_247 + u2: + members: [p2] + spm_unit_size: + 2025: 10 + wv_ccap_countable_income: 9_248 + u3: + members: [p3] + spm_unit_size: + 2025: 11 + wv_ccap_countable_income: 9_440 + u4: + members: [p4] + spm_unit_size: + 2025: 11 + wv_ccap_countable_income: 9_441 + households: + h1: + members: [p1] + state_code: + 2025: WV + h2: + members: [p2] + state_code: + 2025: WV + h3: + members: [p3] + state_code: + 2025: WV + h4: + members: [p4] + state_code: + 2025: WV + output: + # $9,247 for ten people and $9,440 for eleven. + wv_ccap_income_eligible: [true, false, true, false] + +- name: Appendix A caps ten and eleven people at 85% of the October 2024 state median income in October 2026, after two more tables start. + period: 2026-10 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 10 + wv_ccap_countable_income: 9_247 + u2: + members: [p2] + spm_unit_size: + 2026: 10 + wv_ccap_countable_income: 9_248 + u3: + members: [p3] + spm_unit_size: + 2026: 11 + wv_ccap_countable_income: 9_440 + u4: + members: [p4] + spm_unit_size: + 2026: 11 + wv_ccap_countable_income: 9_441 + households: + h1: + members: [p1] + state_code: + 2026: WV + h2: + members: [p2] + state_code: + 2026: WV + h3: + members: [p3] + state_code: + 2026: WV + h4: + members: [p4] + state_code: + 2026: WV output: - # 185% of the 2024 guideline, sizes 1 to 9. - wv_ccap_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] + # $9,247 for ten people and $9,440 for eleven. + wv_ccap_income_eligible: [true, false, true, false] diff --git a/policyengine_us/tests/test_child_care_posted_income_limits.py b/policyengine_us/tests/test_child_care_posted_income_limits.py index c6505ae4b29..24409821ab1 100644 --- a/policyengine_us/tests/test_child_care_posted_income_limits.py +++ b/policyengine_us/tests/test_child_care_posted_income_limits.py @@ -6,9 +6,11 @@ 1. Rules: for every date in RULES and NEVADA_RULES and for any income, a family passes exactly when its income is at or below the rate times that date's guideline or - median income, rounded as the state's chart rounds. This also makes each income - test monotonic in income. Each rule states the limit apart from the formulas, so - it acts as a second implementation. + median income, rounded as the state's chart rounds. In Indiana and West Virginia + the limit stops at 85% of the state median income, which binds only for large + families, so those rules draw families of up to 20 and 11 people. This also makes + each income test monotonic in income. Each rule states the limit apart from the + formulas, so it acts as a second implementation. 2. Enrolled families: a family that passes as a new applicant passes as an enrolled family at the same income, in every state with separate limits. 3. Ohio: the voucher pays only families over the Publicly Funded Child Care limit, @@ -123,6 +125,13 @@ class Program: IN = Program( "IN", "in_ccdf_income_eligible", "in_ccdf_countable_income", "is_in_ccdf_enrolled" ) +IN_ENROLLED = Program( + "IN", + "in_ccdf_income_eligible", + "in_ccdf_countable_income", + "is_in_ccdf_enrolled", + True, +) MO = Program( "MO", "mo_ccs_income_eligible", "mo_ccs_adjusted_income", "mo_ccs_enrolled" ) @@ -201,20 +210,42 @@ def nearest_dollar(amount): def next_dollar(amount): - """Any cents go up, as Idaho and Ohio print.""" + """Any cents go up, as Idaho, Ohio and Indiana's 85% limits print.""" return math.ceil(round(amount, 2)) +def median_share(size): + """A family's share of the four-person state median income (45 CFR 96.85(b)): + 52% for one person, 16 points more for each person through six, and 3 points for + each person after that.""" + return 0.52 + 0.16 * (min(size, 6) - 1) + 0.03 * max(size - 6, 0) + + @dataclass(frozen=True) class Rule: program: Program month: str - guideline_year: int - rate: float - rounding: Callable + # A rule without a guideline year tests the median income limit alone. + guideline_year: Optional[int] + rate: Optional[float] = None + rounding: Optional[Callable] = None + # Indiana's and West Virginia's charts stop at 85% of a four-person state median + # income table, adjusted for family size and rounded as each chart prints. + median: Optional[int] = None + median_rounding: Callable = nearest_dollar + max_size: int = 6 def top(self, size): - return self.rounding(guideline(self.guideline_year, size) * self.rate / 12) + limits = [] + if self.guideline_year is not None: + limits.append( + self.rounding(guideline(self.guideline_year, size) * self.rate / 12) + ) + if self.median is not None: + limits.append( + self.median_rounding(self.median * median_share(size) * 0.85 / 12) + ) + return min(limits) RULES = [ @@ -233,23 +264,44 @@ def top(self, size): Rule(ID, "2025-09", 2024, 1.3, next_dollar), Rule(ID, "2025-10", 2025, 1.3, next_dollar), Rule(ID, "2026-06", 2025, 1.3, next_dollar), - # Indiana's charts move partway through each year. - Rule(IN, "2024-06", 2024, 1.5, nearest_dollar), - Rule(IN, "2025-03", 2024, 1.5, nearest_dollar), - Rule(IN, "2025-06", 2025, 1.5, nearest_dollar), - Rule(IN, "2026-01", 2025, 1.5, nearest_dollar), - Rule(IN, "2026-04", 2025, 1.5, nearest_dollar), - Rule(IN, "2026-05", 2026, 1.35, nearest_dollar), + # Indiana's charts move partway through each year. Each caps families at 85% of + # the four-person median that starts the October before its guideline year, + # rounded up. + Rule(IN, "2024-06", 2024, 1.5, nearest_dollar, 95_373, next_dollar, 20), + Rule(IN, "2025-03", 2024, 1.5, nearest_dollar, 95_373, next_dollar, 20), + Rule(IN, "2025-06", 2025, 1.5, nearest_dollar, 103_324, next_dollar, 20), + Rule(IN, "2026-01", 2025, 1.5, nearest_dollar, 103_324, next_dollar, 20), + Rule(IN, "2026-04", 2025, 1.5, nearest_dollar, 103_324, next_dollar, 20), + Rule(IN, "2026-05", 2026, 1.35, nearest_dollar, 107_555, next_dollar, 20), + Rule( + IN_ENROLLED, + "2026-01", + None, + median=103_324, + median_rounding=next_dollar, + max_size=20, + ), + Rule( + IN_ENROLLED, + "2026-05", + None, + median=107_555, + median_rounding=next_dollar, + max_size=20, + ), # Missouri holds the 2025 guideline through 2026. Rule(MO, "2025-11", 2025, 1.5, nearest_dollar), Rule(MO, "2026-01", 2025, 1.5, nearest_dollar), Rule(MO, "2026-07", 2025, 1.5, nearest_dollar), Rule(MO_ENROLLED, "2026-06", 2025, 2.42, nearest_dollar), Rule(MO_ENROLLED, "2026-07", 2025, 2.15, nearest_dollar), - # West Virginia's Appendix A still prints the 2024 guideline. + # West Virginia's Appendix A still prints the 2024 guideline, and from October 2024 + # stops at 85% of that October's four-person median. Rule(WV, "2024-06", 2024, 1.85, nearest_dollar), - Rule(WV, "2025-03", 2024, 1.85, nearest_dollar), - Rule(WV, "2026-03", 2024, 1.85, nearest_dollar), + Rule(WV, "2024-10", 2024, 1.85, nearest_dollar, 90_661, max_size=11), + Rule(WV, "2025-03", 2024, 1.85, nearest_dollar, 90_661, max_size=11), + Rule(WV, "2026-03", 2024, 1.85, nearest_dollar, 90_661, max_size=11), + Rule(WV, "2026-10", 2024, 1.85, nearest_dollar, 90_661, max_size=11), # Montana's scale moves each July. Rule(MT, "2024-03", 2024, 1.85, nearest_dollar), Rule(MT, "2025-03", 2024, 1.85, nearest_dollar), @@ -270,14 +322,20 @@ def top(self, size): Rule(NV, "2022-06", 2021, 1.3, nearest_dollar), ] -SMALL_FAMILIES = st.lists( - st.tuples( - st.integers(min_value=1, max_value=6), - st.integers(min_value=0, max_value=12_000), - ), - min_size=20, - max_size=20, -) + +def families_up_to(max_size, max_income): + """Twenty (size, monthly income) families.""" + return st.lists( + st.tuples( + st.integers(min_value=1, max_value=max_size), + st.integers(min_value=0, max_value=max_income), + ), + min_size=20, + max_size=20, + ) + + +SMALL_FAMILIES = families_up_to(6, 12_000) @pytest.mark.parametrize( @@ -289,12 +347,17 @@ def top(self, size): ), ) def test_limit_equals_rate_times_dated_guideline(rule): + families_drawn = ( + SMALL_FAMILIES if rule.max_size == 6 else families_up_to(rule.max_size, 16_000) + ) + @settings(max_examples=2, deadline=None, derandomize=True) - @given(families=SMALL_FAMILIES) + @given(families=families_drawn) def check(families): # Each family also sits at its top and one dollar over, the two cases a - # random income almost never lands on. - sizes = sorted({size for size, _ in families}) + # random income almost never lands on, and so does the largest size, where + # a median income cap binds. + sizes = sorted({size for size, _ in families} | {rule.max_size}) edges = [ (size, income) for size in sizes @@ -382,17 +445,7 @@ def test_nevada_limit_equals_rate_times_dated_median_income( ), "2026-01", ), - ( - IN, - Program( - "IN", - "in_ccdf_income_eligible", - "in_ccdf_countable_income", - "is_in_ccdf_enrolled", - True, - ), - "2026-05", - ), + (IN, IN_ENROLLED, "2026-05"), (MO, MO_ENROLLED, "2026-07"), (MT, MT_ENROLLED, "2026-03"), (NV, NV_ENROLLED, "2024-10"), diff --git a/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.py b/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.py index 416447c229c..30a9af30ce9 100644 --- a/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.py +++ b/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_income_eligible.py @@ -10,6 +10,9 @@ class in_ccdf_income_eligible(Variable): reference = ( "https://www.in.gov/fssa/carefinder/files/CCDF-Policy-Manual.pdf#page=5", "https://www.in.gov/dA/3271c7180e/Income-Get-on-CCDF.pdf", + # PDF pages 1-2 + "https://www.in.gov/dA/7fc32972de/CCDFSlidingFeeSchedule_withCopays_2026.pdf#page=1", + "https://www.in.gov/dA/6307709ae5/ACF-118CCDFFFY2025-2027IndianaAmendment.pdf?language_id=1#page=22", ) def formula(spm_unit, period, parameters): @@ -19,12 +22,18 @@ def formula(spm_unit, period, parameters): # Initial applicants are tested against the get-on share of the # federal poverty guideline (127% through Jul 2023, 150% from Aug # 2023, 135% from Apr 2026); enrolled recipients are tested at 85% - # of the state median income. FSSA's charts print each limit to the - # nearest dollar, with half a dollar going up ($3,073.50 prints as - # $3,074). Round to cents first so floating-point noise can't move a tie. - initial_limit = np.floor( + # of the state median income. The plan allows no limit above 85% of + # the state median income, and FSSA's charts cap the get-on limit there + # for the largest families ($13,028 a month for 19 people from April + # 2026). The charts print the get-on limit to the nearest dollar, with + # half a dollar going up ($3,073.50 prints as $3,074), and round the 85% + # limit up to the next dollar ($7,618.48 prints as $7,619 for four). + # Round to cents first so floating-point noise can't move a tie. + fpg_limit = np.floor( np.round(spm_unit("in_ccdf_fpg", period) * p.get_on_fpg_rate, 2) + 0.5 ) - continuing_limit = spm_unit("hhs_smi", period) * p.stay_on_smi_rate - income_limit = where(enrolled, continuing_limit, initial_limit) + smi_limit = np.ceil( + np.round(spm_unit("in_ccdf_smi", period) * p.stay_on_smi_rate, 2) + ) + income_limit = where(enrolled, smi_limit, min_(fpg_limit, smi_limit)) return countable_income <= income_limit diff --git a/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_smi.py b/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_smi.py new file mode 100644 index 00000000000..fb5b235f974 --- /dev/null +++ b/policyengine_us/variables/gov/states/in/fssa/ccdf/eligibility/in_ccdf_smi.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import smi + + +class in_ccdf_smi(Variable): + value_type = float + entity = SPMUnit + unit = USD + definition_period = MONTH + label = "Indiana CCDF monthly state median income" + defined_for = StateCode.IN + reference = ( + # PDF pages 1-2 + "https://www.in.gov/dA/7fc32972de/CCDFSlidingFeeSchedule_withCopays_2026.pdf#page=1", + ) + + def formula(spm_unit, period, parameters): + # Each FSSA schedule pairs the guideline year it adopts with the federal + # state median income table that starts the October before. The April 5, + # 2026 schedule caps a family of four at $7,619 a month, 85% of the + # October 2025 table rounded up, and the March 2023, 2024 and 2025 + # schedules follow the same pattern. The guideline year lag therefore + # also selects the table. + p = parameters(period).gov.states["in"].fssa.ccdf.income + guideline_year = period.start.year - int(p.fpg_year_lag) + size = spm_unit("spm_unit_size", period.this_year) + state = spm_unit.household("state_code_str", period.this_year) + annual_smi = smi(size, state, f"{guideline_year - 1}-10-01", parameters) + return annual_smi / MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_income_eligible.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_income_eligible.py index 428e17f9f85..9a0437d3558 100644 --- a/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_income_eligible.py +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_income_eligible.py @@ -9,21 +9,28 @@ class wv_ccap_income_eligible(Variable): defined_for = StateCode.WV reference = ( "https://bfa.wv.gov/media/6766/download?inline#page=25", + # PDF pages 1 and 5-6 "https://bfa.wv.gov/media/6826/download?inline#page=1", ) def formula(spm_unit, period, parameters): - # NOTE: We model the Appendix A intake cap (~185% FPL). The 85% SMI - # "Over-Income Policy Exception" for enrolled recipients (Manual §4.7.1) - # is not modeled at the moment. We also don't distinguish child-only - # TANF cases (Manual §3.2.1.4 requires them to pass the FPL test) from - # full TANF — is_tanf_enrolled treats both as categorically eligible. + # NOTE: The 85% SMI "Over-Income Policy Exception" for enrolled recipients + # (Manual §4.7.1) is not modeled at the moment. We also don't distinguish + # child-only TANF cases (Manual §3.2.1.4 requires them to pass the FPL + # test) from full TANF — is_tanf_enrolled treats both as categorically + # eligible. p = parameters(period).gov.states.wv.dhhr.ccap.income countable_income = spm_unit("wv_ccap_countable_income", period) - fpg = spm_unit("wv_ccap_fpg", period) - # Appendix A prints each limit to the nearest dollar. Round to cents - # first so floating-point noise can't move a tie. - fpl_limit = np.floor(np.round(fpg * p.fpl_limit, 2) + 0.5) - fpl_eligible = countable_income <= fpl_limit + # Appendix A caps intake at 185% of the guideline, and each scale stops at + # 85% of the state median income, which binds from ten people ($9,247 a + # month). Appendix A prints each limit to the nearest dollar. Round to + # cents first so floating-point noise can't move a tie. + fpl_limit = np.floor( + np.round(spm_unit("wv_ccap_fpg", period) * p.fpl_limit, 2) + 0.5 + ) + smi_limit = np.floor( + np.round(spm_unit("wv_ccap_smi", period) * p.smi_limit, 2) + 0.5 + ) + income_eligible = countable_income <= min_(fpl_limit, smi_limit) is_tanf = spm_unit("is_tanf_enrolled", period) - return is_tanf | fpl_eligible + return is_tanf | income_eligible diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_smi.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_smi.py new file mode 100644 index 00000000000..ad6025b6715 --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_smi.py @@ -0,0 +1,28 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import smi + + +class wv_ccap_smi(Variable): + value_type = float + entity = SPMUnit + unit = USD + definition_period = MONTH + label = "West Virginia CCAP monthly state median income" + defined_for = StateCode.WV + reference = ( + # PDF pages 5-6 + "https://bfa.wv.gov/media/6826/download?inline#page=5", + ) + + def formula(spm_unit, period, parameters): + # Each federal state median income table starts on October 1. Select the + # table for the program year, shifted back by smi_year_lag while Appendix A + # keeps the October 2024 table. + p = parameters(period).gov.states.wv.dhhr.ccap.income + year = period.start.year + program_year = year if period.start.month >= 10 else year - 1 + table_year = program_year - int(p.smi_year_lag) + size = spm_unit("spm_unit_size", period.this_year) + state = spm_unit.household("state_code_str", period.this_year) + annual_smi = smi(size, state, f"{table_year}-10-01", parameters) + return annual_smi / MONTHS_IN_YEAR diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 289bd1fbbf7..a739938be25 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -11765,13 +11765,15 @@ candidates: follows: gap-fill code: - policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/fpl_limit.yaml + - policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/smi_limit.yaml prs: - https://github.com/PolicyEngine/policyengine-us/pull/10670 state: unreviewed note: PE-US follows the manual and Appendix A, which the Bureau for Family Assistance links from its Child Care - Policy page; the PR changes only the guideline year. Check whether the plan's 85% states a limit the Bureau - applies or the federal ceiling. With no statute or rule in the entry, gap-fill means the code follows the manual - and Appendix A, not the plan. + Policy page. The PR changes the guideline year and adds Appendix A's own stop at 85% of state median income, + which binds from ten people ($9,247 a month), so the code takes the lower of the two limits at every size. + Check whether the plan's 85% states a limit the Bureau applies or the federal ceiling. With no statute or rule + in the entry, gap-fill means the code follows the manual and Appendix A, not the plan. - id: us-wv:claim-of-right-subtraction-authority program: income-tax years: From 06611b1570298914faf948d809f2c88720bc04f1 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 8 Nov 2026 14:11:44 -0500 Subject: [PATCH 13/13] Test Maryland's posted scales at every family size MSDE posts initial and continuation scales for families of two to twelve. Two new cases check both against PolicyEngine's limits in March 2026. MSDE rounds each cell, and PolicyEngine computes the limits from the federal fiscal 2025 state median income, so the two differ by less than $2 a year. Each case puts income $2 a year below each printed maximum, which passes, and $2 a year above it, which fails. Co-Authored-By: Claude Opus 5.5 --- .../md/msde/ccs/md_ccs_income_eligible.yaml | 598 ++++++++++++++++++ 1 file changed, 598 insertions(+) diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_income_eligible.yaml index ed43e141ae0..8644a0bbcad 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_income_eligible.yaml @@ -364,3 +364,601 @@ output: # 0.85 * 149_249 * 0.84 / 12 = 8_880.32; the fiscal 2026 median would give 9_170.31 md_ccs_income_eligible: [true, false] + +# Posted charts: MSDE rounds each cell of its scales, while PolicyEngine computes +# the limits from the federal fiscal 2025 state median income, so the two differ +# by less than $2 a year. Each case puts monthly income $2 a year below each +# printed maximum, which passes, and $2 a year above it, which fails, and lists +# the outcomes in size order. + +- name: MSDE's Initial Income Scale effective December 15, 2024 holds within $2 a year at sizes 2 to 12 in March 2026. + period: 2026-03 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 2 + md_ccs_countable_income: 6_342.91 + md_ccs_enrolled: false + u2: + members: [p2] + spm_unit_size: + 2026: 2 + md_ccs_countable_income: 6_343.25 + md_ccs_enrolled: false + u3: + members: [p3] + spm_unit_size: + 2026: 3 + md_ccs_countable_income: 7_835.33 + md_ccs_enrolled: false + u4: + members: [p4] + spm_unit_size: + 2026: 3 + md_ccs_countable_income: 7_835.67 + md_ccs_enrolled: false + u5: + members: [p5] + spm_unit_size: + 2026: 4 + md_ccs_countable_income: 9_327.83 + md_ccs_enrolled: false + u6: + members: [p6] + spm_unit_size: + 2026: 4 + md_ccs_countable_income: 9_328.17 + md_ccs_enrolled: false + u7: + members: [p7] + spm_unit_size: + 2026: 5 + md_ccs_countable_income: 10_820.33 + md_ccs_enrolled: false + u8: + members: [p8] + spm_unit_size: + 2026: 5 + md_ccs_countable_income: 10_820.67 + md_ccs_enrolled: false + u9: + members: [p9] + spm_unit_size: + 2026: 6 + md_ccs_countable_income: 12_312.83 + md_ccs_enrolled: false + u10: + members: [p10] + spm_unit_size: + 2026: 6 + md_ccs_countable_income: 12_313.17 + md_ccs_enrolled: false + u11: + members: [p11] + spm_unit_size: + 2026: 7 + md_ccs_countable_income: 12_592.66 + md_ccs_enrolled: false + u12: + members: [p12] + spm_unit_size: + 2026: 7 + md_ccs_countable_income: 12_593.00 + md_ccs_enrolled: false + u13: + members: [p13] + spm_unit_size: + 2026: 8 + md_ccs_countable_income: 12_872.50 + md_ccs_enrolled: false + u14: + members: [p14] + spm_unit_size: + 2026: 8 + md_ccs_countable_income: 12_872.84 + md_ccs_enrolled: false + u15: + members: [p15] + spm_unit_size: + 2026: 9 + md_ccs_countable_income: 13_152.33 + md_ccs_enrolled: false + u16: + members: [p16] + spm_unit_size: + 2026: 9 + md_ccs_countable_income: 13_152.67 + md_ccs_enrolled: false + u17: + members: [p17] + spm_unit_size: + 2026: 10 + md_ccs_countable_income: 13_432.16 + md_ccs_enrolled: false + u18: + members: [p18] + spm_unit_size: + 2026: 10 + md_ccs_countable_income: 13_432.50 + md_ccs_enrolled: false + u19: + members: [p19] + spm_unit_size: + 2026: 11 + md_ccs_countable_income: 13_712.00 + md_ccs_enrolled: false + u20: + members: [p20] + spm_unit_size: + 2026: 11 + md_ccs_countable_income: 13_712.34 + md_ccs_enrolled: false + u21: + members: [p21] + spm_unit_size: + 2026: 12 + md_ccs_countable_income: 13_991.83 + md_ccs_enrolled: false + u22: + members: [p22] + spm_unit_size: + 2026: 12 + md_ccs_countable_income: 13_992.17 + md_ccs_enrolled: false + households: + h1: + members: [p1] + state_code: + 2026: MD + h2: + members: [p2] + state_code: + 2026: MD + h3: + members: [p3] + state_code: + 2026: MD + h4: + members: [p4] + state_code: + 2026: MD + h5: + members: [p5] + state_code: + 2026: MD + h6: + members: [p6] + state_code: + 2026: MD + h7: + members: [p7] + state_code: + 2026: MD + h8: + members: [p8] + state_code: + 2026: MD + h9: + members: [p9] + state_code: + 2026: MD + h10: + members: [p10] + state_code: + 2026: MD + h11: + members: [p11] + state_code: + 2026: MD + h12: + members: [p12] + state_code: + 2026: MD + h13: + members: [p13] + state_code: + 2026: MD + h14: + members: [p14] + state_code: + 2026: MD + h15: + members: [p15] + state_code: + 2026: MD + h16: + members: [p16] + state_code: + 2026: MD + h17: + members: [p17] + state_code: + 2026: MD + h18: + members: [p18] + state_code: + 2026: MD + h19: + members: [p19] + state_code: + 2026: MD + h20: + members: [p20] + state_code: + 2026: MD + h21: + members: [p21] + state_code: + 2026: MD + h22: + members: [p22] + state_code: + 2026: MD + output: + # Maximum annual income from $76,117 for two to $167,904 for twelve. + md_ccs_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false] + +- name: MSDE's Continuation Income Scale effective April 22, 2024 holds within $2 a year at sizes 2 to 12 in March 2026. + period: 2026-03 + input: + people: + p1: + age: + 2026: 30 + p2: + age: + 2026: 30 + p3: + age: + 2026: 30 + p4: + age: + 2026: 30 + p5: + age: + 2026: 30 + p6: + age: + 2026: 30 + p7: + age: + 2026: 30 + p8: + age: + 2026: 30 + p9: + age: + 2026: 30 + p10: + age: + 2026: 30 + p11: + age: + 2026: 30 + p12: + age: + 2026: 30 + p13: + age: + 2026: 30 + p14: + age: + 2026: 30 + p15: + age: + 2026: 30 + p16: + age: + 2026: 30 + p17: + age: + 2026: 30 + p18: + age: + 2026: 30 + p19: + age: + 2026: 30 + p20: + age: + 2026: 30 + p21: + age: + 2026: 30 + p22: + age: + 2026: 30 + spm_units: + u1: + members: [p1] + spm_unit_size: + 2026: 2 + md_ccs_countable_income: 7_188.66 + md_ccs_enrolled: true + u2: + members: [p2] + spm_unit_size: + 2026: 2 + md_ccs_countable_income: 7_189.00 + md_ccs_enrolled: true + u3: + members: [p3] + spm_unit_size: + 2026: 3 + md_ccs_countable_income: 8_880.08 + md_ccs_enrolled: true + u4: + members: [p4] + spm_unit_size: + 2026: 3 + md_ccs_countable_income: 8_880.42 + md_ccs_enrolled: true + u5: + members: [p5] + spm_unit_size: + 2026: 4 + md_ccs_countable_income: 10_571.58 + md_ccs_enrolled: true + u6: + members: [p6] + spm_unit_size: + 2026: 4 + md_ccs_countable_income: 10_571.92 + md_ccs_enrolled: true + u7: + members: [p7] + spm_unit_size: + 2026: 5 + md_ccs_countable_income: 12_263.08 + md_ccs_enrolled: true + u8: + members: [p8] + spm_unit_size: + 2026: 5 + md_ccs_countable_income: 12_263.42 + md_ccs_enrolled: true + u9: + members: [p9] + spm_unit_size: + 2026: 6 + md_ccs_countable_income: 13_954.58 + md_ccs_enrolled: true + u10: + members: [p10] + spm_unit_size: + 2026: 6 + md_ccs_countable_income: 13_954.92 + md_ccs_enrolled: true + u11: + members: [p11] + spm_unit_size: + 2026: 7 + md_ccs_countable_income: 14_271.66 + md_ccs_enrolled: true + u12: + members: [p12] + spm_unit_size: + 2026: 7 + md_ccs_countable_income: 14_272.00 + md_ccs_enrolled: true + u13: + members: [p13] + spm_unit_size: + 2026: 8 + md_ccs_countable_income: 14_588.83 + md_ccs_enrolled: true + u14: + members: [p14] + spm_unit_size: + 2026: 8 + md_ccs_countable_income: 14_589.17 + md_ccs_enrolled: true + u15: + members: [p15] + spm_unit_size: + 2026: 9 + md_ccs_countable_income: 14_906.00 + md_ccs_enrolled: true + u16: + members: [p16] + spm_unit_size: + 2026: 9 + md_ccs_countable_income: 14_906.34 + md_ccs_enrolled: true + u17: + members: [p17] + spm_unit_size: + 2026: 10 + md_ccs_countable_income: 15_223.16 + md_ccs_enrolled: true + u18: + members: [p18] + spm_unit_size: + 2026: 10 + md_ccs_countable_income: 15_223.50 + md_ccs_enrolled: true + u19: + members: [p19] + spm_unit_size: + 2026: 11 + md_ccs_countable_income: 15_540.33 + md_ccs_enrolled: true + u20: + members: [p20] + spm_unit_size: + 2026: 11 + md_ccs_countable_income: 15_540.67 + md_ccs_enrolled: true + u21: + members: [p21] + spm_unit_size: + 2026: 12 + md_ccs_countable_income: 15_857.50 + md_ccs_enrolled: true + u22: + members: [p22] + spm_unit_size: + 2026: 12 + md_ccs_countable_income: 15_857.84 + md_ccs_enrolled: true + households: + h1: + members: [p1] + state_code: + 2026: MD + h2: + members: [p2] + state_code: + 2026: MD + h3: + members: [p3] + state_code: + 2026: MD + h4: + members: [p4] + state_code: + 2026: MD + h5: + members: [p5] + state_code: + 2026: MD + h6: + members: [p6] + state_code: + 2026: MD + h7: + members: [p7] + state_code: + 2026: MD + h8: + members: [p8] + state_code: + 2026: MD + h9: + members: [p9] + state_code: + 2026: MD + h10: + members: [p10] + state_code: + 2026: MD + h11: + members: [p11] + state_code: + 2026: MD + h12: + members: [p12] + state_code: + 2026: MD + h13: + members: [p13] + state_code: + 2026: MD + h14: + members: [p14] + state_code: + 2026: MD + h15: + members: [p15] + state_code: + 2026: MD + h16: + members: [p16] + state_code: + 2026: MD + h17: + members: [p17] + state_code: + 2026: MD + h18: + members: [p18] + state_code: + 2026: MD + h19: + members: [p19] + state_code: + 2026: MD + h20: + members: [p20] + state_code: + 2026: MD + h21: + members: [p21] + state_code: + 2026: MD + h22: + members: [p22] + state_code: + 2026: MD + output: + # Maximum annual income from $86,266 for two to $190,292 for twelve. + md_ccs_income_eligible: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false]