diff --git a/changelog.d/me-ccap.added.md b/changelog.d/me-ccap.added.md new file mode 100644 index 00000000000..252ba1acf13 --- /dev/null +++ b/changelog.d/me-ccap.added.md @@ -0,0 +1 @@ +Implement Maine CCAP (Child Care Affordability Program). Closes #7756. 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 367612a52ae..addd736856e 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 @@ -4,6 +4,7 @@ values: - ca_child_care_subsidies # California Child Care - co_child_care_subsidies # Colorado Child Care Assistance Program - ma_child_care_subsidies # Massachusetts Child Care Financial Assistance + - me_child_care_subsidies # Maine Child Care Affordability Program - ne_child_care_subsidies # Nebraska Child Care Subsidy metadata: diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_groups/infant_max_months.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_groups/infant_max_months.yaml new file mode 100644 index 00000000000..5dcb5e896d7 --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_groups/infant_max_months.yaml @@ -0,0 +1,11 @@ +description: Maine sets this threshold in months as the upper bound for the infant age group under the Child Care Affordability Program. +values: + 2024-01-01: 12 + +metadata: + unit: month + period: year + label: Maine CCAP infant age group upper bound in months + reference: + - title: 10-148 C.M.R. Chapter 6 §1 Definitions + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=7 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_groups/preschool_max_years.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_groups/preschool_max_years.yaml new file mode 100644 index 00000000000..3f2894983c2 --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_groups/preschool_max_years.yaml @@ -0,0 +1,11 @@ +description: Maine sets this threshold in years as the upper bound for the preschool age group under the Child Care Affordability Program. +values: + 2024-01-01: 5 + +metadata: + unit: year + period: year + label: Maine CCAP preschool age group upper bound in years + reference: + - title: 10-148 C.M.R. Chapter 6 §1 Definitions + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=8 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_groups/toddler_max_months.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_groups/toddler_max_months.yaml new file mode 100644 index 00000000000..bf8ee3195ec --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_groups/toddler_max_months.yaml @@ -0,0 +1,11 @@ +description: Maine sets this threshold in months as the upper bound for the toddler age group under the Child Care Affordability Program. +values: + 2024-01-01: 36 + +metadata: + unit: month + period: year + label: Maine CCAP toddler age group upper bound in months + reference: + - title: 10-148 C.M.R. Chapter 6 §1 Definitions + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=10 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_limit/child.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_limit/child.yaml new file mode 100644 index 00000000000..9bd23ca8978 --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_limit/child.yaml @@ -0,0 +1,11 @@ +description: Maine limits non-disabled child eligibility to this threshold under the Child Care Affordability Program. +values: + 2024-01-01: 13 + +metadata: + unit: year + period: year + label: Maine CCAP child age limit + reference: + - title: 10-148 C.M.R. Chapter 6 §2.A + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=11 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_limit/special_needs.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_limit/special_needs.yaml new file mode 100644 index 00000000000..355c8a7d3ed --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/age_limit/special_needs.yaml @@ -0,0 +1,11 @@ +description: Maine limits special needs child eligibility to this threshold under the Child Care Affordability Program. +values: + 2024-01-01: 19 + +metadata: + unit: year + period: year + label: Maine CCAP special needs child age limit + reference: + - title: 10-148 C.M.R. Chapter 6 §1 Definition 11 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=4 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/copay/cap.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/copay/cap.yaml new file mode 100644 index 00000000000..5b831e2735c --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/copay/cap.yaml @@ -0,0 +1,20 @@ +description: Maine limits total parent fees to this share of eligibility income based on State Median Income level under the Child Care Affordability Program. +metadata: + type: single_amount + threshold_unit: /1 + amount_unit: /1 + period: year + label: Maine CCAP copay cap by SMI percentage + reference: + - title: 10-148 C.M.R. Chapter 6 §5.A.7 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=27 + +brackets: + - threshold: + 2024-01-01: 0 + amount: + 2024-01-01: 0.07 + - threshold: + 2024-01-01: 0.85 + amount: + 2024-01-01: 0.1 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/copay/rate.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/copay/rate.yaml new file mode 100644 index 00000000000..1cb69c5a85c --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/copay/rate.yaml @@ -0,0 +1,57 @@ +description: Maine sets the parent fee as this share of eligibility income based on the family's State Median Income percentage under the Child Care Affordability Program. + +metadata: + type: single_amount + threshold_unit: /1 + amount_unit: /1 + period: year + label: Maine CCAP copay rate by SMI percentage + reference: + - title: 10-148 C.M.R. Chapter 6 §5.B.1 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=27 + +brackets: + - threshold: + 2024-01-01: 0 + amount: + 2024-01-01: 0 + - threshold: + 2024-01-01: 0.3 + amount: + 2024-01-01: 0.01 + - threshold: + 2024-01-01: 0.35 + amount: + 2024-01-01: 0.02 + - threshold: + 2024-01-01: 0.4 + amount: + 2024-01-01: 0.03 + - threshold: + 2024-01-01: 0.45 + amount: + 2024-01-01: 0.04 + - threshold: + 2024-01-01: 0.55 + amount: + 2024-01-01: 0.05 + - threshold: + 2024-01-01: 0.65 + amount: + 2024-01-01: 0.06 + - threshold: + 2024-01-01: 0.75 + amount: + 2024-01-01: 0.07 + - threshold: + 2024-01-01: 0.9 + amount: + 2024-01-01: 0.08 + - threshold: + 2024-01-01: 1 + amount: + 2024-01-01: 0.09 + - threshold: + 2024-01-01: 1.1 + amount: + 2024-01-01: 0.1 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/hours/full_time_threshold.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/hours/full_time_threshold.yaml new file mode 100644 index 00000000000..a5c1d180890 --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/hours/full_time_threshold.yaml @@ -0,0 +1,11 @@ +description: Maine sets this threshold for full-time child care hours per week under the Child Care Affordability Program. +values: + 2024-07-06: 30 + +metadata: + unit: /1 + period: week + label: Maine CCAP full-time hours threshold + reference: + - title: 10-148 C.M.R. Chapter 6 §6.A.2.a + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=28 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/hours/half_time_threshold.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/hours/half_time_threshold.yaml new file mode 100644 index 00000000000..a2ccd170017 --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/hours/half_time_threshold.yaml @@ -0,0 +1,11 @@ +description: Maine sets this threshold for half-time child care hours per week under the Child Care Affordability Program. +values: + 2024-07-06: 10 + +metadata: + unit: /1 + period: week + label: Maine CCAP half-time hours threshold + reference: + - title: Maine Child Care Market Rates July 6, 2024 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/July%206%202024%20Market%20Rates_5_0.pdf diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/hours/part_time_threshold.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/hours/part_time_threshold.yaml new file mode 100644 index 00000000000..148b5a2e7f6 --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/hours/part_time_threshold.yaml @@ -0,0 +1,11 @@ +description: Maine sets this threshold for part-time child care hours per week under the Child Care Affordability Program. +values: + 2024-07-06: 20 + +metadata: + unit: /1 + period: week + label: Maine CCAP part-time hours threshold + reference: + - title: Maine Child Care Market Rates July 6, 2024 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/July%206%202024%20Market%20Rates_5_0.pdf diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/hours/uses_simplified_time.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/hours/uses_simplified_time.yaml new file mode 100644 index 00000000000..3e9a9857e48 --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/hours/uses_simplified_time.yaml @@ -0,0 +1,14 @@ +description: Maine uses this indicator to determine whether the simplified two-category time authorization applies under the Child Care Affordability Program. +values: + 2024-07-06: false + 2025-05-19: true + +metadata: + unit: bool + period: year + label: Maine CCAP simplified time categories in effect + reference: + - title: Maine Child Care Market Rates July 6, 2024 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/July%206%202024%20Market%20Rates_5_0.pdf + - title: Maine Child Care Market Rates May 19, 2025 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/5.19.25%20Child%20Care%20Market%20Rates.pdf diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/income/countable_income/sources.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/income/countable_income/sources.yaml new file mode 100644 index 00000000000..b9f33903647 --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/income/countable_income/sources.yaml @@ -0,0 +1,33 @@ +description: Maine uses these income sources for countable income under the Child Care Affordability Program. +values: + 2024-07-01: + # Earned income (Rule §2.C.3) + - employment_income + - self_employment_income + - farm_income + - rental_income + # Unearned income (Rule §2.C.4) + - social_security + - pension_income + - retirement_distributions + - disability_benefits + - ssi + # TANF is countable per Rule §2.C.4, but excluded here to avoid + # circular dependency: tanf → childcare_expenses → me_ccap → me_ccap_countable_income → tanf + - veterans_benefits + - military_retirement_pay + - unemployment_compensation + - workers_compensation + - interest_income + - dividend_income + - child_support_received + - alimony_income + - capital_gains + +metadata: + unit: list + period: year + label: Maine CCAP countable income sources + reference: + - title: 10-148 C.M.R. Chapter 6 §2.C.3-4 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=13 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/income/smi_limit.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/income/smi_limit.yaml new file mode 100644 index 00000000000..e4f540d37c1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/income/smi_limit.yaml @@ -0,0 +1,11 @@ +description: Maine limits family income to this share of the State Median Income under the Child Care Affordability Program. +values: + 2024-01-01: 1.25 + +metadata: + unit: /1 + period: year + label: Maine CCAP SMI income limit rate + reference: + - title: 10-148 C.M.R. Chapter 6 §2.A.1 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=11 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/market_rate/license_exempt.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/market_rate/license_exempt.yaml new file mode 100644 index 00000000000..5fc40819ae2 --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/market_rate/license_exempt.yaml @@ -0,0 +1,208 @@ +description: Maine provides these weekly reimbursement rates for license-exempt child care under the Child Care Affordability Program. + +metadata: + period: week + unit: currency-USD + label: Maine CCAP license-exempt weekly rates + breakdown: + - me_ccap_region + - me_ccap_age_group + - me_ccap_time_category + reference: + - title: 10-148 C.M.R. Chapter 6 §4.D + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=26 + - title: Maine CCAP Market Rates, effective July 6, 2024 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/July%206%202024%20Market%20Rates_5_0.pdf + - title: Maine CCAP Market Rates, effective May 19, 2025 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/5.19.25%20Child%20Care%20Market%20Rates.pdf + +REGION_1: + INFANT: + FULL_TIME: + 2024-07-06: 171.5 + PART_TIME: + 2024-07-06: 128.63 + HALF_TIME: + 2024-07-06: 85.75 + QUARTER_TIME: + 2024-07-06: 42.88 + TODDLER: + FULL_TIME: + 2024-07-06: 161.54 + PART_TIME: + 2024-07-06: 121.15 + HALF_TIME: + 2024-07-06: 80.77 + QUARTER_TIME: + 2024-07-06: 40.38 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 157.5 + PART_TIME: + 2024-07-06: 118.13 + HALF_TIME: + 2024-07-06: 78.75 + QUARTER_TIME: + 2024-07-06: 39.38 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 122.5 + PART_TIME: + 2024-07-06: 91.88 + 2025-05-19: 98.33 + HALF_TIME: + 2024-07-06: 61.25 + QUARTER_TIME: + 2024-07-06: 30.63 +REGION_2: + INFANT: + FULL_TIME: + 2024-07-06: 147 + PART_TIME: + 2024-07-06: 110.25 + HALF_TIME: + 2024-07-06: 73.5 + QUARTER_TIME: + 2024-07-06: 36.75 + TODDLER: + FULL_TIME: + 2024-07-06: 140 + PART_TIME: + 2024-07-06: 105 + HALF_TIME: + 2024-07-06: 70 + QUARTER_TIME: + 2024-07-06: 35 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 133 + PART_TIME: + 2024-07-06: 99.75 + HALF_TIME: + 2024-07-06: 66.5 + QUARTER_TIME: + 2024-07-06: 33.25 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 119 + PART_TIME: + 2024-07-06: 89.25 + 2025-05-19: 95.51 + HALF_TIME: + 2024-07-06: 59.5 + QUARTER_TIME: + 2024-07-06: 29.75 +KENNEBEC: + INFANT: + FULL_TIME: + 2024-07-06: 147 + PART_TIME: + 2024-07-06: 110.25 + HALF_TIME: + 2024-07-06: 73.5 + QUARTER_TIME: + 2024-07-06: 36.75 + TODDLER: + FULL_TIME: + 2024-07-06: 140 + PART_TIME: + 2024-07-06: 105 + HALF_TIME: + 2024-07-06: 70 + QUARTER_TIME: + 2024-07-06: 35 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 133 + PART_TIME: + 2024-07-06: 99.75 + HALF_TIME: + 2024-07-06: 66.5 + QUARTER_TIME: + 2024-07-06: 33.25 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 119 + PART_TIME: + 2024-07-06: 89.25 + 2025-05-19: 95.51 + HALF_TIME: + 2024-07-06: 59.5 + QUARTER_TIME: + 2024-07-06: 29.75 +KNOX_WALDO: + INFANT: + FULL_TIME: + 2024-07-06: 147 + PART_TIME: + 2024-07-06: 110.25 + HALF_TIME: + 2024-07-06: 73.5 + QUARTER_TIME: + 2024-07-06: 36.75 + TODDLER: + FULL_TIME: + 2024-07-06: 140 + PART_TIME: + 2024-07-06: 105 + HALF_TIME: + 2024-07-06: 70 + QUARTER_TIME: + 2024-07-06: 35 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 133 + PART_TIME: + 2024-07-06: 99.75 + HALF_TIME: + 2024-07-06: 66.5 + QUARTER_TIME: + 2024-07-06: 33.25 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 119 + PART_TIME: + 2024-07-06: 89.25 + 2025-05-19: 95.51 + HALF_TIME: + 2024-07-06: 59.5 + QUARTER_TIME: + 2024-07-06: 29.75 +PENOBSCOT: + INFANT: + FULL_TIME: + 2024-07-06: 147 + PART_TIME: + 2024-07-06: 110.25 + HALF_TIME: + 2024-07-06: 73.5 + QUARTER_TIME: + 2024-07-06: 36.75 + TODDLER: + FULL_TIME: + 2024-07-06: 140 + PART_TIME: + 2024-07-06: 105 + HALF_TIME: + 2024-07-06: 70 + QUARTER_TIME: + 2024-07-06: 35 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 133 + PART_TIME: + 2024-07-06: 99.75 + HALF_TIME: + 2024-07-06: 66.5 + QUARTER_TIME: + 2024-07-06: 33.25 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 119 + PART_TIME: + 2024-07-06: 89.25 + 2025-05-19: 95.51 + HALF_TIME: + 2024-07-06: 59.5 + QUARTER_TIME: + 2024-07-06: 29.75 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/market_rate/licensed_center.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/market_rate/licensed_center.yaml new file mode 100644 index 00000000000..36274c24a8f --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/market_rate/licensed_center.yaml @@ -0,0 +1,207 @@ +description: Maine provides these weekly reimbursement rates for licensed child care centers under the Child Care Affordability Program. + +metadata: + period: week + unit: currency-USD + label: Maine CCAP licensed center weekly rates + breakdown: + - me_ccap_region + - me_ccap_age_group + - me_ccap_time_category + reference: + - title: 10-148 C.M.R. Chapter 6 §4.D + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=26 + - title: Maine CCAP Market Rates, effective July 6, 2024 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/July%206%202024%20Market%20Rates_5_0.pdf + - title: Maine CCAP Market Rates, effective May 19, 2025 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/5.19.25%20Child%20Care%20Market%20Rates.pdf + +REGION_1: + INFANT: + FULL_TIME: + 2024-07-06: 330 + PART_TIME: + 2024-07-06: 247.5 + HALF_TIME: + 2024-07-06: 165 + QUARTER_TIME: + 2024-07-06: 82.5 + TODDLER: + FULL_TIME: + 2024-07-06: 320 + PART_TIME: + 2024-07-06: 240 + HALF_TIME: + 2024-07-06: 160 + QUARTER_TIME: + 2024-07-06: 80 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 300 + PART_TIME: + 2024-07-06: 225 + HALF_TIME: + 2024-07-06: 150 + QUARTER_TIME: + 2024-07-06: 75 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 214 + PART_TIME: + 2024-07-06: 160.5 + 2025-05-19: 171.76 + HALF_TIME: + 2024-07-06: 107 + QUARTER_TIME: + 2024-07-06: 53.5 +REGION_2: + INFANT: + FULL_TIME: + 2024-07-06: 275 + PART_TIME: + 2024-07-06: 206.25 + HALF_TIME: + 2024-07-06: 137.5 + QUARTER_TIME: + 2024-07-06: 68.75 + TODDLER: + FULL_TIME: + 2024-07-06: 250 + PART_TIME: + 2024-07-06: 187.5 + HALF_TIME: + 2024-07-06: 125 + QUARTER_TIME: + 2024-07-06: 62.5 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 244 + PART_TIME: + 2024-07-06: 183 + HALF_TIME: + 2024-07-06: 122 + QUARTER_TIME: + 2024-07-06: 61 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 180 + PART_TIME: + 2024-07-06: 135 + 2025-05-19: 144.47 + HALF_TIME: + 2024-07-06: 90 + QUARTER_TIME: + 2024-07-06: 45 +KENNEBEC: + INFANT: + FULL_TIME: + 2024-07-06: 275 + PART_TIME: + 2024-07-06: 206.25 + HALF_TIME: + 2024-07-06: 137.50 + QUARTER_TIME: + 2024-07-06: 68.75 + TODDLER: + FULL_TIME: + 2024-07-06: 250 + PART_TIME: + 2024-07-06: 187.50 + HALF_TIME: + 2024-07-06: 125 + QUARTER_TIME: + 2024-07-06: 62.50 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 267 + PART_TIME: + 2024-07-06: 200.25 + HALF_TIME: + 2024-07-06: 133.50 + QUARTER_TIME: + 2024-07-06: 66.75 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 180 + PART_TIME: + 2024-07-06: 135 + HALF_TIME: + 2024-07-06: 90 + QUARTER_TIME: + 2024-07-06: 45 +KNOX_WALDO: + INFANT: + FULL_TIME: + 2024-07-06: 275 + PART_TIME: + 2024-07-06: 206.25 + HALF_TIME: + 2024-07-06: 137.50 + QUARTER_TIME: + 2024-07-06: 68.75 + TODDLER: + FULL_TIME: + 2024-07-06: 250 + PART_TIME: + 2024-07-06: 187.50 + HALF_TIME: + 2024-07-06: 125 + QUARTER_TIME: + 2024-07-06: 62.50 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 244 + PART_TIME: + 2024-07-06: 183 + HALF_TIME: + 2024-07-06: 122 + QUARTER_TIME: + 2024-07-06: 61 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 220 + PART_TIME: + 2024-07-06: 165 + 2025-05-19: 176.58 + HALF_TIME: + 2024-07-06: 110 + QUARTER_TIME: + 2024-07-06: 55 +PENOBSCOT: + INFANT: + FULL_TIME: + 2024-07-06: 275 + PART_TIME: + 2024-07-06: 206.25 + HALF_TIME: + 2024-07-06: 137.50 + QUARTER_TIME: + 2024-07-06: 68.75 + TODDLER: + FULL_TIME: + 2024-07-06: 250 + PART_TIME: + 2024-07-06: 187.50 + HALF_TIME: + 2024-07-06: 125 + QUARTER_TIME: + 2024-07-06: 62.50 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 244 + PART_TIME: + 2024-07-06: 183 + HALF_TIME: + 2024-07-06: 122 + QUARTER_TIME: + 2024-07-06: 61 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 200 + PART_TIME: + 2024-07-06: 150 + 2025-05-19: 160.53 + HALF_TIME: + 2024-07-06: 100 + QUARTER_TIME: + 2024-07-06: 50 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/market_rate/licensed_family.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/market_rate/licensed_family.yaml new file mode 100644 index 00000000000..328688cbe76 --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/market_rate/licensed_family.yaml @@ -0,0 +1,208 @@ +description: Maine provides these weekly reimbursement rates for licensed family child care under the Child Care Affordability Program. + +metadata: + period: week + unit: currency-USD + label: Maine CCAP licensed family weekly rates + breakdown: + - me_ccap_region + - me_ccap_age_group + - me_ccap_time_category + reference: + - title: 10-148 C.M.R. Chapter 6 §4.D + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=26 + - title: Maine CCAP Market Rates, effective July 6, 2024 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/July%206%202024%20Market%20Rates_5_0.pdf + - title: Maine CCAP Market Rates, effective May 19, 2025 + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/5.19.25%20Child%20Care%20Market%20Rates.pdf + +REGION_1: + INFANT: + FULL_TIME: + 2024-07-06: 245 + PART_TIME: + 2024-07-06: 183.75 + HALF_TIME: + 2024-07-06: 122.5 + QUARTER_TIME: + 2024-07-06: 61.25 + TODDLER: + FULL_TIME: + 2024-07-06: 230.77 + PART_TIME: + 2024-07-06: 173.08 + HALF_TIME: + 2024-07-06: 115.38 + QUARTER_TIME: + 2024-07-06: 57.69 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 225 + PART_TIME: + 2024-07-06: 168.75 + HALF_TIME: + 2024-07-06: 112.5 + QUARTER_TIME: + 2024-07-06: 56.25 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 175 + PART_TIME: + 2024-07-06: 131.25 + 2025-05-19: 140.46 + HALF_TIME: + 2024-07-06: 87.5 + QUARTER_TIME: + 2024-07-06: 43.75 +REGION_2: + INFANT: + FULL_TIME: + 2024-07-06: 210 + PART_TIME: + 2024-07-06: 157.5 + HALF_TIME: + 2024-07-06: 105 + QUARTER_TIME: + 2024-07-06: 52.5 + TODDLER: + FULL_TIME: + 2024-07-06: 200 + PART_TIME: + 2024-07-06: 150 + HALF_TIME: + 2024-07-06: 100 + QUARTER_TIME: + 2024-07-06: 50 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 190 + PART_TIME: + 2024-07-06: 142.5 + HALF_TIME: + 2024-07-06: 95 + QUARTER_TIME: + 2024-07-06: 47.5 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 170 + PART_TIME: + 2024-07-06: 127.5 + 2025-05-19: 136.45 + HALF_TIME: + 2024-07-06: 85 + QUARTER_TIME: + 2024-07-06: 42.5 +KENNEBEC: + INFANT: + FULL_TIME: + 2024-07-06: 210 + PART_TIME: + 2024-07-06: 157.5 + HALF_TIME: + 2024-07-06: 105 + QUARTER_TIME: + 2024-07-06: 52.5 + TODDLER: + FULL_TIME: + 2024-07-06: 200 + PART_TIME: + 2024-07-06: 150 + HALF_TIME: + 2024-07-06: 100 + QUARTER_TIME: + 2024-07-06: 50 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 190 + PART_TIME: + 2024-07-06: 142.5 + HALF_TIME: + 2024-07-06: 95 + QUARTER_TIME: + 2024-07-06: 47.5 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 170 + PART_TIME: + 2024-07-06: 127.5 + 2025-05-19: 136.45 + HALF_TIME: + 2024-07-06: 85 + QUARTER_TIME: + 2024-07-06: 42.5 +KNOX_WALDO: + INFANT: + FULL_TIME: + 2024-07-06: 210 + PART_TIME: + 2024-07-06: 157.5 + HALF_TIME: + 2024-07-06: 105 + QUARTER_TIME: + 2024-07-06: 52.5 + TODDLER: + FULL_TIME: + 2024-07-06: 200 + PART_TIME: + 2024-07-06: 150 + HALF_TIME: + 2024-07-06: 100 + QUARTER_TIME: + 2024-07-06: 50 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 190 + PART_TIME: + 2024-07-06: 142.5 + HALF_TIME: + 2024-07-06: 95 + QUARTER_TIME: + 2024-07-06: 47.5 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 170 + PART_TIME: + 2024-07-06: 127.5 + 2025-05-19: 136.45 + HALF_TIME: + 2024-07-06: 85 + QUARTER_TIME: + 2024-07-06: 42.5 +PENOBSCOT: + INFANT: + FULL_TIME: + 2024-07-06: 210 + PART_TIME: + 2024-07-06: 157.5 + HALF_TIME: + 2024-07-06: 105 + QUARTER_TIME: + 2024-07-06: 52.5 + TODDLER: + FULL_TIME: + 2024-07-06: 200 + PART_TIME: + 2024-07-06: 150 + HALF_TIME: + 2024-07-06: 100 + QUARTER_TIME: + 2024-07-06: 50 + PRESCHOOL: + FULL_TIME: + 2024-07-06: 190 + PART_TIME: + 2024-07-06: 142.5 + HALF_TIME: + 2024-07-06: 95 + QUARTER_TIME: + 2024-07-06: 47.5 + SCHOOL_AGE: + FULL_TIME: + 2024-07-06: 170 + PART_TIME: + 2024-07-06: 127.5 + 2025-05-19: 136.45 + HALF_TIME: + 2024-07-06: 85 + QUARTER_TIME: + 2024-07-06: 42.5 diff --git a/policyengine_us/parameters/gov/states/me/dhhs/ccap/region_1_counties.yaml b/policyengine_us/parameters/gov/states/me/dhhs/ccap/region_1_counties.yaml new file mode 100644 index 00000000000..34541ef6095 --- /dev/null +++ b/policyengine_us/parameters/gov/states/me/dhhs/ccap/region_1_counties.yaml @@ -0,0 +1,16 @@ +description: Maine sets these counties as Region 1 for market rate purposes under the Child Care Affordability Program. +values: + 2024-01-01: + - CUMBERLAND_COUNTY_ME + - SAGADAHOC_COUNTY_ME + - YORK_COUNTY_ME + +metadata: + unit: list + period: year + label: Maine CCAP Region 1 counties + reference: + - title: 10-148 C.M.R. Chapter 6 §4.D + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=26 + - title: Maine CCAP Market Rates (effective 5/19/2025) + href: https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/5.19.25%20Child%20Care%20Market%20Rates.pdf diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/copay/me_ccap_parent_fee.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/copay/me_ccap_parent_fee.yaml new file mode 100644 index 00000000000..017ddf80347 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/copay/me_ccap_parent_fee.yaml @@ -0,0 +1,376 @@ +# Parent fee tests use me_ccap_smi and me_ccap_countable_income +# as direct inputs to isolate the copay calculation from income pipeline. + +- name: Case 1, below 30% SMI, zero copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_410.26 + me_ccap_countable_income: 1_250 + households: + household: + members: [person1] + state_code: ME + output: + # 19.5% < 30% => 0% fee bracket. + me_ccap_parent_fee: 0 + +- name: Case 2, 30-35% SMI bracket, 1% fee. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_417.97 + me_ccap_countable_income: 2_053.75 + households: + household: + members: [person1] + state_code: ME + output: + # Weekly income = 2053.75 * 12/52 = 473.94. + # Fee = floor(473.94 * 0.01) = floor(4.74) = 4. + # Monthly = 4 * 52/12 = 17.33. + me_ccap_parent_fee: 17.33 + +- name: Case 3, 45-55% SMI bracket, 4% fee. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_418 + me_ccap_countable_income: 3_209 + households: + household: + members: [person1] + state_code: ME + output: + # Weekly income = 3209 * 12/52 = 740.54. + # Fee = floor(740.54 * 0.04) = floor(29.62) = 29. + # Monthly = 29 * 52/12 = 125.67. + me_ccap_parent_fee: 125.67 + +- name: Case 4, 75-90% SMI bracket, 7% fee with 7% cap. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_418.02 + me_ccap_countable_income: 5_134.42 + households: + household: + members: [person1] + state_code: ME + output: + # Weekly income = 5134.42 * 12/52 = 1184.87. + # Fee = floor(1184.87 * 0.07) = floor(82.94) = 82. + # Cap (80% < 85%): floor(1184.87 * 0.07) = floor(82.94) = 82. + # Fee = min(82, 82) = 82. + # Monthly = 82 * 52/12 = 355.33. + me_ccap_parent_fee: 355.33 + +- name: Case 5, 110-125% SMI bracket, 10% fee with 10% cap. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_417.97 + me_ccap_countable_income: 7_380.67 + households: + household: + members: [person1] + state_code: ME + output: + # Weekly income = 7380.67 * 12/52 = 1703.23. + # Fee = floor(1703.23 * 0.10) = floor(170.32) = 170. + # Cap (115% >= 85%): floor(1703.23 * 0.10) = floor(170.32) = 170. + # Monthly = 170 * 52/12 = 736.67. + me_ccap_parent_fee: 736.67 + +# === Edge cases: remaining copay tiers and boundary transitions === + +- name: Case 6, 35-40% SMI bracket, 2% fee. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_690.54 + me_ccap_countable_income: 2_475.50 + households: + household: + members: [person1] + state_code: ME + output: + # Weekly income = 2475.50 * 12/52 = 571.27. + # Raw weekly = floor(571.27 * 0.02) = floor(11.43) = 11. + # Cap (37% < 85%): floor(571.27 * 0.07) = floor(39.99) = 39. + # Fee = min(11, 39) = 11/week. + # Monthly = 11 * 52/12 = 47.67. + me_ccap_parent_fee: 47.67 + +- name: Case 7, 40-45% SMI bracket, 3% fee. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_690.48 + me_ccap_countable_income: 2_810 + households: + household: + members: [person1] + state_code: ME + output: + # Weekly income = 2810 * 12/52 = 648.46. + # Raw weekly = floor(648.46 * 0.03) = floor(19.45) = 19. + # Cap: floor(648.46 * 0.07) = floor(45.39) = 45. + # Fee = min(19, 45) = 19/week. + # Monthly = 19 * 52/12 = 82.33. + me_ccap_parent_fee: 82.33 + +- name: Case 8, 55-65% SMI bracket, 5% fee. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_690.42 + me_ccap_countable_income: 4_014.25 + households: + household: + members: [person1] + state_code: ME + output: + # Weekly income = 4014.25 * 12/52 = 926.37. + # Raw weekly = floor(926.37 * 0.05) = floor(46.32) = 46. + # Cap: floor(926.37 * 0.07) = floor(64.85) = 64. + # Fee = min(46, 64) = 46/week. + # Monthly = 46 * 52/12 = 199.33. + me_ccap_parent_fee: 199.33 + +- name: Case 9, 65-75% SMI bracket, 6% fee. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_690.36 + me_ccap_countable_income: 4_683.25 + households: + household: + members: [person1] + state_code: ME + output: + # Weekly income = 4683.25 * 12/52 = 1080.75. + # Raw weekly = floor(1080.75 * 0.06) = floor(64.85) = 64. + # Cap: floor(1080.75 * 0.07) = floor(75.65) = 75. + # Fee = min(64, 75) = 64/week. + # Monthly = 64 * 52/12 = 277.33. + me_ccap_parent_fee: 277.33 + +- name: Case 10, 90-100% SMI bracket, 8% fee with 10% cap. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_690.35 + me_ccap_countable_income: 6_355.83 + households: + household: + members: [person1] + state_code: ME + output: + # 95% >= 85% => 10% cap applies. + # Weekly income = 6355.83 * 12/52 = 1466.73. + # Raw weekly = floor(1466.73 * 0.08) = floor(117.34) = 117. + # Cap: floor(1466.73 * 0.10) = floor(146.67) = 146. + # Fee = min(117, 146) = 117/week. + # Monthly = 117 * 52/12 = 507. + me_ccap_parent_fee: 507 + +- name: Case 11, 100-110% SMI bracket, 9% fee with 10% cap. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_690.35 + me_ccap_countable_income: 7_024.87 + households: + household: + members: [person1] + state_code: ME + output: + # 105% >= 85% => 10% cap applies. + # Weekly income = 7024.87 * 12/52 = 1621.13. + # Raw weekly = floor(1621.13 * 0.09) = floor(145.90) = 145. + # Cap: floor(1621.13 * 0.10) = floor(162.11) = 162. + # Fee = min(145, 162) = 145/week. + # Monthly = 145 * 52/12 = 628.33. + me_ccap_parent_fee: 628.33 + +- name: Case 12, exactly at 85% SMI boundary, cap transitions from 7% to 10%. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_690.39 + me_ccap_countable_income: 5_687.50 + households: + household: + members: [person1] + state_code: ME + output: + # 85.01% >= 85% => 10% cap applies. + # Weekly income = 5687.50 * 12/52 = 1312.50. + # Raw weekly = floor(1312.50 * 0.07) = floor(91.88) = 91. + # Cap: floor(1312.50 * 0.10) = floor(131.25) = 131. + # Fee = min(91, 131) = 91/week. + # Monthly = 91 * 52/12 = 394.33. + me_ccap_parent_fee: 394.33 + +- name: Case 13, just below 85% SMI, 7% cap binds at same rate as fee. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_689.53 + me_ccap_countable_income: 5_680.08 + households: + household: + members: [person1] + state_code: ME + output: + # 84.91% < 85% => 7% cap applies. + # Weekly income = 5680.08 * 12/52 = 1310.79. + # Raw weekly = floor(1310.79 * 0.07) = floor(91.76) = 91. + # Cap: floor(1310.79 * 0.07) = floor(91.76) = 91. + # Fee = min(91, 91) = 91/week. + # Monthly = 91 * 52/12 = 394.33. + me_ccap_parent_fee: 394.33 + +- name: Case 14, zero income, zero parent fee. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 0 + me_ccap_countable_income: 0 + households: + household: + members: [person1] + state_code: ME + output: + # Zero income => 0% SMI => 0% fee bracket. + me_ccap_parent_fee: 0 + +- name: Case 15, exactly at 30% SMI boundary, enters 1% tier. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_690.54 + me_ccap_countable_income: 2_007.83 + households: + household: + members: [person1] + state_code: ME + output: + # 30.01% => 30-35% bracket => 1% fee. + # Weekly income = 2007.83 * 12/52 = 463.35. + # Raw weekly = floor(463.35 * 0.01) = floor(4.63) = 4. + # Cap: floor(463.35 * 0.07) = floor(32.43) = 32. + # Fee = min(4, 32) = 4/week. + # Monthly = 4 * 52/12 = 17.33. + me_ccap_parent_fee: 17.33 + +- name: Case 16, just below 30% SMI boundary, zero copay. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + me_ccap_smi: 6_690.29 + me_ccap_countable_income: 2_005.75 + households: + household: + members: [person1] + state_code: ME + output: + # 29.98% < 30% => 0% fee bracket. + me_ccap_parent_fee: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/eligibility/me_ccap_activity_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/eligibility/me_ccap_activity_eligible.yaml new file mode 100644 index 00000000000..21a91755a04 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/eligibility/me_ccap_activity_eligible.yaml @@ -0,0 +1,127 @@ +- name: Case 1, employed single parent meets requirement. + period: 2025-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 20 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap_activity_eligible: true + +- name: Case 2, unemployed non-student parent does not meet requirement. + period: 2025-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 0 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap_activity_eligible: false + +- name: Case 3, full time student parent qualifies. + period: 2025-01 + input: + people: + person1: + age: 25 + weekly_hours_worked: 0 + is_full_time_student: true + person2: + age: 3 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap_activity_eligible: true + +- name: Case 4, disabled parent qualifies. + period: 2025-01 + input: + people: + person1: + age: 35 + weekly_hours_worked: 0 + is_disabled: true + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap_activity_eligible: true + +- name: Case 5, two parents both employed. + period: 2025-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 25 + person2: + age: 28 + weekly_hours_worked: 15 + person3: + age: 5 + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: ME + output: + me_ccap_activity_eligible: true + +- name: Case 6, two parents one not employed or studying. + period: 2025-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 25 + person2: + age: 28 + weekly_hours_worked: 0 + person3: + age: 5 + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: ME + output: + me_ccap_activity_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/eligibility/me_ccap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/eligibility/me_ccap_eligible.yaml new file mode 100644 index 00000000000..ec43a651c36 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/eligibility/me_ccap_eligible.yaml @@ -0,0 +1,125 @@ +- name: Case 1, all conditions met, eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_income_eligible: true + is_ccdf_asset_eligible: true + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap_eligible: true + +- name: Case 2, income ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_income_eligible: false + is_ccdf_asset_eligible: true + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap_eligible: false + +- name: Case 3, asset ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_income_eligible: true + is_ccdf_asset_eligible: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap_eligible: false + +- name: Case 4, no eligible child. + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 15 + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_income_eligible: true + is_ccdf_asset_eligible: true + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap_eligible: false + +- name: Case 5, activity ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_income_eligible: true + is_ccdf_asset_eligible: true + me_ccap_activity_eligible: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/eligibility/me_ccap_eligible_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/eligibility/me_ccap_eligible_child.yaml new file mode 100644 index 00000000000..4eff0dff497 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/eligibility/me_ccap_eligible_child.yaml @@ -0,0 +1,229 @@ +- name: Case 1, child under 13, citizen, dependent, eligible. + period: 2025-01 + input: + people: + person1: + age: 5 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: ME + output: + me_ccap_eligible_child: [true] + +- name: Case 2, child age 13, not disabled, ineligible. + period: 2025-01 + input: + people: + person1: + age: 13 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: ME + output: + me_ccap_eligible_child: [false] + +- name: Case 3, child age 12, boundary eligible. + period: 2025-01 + input: + people: + person1: + age: 12 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: ME + output: + me_ccap_eligible_child: [true] + +- name: Case 4, disabled child age 18, eligible under special needs. + period: 2025-01 + input: + people: + person1: + age: 18 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: ME + output: + me_ccap_eligible_child: [true] + +- name: Case 5, disabled child age 19, ineligible. + period: 2025-01 + input: + people: + person1: + age: 19 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: ME + output: + me_ccap_eligible_child: [false] + +- name: Case 6, not a dependent, ineligible. + period: 2025-01 + input: + people: + person1: + age: 5 + is_disabled: false + is_tax_unit_dependent: false + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: ME + output: + me_ccap_eligible_child: [false] + +- name: Case 7, undocumented child, ineligible. + period: 2025-01 + input: + people: + person1: + age: 5 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: UNDOCUMENTED + households: + household: + members: [person1] + state_code: ME + output: + me_ccap_eligible_child: [false] + +- name: Case 8, non-Maine resident, ineligible. + period: 2025-01 + input: + people: + person1: + age: 5 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: NY + output: + me_ccap_eligible_child: [false] + +# === Edge cases === + +- name: Case 9, disabled child exactly age 13, eligible under special needs. + period: 2025-01 + input: + people: + person1: + age: 13 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: ME + output: + # age 13 < 19 (special needs limit) => eligible. + me_ccap_eligible_child: [true] + +- name: Case 10, non-disabled child age 0 (newborn), eligible. + period: 2025-01 + input: + people: + person1: + age: 0 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: ME + output: + me_ccap_eligible_child: [true] + +- name: Case 11, disabled child exactly age 18, eligible. + period: 2025-01 + input: + people: + person1: + age: 18 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: ME + output: + # age 18 < 19 => eligible. + me_ccap_eligible_child: [true] + +- name: Case 12, adult age 30, not eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + is_disabled: false + is_tax_unit_dependent: false + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: ME + output: + # age 30 >= 13 and not dependent => ineligible. + me_ccap_eligible_child: [false] + +- name: Case 13, child age 12 but legal permanent resident, eligible. + period: 2025-01 + input: + people: + person1: + age: 12 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: LEGAL_PERMANENT_RESIDENT + households: + household: + members: [person1] + state_code: ME + output: + me_ccap_eligible_child: [true] + +- name: Case 14, disabled child age 15 but DACA, ineligible. + period: 2025-01 + input: + people: + person1: + age: 15 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: DACA + households: + household: + members: [person1] + state_code: ME + output: + # Age 15 < 19 (special needs) but DACA is not a qualified status. + me_ccap_eligible_child: [false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/eligibility/me_ccap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/eligibility/me_ccap_income_eligible.yaml new file mode 100644 index 00000000000..bf7e564a7c9 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/eligibility/me_ccap_income_eligible.yaml @@ -0,0 +1,247 @@ +# Income eligibility tests use me_ccap_countable_income as direct input +# to isolate from TANF/SSI feedback loop in income pipeline. + +- name: Case 1, family of 4 just below 125% SMI threshold, eligible. + period: 2025-01 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 8 + person4: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + # SMI for ME family of 4 (2024-10-01) = $113,259. + # 125% = $141,573.75/yr. + # Monthly limit = $11,797.81. + # Set monthly income just below. + me_ccap_countable_income: 11_750 + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: ME + output: + me_ccap_income_eligible: true + +- name: Case 2, family of 4 above 125% SMI, ineligible. + period: 2025-01 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 8 + person4: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + # 125% SMI for size 4 = $141,573.75/yr = $11,797.81/mo. + # Set monthly income above. + me_ccap_countable_income: 12_500 + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: ME + output: + me_ccap_income_eligible: false + +- name: Case 3, family of 2 low income, eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_countable_income: 2_500 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap_income_eligible: true + +- name: Case 4, family of 2 moderate income, eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + # 125% SMI for size 2 (2024-10-01) = $96,270.15/yr = $8,022.51/mo. + me_ccap_countable_income: 6_667 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap_income_eligible: true + +# === Edge cases: income boundary tests === +# SMI for ME (2025-10-01) 4-person = $118,065. + +- name: Case 5, income exactly at 125% SMI for size 2, eligible. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + # Size 2 annual SMI = 118,065 * 0.68 = $80,284.20. + # 125% SMI = $100,355.25/yr. + # Monthly limit = $8,362.94. + me_ccap_countable_income: 8_362.92 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + # 8362.92 <= 8362.94 => eligible. + me_ccap_income_eligible: true + +- name: Case 6, income just above 125% SMI for size 2, ineligible. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + # Monthly limit = $8,362.94. + me_ccap_countable_income: 8_363 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + # 8363 > 8362.94 => ineligible. + me_ccap_income_eligible: false + +- name: Case 7, zero income, eligible. + period: 2026-01 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_countable_income: 0 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap_income_eligible: true + +- name: Case 8, family size 1, income at boundary. + period: 2026-01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + # Size 1 annual SMI = 118,065 * 0.52 = $61,393.80. + # 125% SMI = $76,742.25/yr. + # Monthly limit = $6,395.19. + me_ccap_countable_income: 6_395.17 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: ME + output: + # 6395.17 <= 6395.19 => eligible. + me_ccap_income_eligible: true + +- name: Case 9, large family size 10. + period: 2026-01 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 12 + person4: + age: 10 + person5: + age: 8 + person6: + age: 6 + person7: + age: 5 + person8: + age: 4 + person9: + age: 3 + person10: + age: 1 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10] + # Size 10: adjustment = 0.52 + 5*0.16 + 4*0.03 = 1.44. + # Annual SMI = 118,065 * 1.44 = $170,013.60. + # 125% SMI = $212,517.00/yr. + # Monthly limit = $17,709.75. + me_ccap_countable_income: 15_833.33 + tax_units: + tax_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10] + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10] + state_code: ME + output: + # $15,833.33 <= $17,709.75 => eligible. + me_ccap_income_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/income/me_ccap_smi.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/income/me_ccap_smi.yaml new file mode 100644 index 00000000000..3619ebcb639 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/income/me_ccap_smi.yaml @@ -0,0 +1,117 @@ +# Tests for me_ccap_smi: monthly SMI dollar values by family size. +# The formula uses an October 1 fiscal year cutover: +# month >= 10 -> uses current year's SMI +# month < 10 -> uses prior year's SMI +# +# SMI adjustment factors (from hhs_smi): +# size 1: 0.52, size 2: 0.68, size 4: 0.52 + 3*0.16 = 1.00 + +- name: Family of 2, January 2026 uses 2025-10-01 SMI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + # SMI base (2025-10-01 ME) = $118,065. + # Size 2 adjustment = 0.68. + # Annual SMI = 118,065 * 0.68 = $80,284.20. + # Monthly = $80,284.20 / 12 = $6,690.35. + me_ccap_smi: 6_690.35 + +- name: Family of 4, January 2025 uses 2024-10-01 SMI. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 8 + person4: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: ME + output: + # SMI base (2024-10-01 ME) = $113,259. + # Size 4 adjustment = 1.00. + # Annual SMI = $113,259.00. + # Monthly = $113,259.00 / 12 = $9,438.25. + me_ccap_smi: 9_438.25 + +- name: Family of 4, January 2026 uses 2025-10-01 SMI (verifies fiscal year crossover). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + person2: + age: 33 + person3: + age: 8 + person4: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: ME + output: + # SMI base (2025-10-01 ME) = $118,065. + # Size 4 adjustment = 1.00. + # Annual SMI = $118,065.00. + # Monthly = $118,065.00 / 12 = $9,838.75. + me_ccap_smi: 9_838.75 + +- name: Family of 1, January 2026 uses 2025-10-01 SMI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + spm_units: + spm_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: ME + output: + # SMI base (2025-10-01 ME) = $118,065. + # Size 1 adjustment = 0.52. + # Annual SMI = 118,065 * 0.52 = $61,393.80. + # Monthly = $61,393.80 / 12 = $5,116.15. + me_ccap_smi: 5_116.15 diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/integration.yaml new file mode 100644 index 00000000000..97be2fb6550 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/integration.yaml @@ -0,0 +1,624 @@ +- name: Case 1, low-income single parent with one preschooler in Region 1 licensed center, zero copay. + period: 2026-01 + absolute_error_margin: 1 + input: + people: + person1: + age: 28 + employment_income: 20_000 + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSED_CENTER + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 15_000 + spm_unit_assets: 5_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + county_str: CUMBERLAND_COUNTY_ME + output: + # Eligibility: + # - Child age 4 < 13 => eligible child + # - Citizen => immigration eligible + # - Region 1 (Cumberland County) + me_ccap_eligible_child: [false, true] + + # Income: + # - me_ccap_countable_income = $20,000/yr + # - SMI for ME size 2 (2025-10-01): 118,065 * 0.68 = $80,284.20 + # - 125% SMI = $100,355.25 + # - $20,000 <= $100,355.25 => income eligible + me_ccap_income_eligible: true + + # Assets: + # - $5,000 <= $1,000,000 => asset eligible + is_ccdf_asset_eligible: true + me_ccap_eligible: true + + # Age group: age 4 => PRESCHOOL + me_ccap_age_group: [SCHOOL_AGE, PRESCHOOL] + + # Time category: person1 adult (0 hrs => PT), person2 8*5 = 40 hrs/week >= 30 => FULL_TIME + me_ccap_time_category: [PART_TIME, FULL_TIME] + + # Region: Cumberland => REGION_1 + me_ccap_region: REGION_1 + + # SMI percentage: + # Countable income = employment only ($20,000/yr). + # TANF excluded from countable income to avoid circular dependency. + # Monthly = $20,000/12 = $1,667. + # SMI% = 1667 / 6690 = 24.9% => under 30% bracket => 0% fee. + me_ccap_parent_fee: 0 + + # Market rate: Region 1 Licensed Center Preschool FT = $300/week + me_ccap_market_rate: [0, 300] + + # Benefit: + # Expenses (monthly): 15000/12 = $1,250 + # Parent fee (monthly): $0 + # Uncapped: max(1250 - 0, 0) = $1,250 + # Max reimbursement: 300 * 52/12 = $1,300 + # Benefit = min(1250, 1300) = $1,250 + me_ccap: 1_250 + +- name: Case 2, moderate-income family with two children, Region 2, licensed family, 4% copay. + period: 2026-01 + absolute_error_margin: 1 + input: + people: + person1: + age: 35 + employment_income: 45_000 + person2: + age: 32 + employment_income: 10_000 + person3: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSED_FAMILY + person4: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 4 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSED_FAMILY + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + spm_unit_pre_subsidy_childcare_expenses: 20_000 + spm_unit_assets: 50_000 + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: ME + county_str: PENOBSCOT_COUNTY_ME + output: + # Eligibility: + # - person3: age 2 < 13, citizen, dependent => eligible child + # - person4: age 7 < 13, citizen, dependent => eligible child + me_ccap_eligible_child: [false, false, true, true] + + # Income: + # - Total = $45,000 + $10,000 = $55,000 + # - SMI for ME size 4 (2025-10-01): 118,065 * 1.0 = $118,065 + # - 125% SMI = $147,581.25 + # - $55,000 <= $147,581 => income eligible + me_ccap_income_eligible: true + is_ccdf_asset_eligible: true + me_ccap_eligible: true + + # Region: Penobscot => PENOBSCOT + me_ccap_region: PENOBSCOT + + # Age groups: person3 age 2 => TODDLER; person4 age 7 => SCHOOL_AGE + me_ccap_age_group: [SCHOOL_AGE, SCHOOL_AGE, TODDLER, SCHOOL_AGE] + + # Time categories: + # person1,2: adults (0 hrs => PT) + # person3: 8*5 = 40 hrs => FULL_TIME + # person4: 4*5 = 20 hrs => PART_TIME + me_ccap_time_category: [PART_TIME, PART_TIME, FULL_TIME, PART_TIME] + + # SMI percentage: $55,000 / $118,065 = 46.6% => 45-55% bracket => 4% fee + # Weekly income = $55,000 / 52 = $1,057.69 + # Raw weekly fee = floor(1057.69 * 0.04) = floor(42.31) = $42 + # Cap: 46.6% < 85% => 7% cap + # Cap amount = floor(1057.69 * 0.07) = floor(74.04) = $74 + # Fee = min(42, 74) = $42/week + # Monthly = 42 * 52/12 = $182 + me_ccap_parent_fee: 182 + + # Market rates (weekly): + # person3: Penobscot Licensed Family Toddler FT = $200/week (same as Region 2) + # person4: Penobscot Licensed Family School Age PT = $136.45/week (same as Region 2) + me_ccap_market_rate: [0, 0, 200, 136.45] + + # Benefit: + # Max reimbursement: (200 + 136.45) * 52/12 = 336.45 * 4.333 = $1,457.95 + # Expenses (monthly): 20000/12 = $1,666.67 + # Parent fee (monthly): $182 + # Uncapped = max(1666.67 - 182, 0) = $1,484.67 + # Benefit = min(1484.67, 1457.95) = $1,457.95 + me_ccap: 1_458 + +- name: Case 3, income above 125% SMI, ineligible. + period: 2026-01 + absolute_error_margin: 1 + input: + people: + person1: + age: 40 + employment_income: 120_000 + person2: + age: 38 + employment_income: 40_000 + person3: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSED_CENTER + spm_units: + spm_unit: + members: [person1, person2, person3] + spm_unit_pre_subsidy_childcare_expenses: 18_000 + spm_unit_assets: 100_000 + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: ME + county_str: YORK_COUNTY_ME + output: + # Income: $120,000 + $40,000 = $160,000 + # SMI for ME size 3 (2025-10-01): 118,065 * 0.84 = $99,174.60 + # 125% SMI = $123,968.25 + # $160,000 > $123,968.25 => income ineligible + me_ccap_income_eligible: false + me_ccap_eligible: false + me_ccap: 0 + +- name: Case 4, undocumented child, ineligible. + period: 2026-01 + absolute_error_margin: 1 + input: + people: + person1: + age: 30 + employment_income: 25_000 + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: UNDOCUMENTED + childcare_hours_per_day: 8 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSED_CENTER + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 12_000 + spm_unit_assets: 10_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + county_str: CUMBERLAND_COUNTY_ME + output: + # Child is undocumented => not immigration eligible => not eligible child + is_ccdf_immigration_eligible_child: [true, false] + me_ccap_eligible_child: [false, false] + me_ccap_eligible: false + me_ccap: 0 + +- name: Case 5, high-income family at 110% SMI, 10% copay bracket. + period: 2026-01 + absolute_error_margin: 1 + input: + people: + person1: + age: 42 + # SMI for ME size 3 (2025-10-01): 118,065 * 0.84 = $99,174.60. + # Target ~115% SMI => 99,175 * 1.15 = $114,051. + employment_income: 115_000 + person2: + age: 40 + person3: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 9 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSED_CENTER + spm_units: + spm_unit: + members: [person1, person2, person3] + spm_unit_pre_subsidy_childcare_expenses: 25_000 + spm_unit_assets: 200_000 + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: ME + county_str: CUMBERLAND_COUNTY_ME + output: + # Eligibility: + me_ccap_eligible_child: [false, false, true] + + # Income: + # - $115,000 / $99,175 = 115.9% SMI + # - 125% SMI = $123,968.25 + # - $115,000 < $123,968 => income eligible + me_ccap_income_eligible: true + me_ccap_eligible: true + + # Region: Cumberland => REGION_1 + me_ccap_region: REGION_1 + + # Age group: age 1 => TODDLER + me_ccap_age_group: [SCHOOL_AGE, SCHOOL_AGE, TODDLER] + + # Time: person1,2 adults (0 hrs => PT), person3: 9*5 = 45 hrs => FULL_TIME + me_ccap_time_category: [PART_TIME, PART_TIME, FULL_TIME] + + # SMI percentage: $115,000 / $99,175 = 115.9% => 110-125% bracket => 10% fee + # Weekly income = $115,000/52 = $2,211.54 + # Raw weekly fee = floor(2211.54 * 0.10) = floor(221.15) = $221 + # Cap: 115.9% >= 85% => 10% cap + # Cap = floor(2211.54 * 0.10) = floor(221.15) = $221 + # Fee = $221/week => monthly = 221 * 52/12 = $957.67 + me_ccap_parent_fee: 957.67 + + # Market rate: Region 1 Licensed Center Toddler FT = $320/week + me_ccap_market_rate: [0, 0, 320] + + # Benefit: + # Max reimbursement: 320 * 52/12 = $1,386.67 + # Expenses (monthly): 25000/12 = $2,083.33 + # Parent fee (monthly): $957.67 + # Uncapped = max(2083.33 - 957.67, 0) = $1,125.67 + # Benefit = min(1125.67, 1386.67) = $1,125.67 + me_ccap: 1_126 + +- name: Case 6, disabled child age 15, eligible under special needs. + period: 2026-01 + absolute_error_margin: 1 + input: + people: + person1: + age: 45 + employment_income: 50_000 + person2: + age: 15 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 6 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSE_EXEMPT + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 8_000 + spm_unit_assets: 30_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + county_str: OXFORD_COUNTY_ME + output: + # person2: age 15, disabled => age < 19 special needs limit => eligible child + me_ccap_eligible_child: [false, true] + me_ccap_income_eligible: true + me_ccap_eligible: true + + # Region: Oxford => REGION_2 + me_ccap_region: REGION_2 + + # Age group: age 15 => SCHOOL_AGE + me_ccap_age_group: [SCHOOL_AGE, SCHOOL_AGE] + + # Time: person1 adult (0 hrs => PT), person2: 6*5 = 30 hrs => FULL_TIME (boundary) + me_ccap_time_category: [PART_TIME, FULL_TIME] + + # SMI %: $50,000 / $80,284 = 62.3% => 55-65% bracket => 5% fee + # Weekly income = 50000/52 = $961.54 + # Raw weekly fee = floor(961.54 * 0.05) = floor(48.08) = $48 + # Cap: 62.3% < 85% => 7% cap = floor(961.54 * 0.07) = floor(67.31) = $67 + # Fee = min(48, 67) = $48/week => monthly = 48 * 52/12 = $208 + me_ccap_parent_fee: 208 + + # Market rate: Region 2 License-Exempt School Age FT = $119/week + me_ccap_market_rate: [0, 119] + + # Benefit: + # Max reimbursement: 119 * 52/12 = $515.67 + # Expenses (monthly): 8000/12 = $666.67 + # Parent fee (monthly): $208 + # Uncapped = max(666.67 - 208, 0) = $458.67 + # Benefit = min(458.67, 515.67) = $458.67 + me_ccap: 459 + +- name: Case 7, assets over limit, ineligible. + period: 2026-01 + absolute_error_margin: 1 + input: + people: + person1: + age: 35 + employment_income: 60_000 + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSED_CENTER + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 15_000 + spm_unit_assets: 1_500_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + county_str: KENNEBEC_COUNTY_ME + output: + # Assets $1,500,000 > $1,000,000 => asset ineligible + is_ccdf_asset_eligible: false + me_ccap_eligible: false + me_ccap: 0 + +# === Edge case integration tests === + +- name: Case 8, assets exactly at limit, eligible. + period: 2026-01 + absolute_error_margin: 1 + input: + people: + person1: + age: 28 + employment_income: 30_000 + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSED_CENTER + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 15_000 + spm_unit_assets: 1_000_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + county_str: YORK_COUNTY_ME + output: + # Assets $1,000,000 <= $1,000,000 => asset eligible. + is_ccdf_asset_eligible: true + me_ccap_eligible_child: [false, true] + me_ccap_income_eligible: true + me_ccap_eligible: true + # Region 1 (York), Preschool, FT, Licensed Center = $300/week. + me_ccap_region: REGION_1 + me_ccap_age_group: [SCHOOL_AGE, PRESCHOOL] + me_ccap_time_category: [PART_TIME, FULL_TIME] + # SMI% = 30000 / 80284.20 = 37.4% => 35-40% bracket => 2% fee. + # Weekly income = 30000/52 = 576.92. + # Raw weekly = floor(576.92 * 0.02) = floor(11.54) = 11. + # Cap: floor(576.92 * 0.07) = floor(40.38) = 40. + # Fee = 11/week => monthly = 11 * 52/12 = $47.67. + me_ccap_parent_fee: 48 + me_ccap_market_rate: [0, 300] + # Max reimbursement: 300 * 52/12 = $1,300. + # Expenses (monthly) = 15000/12 = $1,250. + # Parent fee (monthly): $47.67. + # Uncapped = max(1250 - 47.67, 0) = $1,202.33. + # Benefit = min(1202.33, 1300) = $1,202.33. + me_ccap: 1_202 + +- name: Case 9, multiple children with different provider types and time categories. + period: 2026-01 + absolute_error_margin: 1 + input: + people: + person1: + age: 35 + employment_income: 35_000 + person2: + age: 33 + person3: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 9 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSED_CENTER + person4: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 4 + childcare_days_per_week: 3 + me_ccap_provider_type: LICENSE_EXEMPT + person5: + age: 8 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 3 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSED_FAMILY + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + spm_unit_pre_subsidy_childcare_expenses: 30_000 + spm_unit_assets: 200_000 + tax_units: + tax_unit: + members: [person1, person2, person3, person4, person5] + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: ME + county_str: SAGADAHOC_COUNTY_ME + output: + me_ccap_eligible_child: [false, false, true, true, true] + + # Size 5: adjustment = 0.52 + 4*0.16 = 1.16. + # Annual SMI = 118,065 * 1.16 = $136,955.40. + # 125% SMI = $171,194.25. + # $35,000 <= $171,194.25 => income eligible. + me_ccap_income_eligible: true + me_ccap_eligible: true + + # Region: Sagadahoc => REGION_1. + me_ccap_region: REGION_1 + + # Age groups: + # person3: age 0 => INFANT. + # person4: age 4 => PRESCHOOL. + # person5: age 8 => SCHOOL_AGE. + me_ccap_age_group: [SCHOOL_AGE, SCHOOL_AGE, INFANT, PRESCHOOL, SCHOOL_AGE] + + # Time categories: + # person1,2: adults (0 hrs => PT). + # person3: 9*5 = 45 hrs >= 30 => FULL_TIME. + # person4: 4*3 = 12 hrs < 30 => PART_TIME. + # person5: 3*5 = 15 hrs < 30 => PART_TIME. + me_ccap_time_category: [PART_TIME, PART_TIME, FULL_TIME, PART_TIME, PART_TIME] + + # SMI%: 35000 / 136955.40 = 25.6% => under 30% => 0% fee. + me_ccap_parent_fee: 0 + + # Market rates (weekly): + # person3: Region 1 Licensed Center Infant FT = 330. + # person4: Region 1 License-Exempt Preschool PT = 118.13. + # person5: Region 1 Licensed Family School Age PT = 140.46. + me_ccap_market_rate: [0, 0, 330, 118.13, 140.46] + + # Max reimbursement: (330 + 118.13 + 140.46) * 52/12 = 588.59 * 4.333 = $2,550.56. + # Expenses (monthly) = 30000/12 = $2,500. + # Parent fee (monthly): $0. + # Uncapped = max(2500 - 0, 0) = $2,500. + # Benefit = min(2500, 2550.56) = $2,500. + me_ccap: 2_500 + +- name: Case 10, high parent fee exceeds cheapest child's market rate but not most expensive. + period: 2026-01 + absolute_error_margin: 1 + input: + people: + person1: + age: 40 + # Target ~110% SMI for size 4 => $118,065 * 1.10 = $129,871.50. + employment_income: 129_872 + person2: + age: 38 + person3: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSED_CENTER + person4: + age: 10 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 3 + childcare_days_per_week: 5 + me_ccap_provider_type: LICENSE_EXEMPT + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + spm_unit_pre_subsidy_childcare_expenses: 30_000 + spm_unit_assets: 50_000 + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: ME + county_str: PENOBSCOT_COUNTY_ME + output: + me_ccap_eligible_child: [false, false, true, true] + + # Size 4 SMI = $118,065. 125% = $147,581.25. + # $129,872 <= $147,581 => eligible. + me_ccap_income_eligible: true + me_ccap_eligible: true + + # Penobscot region (Penobscot county). + me_ccap_region: PENOBSCOT + + # person3: age 0 => INFANT. person4: age 10 => SCHOOL_AGE. + me_ccap_age_group: [SCHOOL_AGE, SCHOOL_AGE, INFANT, SCHOOL_AGE] + + # person1,2: adults (0 hrs => PT). person3: 8*5=40 => FT. person4: 3*5=15 => PT. + me_ccap_time_category: [PART_TIME, PART_TIME, FULL_TIME, PART_TIME] + + # SMI% = 129872 / 118065 = 1.1000 => 100-110% bracket => 9% fee. + # But wait, need 110-125% bracket = threshold 1.1 => 10%. + # Actually, 1.1000 exactly: the bracket threshold at 1.1 gives 10%. + # But single_amount: the value at exactly 1.1 is 0.10 (the 110% threshold). + # Weekly income = 129872/52 = 2497.54. + # Raw weekly = floor(2497.54 * 0.10) = floor(249.75) = 249. + # Cap (110% >= 85%): floor(2497.54 * 0.10) = floor(249.75) = 249. + # Fee = 249/week. + # SMI% = 129872 / 118065 = 1.10 => 110-125% bracket => 10% fee. + # Weekly income = 129872/52 = $2,497.54. + # Raw weekly = floor(2497.54 * 0.10) = floor(249.75) = $249. + # Cap (110% >= 85%): floor(2497.54 * 0.10) = floor(249.75) = $249. + # Fee = 249/week => monthly = 249 * 52/12 = $1,079. + me_ccap_parent_fee: 1_079 + + # Market rates (weekly): + # person3: Penobscot Licensed Center Infant FT = $275 (same as Region 2). + # person4: Penobscot License-Exempt School Age PT = $95.51 (same as Region 2). + me_ccap_market_rate: [0, 0, 275, 95.51] + + # Max reimbursement: (275 + 95.51) * 52/12 = 370.51 * 4.333 = $1,605.54. + # Expenses (monthly): 30000/12 = $2,500. + # Parent fee (monthly): $1,079. + # Uncapped = max(2500 - 1079, 0) = $1,421. + # Benefit = min(1421, 1605.54) = $1,421. + me_ccap: 1_421 diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/me_ccap.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/me_ccap.yaml new file mode 100644 index 00000000000..a3da7894ddd --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/me_ccap.yaml @@ -0,0 +1,324 @@ +- name: Case 1, eligible family, benefit is min of expenses minus fee and market rate. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + me_ccap_eligible_child: true + me_ccap_market_rate: 300 + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_eligible: true + me_ccap_parent_fee: 216.67 + spm_unit_pre_subsidy_childcare_expenses: 20_800 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + # Market rate (weekly): $300 => monthly = 300 * 52/12 = $1,300. + # Parent fee (monthly): $216.67. + # Expenses (monthly): 20800/12 = $1,733.33. + # Uncapped: max(1733.33 - 216.67, 0) = $1,516.67. + # Max reimbursement: $1,300. + # Benefit = min(1516.67, 1300) = $1,300. + me_ccap: 1_300 + +- name: Case 2, ineligible family, zero benefit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_eligible: false + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + me_ccap: 0 + +- name: Case 3, expenses less than market rate, benefit capped at expenses minus fee. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + me_ccap_eligible_child: true + me_ccap_market_rate: 300 + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_eligible: true + me_ccap_parent_fee: 216.67 + spm_unit_pre_subsidy_childcare_expenses: 10_400 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + # Market rate (weekly): $300 => monthly = $1,300. + # Parent fee (monthly): $216.67. + # Expenses (monthly): 10400/12 = $866.67. + # Uncapped: max(866.67 - 216.67, 0) = $650. + # Max reimbursement: $1,300. + # Benefit = min(650, 1300) = $650. + me_ccap: 650 + +- name: Case 4, parent fee exceeds expenses, zero benefit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + me_ccap_eligible_child: true + me_ccap_market_rate: 115.38 + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_eligible: true + me_ccap_parent_fee: 700 + spm_unit_pre_subsidy_childcare_expenses: 6_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + # Expenses (monthly): 6000/12 = $500. + # Uncapped: max(500 - 700, 0) = $0. + # Benefit = min(0, 500) = $0. + me_ccap: 0 + +# === Edge cases === + +- name: Case 5, parent fee exceeds market rate for child (REQ-024). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 10 + me_ccap_eligible_child: true + me_ccap_market_rate: 95.51 + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_eligible: true + me_ccap_parent_fee: 650 + spm_unit_pre_subsidy_childcare_expenses: 10_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + # Weekly market rate: $95.51 => monthly = 95.51 * 52/12 = $413.88. + # Parent fee (monthly): $650. + # Expenses (monthly): 10000/12 = $833.33. + # Uncapped: max(833.33 - 650, 0) = $183.33. + # Max reimbursement: $413.88. + # Benefit = min(183.33, 413.88) = $183.33. + me_ccap: 183.33 + +- name: Case 6, multiple children, different age groups, one fee for family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 0 + me_ccap_eligible_child: true + me_ccap_market_rate: 330 + person3: + age: 7 + me_ccap_eligible_child: true + me_ccap_market_rate: 214 + spm_units: + spm_unit: + members: [person1, person2, person3] + me_ccap_eligible: true + me_ccap_parent_fee: 216.67 + spm_unit_pre_subsidy_childcare_expenses: 30_000 + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: ME + output: + # Weekly market rates: infant $330 + school age $214 = $544. + # Max reimbursement: 544 * 52/12 = $2,357.33. + # Expenses (monthly): 30000/12 = $2,500. + # Parent fee (monthly): $216.67. + # Uncapped: max(2500 - 216.67, 0) = $2,283.33. + # Benefit = min(2283.33, 2357.33) = $2,283.33. + me_ccap: 2_283.33 + +- name: Case 7, multiple children, parent fee exceeds market rate for one child only. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 0 + me_ccap_eligible_child: true + me_ccap_market_rate: 275 + person3: + age: 10 + me_ccap_eligible_child: true + me_ccap_market_rate: 95.51 + spm_units: + spm_unit: + members: [person1, person2, person3] + me_ccap_eligible: true + me_ccap_parent_fee: 520 + spm_unit_pre_subsidy_childcare_expenses: 25_000 + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: ME + output: + # Weekly market rates: infant $275 + school age $95.51 = $370.51. + # Max reimbursement: 370.51 * 52/12 = $1,605.54. + # Expenses (monthly): 25000/12 = $2,083.33. + # Parent fee (monthly): $520. + # Uncapped: max(2083.33 - 520, 0) = $1,563.33. + # Benefit = min(1563.33, 1605.54) = $1,563.33. + me_ccap: 1_563.33 + +- name: Case 8, zero childcare expenses, benefit capped at zero. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + me_ccap_eligible_child: true + me_ccap_market_rate: 300 + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_eligible: true + me_ccap_parent_fee: 0 + spm_unit_pre_subsidy_childcare_expenses: 0 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + # Expenses = 0. + # Uncapped: max(0 - 0, 0) = 0. + # Benefit = min(0, 1300) = 0. + me_ccap: 0 + +- name: Case 9, parent fee exactly equals monthly market rate equivalent. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + me_ccap_eligible_child: true + me_ccap_market_rate: 200 + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_eligible: true + me_ccap_parent_fee: 866.67 + spm_unit_pre_subsidy_childcare_expenses: 15_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + # Weekly market rate: $200 => monthly = 200 * 52/12 = $866.67. + # Parent fee (monthly): $866.67. + # Expenses (monthly): 15000/12 = $1,250. + # Uncapped: max(1250 - 866.67, 0) = $383.33. + # Max reimbursement: $866.67. + # Benefit = min(383.33, 866.67) = $383.33. + me_ccap: 383.33 + +- name: Case 10, negative countable income does not inflate benefit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + self_employment_income: -60_000_000 + person2: + age: 4 + me_ccap_eligible_child: true + me_ccap_market_rate: 300 + spm_units: + spm_unit: + members: [person1, person2] + me_ccap_eligible: true + spm_unit_pre_subsidy_childcare_expenses: 10_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: ME + output: + # Negative income -> parent fee = 0 (floor of negative = 0) + # Weekly market rate: $300 => monthly = 300 * 52/12 = $1,300. + # Expenses (monthly): 10,000/12 = $833.33. + # Uncapped: max(833.33 - 0, 0) = $833.33. + # Max reimbursement: $1,300. + # Benefit = min(833.33, 1,300) = $833.33. + # Benefit capped at expenses, NOT inflated by negative income. + me_ccap: 833.33 diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/payment/me_ccap_age_group.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/payment/me_ccap_age_group.yaml new file mode 100644 index 00000000000..0878729f925 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/payment/me_ccap_age_group.yaml @@ -0,0 +1,93 @@ +- name: Case 1, infant, 6 months old. + period: 2025-01 + input: + age: 0.5 + state_code: ME + output: + me_ccap_age_group: INFANT + +- name: Case 2, infant at upper boundary, 11 months. + period: 2025-01 + input: + age: 0.92 + state_code: ME + output: + me_ccap_age_group: INFANT + +- name: Case 3, toddler, 1 year old. + period: 2025-01 + input: + age: 1 + state_code: ME + output: + me_ccap_age_group: TODDLER + +- name: Case 4, toddler, 2 years old. + period: 2025-01 + input: + age: 2 + state_code: ME + output: + me_ccap_age_group: TODDLER + +- name: Case 5, preschool, 3 years old. + period: 2025-01 + input: + age: 3 + state_code: ME + output: + me_ccap_age_group: PRESCHOOL + +- name: Case 6, preschool, 4 years old. + period: 2025-01 + input: + age: 4 + state_code: ME + output: + me_ccap_age_group: PRESCHOOL + +- name: Case 7, school age, 5 years old. + period: 2025-01 + input: + age: 5 + state_code: ME + output: + me_ccap_age_group: SCHOOL_AGE + +- name: Case 8, school age, 10 years old. + period: 2025-01 + input: + age: 10 + state_code: ME + output: + me_ccap_age_group: SCHOOL_AGE + +# === Edge cases: boundary ages === + +- name: Case 9, newborn, age 0, infant. + period: 2025-01 + input: + age: 0 + state_code: ME + output: + # 0 months <= 12 months => INFANT. + me_ccap_age_group: INFANT + +- name: Case 10, school age boundary, 12 years old. + period: 2025-01 + input: + age: 12 + state_code: ME + output: + # age 12 > 5 => SCHOOL_AGE. + me_ccap_age_group: SCHOOL_AGE + +- name: Case 11, special needs child age 17, still school age group. + period: 2025-01 + input: + age: 17 + state_code: ME + output: + # Even though special needs children are eligible up to age 19, + # the age group is still SCHOOL_AGE for all children 5+. + me_ccap_age_group: SCHOOL_AGE diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/payment/me_ccap_market_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/payment/me_ccap_market_rate.yaml new file mode 100644 index 00000000000..0b57be51c58 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/payment/me_ccap_market_rate.yaml @@ -0,0 +1,1029 @@ +- name: Case 1, Region 1 infant full-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: INFANT + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Center Infant FT = $330/week + me_ccap_market_rate: [330] + +- name: Case 2, Region 2 toddler part-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: TODDLER + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Family Toddler PT = $150/week + me_ccap_market_rate: [150] + +- name: Case 3, Region 1 preschool full-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 License-Exempt Preschool FT = $157.5/week + me_ccap_market_rate: [157.5] + +- name: Case 4, Region 2 school age part-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Center School Age PT = $144.47/week + me_ccap_market_rate: [144.47] + +- name: Case 5, Region 2 infant full-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: INFANT + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 License-Exempt Infant FT = $147/week + me_ccap_market_rate: [147] + +- name: Case 6, Region 1 school age full-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Family School Age FT = $175/week + me_ccap_market_rate: [175] + +# === Edge cases: remaining rate combinations === + +- name: Case 7, Region 1 infant part-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: INFANT + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Center Infant PT = $247.50/week + me_ccap_market_rate: [247.50] + +- name: Case 8, Region 1 toddler full-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: TODDLER + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Center Toddler FT = $320/week + me_ccap_market_rate: [320] + +- name: Case 9, Region 1 toddler part-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: TODDLER + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Center Toddler PT = $240/week + me_ccap_market_rate: [240] + +- name: Case 10, Region 1 preschool full-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Center Preschool FT = $300/week + me_ccap_market_rate: [300] + +- name: Case 11, Region 1 preschool part-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Center Preschool PT = $225/week + me_ccap_market_rate: [225] + +- name: Case 12, Region 1 school age full-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Center School Age FT = $214/week + me_ccap_market_rate: [214] + +- name: Case 13, Region 1 school age part-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Center School Age PT = $171.76/week + me_ccap_market_rate: [171.76] + +- name: Case 14, Region 2 infant full-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: INFANT + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Center Infant FT = $275/week + me_ccap_market_rate: [275] + +- name: Case 15, Region 2 infant part-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: INFANT + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Center Infant PT = $206.25/week + me_ccap_market_rate: [206.25] + +- name: Case 16, Region 2 toddler full-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: TODDLER + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Center Toddler FT = $250/week + me_ccap_market_rate: [250] + +- name: Case 17, Region 2 toddler part-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: TODDLER + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Center Toddler PT = $187.50/week + me_ccap_market_rate: [187.50] + +- name: Case 18, Region 2 preschool full-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Center Preschool FT = $244/week + me_ccap_market_rate: [244] + +- name: Case 19, Region 2 preschool part-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Center Preschool PT = $183/week + me_ccap_market_rate: [183] + +- name: Case 20, Region 2 school age full-time licensed center. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Center School Age FT = $180/week + me_ccap_market_rate: [180] + +- name: Case 21, Region 1 infant full-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: INFANT + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Family Infant FT = $245/week + me_ccap_market_rate: [245] + +- name: Case 22, Region 1 infant part-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: INFANT + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Family Infant PT = $183.75/week + me_ccap_market_rate: [183.75] + +- name: Case 23, Region 1 toddler full-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: TODDLER + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Family Toddler FT = $230.77/week + me_ccap_market_rate: [230.77] + +- name: Case 24, Region 1 toddler part-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: TODDLER + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Family Toddler PT = $173.08/week + me_ccap_market_rate: [173.08] + +- name: Case 25, Region 1 preschool full-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Family Preschool FT = $225/week + me_ccap_market_rate: [225] + +- name: Case 26, Region 1 preschool part-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Family Preschool PT = $168.75/week + me_ccap_market_rate: [168.75] + +- name: Case 27, Region 1 school age part-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 Licensed Family School Age PT = $140.46/week + me_ccap_market_rate: [140.46] + +- name: Case 28, Region 2 infant full-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: INFANT + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Family Infant FT = $210/week + me_ccap_market_rate: [210] + +- name: Case 29, Region 2 infant part-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: INFANT + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Family Infant PT = $157.50/week + me_ccap_market_rate: [157.50] + +- name: Case 30, Region 2 toddler full-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: TODDLER + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Family Toddler FT = $200/week + me_ccap_market_rate: [200] + +- name: Case 31, Region 2 preschool full-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Family Preschool FT = $190/week + me_ccap_market_rate: [190] + +- name: Case 32, Region 2 preschool part-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Family Preschool PT = $142.50/week + me_ccap_market_rate: [142.50] + +- name: Case 33, Region 2 school age full-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Family School Age FT = $170/week + me_ccap_market_rate: [170] + +- name: Case 34, Region 2 school age part-time licensed family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSED_FAMILY + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 Licensed Family School Age PT = $136.45/week + me_ccap_market_rate: [136.45] + +- name: Case 35, Region 1 infant full-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: INFANT + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 License-Exempt Infant FT = $171.50/week + me_ccap_market_rate: [171.50] + +- name: Case 36, Region 1 infant part-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: INFANT + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 License-Exempt Infant PT = $128.63/week + me_ccap_market_rate: [128.63] + +- name: Case 37, Region 1 toddler full-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: TODDLER + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 License-Exempt Toddler FT = $161.54/week + me_ccap_market_rate: [161.54] + +- name: Case 38, Region 1 toddler part-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: TODDLER + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 License-Exempt Toddler PT = $121.15/week + me_ccap_market_rate: [121.15] + +- name: Case 39, Region 1 preschool part-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 License-Exempt Preschool PT = $118.13/week + me_ccap_market_rate: [118.13] + +- name: Case 40, Region 1 school age full-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 License-Exempt School Age FT = $122.50/week + me_ccap_market_rate: [122.50] + +- name: Case 41, Region 1 school age part-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_1 + output: + # Region 1 License-Exempt School Age PT = $98.33/week + me_ccap_market_rate: [98.33] + +- name: Case 42, Region 2 infant part-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: INFANT + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 License-Exempt Infant PT = $110.25/week + me_ccap_market_rate: [110.25] + +- name: Case 43, Region 2 toddler full-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: TODDLER + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 License-Exempt Toddler FT = $140/week + me_ccap_market_rate: [140] + +- name: Case 44, Region 2 toddler part-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: TODDLER + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 License-Exempt Toddler PT = $105/week + me_ccap_market_rate: [105] + +- name: Case 45, Region 2 preschool full-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 License-Exempt Preschool FT = $133/week + me_ccap_market_rate: [133] + +- name: Case 46, Region 2 preschool part-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 License-Exempt Preschool PT = $99.75/week + me_ccap_market_rate: [99.75] + +- name: Case 47, Region 2 school age full-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 License-Exempt School Age FT = $119/week + me_ccap_market_rate: [119] + +- name: Case 48, Region 2 school age part-time license-exempt. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: PART_TIME + me_ccap_provider_type: LICENSE_EXEMPT + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: REGION_2 + output: + # Region 2 License-Exempt School Age PT = $95.51/week + me_ccap_market_rate: [95.51] + +# === County-specific region rate tests === + +- name: Case 49, Kennebec Licensed Center Preschool FT 2024 rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: KENNEBEC + output: + # Kennebec Licensed Center Preschool FT = $267/week (2024 rate) + me_ccap_market_rate: [267] + +- name: Case 50, Knox Licensed Center School Age FT 2024 rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: KNOX_WALDO + output: + # Knox/Waldo Licensed Center School Age FT = $220/week (2024 rate) + me_ccap_market_rate: [220] + +- name: Case 51, Knox Licensed Center School Age FT 2025 rate retained. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: KNOX_WALDO + output: + # Knox/Waldo Licensed Center School Age FT = $220/week (retains unique rate per May 2025 PDF) + me_ccap_market_rate: [220] + +- name: Case 52, Kennebec Licensed Center Preschool FT 2025 rate retained. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: PRESCHOOL + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: KENNEBEC + output: + # Kennebec Licensed Center Preschool FT = $267/week (retains unique rate per May 2025 PDF) + me_ccap_market_rate: [267] + +- name: Case 53, Penobscot Licensed Center School Age FT 2024 rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: PENOBSCOT + output: + # Penobscot Licensed Center School Age FT = $200/week (2024 rate) + me_ccap_market_rate: [200] + +- name: Case 54, Penobscot Licensed Center School Age FT 2025 rate retained. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + me_ccap_age_group: SCHOOL_AGE + me_ccap_time_category: FULL_TIME + me_ccap_provider_type: LICENSED_CENTER + me_ccap_eligible_child: true + households: + household: + members: [person1] + state_code: ME + me_ccap_region: PENOBSCOT + output: + # Penobscot Licensed Center School Age FT = $200/week (retains unique rate per May 2025 PDF) + me_ccap_market_rate: [200] diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/payment/me_ccap_region.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/payment/me_ccap_region.yaml new file mode 100644 index 00000000000..00243477bf9 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/payment/me_ccap_region.yaml @@ -0,0 +1,63 @@ +- name: Case 1, Cumberland County, Region 1. + period: 2025-01 + input: + county_str: CUMBERLAND_COUNTY_ME + state_code: ME + output: + me_ccap_region: REGION_1 + +- name: Case 2, York County, Region 1. + period: 2025-01 + input: + county_str: YORK_COUNTY_ME + state_code: ME + output: + me_ccap_region: REGION_1 + +- name: Case 3, Sagadahoc County, Region 1. + period: 2025-01 + input: + county_str: SAGADAHOC_COUNTY_ME + state_code: ME + output: + me_ccap_region: REGION_1 + +- name: Case 4, Penobscot County, PENOBSCOT region. + period: 2025-01 + input: + county_str: PENOBSCOT_COUNTY_ME + state_code: ME + output: + me_ccap_region: PENOBSCOT + +- name: Case 5, Kennebec County, KENNEBEC region. + period: 2025-01 + input: + county_str: KENNEBEC_COUNTY_ME + state_code: ME + output: + me_ccap_region: KENNEBEC + +- name: Case 6, Aroostook County, Region 2. + period: 2025-01 + input: + county_str: AROOSTOOK_COUNTY_ME + state_code: ME + output: + me_ccap_region: REGION_2 + +- name: Case 7, Knox county maps to KNOX_WALDO region. + period: 2025-01 + input: + county_str: KNOX_COUNTY_ME + state_code: ME + output: + me_ccap_region: KNOX_WALDO + +- name: Case 8, Waldo county maps to KNOX_WALDO region. + period: 2025-01 + input: + county_str: WALDO_COUNTY_ME + state_code: ME + output: + me_ccap_region: KNOX_WALDO diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/payment/me_ccap_time_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/payment/me_ccap_time_category.yaml new file mode 100644 index 00000000000..1332412d771 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/me/dhhs/ccap/payment/me_ccap_time_category.yaml @@ -0,0 +1,180 @@ +# === 2026: Simplified two-category system (uses_simplified_time = true) === + +- name: Case 1, 40 hours per week, full time (simplified). + period: 2026-01 + input: + childcare_hours_per_day: 8 + childcare_days_per_week: 5 + state_code: ME + output: + me_ccap_time_category: FULL_TIME + +- name: Case 2, 30 hours per week, full time boundary (simplified). + period: 2026-01 + input: + childcare_hours_per_day: 6 + childcare_days_per_week: 5 + state_code: ME + output: + me_ccap_time_category: FULL_TIME + +- name: Case 3, 25 hours per week, part time (simplified). + period: 2026-01 + input: + childcare_hours_per_day: 5 + childcare_days_per_week: 5 + state_code: ME + output: + me_ccap_time_category: PART_TIME + +- name: Case 4, 29 hours per week, part time boundary (simplified). + period: 2026-01 + input: + childcare_hours_per_day: 5.8 + childcare_days_per_week: 5 + state_code: ME + output: + me_ccap_time_category: PART_TIME + +- name: Case 5, 10 hours per week, part time (simplified). + period: 2026-01 + input: + childcare_hours_per_day: 5 + childcare_days_per_week: 2 + state_code: ME + output: + me_ccap_time_category: PART_TIME + +# === Edge cases (simplified) === + +- name: Case 6, 1 hour per week, minimum part time (simplified). + period: 2026-01 + input: + childcare_hours_per_day: 1 + childcare_days_per_week: 1 + state_code: ME + output: + # 1 hour < 30 => PART_TIME. + me_ccap_time_category: PART_TIME + +- name: Case 7, zero hours per week (simplified). + period: 2026-01 + input: + childcare_hours_per_day: 0 + childcare_days_per_week: 0 + state_code: ME + output: + # 0 hours < 30 => PART_TIME. + me_ccap_time_category: PART_TIME + +- name: Case 8, 50 hours per week, maximum full time (simplified). + period: 2026-01 + input: + childcare_hours_per_day: 10 + childcare_days_per_week: 5 + state_code: ME + output: + # 50 hours >= 30 => FULL_TIME. + me_ccap_time_category: FULL_TIME + +# === 2025: Four-category system (uses_simplified_time = false) === + +- name: Case 9, 35 hours per week, full time (4-category). + period: 2025-01 + input: + childcare_hours_per_day: 7 + childcare_days_per_week: 5 + state_code: ME + output: + # 35 hours >= 30 => FULL_TIME. + me_ccap_time_category: FULL_TIME + +- name: Case 10, 30 hours per week, full time boundary (4-category). + period: 2025-01 + input: + childcare_hours_per_day: 6 + childcare_days_per_week: 5 + state_code: ME + output: + # 30 hours >= 30 => FULL_TIME. + me_ccap_time_category: FULL_TIME + +- name: Case 11, 25 hours per week, part time (4-category). + period: 2025-01 + input: + childcare_hours_per_day: 5 + childcare_days_per_week: 5 + state_code: ME + output: + # 25 hours >= 20 => PART_TIME. + me_ccap_time_category: PART_TIME + +- name: Case 12, 20 hours per week, part time boundary (4-category). + period: 2025-01 + input: + childcare_hours_per_day: 4 + childcare_days_per_week: 5 + state_code: ME + output: + # 20 hours >= 20 => PART_TIME. + me_ccap_time_category: PART_TIME + +- name: Case 13, 15 hours per week, half time (4-category). + period: 2025-01 + input: + childcare_hours_per_day: 3 + childcare_days_per_week: 5 + state_code: ME + output: + # 15 hours >= 10 => HALF_TIME. + me_ccap_time_category: HALF_TIME + +- name: Case 14, 10 hours per week, half time boundary (4-category). + period: 2025-01 + input: + childcare_hours_per_day: 2 + childcare_days_per_week: 5 + state_code: ME + output: + # 10 hours >= 10 => HALF_TIME. + me_ccap_time_category: HALF_TIME + +- name: Case 15, 5 hours per week, quarter time (4-category). + period: 2025-01 + input: + childcare_hours_per_day: 1 + childcare_days_per_week: 5 + state_code: ME + output: + # 5 hours < 10 => QUARTER_TIME. + me_ccap_time_category: QUARTER_TIME + +- name: Case 16, 9 hours per week, quarter time boundary (4-category). + period: 2025-01 + input: + childcare_hours_per_day: 3 + childcare_days_per_week: 3 + state_code: ME + output: + # 9 hours < 10 => QUARTER_TIME. + me_ccap_time_category: QUARTER_TIME + +- name: Case 17, zero hours per week, quarter time (4-category). + period: 2025-01 + input: + childcare_hours_per_day: 0 + childcare_days_per_week: 0 + state_code: ME + output: + # 0 hours < 10 => QUARTER_TIME. + me_ccap_time_category: QUARTER_TIME + +- name: Case 18, 19 hours per week, half time (4-category). + period: 2025-01 + input: + childcare_hours_per_day: 3.8 + childcare_days_per_week: 5 + state_code: ME + output: + # 19 hours >= 10 but < 20 => HALF_TIME. + me_ccap_time_category: HALF_TIME diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/copay/me_ccap_parent_fee.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/copay/me_ccap_parent_fee.py new file mode 100644 index 00000000000..e144b30a4cb --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/copay/me_ccap_parent_fee.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class me_ccap_parent_fee(Variable): + value_type = float + entity = SPMUnit + label = "Maine CCAP monthly parent fee" + unit = USD + definition_period = MONTH + defined_for = StateCode.ME + reference = ( + "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=26", + "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=27", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.me.dhhs.ccap.copay + countable_income = spm_unit("me_ccap_countable_income", period) + monthly_smi = spm_unit("me_ccap_smi", period) + smi_percentage = where(monthly_smi > 0, countable_income / monthly_smi, 0) + weekly_income = countable_income * MONTHS_IN_YEAR / WEEKS_IN_YEAR + + fee_rate = p.rate.calc(smi_percentage) + raw_weekly_fee = np.floor(weekly_income * fee_rate) + + cap_rate = p.cap.calc(smi_percentage) + capped_weekly_fee = np.floor(weekly_income * cap_rate) + + weekly_fee = min_(raw_weekly_fee, capped_weekly_fee) + return weekly_fee * WEEKS_IN_YEAR / MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/eligibility/me_ccap_activity_eligible.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/eligibility/me_ccap_activity_eligible.py new file mode 100644 index 00000000000..2eeda3377e1 --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/eligibility/me_ccap_activity_eligible.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class me_ccap_activity_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Maine CCAP based on activity requirements" + definition_period = MONTH + defined_for = StateCode.ME + reference = "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=12" + + def formula(spm_unit, period, parameters): + person = spm_unit.members + is_head_or_spouse = person("is_tax_unit_head_or_spouse", period.this_year) + hours_worked = person("weekly_hours_worked", period.this_year) + is_employed = hours_worked > 0 + is_student = person("is_full_time_student", period.this_year) + is_disabled = person("is_disabled", period.this_year) + individually_eligible = is_employed | is_student | is_disabled + return spm_unit.sum(is_head_or_spouse & ~individually_eligible) == 0 diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/eligibility/me_ccap_eligible.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/eligibility/me_ccap_eligible.py new file mode 100644 index 00000000000..5f02d5aaf61 --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/eligibility/me_ccap_eligible.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class me_ccap_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Maine Child Care Affordability Program" + definition_period = MONTH + defined_for = StateCode.ME + reference = "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=11" + + def formula(spm_unit, period, parameters): + has_eligible_child = add(spm_unit, period, ["me_ccap_eligible_child"]) > 0 + income_eligible = spm_unit("me_ccap_income_eligible", period) + asset_eligible = spm_unit("is_ccdf_asset_eligible", period.this_year) + activity_eligible = spm_unit("me_ccap_activity_eligible", period) + return has_eligible_child & income_eligible & asset_eligible & activity_eligible diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/eligibility/me_ccap_eligible_child.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/eligibility/me_ccap_eligible_child.py new file mode 100644 index 00000000000..a9cb8a68732 --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/eligibility/me_ccap_eligible_child.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class me_ccap_eligible_child(Variable): + value_type = bool + entity = Person + label = "Eligible child for Maine CCAP" + definition_period = MONTH + defined_for = StateCode.ME + reference = "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=11" + + def formula(person, period, parameters): + p = parameters(period).gov.states.me.dhhs.ccap.age_limit + age = person("monthly_age", period) + is_disabled = person("is_disabled", period.this_year) + age_limit = where(is_disabled, p.special_needs, p.child) + age_eligible = age < age_limit + is_dependent = person("is_tax_unit_dependent", period.this_year) + immigration_eligible = person( + "is_ccdf_immigration_eligible_child", period.this_year + ) + return age_eligible & is_dependent & immigration_eligible diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/eligibility/me_ccap_income_eligible.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/eligibility/me_ccap_income_eligible.py new file mode 100644 index 00000000000..dcd1c7356ca --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/eligibility/me_ccap_income_eligible.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class me_ccap_income_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Income eligible for Maine CCAP" + definition_period = MONTH + defined_for = StateCode.ME + reference = "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=12" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.me.dhhs.ccap.income + countable_income = spm_unit("me_ccap_countable_income", period) + monthly_smi = spm_unit("me_ccap_smi", period) + income_limit = monthly_smi * p.smi_limit + return countable_income <= income_limit diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/income/me_ccap_countable_income.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/income/me_ccap_countable_income.py new file mode 100644 index 00000000000..c67bbd157a9 --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/income/me_ccap_countable_income.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class me_ccap_countable_income(Variable): + value_type = float + entity = SPMUnit + label = "Maine CCAP countable income" + unit = USD + definition_period = MONTH + defined_for = StateCode.ME + reference = "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=13" + + adds = "gov.states.me.dhhs.ccap.income.countable_income.sources" diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/income/me_ccap_smi.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/income/me_ccap_smi.py new file mode 100644 index 00000000000..45cbbcb4461 --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/income/me_ccap_smi.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.hhs.hhs_smi import smi + + +class me_ccap_smi(Variable): + value_type = float + entity = SPMUnit + label = "Maine CCAP State Median Income for family size" + unit = USD + definition_period = MONTH + defined_for = StateCode.ME + reference = "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=12" + + def formula(spm_unit, period, parameters): + 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" + size = spm_unit("spm_unit_size", period.this_year) + state = spm_unit.household("state_code_str", period.this_year) + return smi(size, state, instant_str, parameters) / MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/me_ccap.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/me_ccap.py new file mode 100644 index 00000000000..6c3e53d2c2a --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/me_ccap.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class me_ccap(Variable): + value_type = float + entity = SPMUnit + label = "Maine Child Care Affordability Program benefit" + unit = USD + definition_period = MONTH + defined_for = "me_ccap_eligible" + reference = "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=26" + + def formula(spm_unit, period, parameters): + parent_fee = spm_unit("me_ccap_parent_fee", period) + + person = spm_unit.members + is_eligible_child = person("me_ccap_eligible_child", period) + weekly_market_rate = person("me_ccap_market_rate", period) + weekly_to_monthly = WEEKS_IN_YEAR / MONTHS_IN_YEAR + max_reimbursement = ( + spm_unit.sum(weekly_market_rate * is_eligible_child) * weekly_to_monthly + ) + + actual_expenses = spm_unit("spm_unit_pre_subsidy_childcare_expenses", period) + uncapped_benefit = max_(actual_expenses - parent_fee, 0) + return min_(uncapped_benefit, max_reimbursement) diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_age_group.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_age_group.py new file mode 100644 index 00000000000..e6700b13b79 --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_age_group.py @@ -0,0 +1,37 @@ +from policyengine_us.model_api import * + + +class MECCAPAgeGroup(Enum): + INFANT = "Infant" + TODDLER = "Toddler" + PRESCHOOL = "Preschool" + SCHOOL_AGE = "School Age" + + +class me_ccap_age_group(Variable): + value_type = Enum + entity = Person + possible_values = MECCAPAgeGroup + default_value = MECCAPAgeGroup.INFANT + definition_period = MONTH + defined_for = StateCode.ME + label = "Maine CCAP child age group" + reference = "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=7" + + def formula(person, period, parameters): + p = parameters(period).gov.states.me.dhhs.ccap.age_groups + age = person("monthly_age", period) + age_months = age * MONTHS_IN_YEAR + return select( + [ + age_months < p.infant_max_months, + age_months < p.toddler_max_months, + age < p.preschool_max_years, + ], + [ + MECCAPAgeGroup.INFANT, + MECCAPAgeGroup.TODDLER, + MECCAPAgeGroup.PRESCHOOL, + ], + default=MECCAPAgeGroup.SCHOOL_AGE, + ) diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_market_rate.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_market_rate.py new file mode 100644 index 00000000000..4c29193152a --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_market_rate.py @@ -0,0 +1,39 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.me.dhhs.ccap.payment.me_ccap_provider_type import ( + MECCAPProviderType, +) + + +class me_ccap_market_rate(Variable): + value_type = float + entity = Person + label = "Maine CCAP weekly market rate per child" + unit = USD + definition_period = MONTH + defined_for = "me_ccap_eligible_child" + reference = "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=25" + + def formula(person, period, parameters): + p = parameters(period).gov.states.me.dhhs.ccap.market_rate + region = person.household("me_ccap_region", period) + age_group = person("me_ccap_age_group", period) + time_category = person("me_ccap_time_category", period) + provider_type = person("me_ccap_provider_type", period) + + center_rate = p.licensed_center[region][age_group][time_category] + family_rate = p.licensed_family[region][age_group][time_category] + exempt_rate = p.license_exempt[region][age_group][time_category] + + return select( + [ + provider_type == MECCAPProviderType.LICENSED_CENTER, + provider_type == MECCAPProviderType.LICENSED_FAMILY, + provider_type == MECCAPProviderType.LICENSE_EXEMPT, + ], + [ + center_rate, + family_rate, + exempt_rate, + ], + default=center_rate, + ) diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_provider_type.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_provider_type.py new file mode 100644 index 00000000000..5f8360857bd --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_provider_type.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class MECCAPProviderType(Enum): + LICENSED_CENTER = "Licensed Child Care Center" + LICENSED_FAMILY = "Licensed Family Child Care" + LICENSE_EXEMPT = "License-Exempt Child Care" + + +class me_ccap_provider_type(Variable): + value_type = Enum + entity = Person + possible_values = MECCAPProviderType + default_value = MECCAPProviderType.LICENSED_CENTER + definition_period = MONTH + defined_for = StateCode.ME + label = "Maine CCAP child care provider type" + reference = "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=25" diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_region.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_region.py new file mode 100644 index 00000000000..9eca1e31bd3 --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_region.py @@ -0,0 +1,41 @@ +from policyengine_us.model_api import * + + +class MECCAPRegion(Enum): + REGION_1 = "Region 1" + REGION_2 = "Region 2" + KENNEBEC = "Kennebec" + KNOX_WALDO = "Knox/Waldo" + PENOBSCOT = "Penobscot" + + +class me_ccap_region(Variable): + value_type = Enum + entity = Household + possible_values = MECCAPRegion + default_value = MECCAPRegion.REGION_2 + definition_period = MONTH + defined_for = StateCode.ME + label = "Maine CCAP geographic region" + reference = ( + "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=25", + "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/July%206%202024%20Market%20Rates_5_0.pdf", + ) + + def formula(household, period, parameters): + county = household("county_str", period) + p = parameters(period).gov.states.me.dhhs.ccap + is_region_1 = np.isin(county, p.region_1_counties) + is_kennebec = np.isin(county, ["KENNEBEC_COUNTY_ME"]) + is_knox_waldo = np.isin(county, ["KNOX_COUNTY_ME", "WALDO_COUNTY_ME"]) + is_penobscot = np.isin(county, ["PENOBSCOT_COUNTY_ME"]) + return select( + [is_region_1, is_kennebec, is_knox_waldo, is_penobscot], + [ + MECCAPRegion.REGION_1, + MECCAPRegion.KENNEBEC, + MECCAPRegion.KNOX_WALDO, + MECCAPRegion.PENOBSCOT, + ], + default=MECCAPRegion.REGION_2, + ) diff --git a/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_time_category.py b/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_time_category.py new file mode 100644 index 00000000000..a7c7b1d09e9 --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/ccap/payment/me_ccap_time_category.py @@ -0,0 +1,45 @@ +from policyengine_us.model_api import * + + +class MECCAPTimeCategory(Enum): + FULL_TIME = "Full Time" + PART_TIME = "Part Time" + HALF_TIME = "Half Time" + QUARTER_TIME = "Quarter Time" + + +class me_ccap_time_category(Variable): + value_type = Enum + entity = Person + possible_values = MECCAPTimeCategory + default_value = MECCAPTimeCategory.FULL_TIME + definition_period = MONTH + defined_for = StateCode.ME + label = "Maine CCAP time category" + reference = ( + "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/CCAP%20Full%20Rule%208.18.2025_1.pdf#page=28", + "https://www.maine.gov/dhhs/sites/maine.gov.dhhs/files/inline-files/July%206%202024%20Market%20Rates_5_0.pdf", + ) + + def formula(person, period, parameters): + hours = person("childcare_hours_per_week", period.this_year) + p = parameters(period).gov.states.me.dhhs.ccap.hours + if p.uses_simplified_time: + return where( + hours >= p.full_time_threshold, + MECCAPTimeCategory.FULL_TIME, + MECCAPTimeCategory.PART_TIME, + ) + return select( + [ + hours >= p.full_time_threshold, + hours >= p.part_time_threshold, + hours >= p.half_time_threshold, + ], + [ + MECCAPTimeCategory.FULL_TIME, + MECCAPTimeCategory.PART_TIME, + MECCAPTimeCategory.HALF_TIME, + ], + default=MECCAPTimeCategory.QUARTER_TIME, + ) diff --git a/policyengine_us/variables/gov/states/me/dhhs/me_child_care_subsidies.py b/policyengine_us/variables/gov/states/me/dhhs/me_child_care_subsidies.py new file mode 100644 index 00000000000..b4865a05ba5 --- /dev/null +++ b/policyengine_us/variables/gov/states/me/dhhs/me_child_care_subsidies.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class me_child_care_subsidies(Variable): + value_type = float + entity = SPMUnit + label = "Maine child care subsidies" + unit = USD + definition_period = YEAR + defined_for = StateCode.ME + adds = ["me_ccap"] diff --git a/uv.lock b/uv.lock index efec4d8555d..7adaf13620b 100644 --- a/uv.lock +++ b/uv.lock @@ -1492,7 +1492,7 @@ wheels = [ [[package]] name = "policyengine-us" -version = "1.592.1" +version = "1.598.0" source = { editable = "." } dependencies = [ { name = "microdf-python" },