diff --git a/changelog.d/md-ccap.added.md b/changelog.d/md-ccap.added.md new file mode 100644 index 00000000000..379dc3540da --- /dev/null +++ b/changelog.d/md-ccap.added.md @@ -0,0 +1 @@ +Implement Maryland Child Care Scholarship (CCS) program. diff --git a/lessons/agent-lessons.md b/lessons/agent-lessons.md new file mode 100644 index 00000000000..b2bcee7c7df --- /dev/null +++ b/lessons/agent-lessons.md @@ -0,0 +1,18 @@ +# Agent Lessons Learned + +Accumulated from /encode-policy-v2 and /backdate-program runs across all contributors. +Loaded by implementation agents on future runs. + +## New Lessons from Maryland CCS (2026-03-26) + +### VARIABLE +- When a formula uses `select()` with a default/fallback for one category, replace it with explicit matching for ALL categories including the default; implicit defaults silently swallow new or misspelled values and make the "default" category untestable in isolation. + +### REFERENCE +- When a state regulation portal migrates domains (e.g., `dsd.maryland.gov` to `regs.maryland.gov`), ALL parameter files referencing the old domain must be updated in one pass; broken redirects (301 to 404) are systematic, not isolated, so always search-and-replace across the entire state directory rather than fixing one file at a time. +- When a parameter encodes a state policy choice (e.g., state sets 85% SMI threshold), cite the state regulation as the primary reference, not the federal CFR that merely sets the ceiling; federal authority is context, not the source of the state's specific value. +- When correcting a wrong COMAR/regulation subsection citation, verify the replacement subsection's content in the same review round; three of four citation corrections in this session initially pointed to the wrong subsection because adjacent subsections cover different provisions with similar-sounding names (e.g., .03(B) = citizenship vs .03(H) = income eligibility). + +### WORKFLOW +- When implementing a new state program, add it to `programs.yaml` as part of the initial implementation, not as an afterthought; missing registry entries block the program from appearing in the metadata API and coverage page. +- When a `select()` or similar lookup relies on a parameter file for each category, verify that ALL categories have corresponding parameter files before the first review round; a missing file for one category (e.g., Region W counties) forces the formula to use an implicit default, hiding a data gap. 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 7a253af1f86..1d8237aacd3 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 + - md_child_care_subsidies # Maryland Child Care Scholarship - me_child_care_subsidies # Maine Child Care Affordability Program - ne_child_care_subsidies # Nebraska Child Care Subsidy - nh_child_care_subsidies # New Hampshire Child Care Scholarship Program diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/age_threshold/child.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/age_threshold/child.yaml new file mode 100644 index 00000000000..f69a9aff0c5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/age_threshold/child.yaml @@ -0,0 +1,11 @@ +description: Maryland limits the Child Care Scholarship program to children under this age. +values: + 2018-01-01: 13 + +metadata: + unit: year + period: year + label: Maryland CCS child age threshold + reference: + - title: COMAR 13A.14.06.02 - Definitions, "Child" + href: https://regs.maryland.gov/us/md/exec/comar/13A.14.06.02 diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/age_threshold/disabled_child.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/age_threshold/disabled_child.yaml new file mode 100644 index 00000000000..a7337cb6fdd --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/age_threshold/disabled_child.yaml @@ -0,0 +1,11 @@ +description: Maryland limits the Child Care Scholarship program to disabled children under this age. +values: + 2018-01-01: 19 + +metadata: + unit: year + period: year + label: Maryland CCS disabled child age threshold + reference: + - title: COMAR 13A.14.06.02 - Definitions, "Child" + href: https://regs.maryland.gov/us/md/exec/comar/13A.14.06.02 diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/copay/federal_cap_rate.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/copay/federal_cap_rate.yaml new file mode 100644 index 00000000000..972e835c739 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/copay/federal_cap_rate.yaml @@ -0,0 +1,11 @@ +description: Maryland limits copayments to this share of family gross income under the Child Care Scholarship program per federal requirements. +values: + 2022-05-01: 0.07 + +metadata: + unit: /1 + period: year + label: Maryland CCS federal copayment cap rate + reference: + - title: 45 CFR 98.45(k) + href: https://www.ecfr.gov/current/title-45/section-98.45#p-98.45(k) diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/copay/max_children_with_copay.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/copay/max_children_with_copay.yaml new file mode 100644 index 00000000000..6c8e59955c2 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/copay/max_children_with_copay.yaml @@ -0,0 +1,11 @@ +description: Maryland assesses copayments for up to this many children under the Child Care Scholarship program. +values: + 2022-05-01: 3 + +metadata: + unit: person + period: year + label: Maryland CCS maximum children with copayment + reference: + - title: COMAR 13A.14.06.12 + href: https://regs.maryland.gov/us/md/exec/comar/13A.14.06.12 diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/copay/unit_hours.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/copay/unit_hours.yaml new file mode 100644 index 00000000000..d445e101fc4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/copay/unit_hours.yaml @@ -0,0 +1,25 @@ +description: Maryland determines the number of service units based on daily hours of care under the Child Care Scholarship program. + +metadata: + type: single_amount + threshold_unit: hour + amount_unit: /1 + period: year + label: Maryland CCS service units by daily hours + reference: + - title: COMAR 13A.14.06.11 + href: https://regs.maryland.gov/us/md/exec/comar/13A.14.06.11 + +brackets: + - threshold: + 2022-05-01: 0 + amount: + 2022-05-01: 1 + - threshold: + 2022-05-01: 3.0001 + amount: + 2022-05-01: 2 + - threshold: + 2022-05-01: 6 + amount: + 2022-05-01: 3 diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/copay/weekly_amount.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/copay/weekly_amount.yaml new file mode 100644 index 00000000000..b351e54da59 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/copay/weekly_amount.yaml @@ -0,0 +1,20 @@ +description: Maryland sets this amount as the weekly copayment by service unit under the Child Care Scholarship program. + +metadata: + unit: currency-USD + period: week + label: Maryland CCS weekly copayment by service unit + breakdown: + - md_ccs_service_unit + reference: + - title: Chapter 717 of 2024 + href: https://mgaleg.maryland.gov/2024RS/Chapters_noln/CH_717_sb0482e.pdf#page=1 + - title: COMAR 13A.14.06.12 + href: https://regs.maryland.gov/us/md/exec/comar/13A.14.06.12 + +UNIT_3: + 2022-05-01: 3 +UNIT_2: + 2022-05-01: 2 +UNIT_1: + 2022-05-01: 1 diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/income/countable_income/sources.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/income/countable_income/sources.yaml new file mode 100644 index 00000000000..587f31f087d --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/income/countable_income/sources.yaml @@ -0,0 +1,31 @@ +description: Maryland counts these income sources under the Child Care Scholarship program. +values: + 2022-05-01: + - employment_income + # Note: self_employment_income is handled separately in the formula + # with a 30% deduction per COMAR 13A.14.06.03(F)(8)(a)(i) + - social_security + - pension_income + - interest_income + - dividend_income + - rental_income + - alimony_income + - unemployment_compensation + - workers_compensation + - veterans_benefits + - disability_benefits + - capital_gains + - farm_income + - military_retirement_pay + # NOT included: + # - child_support_received (excluded per Chapters 525/526 of 2022) + +metadata: + unit: list + period: year + label: Maryland CCS countable income sources + reference: + - title: COMAR 13A.14.06.02 - Definition of "Gross income" + href: https://regs.maryland.gov/us/md/exec/comar/13A.14.06.02 + - title: Chapters 525/526 of 2022 + href: https://mgaleg.maryland.gov/2022RS/Chapters_noln/CH_525_hb0275e.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/income/self_employment_deduction_rate.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/income/self_employment_deduction_rate.yaml new file mode 100644 index 00000000000..1204f6afe01 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/income/self_employment_deduction_rate.yaml @@ -0,0 +1,11 @@ +description: Maryland deducts this share of self-employment income for business expenses under the Child Care Scholarship program. +values: + 2018-01-01: 0.3 + +metadata: + unit: /1 + period: year + label: Maryland CCS self-employment deduction rate + reference: + - title: COMAR 13A.14.06.03(F)(8)(a)(i) - Self-Employment Deduction + href: https://regs.maryland.gov/us/md/exec/comar/13A.14.06.03 diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_rate/continuation.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_rate/continuation.yaml new file mode 100644 index 00000000000..97ceccfd3e8 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_rate/continuation.yaml @@ -0,0 +1,15 @@ +description: Maryland limits continuation eligibility for the Child Care Scholarship program to families with income at or below this share of State Median Income. +values: + 2018-01-01: 0.85 + +metadata: + unit: /1 + period: year + label: Maryland CCS continuation eligibility SMI rate + reference: + - title: COMAR 13A.14.06.03(H) - Income Eligibility Scale + href: https://regs.maryland.gov/us/md/exec/comar/13A.14.06.03 + - title: Chapters 525/526 of 2022 + href: https://mgaleg.maryland.gov/2022RS/Chapters_noln/CH_525_hb0275e.pdf#page=1 + - title: 45 CFR 98.21(b) - Federal ceiling + href: https://www.ecfr.gov/current/title-45/section-98.21#p-98.21(b) diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_rate/initial.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_rate/initial.yaml new file mode 100644 index 00000000000..6f36e46c586 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/income/smi_rate/initial.yaml @@ -0,0 +1,15 @@ +description: Maryland limits initial eligibility for the Child Care Scholarship program to families with income at or below this share of State Median Income. +values: + 2018-01-01: 0.5 + 2019-01-01: 0.65 + 2022-05-01: 0.75 + +metadata: + unit: /1 + period: year + label: Maryland CCS initial eligibility SMI rate + reference: + - title: Chapters 595/596 of 2018 + href: https://mgaleg.maryland.gov/2018RS/Chapters_noln/CH_595_hb0377e.pdf#page=1 + - title: Chapters 525/526 of 2022 + href: https://mgaleg.maryland.gov/2022RS/Chapters_noln/CH_525_hb0275e.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/payment/baltimore_city_counties.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/baltimore_city_counties.yaml new file mode 100644 index 00000000000..cb09fb47d74 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/baltimore_city_counties.yaml @@ -0,0 +1,12 @@ +description: Maryland sets Baltimore City as its own region for Child Care Scholarship rate purposes. +values: + 2020-11-23: + - BALTIMORE_CITY_MD + +metadata: + unit: list + period: year + label: Maryland CCS Baltimore City region + reference: + - title: Maryland CCS Scholarship Rates + href: https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/payment/formal/licensed_center.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/formal/licensed_center.yaml new file mode 100644 index 00000000000..aa6b3aeadbd --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/formal/licensed_center.yaml @@ -0,0 +1,119 @@ +description: Maryland provides these weekly reimbursement rates for licensed child care centers under the Child Care Scholarship program. + +metadata: + period: week + unit: currency-USD + label: Maryland CCS licensed center weekly rates + breakdown: + - md_ccs_region + - md_ccs_age_group + - md_ccs_service_unit + reference: + - title: Maryland CCS Scholarship Rates (Formal Rates, 60th Percentile, 2024 Market Rate Survey) + href: https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates + +REGION_U: + REGULAR: + UNIT_3: + 2026-03-01: 244 + UNIT_2: + 2026-03-01: 163 + UNIT_1: + 2026-03-01: 82 + INFANT: + UNIT_3: + 2026-03-01: 325 + UNIT_2: + 2026-03-01: 217 + UNIT_1: + 2026-03-01: 109 +REGION_V: + REGULAR: + UNIT_3: + 2026-03-01: 200 + UNIT_2: + 2026-03-01: 133 + UNIT_1: + 2026-03-01: 67 + INFANT: + UNIT_3: + 2026-03-01: 264 + UNIT_2: + 2026-03-01: 176 + UNIT_1: + 2026-03-01: 88 +REGION_W: + REGULAR: + UNIT_3: + 2026-03-01: 305 + UNIT_2: + 2026-03-01: 204 + UNIT_1: + 2026-03-01: 102 + INFANT: + UNIT_3: + 2026-03-01: 420 + UNIT_2: + 2026-03-01: 280 + UNIT_1: + 2026-03-01: 140 +REGION_X: + REGULAR: + UNIT_3: + 2026-03-01: 424 + UNIT_2: + 2026-03-01: 283 + UNIT_1: + 2026-03-01: 142 + INFANT: + UNIT_3: + 2026-03-01: 554 + UNIT_2: + 2026-03-01: 369 + UNIT_1: + 2026-03-01: 185 +REGION_Y: + REGULAR: + UNIT_3: + 2026-03-01: 278 + UNIT_2: + 2026-03-01: 185 + UNIT_1: + 2026-03-01: 93 + INFANT: + UNIT_3: + 2026-03-01: 378 + UNIT_2: + 2026-03-01: 252 + UNIT_1: + 2026-03-01: 126 +REGION_Z: + REGULAR: + UNIT_3: + 2026-03-01: 207 + UNIT_2: + 2026-03-01: 138 + UNIT_1: + 2026-03-01: 69 + INFANT: + UNIT_3: + 2026-03-01: 297 + UNIT_2: + 2026-03-01: 198 + UNIT_1: + 2026-03-01: 99 +BALTIMORE_CITY: + REGULAR: + UNIT_3: + 2026-03-01: 282 + UNIT_2: + 2026-03-01: 188 + UNIT_1: + 2026-03-01: 94 + INFANT: + UNIT_3: + 2026-03-01: 376 + UNIT_2: + 2026-03-01: 251 + UNIT_1: + 2026-03-01: 126 diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/payment/formal/licensed_family.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/formal/licensed_family.yaml new file mode 100644 index 00000000000..e0ea886e198 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/formal/licensed_family.yaml @@ -0,0 +1,119 @@ +description: Maryland provides these weekly reimbursement rates for licensed family child care homes under the Child Care Scholarship program. + +metadata: + period: week + unit: currency-USD + label: Maryland CCS licensed family weekly rates + breakdown: + - md_ccs_region + - md_ccs_age_group + - md_ccs_service_unit + reference: + - title: Maryland CCS Scholarship Rates (Formal Rates, 60th Percentile, 2024 Market Rate Survey) + href: https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates + +REGION_U: + REGULAR: + UNIT_3: + 2026-03-01: 200 + UNIT_2: + 2026-03-01: 134 + UNIT_1: + 2026-03-01: 67 + INFANT: + UNIT_3: + 2026-03-01: 225 + UNIT_2: + 2026-03-01: 150 + UNIT_1: + 2026-03-01: 75 +REGION_V: + REGULAR: + UNIT_3: + 2026-03-01: 175 + UNIT_2: + 2026-03-01: 117 + UNIT_1: + 2026-03-01: 59 + INFANT: + UNIT_3: + 2026-03-01: 200 + UNIT_2: + 2026-03-01: 134 + UNIT_1: + 2026-03-01: 67 +REGION_W: + REGULAR: + UNIT_3: + 2026-03-01: 265 + UNIT_2: + 2026-03-01: 177 + UNIT_1: + 2026-03-01: 89 + INFANT: + UNIT_3: + 2026-03-01: 300 + UNIT_2: + 2026-03-01: 200 + UNIT_1: + 2026-03-01: 100 +REGION_X: + REGULAR: + UNIT_3: + 2026-03-01: 325 + UNIT_2: + 2026-03-01: 217 + UNIT_1: + 2026-03-01: 109 + INFANT: + UNIT_3: + 2026-03-01: 350 + UNIT_2: + 2026-03-01: 234 + UNIT_1: + 2026-03-01: 117 +REGION_Y: + REGULAR: + UNIT_3: + 2026-03-01: 220 + UNIT_2: + 2026-03-01: 147 + UNIT_1: + 2026-03-01: 73 + INFANT: + UNIT_3: + 2026-03-01: 250 + UNIT_2: + 2026-03-01: 167 + UNIT_1: + 2026-03-01: 83 +REGION_Z: + REGULAR: + UNIT_3: + 2026-03-01: 170 + UNIT_2: + 2026-03-01: 114 + UNIT_1: + 2026-03-01: 57 + INFANT: + UNIT_3: + 2026-03-01: 185 + UNIT_2: + 2026-03-01: 124 + UNIT_1: + 2026-03-01: 62 +BALTIMORE_CITY: + REGULAR: + UNIT_3: + 2026-03-01: 225 + UNIT_2: + 2026-03-01: 150 + UNIT_1: + 2026-03-01: 75 + INFANT: + UNIT_3: + 2026-03-01: 252 + UNIT_2: + 2026-03-01: 168 + UNIT_1: + 2026-03-01: 84 diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/payment/infant_age_threshold.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/infant_age_threshold.yaml new file mode 100644 index 00000000000..cd45ea9efe8 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/infant_age_threshold.yaml @@ -0,0 +1,13 @@ +description: Maryland defines infants as children under this age in months for Child Care Scholarship rate purposes. +values: + 2020-11-23: 24 + +metadata: + unit: month + period: year + label: Maryland CCS infant age threshold in months + reference: + - title: Maryland CCS Scholarship Rates + href: https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates + - title: COMAR 13A.14.06.02 - Definitions + href: https://regs.maryland.gov/us/md/exec/comar/13A.14.06.02 diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/payment/informal/rates.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/informal/rates.yaml new file mode 100644 index 00000000000..e0bc3b53a0d --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/informal/rates.yaml @@ -0,0 +1,370 @@ +description: Maryland provides these weekly reimbursement rates for informal child care providers under the Child Care Scholarship program. + +metadata: + period: week + unit: currency-USD + label: Maryland CCS informal provider weekly rates + reference: + - title: Maryland CCS Scholarship Rates (Informal Rates, 70th Percentile, March 2021 Market Rate Survey) + href: https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates + +ALLEGANY_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 83 + UNIT_2: + 2020-11-23: 55 + UNIT_1: + 2020-11-23: 28 + INFANT: + UNIT_3: + 2020-11-23: 90 + UNIT_2: + 2020-11-23: 60 + UNIT_1: + 2020-11-23: 30 +ANNE_ARUNDEL_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 135 + UNIT_2: + 2020-11-23: 90 + UNIT_1: + 2020-11-23: 45 + INFANT: + UNIT_3: + 2020-11-23: 150 + UNIT_2: + 2020-11-23: 100 + UNIT_1: + 2020-11-23: 50 +BALTIMORE_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 125 + UNIT_2: + 2020-11-23: 83 + UNIT_1: + 2020-11-23: 42 + INFANT: + UNIT_3: + 2020-11-23: 150 + UNIT_2: + 2020-11-23: 100 + UNIT_1: + 2020-11-23: 50 +CALVERT_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 135 + UNIT_2: + 2020-11-23: 90 + UNIT_1: + 2020-11-23: 45 + INFANT: + UNIT_3: + 2020-11-23: 150 + UNIT_2: + 2020-11-23: 100 + UNIT_1: + 2020-11-23: 50 +CAROLINE_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 84 + UNIT_2: + 2020-11-23: 56 + UNIT_1: + 2020-11-23: 28 + INFANT: + UNIT_3: + 2020-11-23: 100 + UNIT_2: + 2020-11-23: 67 + UNIT_1: + 2020-11-23: 33 +CARROLL_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 135 + UNIT_2: + 2020-11-23: 90 + UNIT_1: + 2020-11-23: 45 + INFANT: + UNIT_3: + 2020-11-23: 150 + UNIT_2: + 2020-11-23: 100 + UNIT_1: + 2020-11-23: 50 +CECIL_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 105 + UNIT_2: + 2020-11-23: 70 + UNIT_1: + 2020-11-23: 35 + INFANT: + UNIT_3: + 2020-11-23: 120 + UNIT_2: + 2020-11-23: 80 + UNIT_1: + 2020-11-23: 40 +CHARLES_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 135 + UNIT_2: + 2020-11-23: 90 + UNIT_1: + 2020-11-23: 45 + INFANT: + UNIT_3: + 2020-11-23: 150 + UNIT_2: + 2020-11-23: 100 + UNIT_1: + 2020-11-23: 50 +DORCHESTER_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 84 + UNIT_2: + 2020-11-23: 56 + UNIT_1: + 2020-11-23: 28 + INFANT: + UNIT_3: + 2020-11-23: 100 + UNIT_2: + 2020-11-23: 67 + UNIT_1: + 2020-11-23: 33 +FREDERICK_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 125 + UNIT_2: + 2020-11-23: 83 + UNIT_1: + 2020-11-23: 42 + INFANT: + UNIT_3: + 2020-11-23: 150 + UNIT_2: + 2020-11-23: 100 + UNIT_1: + 2020-11-23: 50 +GARRETT_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 83 + UNIT_2: + 2020-11-23: 55 + UNIT_1: + 2020-11-23: 28 + INFANT: + UNIT_3: + 2020-11-23: 90 + UNIT_2: + 2020-11-23: 60 + UNIT_1: + 2020-11-23: 30 +HARFORD_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 125 + UNIT_2: + 2020-11-23: 83 + UNIT_1: + 2020-11-23: 42 + INFANT: + UNIT_3: + 2020-11-23: 150 + UNIT_2: + 2020-11-23: 100 + UNIT_1: + 2020-11-23: 50 +HOWARD_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 177 + UNIT_2: + 2020-11-23: 118 + UNIT_1: + 2020-11-23: 59 + INFANT: + UNIT_3: + 2020-11-23: 195 + UNIT_2: + 2020-11-23: 130 + UNIT_1: + 2020-11-23: 65 +KENT_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 84 + UNIT_2: + 2020-11-23: 56 + UNIT_1: + 2020-11-23: 28 + INFANT: + UNIT_3: + 2020-11-23: 100 + UNIT_2: + 2020-11-23: 67 + UNIT_1: + 2020-11-23: 33 +MONTGOMERY_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 177 + UNIT_2: + 2020-11-23: 118 + UNIT_1: + 2020-11-23: 59 + INFANT: + UNIT_3: + 2020-11-23: 195 + UNIT_2: + 2020-11-23: 130 + UNIT_1: + 2020-11-23: 65 +PRINCE_GEORGE_S_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 135 + UNIT_2: + 2020-11-23: 90 + UNIT_1: + 2020-11-23: 45 + INFANT: + UNIT_3: + 2020-11-23: 150 + UNIT_2: + 2020-11-23: 100 + UNIT_1: + 2020-11-23: 50 +QUEEN_ANNE_S_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 105 + UNIT_2: + 2020-11-23: 70 + UNIT_1: + 2020-11-23: 35 + INFANT: + UNIT_3: + 2020-11-23: 120 + UNIT_2: + 2020-11-23: 80 + UNIT_1: + 2020-11-23: 40 +ST_MARY_S_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 105 + UNIT_2: + 2020-11-23: 70 + UNIT_1: + 2020-11-23: 35 + INFANT: + UNIT_3: + 2020-11-23: 120 + UNIT_2: + 2020-11-23: 80 + UNIT_1: + 2020-11-23: 40 +SOMERSET_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 84 + UNIT_2: + 2020-11-23: 56 + UNIT_1: + 2020-11-23: 28 + INFANT: + UNIT_3: + 2020-11-23: 100 + UNIT_2: + 2020-11-23: 67 + UNIT_1: + 2020-11-23: 33 +TALBOT_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 105 + UNIT_2: + 2020-11-23: 70 + UNIT_1: + 2020-11-23: 35 + INFANT: + UNIT_3: + 2020-11-23: 120 + UNIT_2: + 2020-11-23: 80 + UNIT_1: + 2020-11-23: 40 +WASHINGTON_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 105 + UNIT_2: + 2020-11-23: 70 + UNIT_1: + 2020-11-23: 35 + INFANT: + UNIT_3: + 2020-11-23: 120 + UNIT_2: + 2020-11-23: 80 + UNIT_1: + 2020-11-23: 40 +WICOMICO_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 84 + UNIT_2: + 2020-11-23: 56 + UNIT_1: + 2020-11-23: 28 + INFANT: + UNIT_3: + 2020-11-23: 100 + UNIT_2: + 2020-11-23: 67 + UNIT_1: + 2020-11-23: 33 +WORCESTER_COUNTY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 83 + UNIT_2: + 2020-11-23: 55 + UNIT_1: + 2020-11-23: 28 + INFANT: + UNIT_3: + 2020-11-23: 90 + UNIT_2: + 2020-11-23: 60 + UNIT_1: + 2020-11-23: 30 +BALTIMORE_CITY_MD: + REGULAR: + UNIT_3: + 2020-11-23: 106 + UNIT_2: + 2020-11-23: 71 + UNIT_1: + 2020-11-23: 35 + INFANT: + UNIT_3: + 2020-11-23: 120 + UNIT_2: + 2020-11-23: 80 + UNIT_1: + 2020-11-23: 40 diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_u_counties.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_u_counties.yaml new file mode 100644 index 00000000000..6aaca3f2c63 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_u_counties.yaml @@ -0,0 +1,16 @@ +description: Maryland sets these counties as Region U for Child Care Scholarship rate purposes. +values: + 2020-11-23: + - CECIL_COUNTY_MD + - QUEEN_ANNE_S_COUNTY_MD + - ST_MARY_S_COUNTY_MD + - TALBOT_COUNTY_MD + - WASHINGTON_COUNTY_MD + +metadata: + unit: list + period: year + label: Maryland CCS Region U counties + reference: + - title: Maryland CCS Scholarship Rates + href: https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_v_counties.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_v_counties.yaml new file mode 100644 index 00000000000..5cf99beec1e --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_v_counties.yaml @@ -0,0 +1,16 @@ +description: Maryland sets these counties as Region V for Child Care Scholarship rate purposes. +values: + 2020-11-23: + - CAROLINE_COUNTY_MD + - DORCHESTER_COUNTY_MD + - KENT_COUNTY_MD + - SOMERSET_COUNTY_MD + - WICOMICO_COUNTY_MD + +metadata: + unit: list + period: year + label: Maryland CCS Region V counties + reference: + - title: Maryland CCS Scholarship Rates + href: https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_w_counties.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_w_counties.yaml new file mode 100644 index 00000000000..4d1b9a0d9c7 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_w_counties.yaml @@ -0,0 +1,16 @@ +description: Maryland sets these counties as Region W for Child Care Scholarship rate purposes. +values: + 2020-11-23: + - ANNE_ARUNDEL_COUNTY_MD + - CALVERT_COUNTY_MD + - CARROLL_COUNTY_MD + - CHARLES_COUNTY_MD + - PRINCE_GEORGE_S_COUNTY_MD + +metadata: + unit: list + period: year + label: Maryland CCS Region W counties + reference: + - title: Maryland CCS Scholarship Rates + href: https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_x_counties.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_x_counties.yaml new file mode 100644 index 00000000000..0cc357c3df6 --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_x_counties.yaml @@ -0,0 +1,13 @@ +description: Maryland sets these counties as Region X for Child Care Scholarship rate purposes. +values: + 2020-11-23: + - HOWARD_COUNTY_MD + - MONTGOMERY_COUNTY_MD + +metadata: + unit: list + period: year + label: Maryland CCS Region X counties + reference: + - title: Maryland CCS Scholarship Rates + href: https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_y_counties.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_y_counties.yaml new file mode 100644 index 00000000000..1ae3f1de0af --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_y_counties.yaml @@ -0,0 +1,14 @@ +description: Maryland sets these counties as Region Y for Child Care Scholarship rate purposes. +values: + 2020-11-23: + - BALTIMORE_COUNTY_MD + - FREDERICK_COUNTY_MD + - HARFORD_COUNTY_MD + +metadata: + unit: list + period: year + label: Maryland CCS Region Y counties + reference: + - title: Maryland CCS Scholarship Rates + href: https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates diff --git a/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_z_counties.yaml b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_z_counties.yaml new file mode 100644 index 00000000000..99055a52bac --- /dev/null +++ b/policyengine_us/parameters/gov/states/md/msde/ccs/payment/region_z_counties.yaml @@ -0,0 +1,14 @@ +description: Maryland sets these counties as Region Z for Child Care Scholarship rate purposes. +values: + 2020-11-23: + - ALLEGANY_COUNTY_MD + - GARRETT_COUNTY_MD + - WORCESTER_COUNTY_MD + +metadata: + unit: list + period: year + label: Maryland CCS Region Z counties + reference: + - title: Maryland CCS Scholarship Rates + href: https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 32409746ae5..1e4f6a435dd 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -421,7 +421,7 @@ programs: category: Benefits agency: HHS status: partial - coverage: CA, CO, IL, MA, DC, NC, TX + coverage: CA, CO, DC, IL, MA, MD, NC, TX state_implementations: - state: CA status: complete @@ -444,6 +444,11 @@ programs: status: complete name: Massachusetts CCFA full_name: Massachusetts Child Care Financial Assistance + - state: MD + status: complete + name: Maryland CCS + full_name: Maryland Child Care Scholarship + variable: md_child_care_subsidies - state: DC status: complete name: DC CCSP diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/edge_cases.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/edge_cases.yaml new file mode 100644 index 00000000000..d3ef27886d3 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/edge_cases.yaml @@ -0,0 +1,1236 @@ +# Maryland CCS Edge Case Tests +# Tests boundary conditions for eligibility, copayment, and benefit calculations. +# FY2025 MD SMI base: $149,249 +# +# SMI by family size: +# Fam 1: 149,249 * 0.52 = 77,609.48 +# Fam 2: 149,249 * 0.68 = 101,489.32 +# Fam 7: 149,249 * (0.52 + 0.16*5 + 0.03) = 149,249 * 1.35 = 201,486.15 +# Fam 8: 149,249 * (0.52 + 0.16*5 + 0.03*2) = 149,249 * 1.38 = 205,963.62 +# +# 75% SMI (initial): Fam 1 = 58,207.11, Fam 2 = 76,116.99 +# 85% SMI (continuation): Fam 2 = 86,265.92 + +# === Income threshold boundary: 75% SMI === + +- name: Case 1, income just below 75 percent SMI threshold for family of 2. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + # 75% SMI for fam 2 ~ 76,116.99 annually + # Use 76,116 to stay just below threshold (avoids float precision) + employment_income: 76_116 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # monthly countable: 76,116 / 12 = 6,343.00 + # monthly 75% SMI: ~6,343.08 + # 6,343.00 <= 6,343.08 -> eligible + md_ccs_income_eligible: true + +- name: Case 2, income one dollar above 75 percent SMI threshold for family of 2. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 76_118 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # monthly countable: 76,118 / 12 = 6,343.17 + # monthly 75% SMI: 6,343.08 + # 6,343.17 > 6,343.08 -> not eligible + md_ccs_income_eligible: false + +# === Income threshold boundary: 85% SMI (continuation) === + +- name: Case 3, enrolled family income just below 85 percent SMI threshold. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + # 85% SMI for fam 2 ~ 86,265.92 annually + # Use 86,265 to stay just below threshold (avoids float precision) + employment_income: 86_265 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + md_ccs_enrolled: true + households: + household: + members: [person1, person2] + state_code: MD + output: + # monthly countable: 86,265 / 12 = 7,188.75 + # monthly 85% SMI: ~7,188.83 + # 7,188.75 <= 7,188.83 -> eligible + md_ccs_income_eligible: true + +- name: Case 4, enrolled family income one dollar above 85 percent SMI threshold. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 86_267 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + md_ccs_enrolled: true + households: + household: + members: [person1, person2] + state_code: MD + output: + # monthly countable: 86,267 / 12 = 7,188.92 + # monthly 85% SMI: 7,188.83 + # 7,188.92 > 7,188.83 -> not eligible + md_ccs_income_eligible: false + +# === Enrolled between 75-85% SMI: initial vs continuation === + +- name: Case 5, not enrolled with income between 75 and 85 percent SMI is not eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + # 80,000 is between 75% SMI (76,117) and 85% SMI (86,266) for fam 2 + employment_income: 80_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + md_ccs_enrolled: false + households: + household: + members: [person1, person2] + state_code: MD + output: + # Not enrolled -> initial threshold (75% SMI) + # monthly countable: 80,000 / 12 = 6,666.67 + # monthly 75% SMI: 6,343.08 + # 6,666.67 > 6,343.08 -> not eligible + md_ccs_income_eligible: false + +- name: Case 6, enrolled with income between 75 and 85 percent SMI is eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 80_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + md_ccs_enrolled: true + households: + household: + members: [person1, person2] + state_code: MD + output: + # Enrolled -> continuation threshold (85% SMI) + # monthly countable: 80,000 / 12 = 6,666.67 + # monthly 85% SMI: 7,188.83 + # 6,666.67 <= 7,188.83 -> eligible + md_ccs_income_eligible: true + +# === Zero income === + +- name: Case 7, zero income family is income eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 0 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # 0 <= 75% SMI -> eligible + md_ccs_income_eligible: true + +# === Very high income === + +- name: Case 8, very high income family is not income eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 500_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # 500,000/12 = 41,666.67 >> 75% SMI -> not eligible + md_ccs_income_eligible: false + +# === Family size: minimum (1 person, adult only) === + +- name: Case 9, single adult with no children has no eligible child. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 30_000 + is_tax_unit_head_or_spouse: true + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MD + output: + md_ccs_eligible_child: [false] + md_ccs_eligible: false + +# === Family size: large (8 people, 6 children) === + +- name: Case 10, large family of 8 with 6 children. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 120_000 + is_tax_unit_head_or_spouse: true + person2: + age: 38 + is_tax_unit_head_or_spouse: true + person3: + age: 12 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person4: + age: 10 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person5: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person6: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person7: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 4 + person8: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: MD + output: + # All 6 children under 13 -> all eligible + md_ccs_eligible_child: [false, false, true, true, true, true, true, true] + + # hhs_smi for fam 8 = 149,249 * (0.52 + 0.16*5 + 0.03*2) = 149,249 * 1.38 = 205,963.62 + # monthly 75% SMI = 205,963.62 * 0.75 / 12 = 12,872.73 + # monthly countable: 120,000 / 12 = 10,000 + # 10,000 <= 12,872.73 -> eligible + md_ccs_income_eligible: true + +# === Self-employment income edge cases === + +- name: Case 11, family with 100 percent self-employment income. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + self_employment_income: 60_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # self_employment_income: 60,000 * (1 - 0.30) = 42,000 + # monthly: 42,000 / 12 = 3,500 + md_ccs_countable_income: 3_500 + +- name: Case 12, family with zero self-employment income. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + self_employment_income: 0 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # employment: 50,000, self_employment: 0 * 0.70 = 0 + # monthly: 50,000 / 12 = 4,166.67 + md_ccs_countable_income: 4_166.67 + +# === Age boundary: child exactly age 13 (non-disabled) === + +- name: Case 13, child exactly age 13 not disabled is not eligible. + period: 2025-01 + input: + people: + person1: + age: 40 + is_tax_unit_head_or_spouse: true + person2: + age: 13 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # age 13, threshold is < 13 -> not eligible + md_ccs_eligible_child: [false, false] + +# === Age boundary: disabled child exactly age 18 === + +- name: Case 14, disabled child exactly age 18 is eligible. + period: 2025-01 + input: + people: + person1: + age: 45 + is_tax_unit_head_or_spouse: true + person2: + age: 18 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # age 18 < 19 (disabled threshold) -> eligible + md_ccs_eligible_child: [false, true] + +# === Age boundary: disabled child exactly age 19 === + +- name: Case 15, disabled child exactly age 19 is not eligible. + period: 2025-01 + input: + people: + person1: + age: 45 + is_tax_unit_head_or_spouse: true + person2: + age: 19 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # age 19, threshold is < 19 -> not eligible + md_ccs_eligible_child: [false, false] + +# === Multiple children copay scaling === + +- name: Case 16, one child copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # 1 child, full-time -> $3/week + # capped_count = min(1, 3) = 1 + # scale = 1/1 = 1 + # total = $3 * 1 = $3/week + md_ccs_weekly_copay: 3 + +- name: Case 17, two children copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person3: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: MD + output: + # 2 children, each full-time -> $3 + $3 = $6/week + # capped_count = min(2, 3) = 2, scale = 2/2 = 1 + # total = $6/week + md_ccs_weekly_copay: 6 + +- name: Case 18, three children copay at max. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 10 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person3: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person4: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: MD + output: + # 3 children, each full-time -> $3*3 = $9/week + # capped_count = min(3, 3) = 3, scale = 3/3 = 1 + # total = $9/week + md_ccs_weekly_copay: 9 + +- name: Case 19, four children copay capped at 3 children. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 10 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person3: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person4: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person5: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2, person3, person4, person5] + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: MD + output: + # 4 eligible children, each full-time -> raw total = $3*4 = $12/week + # capped_count = min(4, 3) = 3, scale = 3/4 = 0.75 + # scaled total = $12 * 0.75 = $9/week + md_ccs_weekly_copay: 9 + +- name: Case 20, five children copay capped at 3 children. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 11 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person3: + age: 9 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person4: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person5: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person6: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2, person3, person4, person5, person6] + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6] + households: + household: + members: [person1, person2, person3, person4, person5, person6] + state_code: MD + output: + # 5 eligible children, each full-time -> raw total = $3*5 = $15/week + # capped_count = min(5, 3) = 3, scale = 3/5 = 0.6 + # scaled total = $15 * 0.6 = $9/week + md_ccs_weekly_copay: 9 + +# === Copay federal cap edge cases === + +- name: Case 21, copay exactly at 7 percent federal cap. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + # Target: 7% of weekly income = $3/week (full-time copay) + # weekly income = $3 / 0.07 = $42.86/week + # annual = $42.86 * 52 = $2,228.57 + # Need income where 7% cap = $3/week exactly + employment_income: 2_229 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # monthly countable = 2,229 / 12 = 185.75 + # weekly income = 185.75 * 12 / 52 = 42.87 + # 7% cap = 42.87 * 0.07 = 3.00 + # raw copay = $3/week (full-time) + # min($3, $3.00) = $3 -> cap does not reduce copay + md_ccs_weekly_copay: 3 + +- name: Case 22, copay below 7 percent federal cap with very low income. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 1_200 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # monthly countable = 1,200 / 12 = 100 + # weekly income = 100 * 12 / 52 = 23.08 + # 7% cap = 23.08 * 0.07 = 1.62 + # raw copay = $3/week (full-time, 8 hrs) + # min($3, $1.62) = $1.62 -> cap applies + md_ccs_weekly_copay: 1.62 + +- name: Case 23, zero income results in zero copay via federal cap. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 0 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # weekly income = 0 + # 7% cap = 0 * 0.07 = 0 + # min($3, $0) = $0 + md_ccs_weekly_copay: 0 + +# === Zero childcare expenses === + +- name: Case 24, zero childcare expenses results in zero benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 0 + households: + household: + members: [person1, person2] + state_code: MD + output: + # expenses = 0, copay = $3 * 52 / 12 = $13/month + # benefit = max(0 - 13, 0) = 0 + md_ccs: 0 + +# === Expenses less than copay === + +- name: Case 25, expenses less than copay results in zero benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 100 + households: + household: + members: [person1, person2] + state_code: MD + output: + # annual copay = $3 * 52 = $156 + # annual expenses = $100 + # benefit = max(100 - 156, 0) = 0 (floored at 0) + md_ccs: 0 + +# === Service unit boundary: hours per day === + +- name: Case 26, childcare exactly 3 hours per day gets hourly rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 3 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # 3 hrs/day: bracket threshold 0->1 unit, next at 3.0001 + # 3 < 3.0001 -> 1 unit (hourly) -> $1/week + md_ccs_weekly_copay: 1 + +- name: Case 27, childcare 3.5 hours per day gets part-time rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 3.5 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # 3.5 hrs/day >= 3.0001 -> 2 units (part-time) -> $2/week + md_ccs_weekly_copay: 2 + +- name: Case 28, childcare exactly 6 hours per day gets full-time rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 6 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # 6 hrs/day >= 6 -> 3 units (full-time) -> $3/week + md_ccs_weekly_copay: 3 + +- name: Case 29, childcare 5.99 hours per day gets part-time rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 5.99 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # 5.99 hrs/day < 6 -> 2 units (part-time) -> $2/week + md_ccs_weekly_copay: 2 + +# === Mixed service units across children === + +- name: Case 30, two children with different service levels. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 8 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person3: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 2 + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: MD + output: + # person2: 8 hrs -> 3 units -> $3/week + # person3: 2 hrs -> 1 unit -> $1/week + # total: $3 + $1 = $4/week + md_ccs_weekly_copay: 4 + +# === Immigration ineligible child === + +- name: Case 31, undocumented child is not eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 30_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: UNDOCUMENTED + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # CCDF immigration check fails for undocumented children + md_ccs_eligible_child: [false, false] + md_ccs_eligible: false + +# === Non-dependent child === + +- name: Case 32, non-dependent child under 13 is not eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: false + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # Not a dependent -> not eligible child + md_ccs_eligible_child: [false, false] + +# === TCA exemption with very high income === + +- name: Case 33, TCA recipient eligible despite income far above 85 percent SMI. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 300_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + is_tanf_enrolled: true + households: + household: + members: [person1, person2] + state_code: MD + output: + # TCA -> income test waived regardless of how high income is + md_ccs_eligible: true + +# === SSI exemption with very high income === + +- name: Case 34, SSI recipient eligible despite income far above 85 percent SMI. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 300_000 + ssi: 9_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # SSI recipient (ssi > 0) -> income test waived + md_ccs_eligible: true + +# === Federal cap with multiple children === + +- name: Case 35, federal 7 percent cap applies with three children. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 3_600 + is_tax_unit_head_or_spouse: true + person2: + age: 10 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person3: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person4: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: MD + output: + # 3 children, each full-time -> raw = $3 * 3 = $9/week + # capped_count = min(3, 3) = 3, scale = 1 + # monthly countable = 3,600 / 12 = 300 + # weekly income = 300 * 12 / 52 = 69.23 + # 7% cap = 69.23 * 0.07 = 4.85 + # min($9, $4.85) = $4.85 -> cap applies + md_ccs_weekly_copay: 4.85 + +# === Zero childcare hours === + +- name: Case 36, zero childcare hours per day gets hourly rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 0 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # 0 hrs/day -> 1 unit (hourly) -> $1/week + md_ccs_weekly_copay: 1 + +# === Benefit floor at zero: copay exceeds expenses === + +- name: Case 37, negative countable income from self-employment does not inflate benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + self_employment_income: -60_000_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + is_tanf_enrolled: true + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2] + state_code: MD + output: + # TCA -> copay exempt -> $0 copay + # benefit = max(10,000 - 0, 0) = 10,000 + # monthly: 10,000 / 12 = 833.33 + # Negative self-employment income does not inflate benefit (benefit formula + # uses expenses - copay, not income-based formula) + md_ccs: 833.33 diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/integration.yaml new file mode 100644 index 00000000000..d8f0050bf2b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/integration.yaml @@ -0,0 +1,424 @@ +# Maryland CCS Integration Tests +# FY2025 SMI base for MD (from 2024-10-01): $149,249 +# Family of 2: hhs_smi = 149,249 * 0.68 = 101,489.32 +# Family of 3: hhs_smi = 149,249 * 0.84 = 125,369.16 +# Family of 4: hhs_smi = 149,249 * 1.00 = 149,249 +# +# 75% SMI (initial): fam 2 = 76,116.99, fam 4 = 111,936.75 +# 85% SMI (continuation): fam 2 = 86,265.92, fam 4 = 126,861.65 + +- name: Case 1, single parent with one child age 3 and full-time care. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 12_000 + households: + household: + members: [person1, person2] + state_code: MD + output: + # === Child eligibility === + # person1: adult, not dependent -> false + # person2: age 3 < 13, dependent, citizen -> true + md_ccs_eligible_child: [false, true] + + # === Income === + # employment_income: 50,000 + # monthly countable: 50,000 / 12 = 4,166.67 + md_ccs_countable_income: 4_166.67 + + # === Income eligibility === + # hhs_smi for fam 2 = 101,489.32 annual + # monthly 75% SMI = 101,489.32 * 0.75 / 12 = 6,343.08 + # 4,166.67 <= 6,343.08 -> eligible + md_ccs_income_eligible: true + + # === Overall eligibility === + md_ccs_eligible: true + + # === Copay === + # 8 hrs/day >= 6 -> 3 units (full-time) -> $3/week + # Not TCA/SSI/SNAP/WIC -> standard copay + md_ccs_weekly_copay: 3 + + # === Benefit === + # Default county: Allegany = Region Z, REGULAR, UNIT_3 -> $207/week + # annual max reimbursement: $207 * 52 = $10,764 + # annual copay: $3 * 52 = $156 + # uncapped: max(12,000 - 156, 0) = 11,844 + # capped: min(11,844, 10,764) = 10,764 + # monthly: 10,764 / 12 = 897 + md_ccs: 897 + +- name: Case 2, two-parent family with two children and mixed income. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 60_000 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + person2: + age: 33 + self_employment_income: 20_000 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + person3: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person4: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 4 + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + spm_unit_pre_subsidy_childcare_expenses: 18_000 + households: + household: + members: [person1, person2, person3, person4] + state_code: MD + output: + # === Child eligibility === + # person1: adult -> false + # person2: adult -> false + # person3: age 7 < 13, dependent, citizen -> true + # person4: age 3 < 13, dependent, citizen -> true + md_ccs_eligible_child: [false, false, true, true] + + # === Income === + # employment: 60,000 + # self_employment: 20,000 * (1 - 0.30) = 14,000 + # total annual: 60,000 + 14,000 = 74,000 + # monthly countable: 74,000 / 12 = 6,166.67 + md_ccs_countable_income: 6_166.67 + + # === Income eligibility === + # hhs_smi for fam 4 = 149,249 + # monthly 75% SMI = 149,249 * 0.75 / 12 = 9,328.06 + # 6,166.67 <= 9,328.06 -> eligible + md_ccs_income_eligible: true + + md_ccs_eligible: true + + # === Copay === + # person3: 8 hrs/day >= 6 -> 3 units -> $3/week + # person4: 4 hrs/day, >3 and <6 -> 2 units -> $2/week + # total weekly copay: $3 + $2 = $5 + md_ccs_weekly_copay: 5 + + # === Benefit === + # annual copay: $5 * 52 = $260 + # annual benefit: max(18,000 - 260, 0) = 17,740 + # monthly: 17,740 / 12 = 1_478.33 + md_ccs: 1_478.33 + +- name: Case 3, TCA recipient family with zero copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 25 + employment_income: 15_000 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + is_tanf_enrolled: true + spm_unit_pre_subsidy_childcare_expenses: 8_000 + households: + household: + members: [person1, person2] + state_code: MD + output: + # === Child eligibility === + md_ccs_eligible_child: [false, true] + + # === Income === + # monthly: 15,000 / 12 = 1,250 + md_ccs_countable_income: 1_250 + + # === Eligibility === + # TCA -> income test waived + md_ccs_income_eligible: true + md_ccs_eligible: true + + # === Copay === + # TCA recipient -> $0 + md_ccs_weekly_copay: 0 + + # === Benefit === + # annual: max(8,000 - 0, 0) = 8,000 + # monthly: 8,000 / 12 = 666.67 + md_ccs: 666.67 + +- name: Case 4, family at income boundary just below 75 percent SMI. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 100_000 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + person2: + age: 33 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + person3: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person4: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + spm_unit_pre_subsidy_childcare_expenses: 20_000 + households: + household: + members: [person1, person2, person3, person4] + state_code: MD + output: + # === Child eligibility === + md_ccs_eligible_child: [false, false, true, true] + + # === Income === + # monthly countable: 100,000 / 12 = 8,333.33 + md_ccs_countable_income: 8_333.33 + + # === Income eligibility === + # hhs_smi fam 4 = 149,249 + # monthly 75% SMI = 149,249 * 0.75 / 12 = 9,328.06 + # 8,333.33 <= 9,328.06 -> eligible + md_ccs_income_eligible: true + + md_ccs_eligible: true + + # === Copay === + # 2 children, each full-time (8 hrs >= 6) -> $3 + $3 = $6/week + md_ccs_weekly_copay: 6 + + # === Benefit === + # annual copay: $6 * 52 = $312 + # annual benefit: max(20,000 - 312, 0) = 19,688 + # monthly: 19,688 / 12 = 1_640.67 + md_ccs: 1_640.67 + +- name: Case 5, enrolled family between 75 and 85 percent SMI with continuation eligibility. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 120_000 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + person2: + age: 33 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + person3: + age: 6 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person4: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + md_ccs_enrolled: true + spm_unit_pre_subsidy_childcare_expenses: 22_000 + households: + household: + members: [person1, person2, person3, person4] + state_code: MD + output: + # === Child eligibility === + md_ccs_eligible_child: [false, false, true, true] + + # === Income === + # monthly: 120,000 / 12 = 10,000 + md_ccs_countable_income: 10_000 + + # === Income eligibility === + # monthly 75% SMI = 9,328.06 -> 10,000 > 9,328.06 (would fail initial) + # enrolled -> use 85% SMI = 149,249 * 0.85 / 12 = 10,571.81 + # 10,000 <= 10,571.81 -> eligible (continuation) + md_ccs_income_eligible: true + + md_ccs_eligible: true + + # === Copay === + # 2 children, each full-time -> $3 + $3 = $6/week + md_ccs_weekly_copay: 6 + + # === Benefit === + # Default county: Allegany = Region Z + # person3 (age 6): REGULAR, UNIT_3 -> $207/week + # person4 (age 2 = 24 months, not < 24): REGULAR, UNIT_3 -> $207/week + # annual max reimbursement: ($207 + $207) * 52 = $21,528 + # annual copay: $6 * 52 = $312 + # uncapped: max(22,000 - 312, 0) = 21,688 + # capped: min(21,688, 21,528) = 21,528 + # monthly: 21,528 / 12 = 1,794 + md_ccs: 1_794 + +- name: Case 6, SSI recipient with disabled teenager. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + employment_income: 200_000 + ssi: 9_000 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + person2: + age: 16 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 6 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 15_000 + households: + household: + members: [person1, person2] + state_code: MD + output: + # === Child eligibility === + # person2: age 16 < 19 (disabled threshold), disabled, dependent -> true + md_ccs_eligible_child: [false, true] + + # === Income === + # sources list does NOT include ssi (only employment_income counts here) + # employment_income: 200,000 / 12 = 16,666.67 + md_ccs_countable_income: 16_666.67 + + # === Eligibility === + # income $16,666.67/month > 75% SMI for fam 2 ($6,343.08) -> income test fails + md_ccs_income_eligible: false + # BUT SSI recipient (ssi > 0) -> overall eligibility via SSI bypass + md_ccs_eligible: true + + # === Copay === + # SSI recipient -> $0 + md_ccs_weekly_copay: 0 + + # === Benefit === + # Default county: Allegany = Region Z, REGULAR, UNIT_3 -> $207/week + # annual max reimbursement: $207 * 52 = $10,764 + # uncapped: max(15,000 - 0, 0) = 15,000 + # capped: min(15,000, 10,764) = 10,764 + # monthly: 10,764 / 12 = 897 + md_ccs: 897 + +- name: Case 7, family with income above 85 percent SMI is not eligible even when enrolled. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 140_000 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + person2: + age: 33 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + person3: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + person4: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + md_ccs_enrolled: true + spm_unit_pre_subsidy_childcare_expenses: 20_000 + households: + household: + members: [person1, person2, person3, person4] + state_code: MD + output: + # === Child eligibility === + md_ccs_eligible_child: [false, false, true, true] + + # === Income === + # monthly: 140,000 / 12 = 11,666.67 + md_ccs_countable_income: 11_666.67 + + # === Income eligibility === + # enrolled -> use 85% SMI = 149,249 * 0.85 / 12 = 10,571.81 + # 11,666.67 > 10,571.81 -> not eligible + md_ccs_income_eligible: false + + md_ccs_eligible: false + md_ccs: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs.yaml new file mode 100644 index 00000000000..fcf5b997754 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs.yaml @@ -0,0 +1,176 @@ +# Tests for md_ccs (main benefit variable) +# Benefit = min(max(expenses - annual_copay, 0), max_reimbursement) / 12 +# COMAR 13A.14.06.11 + +- name: Case 1, eligible family with expenses under rate cap. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 12_000 + households: + household: + members: [person1, person2] + state_code: MD + output: + # Default provider: LICENSED_CENTER, default county: Allegany = Region Z + # age 5 = REGULAR, 8hrs = UNIT_3 + # weekly rate: $207, annual max reimbursement: $207 * 52 = $10,764 + # weekly copay: $3, annual copay: $3 * 52 = $156 + # uncapped: max(12,000 - 156, 0) = 11,844 + # capped: min(11,844, 10,764) = 10,764 + # monthly: 10,764 / 12 = 897 + md_ccs: 897 + +- name: Case 2, ineligible family gets zero benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 15 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 12_000 + households: + household: + members: [person1, person2] + state_code: MD + output: + # child age 15 >= 13, not disabled -> no eligible child -> not eligible + md_ccs: 0 + +- name: Case 3, TCA family with zero copay gets full benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + is_tanf_enrolled: true + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2] + state_code: MD + output: + # TCA: copay $0 + # weekly rate: $207 (default center, Allegany = Region Z, regular, unit 3) + # annual max reimbursement: $207 * 52 = $10,764 + # uncapped: max(10,000 - 0, 0) = 10,000 + # capped: min(10,000, 10,764) = 10,000 + # monthly: 10,000 / 12 = 833.33 + md_ccs: 833.33 + +- name: Case 4, benefit capped at max reimbursement rate. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 40_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 4 + md_ccs_provider_type: LICENSED_FAMILY + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 20_000 + households: + household: + members: [person1, person2] + state_code: MD + county: ALLEGANY_COUNTY_MD + output: + # Provider: LICENSED_FAMILY, Region Z (Allegany), REGULAR (age 5), UNIT_2 (4hrs) + # weekly rate: $114 + # annual max reimbursement: $114 * 52 = $5,928 + # weekly copay: $3 (part-time), annual copay: $3 * 52 = $156 + # uncapped: max(20,000 - 156, 0) = 19,844 + # capped: min(19,844, 5,928) = 5,928 + # monthly: 5,928 / 12 = 494 + md_ccs: 494 + +- name: Case 5, informal provider rate by county. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 40_000 + is_tax_unit_head_or_spouse: true + person2: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + md_ccs_provider_type: INFORMAL + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 20_000 + households: + household: + members: [person1, person2] + state_code: MD + county: HOWARD_COUNTY_MD + output: + # Provider: INFORMAL, Howard County, INFANT (age 1 = 12 months < 24), UNIT_3 (8hrs) + # weekly rate: $195 + # annual max reimbursement: $195 * 52 = $10,140 + # weekly copay: $3, annual copay: $3 * 52 = $156 + # uncapped: max(20,000 - 156, 0) = 19,844 + # capped: min(19,844, 10,140) = 10,140 + # monthly: 10,140 / 12 = 845 + md_ccs: 845 diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_countable_income.yaml new file mode 100644 index 00000000000..f17d9b842fb --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_countable_income.yaml @@ -0,0 +1,98 @@ +# Tests for md_ccs_countable_income +# Countable income = adds sources + self_employment_income * (1 - 0.30) +# Child support received is excluded since 2022. +# COMAR 13A.14.06.03(F)(3)-(8) + +- name: Case 1, employment income only. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 30_000 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # employment_income is in sources list + # 30,000 / 12 = 2,500 + md_ccs_countable_income: 2_500 + +- name: Case 2, self-employment income with 30 percent deduction. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + self_employment_income: 20_000 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # self_employment_income 20,000 * (1 - 0.30) = 14,000 + # 14,000 / 12 = 1,166.67 + md_ccs_countable_income: 1_166.67 + +- name: Case 3, mixed employment and self-employment income. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 30_000 + self_employment_income: 20_000 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # employment_income: 30,000 + # self_employment_income: 20,000 * (1 - 0.30) = 14,000 + # total annual: 30,000 + 14,000 = 44,000 + # monthly: 44,000 / 12 = 3,666.67 + md_ccs_countable_income: 3_666.67 + +- name: Case 4, child support received is excluded from income. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 30_000 + child_support_received: 6_000 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # employment_income: 30,000 (counted) + # child_support_received: 6,000 (EXCLUDED per Ch 525/526 of 2022) + # total annual: 30,000 + # monthly: 30,000 / 12 = 2,500 + md_ccs_countable_income: 2_500 diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_eligible.yaml new file mode 100644 index 00000000000..cda4399c201 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_eligible.yaml @@ -0,0 +1,114 @@ +# Tests for md_ccs_eligible +# Eligible when: has at least one eligible child + income eligible +# OR TCA/SSI recipient (income test waived) + +- name: Case 1, basic eligible family with eligible child and income eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # child age 5 < 13, dependent, citizen -> eligible child + # income 50,000 well below 75% SMI for family of 2 + # (75% SMI for fam 2 = 101,489.32 * 0.75 = 76,116.99) + md_ccs_eligible: true + +- name: Case 2, TCA recipient is eligible regardless of income. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 200_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + is_tanf_enrolled: true + households: + household: + members: [person1, person2] + state_code: MD + output: + # TCA recipient -> income test waived + # Has eligible child -> eligible + md_ccs_eligible: true + +- name: Case 3, SSI recipient is eligible regardless of income. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 200_000 + ssi: 9_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # SSI recipient (ssi > 0) -> income test waived + # Has eligible child -> eligible + md_ccs_eligible: true + +- name: Case 4, no eligible children means not eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 15 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # child age 15 >= 13, not disabled -> not eligible child + # no eligible children -> not eligible + md_ccs_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_eligible_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_eligible_child.yaml new file mode 100644 index 00000000000..12ce3947a4a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_eligible_child.yaml @@ -0,0 +1,132 @@ +# Tests for md_ccs_eligible_child +# Child must be: under 13 (or under 19 if disabled), a tax unit dependent, +# and CCDF immigration eligible. +# COMAR 13A.14.06.02 (definition of "Child") + +- name: Case 1, child age 5 not disabled is eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # person1: adult, not dependent -> false + # person2: age 5 < 13, dependent, citizen -> true + md_ccs_eligible_child: [false, true] + +- name: Case 2, child age 14 not disabled is not eligible. + period: 2025-01 + input: + people: + person1: + age: 40 + is_tax_unit_head_or_spouse: true + person2: + age: 14 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # person2: age 14 >= 13 (non-disabled threshold) -> false + md_ccs_eligible_child: [false, false] + +- name: Case 3, disabled child age 14 is eligible. + period: 2025-01 + input: + people: + person1: + age: 40 + is_tax_unit_head_or_spouse: true + person2: + age: 14 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # person2: age 14 < 19 (disabled threshold), disabled -> true + md_ccs_eligible_child: [false, true] + +- name: Case 4, disabled child age 19 is not eligible. + period: 2025-01 + input: + people: + person1: + age: 45 + is_tax_unit_head_or_spouse: true + person2: + age: 19 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # person2: age 19 >= 19 (disabled threshold) -> false + md_ccs_eligible_child: [false, false] + +- name: Case 5, child age 12 at boundary is eligible. + period: 2025-01 + input: + people: + person1: + age: 35 + is_tax_unit_head_or_spouse: true + person2: + age: 12 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # person2: age 12 < 13 -> true + md_ccs_eligible_child: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_income_eligible.yaml new file mode 100644 index 00000000000..1fa9a6355f2 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_income_eligible.yaml @@ -0,0 +1,115 @@ +# Tests for md_ccs_income_eligible +# Initial applicants: income <= 75% SMI +# Continuing families (md_ccs_enrolled): income <= 85% SMI +# TCA/SSI recipients: income test waived +# +# For MD family of 4 in 2025 (FY2025 SMI base = $149,249): +# hhs_smi = 149,249 * (0.52 + 0.16 * 3) = 149,249 +# 75% SMI = 149,249 * 0.75 = 111,936.75 annual +# 85% SMI = 149,249 * 0.85 = 126,861.65 annual + +- name: Case 1, family of 4 with income below 75 percent SMI is eligible. + period: 2025-01 + input: + people: + person1: + age: 35 + employment_income: 100_000 + person2: + age: 33 + person3: + age: 8 + person4: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: MD + output: + # Monthly countable income: 100,000 / 12 = 8,333.33 + # Monthly 75% SMI threshold: 149,249 * 0.75 / 12 = 9,328.06 + # 8,333.33 <= 9,328.06 -> eligible + md_ccs_income_eligible: true + +- name: Case 2, family of 4 with income above 75 percent SMI is not eligible. + period: 2025-01 + input: + people: + person1: + age: 35 + employment_income: 120_000 + person2: + age: 33 + person3: + age: 8 + person4: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: MD + output: + # Monthly countable income: 120,000 / 12 = 10,000 + # Monthly 75% SMI threshold: 149,249 * 0.75 / 12 = 9,328.06 + # 10,000 > 9,328.06 -> not eligible (new applicant) + md_ccs_income_eligible: false + +- name: Case 3, enrolled family of 4 with income between 75 and 85 percent SMI is eligible. + period: 2025-01 + input: + people: + person1: + age: 35 + employment_income: 120_000 + person2: + age: 33 + person3: + age: 8 + person4: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + md_ccs_enrolled: true + households: + household: + members: [person1, person2, person3, person4] + state_code: MD + output: + # Monthly countable income: 120,000 / 12 = 10,000 + # Monthly 85% SMI threshold: 149,249 * 0.85 / 12 = 10,571.81 + # 10,000 <= 10,571.81 -> eligible (continuation) + md_ccs_income_eligible: true + +- name: Case 4, enrolled family of 4 with income above 85 percent SMI is not eligible. + period: 2025-01 + input: + people: + person1: + age: 35 + employment_income: 130_000 + person2: + age: 33 + person3: + age: 8 + person4: + age: 5 + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + md_ccs_enrolled: true + households: + household: + members: [person1, person2, person3, person4] + state_code: MD + output: + # Monthly countable income: 130,000 / 12 = 10,833.33 + # Monthly 85% SMI threshold: 149,249 * 0.85 / 12 = 10,571.81 + # 10,833.33 > 10,571.81 -> not eligible + md_ccs_income_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_payment_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_payment_rate.yaml new file mode 100644 index 00000000000..1cb4c1ec973 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_payment_rate.yaml @@ -0,0 +1,122 @@ +# Tests for md_ccs_payment_rate (weekly rate lookup) +# Formal rates by region/age/unit, informal rates by county/age/unit + +- name: Licensed center, Region X (Howard), regular age, full-time. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 40_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + md_ccs_provider_type: LICENSED_CENTER + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + county: HOWARD_COUNTY_MD + output: + # Region X, REGULAR (age 5), UNIT_3 (8hrs): $424/week + md_ccs_payment_rate: [0, 424] + +- name: Licensed family, Region Y (Baltimore Co), infant, part-time. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 40_000 + is_tax_unit_head_or_spouse: true + person2: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 4 + md_ccs_provider_type: LICENSED_FAMILY + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + county: BALTIMORE_COUNTY_MD + output: + # Region Y, INFANT (age 1 = 12 months < 24), UNIT_2 (4hrs): $167/week + md_ccs_payment_rate: [0, 167] + +- name: Informal provider, Montgomery County, regular, hourly. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 40_000 + is_tax_unit_head_or_spouse: true + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 2 + md_ccs_provider_type: INFORMAL + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + county: MONTGOMERY_COUNTY_MD + output: + # Informal, Montgomery Co, REGULAR (age 3 = 36 months >= 24), UNIT_1 (2hrs): $59/week + md_ccs_payment_rate: [0, 59] + +- name: Licensed center, Baltimore City, infant, full-time. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 40_000 + is_tax_unit_head_or_spouse: true + person2: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + md_ccs_provider_type: LICENSED_CENTER + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + county: BALTIMORE_CITY_MD + output: + # Baltimore City, INFANT (age 1 = 12 months), UNIT_3 (8hrs): $376/week + md_ccs_payment_rate: [0, 376] diff --git a/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_weekly_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_weekly_copay.yaml new file mode 100644 index 00000000000..3d0058ea60e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/md/msde/ccs/md_ccs_weekly_copay.yaml @@ -0,0 +1,242 @@ +# Tests for md_ccs_weekly_copay +# Weekly copay by service units: +# Full-time (>=6 hrs/day, 3 units): $3/week +# Part-time (>3 to <6 hrs/day, 2 units): $2/week +# Hourly (<=3 hrs/day, 1 unit): $1/week +# Exempt: TCA, SSI, SNAP, WIC recipients pay $0 +# Federal 7% cap: annual copay cannot exceed 7% of countable income +# Copay assessed for up to 3 children +# COMAR 13A.14.06.12; Chapter 717 of 2024; 45 CFR 98.45(k) + +- name: Case 1, standard family with full-time care. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # child hours/day = 8 >= 6 -> 3 units (full-time) -> $3/week + # annual copay: $3 * 52 = $156 -> well below 7% of $50,000 ($3,500) + md_ccs_weekly_copay: 3 + +- name: Case 2, standard family with part-time care. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 5 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # child hours/day = 5, >3 and <6 -> 2 units (part-time) -> $2/week + md_ccs_weekly_copay: 2 + +- name: Case 3, standard family with hourly care. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 2 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # child hours/day = 2, <=3 -> 1 unit (hourly) -> $1/week + md_ccs_weekly_copay: 1 + +- name: Case 4, TCA recipient pays zero copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + is_tanf_enrolled: true + households: + household: + members: [person1, person2] + state_code: MD + output: + # TCA recipient -> copay exempt + md_ccs_weekly_copay: 0 + +- name: Case 5, SSI recipient pays zero copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + ssi: 9_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # SSI recipient (ssi > 0) -> copay exempt + md_ccs_weekly_copay: 0 + +- name: Case 6, SNAP eligible family pays zero copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + md_ccs_receives_snap: true + households: + household: + members: [person1, person2] + state_code: MD + output: + # SNAP recipient -> copay waived per Ch 525/526 of 2022 (bare input) + md_ccs_weekly_copay: 0 + +- name: Case 7, WIC eligible parent pays zero copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + md_ccs_receives_wic: true + households: + household: + members: [person1, person2] + state_code: MD + output: + # WIC recipient -> copay waived per Ch 525/526 of 2022 + md_ccs_weekly_copay: 0 + +- name: Case 8, federal 7 percent cap on very low income family. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 2_000 + is_tax_unit_head_or_spouse: true + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MD + output: + # Full-time -> $3/week raw copay + # Annual raw copay: $3 * 52 = $156 + # 7% of annual income: $2,000 * 0.07 = $140 + # $156 > $140 -> 7% cap applies + # Capped weekly: $140 / 52 = $2.69 + md_ccs_weekly_copay: 2.69 diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/eligibility/md_ccs_eligible.py b/policyengine_us/variables/gov/states/md/msde/ccs/eligibility/md_ccs_eligible.py new file mode 100644 index 00000000000..dbca8e755fc --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/eligibility/md_ccs_eligible.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class md_ccs_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Maryland Child Care Scholarship (CCS)" + definition_period = MONTH + defined_for = StateCode.MD + reference = ( + "https://dsd.maryland.gov/regulations/Pages/13A.14.06.03.aspx", + "https://mgaleg.maryland.gov/2022RS/Chapters_noln/CH_525_hb0275e.pdf", + ) + + def formula(spm_unit, period, parameters): + has_eligible_child = add(spm_unit, period, ["md_ccs_eligible_child"]) > 0 + income_eligible = spm_unit("md_ccs_income_eligible", period) + is_tca = spm_unit("is_tanf_enrolled", period) + receives_ssi = add(spm_unit, period, ["ssi"]) > 0 + return has_eligible_child & (income_eligible | is_tca | receives_ssi) diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/eligibility/md_ccs_eligible_child.py b/policyengine_us/variables/gov/states/md/msde/ccs/eligibility/md_ccs_eligible_child.py new file mode 100644 index 00000000000..de54e423f9c --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/eligibility/md_ccs_eligible_child.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class md_ccs_eligible_child(Variable): + value_type = bool + entity = Person + label = "Eligible child for Maryland Child Care Scholarship (CCS)" + definition_period = MONTH + defined_for = StateCode.MD + reference = "https://dsd.maryland.gov/regulations/Pages/13A.14.06.02.aspx" + + def formula(person, period, parameters): + p = parameters(period).gov.states.md.msde.ccs.age_threshold + age = person("age", period.this_year) + is_disabled = person("is_disabled", period.this_year) + age_limit = where(is_disabled, p.disabled_child, 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/md/msde/ccs/md_ccs.py b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs.py new file mode 100644 index 00000000000..8f35d2b6a95 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs.py @@ -0,0 +1,33 @@ +from policyengine_us.model_api import * + + +class md_ccs(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "Maryland Child Care Scholarship (CCS) benefit amount" + definition_period = MONTH + defined_for = "md_ccs_eligible" + reference = ( + "https://dsd.maryland.gov/regulations/Pages/13A.14.06.11.aspx", + "https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates", + ) + + def formula(spm_unit, period, parameters): + weekly_copay = spm_unit("md_ccs_weekly_copay", period) + annual_copay = weekly_copay * WEEKS_IN_YEAR + + actual_expenses = spm_unit( + "spm_unit_pre_subsidy_childcare_expenses", period.this_year + ) + + person = spm_unit.members + is_eligible_child = person("md_ccs_eligible_child", period) + weekly_rate = person("md_ccs_payment_rate", period) + weekly_to_annual = WEEKS_IN_YEAR + max_reimbursement = ( + spm_unit.sum(weekly_rate * is_eligible_child) * weekly_to_annual + ) + + uncapped_benefit = max_(actual_expenses - annual_copay, 0) + return min_(uncapped_benefit, max_reimbursement) / MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_countable_income.py b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_countable_income.py new file mode 100644 index 00000000000..4dcaa4e2bfb --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_countable_income.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class md_ccs_countable_income(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "Maryland Child Care Scholarship (CCS) countable income" + definition_period = MONTH + defined_for = StateCode.MD + reference = ( + "https://dsd.maryland.gov/regulations/Pages/13A.14.06.03.aspx", + "https://mgaleg.maryland.gov/2022RS/Chapters_noln/CH_525_hb0275e.pdf", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.md.msde.ccs.income + sources_income = add( + spm_unit, + period, + p.countable_income.sources, + ) + self_employment_income = add(spm_unit, period, ["self_employment_income"]) + return sources_income + self_employment_income * ( + 1 - p.self_employment_deduction_rate + ) diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_enrolled.py b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_enrolled.py new file mode 100644 index 00000000000..79dca26a13c --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_enrolled.py @@ -0,0 +1,9 @@ +from policyengine_us.model_api import * + + +class md_ccs_enrolled(Variable): + value_type = bool + entity = SPMUnit + definition_period = MONTH + label = "Whether the family is currently enrolled in Maryland Child Care Scholarship (CCS)" + defined_for = StateCode.MD diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_income_eligible.py b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_income_eligible.py new file mode 100644 index 00000000000..0cded2ffe0b --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_income_eligible.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class md_ccs_income_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Maryland Child Care Scholarship (CCS) income eligible" + definition_period = MONTH + defined_for = StateCode.MD + reference = ( + "https://dsd.maryland.gov/regulations/Pages/13A.14.06.03.aspx", + "https://mgaleg.maryland.gov/2022RS/Chapters_noln/CH_525_hb0275e.pdf", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.md.msde.ccs.income.smi_rate + countable_income = spm_unit("md_ccs_countable_income", period) + # TODO: Maryland froze SMI base years for historical periods + # (FY2019-2022 used 2018 SMI, FY2023-2024 used 2021 SMI). + # This formula uses the current-year SMI, which is correct for + # 2025+ but overstates historical thresholds. Follow-up PR + # should parameterize the SMI base year. + smi = spm_unit("hhs_smi", period) + enrolled = spm_unit("md_ccs_enrolled", period) + income_limit = where( + enrolled, + smi * p.continuation, + smi * p.initial, + ) + return countable_income <= income_limit diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_provider_type.py b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_provider_type.py new file mode 100644 index 00000000000..ffe391bad0a --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_provider_type.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class MDCCSProviderType(Enum): + LICENSED_CENTER = "Licensed Child Care Center" + LICENSED_FAMILY = "Licensed Family Child Care Home" + INFORMAL = "Informal/License-Exempt" + + +class md_ccs_provider_type(Variable): + value_type = Enum + entity = Person + possible_values = MDCCSProviderType + default_value = MDCCSProviderType.LICENSED_CENTER + definition_period = MONTH + label = "Maryland CCS child care provider type" + defined_for = StateCode.MD + reference = "https://dsd.maryland.gov/regulations/Pages/13A.14.06.11.aspx" diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_receives_snap.py b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_receives_snap.py new file mode 100644 index 00000000000..b7d9d39a840 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_receives_snap.py @@ -0,0 +1,9 @@ +from policyengine_us.model_api import * + + +class md_ccs_receives_snap(Variable): + value_type = bool + entity = SPMUnit + definition_period = MONTH + label = "Whether the family receives SNAP (used for Maryland CCS copay waiver)" + defined_for = StateCode.MD diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_receives_wic.py b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_receives_wic.py new file mode 100644 index 00000000000..7b85d732492 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_receives_wic.py @@ -0,0 +1,9 @@ +from policyengine_us.model_api import * + + +class md_ccs_receives_wic(Variable): + value_type = bool + entity = SPMUnit + definition_period = MONTH + label = "Whether the family receives WIC (used for Maryland CCS copay waiver)" + defined_for = StateCode.MD diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_weekly_copay.py b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_weekly_copay.py new file mode 100644 index 00000000000..84148219da6 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/md_ccs_weekly_copay.py @@ -0,0 +1,54 @@ +from policyengine_us.model_api import * + + +class md_ccs_weekly_copay(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "Maryland Child Care Scholarship (CCS) weekly copayment" + definition_period = MONTH + defined_for = StateCode.MD + reference = ( + "https://dsd.maryland.gov/regulations/Pages/13A.14.06.12.aspx", + "https://mgaleg.maryland.gov/2024RS/Chapters_noln/CH_717_sb0482e.pdf", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.md.msde.ccs.copay + + # TCA/SSI recipients pay $0 copayment per COMAR 13A.14.06.12(A)(1) + is_tca = spm_unit("is_tanf_enrolled", period) + receives_ssi = add(spm_unit, period, ["ssi"]) > 0 + + # SNAP/WIC recipients have copayments waived per Chapters 525/526 of 2022 + # Use bare inputs to avoid circular dependency through SNAP/TANF/childcare chain + is_snap = spm_unit("md_ccs_receives_snap", period) + receives_wic = spm_unit("md_ccs_receives_wic", period) + exempt = is_tca | receives_ssi | is_snap | receives_wic + + # Weekly copay per child based on service unit (enum-keyed lookup) + person = spm_unit.members + service_unit = person("md_ccs_service_unit", period) + weekly_per_child = p.weekly_amount[service_unit] + + # Only charge copay for eligible children + is_eligible_child = person("md_ccs_eligible_child", period) + weekly_per_child = where(is_eligible_child, weekly_per_child, 0) + + # Copay assessed for up to max_children_with_copay children + eligible_child_count = add(spm_unit, period, ["md_ccs_eligible_child"]) + capped_count = min_(eligible_child_count, p.max_children_with_copay) + total_weekly = spm_unit.sum(weekly_per_child) + scale = where( + eligible_child_count > 0, + capped_count / eligible_child_count, + 0, + ) + scaled_weekly = total_weekly * scale + + # Federal cap: copay cannot exceed 7% of gross income per 45 CFR 98.45(k) + countable_income = spm_unit("md_ccs_countable_income", period) + weekly_income = countable_income * MONTHS_IN_YEAR / WEEKS_IN_YEAR + federal_cap = weekly_income * p.federal_cap_rate + + return where(exempt, 0, min_(scaled_weekly, federal_cap)) diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/md_child_care_subsidies.py b/policyengine_us/variables/gov/states/md/msde/ccs/md_child_care_subsidies.py new file mode 100644 index 00000000000..7c31208d248 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/md_child_care_subsidies.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class md_child_care_subsidies(Variable): + value_type = float + entity = SPMUnit + label = "Maryland child care subsidies" + unit = USD + definition_period = YEAR + defined_for = StateCode.MD + adds = ["md_ccs"] diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/payment/md_ccs_age_group.py b/policyengine_us/variables/gov/states/md/msde/ccs/payment/md_ccs_age_group.py new file mode 100644 index 00000000000..7d4bcadfe87 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/payment/md_ccs_age_group.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class MDCCSAgeGroup(Enum): + REGULAR = "Regular" + INFANT = "Infant" + + +class md_ccs_age_group(Variable): + value_type = Enum + entity = Person + possible_values = MDCCSAgeGroup + default_value = MDCCSAgeGroup.REGULAR + definition_period = MONTH + defined_for = StateCode.MD + label = "Maryland CCS child age group for rate purposes" + reference = "https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates" + + def formula(person, period, parameters): + p = parameters(period).gov.states.md.msde.ccs.payment + age_months = person("age", period.this_year) * MONTHS_IN_YEAR + return where( + age_months < p.infant_age_threshold, + MDCCSAgeGroup.INFANT, + MDCCSAgeGroup.REGULAR, + ) diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/payment/md_ccs_payment_rate.py b/policyengine_us/variables/gov/states/md/msde/ccs/payment/md_ccs_payment_rate.py new file mode 100644 index 00000000000..9dd663258c1 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/payment/md_ccs_payment_rate.py @@ -0,0 +1,41 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.md.msde.ccs.md_ccs_provider_type import ( + MDCCSProviderType, +) + + +class md_ccs_payment_rate(Variable): + value_type = float + entity = Person + unit = USD + label = "Maryland Child Care Scholarship (CCS) weekly payment rate" + definition_period = MONTH + defined_for = "md_ccs_eligible_child" + reference = "https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates" + + def formula(person, period, parameters): + p = parameters(period).gov.states.md.msde.ccs.payment + provider_type = person("md_ccs_provider_type", period) + age_group = person("md_ccs_age_group", period) + service_unit = person("md_ccs_service_unit", period) + region = person.household("md_ccs_region", period) + + # Formal rates: by region, age group, and service unit + center_rate = p.formal.licensed_center[region][age_group][service_unit] + family_rate = p.formal.licensed_family[region][age_group][service_unit] + + # Informal rates: by county, age group, and service unit + county = person.household("county_str", period) + in_md = person.household("state_code_str", period) == "MD" + safe_county = where(in_md, county, "ALLEGANY_COUNTY_MD") + informal_rate = p.informal.rates[safe_county][age_group][service_unit] + + return select( + [ + provider_type == MDCCSProviderType.LICENSED_CENTER, + provider_type == MDCCSProviderType.LICENSED_FAMILY, + provider_type == MDCCSProviderType.INFORMAL, + ], + [center_rate, family_rate, informal_rate], + default=center_rate, + ) diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/payment/md_ccs_region.py b/policyengine_us/variables/gov/states/md/msde/ccs/payment/md_ccs_region.py new file mode 100644 index 00000000000..3d066d60349 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/payment/md_ccs_region.py @@ -0,0 +1,54 @@ +from policyengine_us.model_api import * + + +class MDCCSRegion(Enum): + REGION_U = "Region U" + REGION_V = "Region V" + REGION_W = "Region W" + REGION_X = "Region X" + REGION_Y = "Region Y" + REGION_Z = "Region Z" + BALTIMORE_CITY = "Baltimore City" + + +class md_ccs_region(Variable): + value_type = Enum + entity = Household + possible_values = MDCCSRegion + default_value = MDCCSRegion.REGION_W + definition_period = MONTH + defined_for = StateCode.MD + label = "Maryland CCS rate region" + reference = "https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates" + + def formula(household, period, parameters): + county = household("county_str", period) + p = parameters(period).gov.states.md.msde.ccs.payment + is_region_u = np.isin(county, p.region_u_counties) + is_region_v = np.isin(county, p.region_v_counties) + is_region_w = np.isin(county, p.region_w_counties) + is_region_x = np.isin(county, p.region_x_counties) + is_region_y = np.isin(county, p.region_y_counties) + is_region_z = np.isin(county, p.region_z_counties) + is_baltimore_city = np.isin(county, p.baltimore_city_counties) + return select( + [ + is_region_u, + is_region_v, + is_region_w, + is_region_x, + is_region_y, + is_region_z, + is_baltimore_city, + ], + [ + MDCCSRegion.REGION_U, + MDCCSRegion.REGION_V, + MDCCSRegion.REGION_W, + MDCCSRegion.REGION_X, + MDCCSRegion.REGION_Y, + MDCCSRegion.REGION_Z, + MDCCSRegion.BALTIMORE_CITY, + ], + default=MDCCSRegion.REGION_W, + ) diff --git a/policyengine_us/variables/gov/states/md/msde/ccs/payment/md_ccs_service_unit.py b/policyengine_us/variables/gov/states/md/msde/ccs/payment/md_ccs_service_unit.py new file mode 100644 index 00000000000..0d4b6cf4ab3 --- /dev/null +++ b/policyengine_us/variables/gov/states/md/msde/ccs/payment/md_ccs_service_unit.py @@ -0,0 +1,28 @@ +from policyengine_us.model_api import * + + +class MDCCSServiceUnit(Enum): + UNIT_1 = "1 Unit (3 hours or less per day)" + UNIT_2 = "2 Units (more than 3 to less than 6 hours per day)" + UNIT_3 = "3 Units (6 or more hours per day)" + + +class md_ccs_service_unit(Variable): + value_type = Enum + entity = Person + possible_values = MDCCSServiceUnit + default_value = MDCCSServiceUnit.UNIT_3 + definition_period = MONTH + defined_for = StateCode.MD + label = "Maryland CCS service unit category" + reference = "https://dsd.maryland.gov/regulations/Pages/13A.14.06.11.aspx" + + def formula(person, period, parameters): + hours_per_day = person("childcare_hours_per_day", period.this_year) + p = parameters(period).gov.states.md.msde.ccs.copay + units = p.unit_hours.calc(hours_per_day) + return select( + [units == 3, units == 2], + [MDCCSServiceUnit.UNIT_3, MDCCSServiceUnit.UNIT_2], + default=MDCCSServiceUnit.UNIT_1, + ) diff --git a/sources/working_references.md b/sources/working_references.md new file mode 100644 index 00000000000..02cadffe599 --- /dev/null +++ b/sources/working_references.md @@ -0,0 +1,271 @@ +# Maryland Child Care Scholarship (CCS) Program - Working References + +## Official Program Name +**Child Care Scholarship (CCS) Program** (formerly "Child Care Subsidy Program") + +## Administering Agency +Maryland State Department of Education (MSDE), Division of Early Childhood, Office of Child Care + +## Primary Regulations + +### COMAR 13A.14.06 - Child Care Subsidy Program (Full Chapter) +- **URL**: http://mdrules.elaws.us/comar/13a.14.06 +- **PDF (Jan 2023 version with income tables)**: https://marylandpublicschools.org/stateboard/Documents/2023/0124/COMAR13A.14.06.pdf +- **Local copy**: `/tmp/md-comar-13a1406.pdf` +- **Sections**: + - .01 Purpose + - .02 Definitions + - .03 Eligibility (income scales, need requirements, categorical exemptions) + - .04 Pursuit of Child Support Obligations + - .05 Application Process + - .06 Provider Requirements + - .07 Child Care Vouchers + - .08 Service Groups (priority levels) + - .09 Redetermination + - .10 Termination + - .11 Payments for Child Care Services + - .12 Copayments (regional copayment tables, income levels A-J) + - .13 Confidentiality + - .14 Intentional Program Violations + - .15 Hearings and Appeals + +### Individual COMAR Sections Online +- **Definitions**: http://mdrules.elaws.us/comar/13a.14.06.02 +- **Eligibility**: http://mdrules.elaws.us/comar/13a.14.06.03 +- **Service Groups**: http://mdrules.elaws.us/comar/13a.14.06.08 +- **Copayments**: http://mdrules.elaws.us/comar/13a.14.06.12 +- **Cornell LII (full chapter)**: https://www.law.cornell.edu/regulations/maryland/title-13A/subtitle-14/chapter-13A.14.06 + +## Income Eligibility + +### Current Income Eligibility Scale (updated Dec 15, 2024) +- **Source**: CCS Scholarship Brochure (most current) +- **URL**: https://earlychildhood.marylandpublicschools.org/system/files/filedepot/2/scholarship-brochure-4.pdf +- **Local copy**: `/tmp/md-ccs-brochure.pdf` +- **Standard**: 75% of State Median Income (SMI) for initial eligibility; 85% SMI for continuation +- **Initial Income Scale (annual)**: + - Family of 2: $76,117 + - Family of 3: $94,026 + - Family of 4: $111,936 + - Family of 5: $129,846 + - Family of 6: $147,756 + - Family of 7: $151,114 + - Family of 8: $154,472 + - Family of 9: $157,830 + - Family of 10: $161,188 + - Family of 11: $164,546 + - Family of 12: $167,904 +- **Continuation Income Scale (annual)**: + - Family of 2: $86,266 + - Family of 3: $106,563 + - Family of 4: $126,861 + - Family of 5: $147,159 + - Family of 6: $167,457 + - Family of 7: $171,262 + - Family of 8: $175,068 + - Family of 9: $178,874 + - Family of 10: $182,680 + - Family of 11: $186,486 + - Family of 12: $190,292 + +### Previous Income Eligibility Scale (pre-Dec 2024) +- **Source**: CCS Income Eligibility Scale PDF +- **URL**: https://earlychildhood.marylandpublicschools.org/system/files/filedepot/2/income_eligibility_scale.pdf +- **Local copy**: `/tmp/md-ccs-income-scale.pdf` +- **Initial thresholds**: Family of 2: $61,222; Family of 4: $90,033 +- **Continuation thresholds**: Family of 2: $73,899; Family of 4: $108,675 + +### Historical Income Eligibility Thresholds (from Feb 2026 briefing) +| Fiscal Year | % of SMI | SMI Vintage | Family of 4 Threshold | +|---|---|---|---| +| 2016 | 50% | current | $54,631 | +| 2017 | 50% | current | $55,019 | +| 2018 | 50% | current | $55,839 | +| 2019 | 65% | 2018 SMI | $75,590 | +| 2020 | 65% | 2018 SMI | $75,590 | +| 2021 | 65% | 2018 SMI | $75,590 | +| 2022 | 65% | 2018 SMI | $75,590 | +| 2023 | 75% | 2021 SMI | $93,605 | +| 2024 | 75% | 2021 SMI | $93,605 | +| 2025 | 75% | 2025 SMI | $115,588 | +| 2026 | 75% | 2025 SMI | $115,588 | + +### State Median Income (SMI) Data +- **LIHEAP FY2026 SMI for Maryland**: $154,117 (4-person family) +- **Source**: https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM2025-02_SMIStateTable_Att4.pdf +- **60% SMI by household size (FY26)**: + - 1 person: $48,084 + - 2 persons: $62,879 + - 3 persons: $77,674 + - 4 persons: $92,470 + - 5 persons: $107,265 + - 6 persons: $122,060 +- **CCS uses ACF SMI estimates for FY2025** (per Feb 2026 briefing, slide 20): + - SMI for household of 2: $101,489 + - SMI for household of 4: $149,249 + +### CCDF Family Income Eligibility Levels by State (Jan 2025) +- **URL**: https://acf.gov/sites/default/files/documents/occ/CCDF-Family-Income-Eligibility-Levels-by-State.pdf +- **Local copy**: `/tmp/md-ccdf-income-levels.pdf` +- **Maryland entry**: 60% SMI (based on CCDF methodology), $6,302/month for family of 3, $7,503/month for family of 4 +- **Note**: CCDF and state report different % because they use different SMI bases + +## COMAR Income Eligibility Scale (Regulation .03H) - Older Values +- **Source**: COMAR 13A.14.06 PDF (Jan 2023 version) +- **Note**: These are the 2018 SMI-based values codified in regulation, superseded by Dec 2024 update +- Family of 1: $0-$37,193 (Level J max) +- Family of 2: $0-$48,637 (Level J max) +- Family of 3: $0-$60,081 (Level J max) +- Family of 4: $0-$71,525 (Level J max) +- Family of 5: $0-$82,969 +- Family of 6: $0-$94,413 +- Family of 7: $0-$96,558 +- Family of 8: $0-$98,704 +- Family of 9: $0-$100,850 +- Family of 10: $0-$102,996 + +## Copayments + +### Current Copayment Policy +- **TCA recipients**: $0 copayment (exempt) +- **SSI recipients**: $0 copayment (exempt) +- **SNAP, WIC, Section 8 recipients**: Copayments waived since May 23, 2022 (Chapters 525/526 of 2022) +- **All other families**: Maximum $3/week per 3-unit scholarship, $2/week per 2-unit, $1/week per 1-unit +- **Chapter 717 of 2024**: Prohibits MSDE from increasing copayment levels in effect as of Jan 1, 2024 +- **Federal CCDF 2024 Final Rule**: Caps copayments at 7% of family gross income + +### COMAR Copayment Tables (Regulation .12) +- **Regional copayment tables** by income level (A-J), region (U, V, W, X, Y, Z, BC), child age (<24 months vs >=24 months) +- **Copayment assessed for up to 3 children**: youngest gets highest, 2nd and 3rd get lower, 4th+ free +- **Units of service**: 1 unit (<=3 hrs), 2 units (>3 to <6 hrs), 3 units (>=6 hrs) +- **2-unit and 1-unit copayments**: multiply 3-unit figures by 2/3 and 1/3 respectively +- **Informal care copayments**: percentage of informal care weekly rate (5%-50% for first child by level A-J) +- **Note**: The COMAR regulation copayment tables appear to be from the pre-2022 era; current copayments are minimal ($1-$3/week) per legislative changes + +## Market Regions +- **Source**: RESI of Towson University, "Maryland Child Care Scholarship Program Reimbursement Rate Adjustments" (Sep 2023) +- **URL**: https://dlslibrary.state.md.us/publications/Exec/MSDE/ED9.5-111(c)_2022.pdf +- **Local copy**: `/tmp/md-ccs-reimbursement-2022.pdf` + +| Region | Counties | +|---|---| +| Region U | Cecil, Queen Anne's, St. Mary's, Talbot, Washington | +| Region V | Caroline, Dorchester, Kent, Somerset, Wicomico | +| Region W | Anne Arundel, Calvert, Carroll, Charles, Prince George's | +| Region X | Howard, Montgomery | +| Region Y | Baltimore, Frederick, Harford | +| Region Z | Allegany, Garrett, Worcester | +| Region B/BC | Baltimore City | + +## Eligibility Requirements Summary + +### Child Age +- Under 13 years (non-disabled) +- Under 19 years (disabled) +- **Source**: COMAR 13A.14.06.02 (definition of "Child") + +### Residency +- Must be a resident of the State of Maryland +- **Source**: COMAR 13A.14.06.03(A)(1) + +### Citizenship +- Children must be U.S. citizens or qualified aliens +- Parents do NOT have to be U.S. citizens +- **Source**: COMAR 13A.14.06.03(B); CCS Brochure + +### Activity Requirement (Need) +- Parent/caretaker must be working/employed, in an approved training program, or attending school +- For two-parent households, both parents must meet requirements +- **Source**: COMAR 13A.14.06.03(E); CCS Brochure + +### Categorical Eligibility +- TCA recipients: exempt from income limits and copayments +- SSI recipients: exempt from income limits and copayments +- **Source**: COMAR 13A.14.06.03(F)(1), .12(A)(1) + +### Income Calculation +- Annual gross income used +- Self-employment: flat 30% deducted for business expenses +- Military housing: paid rental/mortgage fees deducted from allowance +- Child support: averaged over 3 most recent consecutive months (excluded from income per 2022 legislation) +- **Source**: COMAR 13A.14.06.03(F)(3)-(8) + +### Immunizations +- Required for children before receiving services +- Exemptions for medical contraindications or religious objections +- **Source**: COMAR 13A.14.06.03(D) + +### Child Support Cooperation +- Must pursue child support obligations unless good cause exists +- **Source**: COMAR 13A.14.06.04 + +### Eligibility Period +- 12-month minimum (per federal mandate); Maryland uses 24-month eligibility periods +- **Source**: Jan 2025 briefing slide 7 + +## Legislative History + +| Year | Legislation | Key Changes | +|---|---|---| +| 2017 | Ch 209/210 | Required periodic reimbursement rate analysis | +| 2018 | Ch 555/556 | Supplemental Head Start funding | +| 2018 | (MSDE action) | Reimbursement 9th -> 20th percentile; eligibility 32% -> 50% SMI | +| 2019 | Ch 595/596 | Required 60th percentile market rate adjustment; eligibility -> 65% SMI | +| 2020 | (COVID) | All copays waived Mar-Sep 2020; reimbursement -> 60th percentile | +| 2021 | Ch 36/55 | Annual funding for Judy Centers, EXCELS, Blueprint capacity | +| 2022 | Ch 525/526 | Copay waivers for SNAP/WIC/TCA/Section 8/SSI; removed child support from income; created presumptive eligibility; eligibility -> 75% SMI; reimbursement -> 70th percentile | +| 2022 | Ch 498/499 | Therapeutic Child Care Grant Program | +| 2023 | Ch 731/732 | Restrict MSDE from changing key CCS policies as of Jan 1, 2023 | +| 2024 | Ch 717 | Prohibit MSDE from increasing copayment levels as of Jan 1, 2024 | +| 2025 | Ch 369 | Expanded CCS to parenting foster youth | + +## Briefings and Presentations + +### Feb 2026 Ways and Means Committee Briefing +- **URL**: https://mgaleg.maryland.gov/meeting_material/2026/w&m%20-%20134146885147130127%20-%20Briefing%20materials.pdf +- **Local copy**: `/tmp/md-ccs-briefing-2026.pdf` +- **Key data**: 41,148 children / 27,235 families (Jan 2026); waitlist ~4,929 children; current SMI threshold table; demographic breakdowns + +### Jan 2025 Early Childhood Subcommittee Briefing +- **URL**: https://mgaleg.maryland.gov/meeting_material/2025/app%20-%20133815104940229083%20-%20MSDE-Child%20Care%20Scholarship%20Program%20Update%20to%20Subcommittee%20(1).pdf +- **Local copy**: `/tmp/md-ccs-briefing-2025.pdf` +- **Key data**: $568M proposed investment; enrollment freeze May 2025; copayment policy details + +### Jan 2025 CCS Info Session +- **URL**: https://earlychildhood.marylandpublicschools.org/system/files/filedepot/3/january_2025_occ_info_session.pdf +- **Local copy**: `/tmp/md-ccs-info-session-jan2025.pdf` +- **Key data**: Income eligibility increased effective Dec 15, 2024 (family of 2: $76,117; family of 4: $111,936) + +### Jan 2024 Early Childhood Subcommittee Briefing +- **URL**: https://mgaleg.maryland.gov/cmte_testimony/2024/ecm/1qQzLR-gr9jXICeb4E76YUf3vjAwJekVU.pdf +- **Local copy**: `/tmp/md-ccs-briefing-2024.pdf` +- **Key data**: Historical timeline of policy changes; copayment sliding scale proposal (3% for ~$43K-$65K, 7% for >$66K) + +### Oct 2025 Child Care in Maryland (DLS) +- **URL**: https://mgaleg.maryland.gov/meeting_material/2025/app%20-%20134063072915355066%20-%20ChildCarePresentation.pdf +- **Local copy**: `/tmp/md-ccs-childcare-in-md-2025.pdf` +- **Key data**: Comprehensive program overview; freeze status; market rate timeline; federal rule changes + +## Market Rate Survey +- **2024 Market Rate Survey**: https://earlychildhood.marylandpublicschools.org/system/files/filedepot/3/md-market-rate-survey-2024-2.pdf +- **Reimbursement Rate Analysis (2022 data, Sep 2023 report)**: https://dlslibrary.state.md.us/publications/Exec/MSDE/ED9.5-111(c)_2022.pdf +- **Local copy**: `/tmp/md-ccs-reimbursement-2022.pdf` + +## Program Websites +- **Official CCS Program**: https://earlychildhood.marylandpublicschools.org/child-care-providers/child-care-scholarship-program +- **Family Portal**: https://family.childcareportals.org/s/?language=en_US +- **money4childcare.com**: www.money4childcare.com (main family-facing site) +- **CCS Rates**: https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates +- **CCDF State Plan**: https://earlychildhood.marylandpublicschools.org/about/ccdf-state-plan +- **Enrollment Data**: https://earlychildhood.marylandpublicschools.org/data + +## Failed Fetches +| URL | Status | Likely Content | +|---|---|---| +| https://earlychildhood.marylandpublicschools.org/child-care-providers/child-care-scholarship-program | 403 | Main program page with eligibility details and links | +| https://earlychildhood.marylandpublicschools.org/changes-subsidy-eligibility | 403 | Details of eligibility changes over time | +| https://earlychildhood.marylandpublicschools.org/families/child-care-scholarship-program/child-care-scholarship-rates | Not fetched | Current provider reimbursement rate tables by region/age/quality | +| https://earlychildhood.marylandpublicschools.org/about/ccdf-state-plan | 403 | CCDF state plan documents with full eligibility and copayment details | +| https://earlychildhood.marylandpublicschools.org/system/files/filedepot/2/income_eligibility_scale.pdf | 403 | Older income eligibility scale PDF (data obtained from text version) | +| https://acf.gov/sites/default/files/documents/ocs/COMM_LIHEAP_IM202502_SMIStateTable_Att4.pdf | 404 | FY26 SMI table (obtained via alternate URL) | +| https://regulations.justia.com/states/maryland/title-13a/subtitle-14/chapter-13a-14-06/section-13a-14-06-02/ | 403 | COMAR definitions (obtained from mdrules.elaws.us) |