Skip to content

Add Montana Child Care Assistance Program (Best Beginnings Child Care Scholarship)#8662

Open
hua7450 wants to merge 9 commits into
PolicyEngine:mainfrom
hua7450:mt-ccap
Open

Add Montana Child Care Assistance Program (Best Beginnings Child Care Scholarship)#8662
hua7450 wants to merge 9 commits into
PolicyEngine:mainfrom
hua7450:mt-ccap

Conversation

@hua7450

@hua7450 hua7450 commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Implements Montana's Child Care Assistance Program (Best Beginnings Child Care Scholarship) in PolicyEngine. The program is administered by Montana DPHHS, Early Childhood Services Bureau (ECSB), and is CCDF-funded. Subsidy = lesser of the provider's charge or the state maximum rate, minus the parent's sliding-scale copayment, floored at $0.

Closes #8661

Regulatory Authority

Eligibility

Requirement Source How modeled
Income limit (initial / graduated) ARM 37.80.202(1)-(2) mt_ccap_income_eligible — non-TANF applicant ≤ 150% FPG; non-TANF continuing recipient (mt_ccap_enrolled) ≤ 185% FPG at redetermination; TANF families categorically eligible
Over 85% SMI => not eligible Sliding Fee Scale footnote; 45 CFR 98.20(a)(2) mt_ccap_income_eligiblecountable_income <= hhs_smi * 0.85 (param income/income_limit_smi_rate.yaml = 0.85); rarely binds (FPG limit is tighter)
Activity hours ARM 37.80.201; CC 2-3 mt_ccap_activity_eligible — two-parent 120/mo combined, single-parent 60/mo (from weekly_hours_worked_before_lsr); per-parent waivers for full-time students (incl. teens in HS), disabled parents, and incarcerated parents in two-parent families
CCDF asset test ARM 37.80.202 (= 42 USC 9858n(4)(B)) reuses federal is_ccdf_asset_eligible
Immigration (child) landing page; 45 CFR 98.20 reuses federal is_ccdf_immigration_eligible_child
Montana residency + parent/child cohabitation ARM 37.80.201; CC 2-2 defined_for = StateCode.MT on mt_ccap_eligible; SPM-unit grouping co-locates parent and child
At least one eligible child ARM 37.80.202 add(spm_unit, period, ["mt_ccap_eligible_child"]) > 0
Eligible child age ARM 37.80.201; CC 2-1 (CCDF default) mt_ccap_eligible_child — age < 13, or < 19 if special needs (params eligibility/child_age_limit.yaml = 13, eligibility/special_needs_child_age_limit.yaml = 19)
Eligibility categories CC 1-7 non-TANF income pathway AND TANF categorical pathway via is_tanf_enrolled

Income Standards

Per ARM 37.80.202(1)-(2):

  • Initial eligibility (first-time applicant): non-TANF countable income at or below 150% FPG (income/fpg_limit/initial.yaml = 1.5).
  • Graduated eligibility (continuing recipient, at annual redetermination): non-TANF countable income at or below 185% FPG (income/fpg_limit/graduated.yaml = 1.85). The applicant-vs-redetermination split is driven by the mt_ccap_enrolled input (default = applicant).
  • TANF families: categorically income-eligible via is_tanf_enrolled (their income is far below the FPG limits regardless).
  • SMI ceiling: countable income above 85% of state median income (SMI) is a hard ineligibility overlay (hhs_smi * 0.85). With the 185% FPG ceiling the FPG limit binds first for all but the largest households (size 13+ in 2026), so this rarely controls.

Benefit Calculation

Subsidy = min(provider charge, state maximum rate) - copay, floored at $0, summed across eligible children.

  • Copay = max(GMI x FPG-bracket %, $10) for non-TANF families. TANF recipients (is_tanf_enrolled) pay a flat $10. The $10 minimum (param copayment/minimum.yaml) is both the non-TANF floor and the TANF flat amount.
  • Copay sliding scale (param copayment/copay_rate.yaml, a single_amount bracket keyed on the % FPG ratio): 14 rate tiers from 0.5% (at/below 100% FPG) stepping up to 7.0%. Per the Sliding Fee Scale footnote ("the co-payments listed are minimums and correspond to the lowest level for each income range"), each labeled FPG% is the floor of its tier — e.g. the 1.0% tier runs 105% up to 115% FPG. Bracket thresholds are the labeled % values (0, 1.05, 1.15, …, 1.85) with no offset, since single_amount is "at or above threshold." The published scale's tiers run to 200% FPG, but income eligibility caps at 185% FPG for non-TANF families, so tiers above 185% are unreachable for eligible families (retained only to mirror the published scale).
  • Provider maximum rate (param rates/provider_rates.yaml) is a 3-dimensional lookup: provider type (6) x age group (3) x half/full-time (2). Half-time = 5 or fewer hours/day; full-time = more than 5 up to 12 hours/day (ARM 37.80.205). mt_ccap_care_time defaults to FULL_TIME (we don't track per-day care hours at the moment). RCE / School-Age-Provider NA cells are encoded as 0 (not payable).

Requirements Coverage

REQ Description Parameter Variable Test
REQ-001 Eligible child under age limit (13 / special-needs 19) eligibility/child_age_limit.yaml, eligibility/special_needs_child_age_limit.yaml mt_ccap_eligible_child.py mt_ccap_eligible_child.yaml
REQ-002 Child + parent live together in Montana mt_ccap_eligible.py (defined_for=StateCode.MT) mt_ccap_eligible.yaml (Case 2 WY)
REQ-003 Household has >=1 eligible child mt_ccap_eligible.py mt_ccap_eligible.yaml (Case 3)
REQ-004 Activity hours (two-parent 120, single 60) + per-parent waivers eligibility/activity_hours/{two_parent,single_parent}.yaml mt_ccap_activity_eligible.py mt_ccap_activity_eligible.yaml (18 cases)
REQ-005 Full-time-student / teen-in-HS parent: work requirement waived* mt_ccap_activity_eligible.py (is_full_time_student waiver) mt_ccap_activity_eligible.yaml (Cases 3, 12)
REQ-006 Disabled parent excluded from family minimum-hour calc mt_ccap_activity_eligible.py (is_disabled waiver) mt_ccap_activity_eligible.yaml (Cases 13-15)
REQ-007 CCDF immigration check (federal) mt_ccap_eligible_child.py (is_ccdf_immigration_eligible_child) mt_ccap_eligible_child.yaml (Case 6)
REQ-008 CCDF asset test (federal) mt_ccap_eligible.py (is_ccdf_asset_eligible) mt_ccap_eligible.yaml (Cases 6, 7)
REQ-009 FPG income limit — applicant 150% / redetermination 185% (ARM 37.80.202(1)-(2)) income/fpg_limit/initial.yaml (1.5), income/fpg_limit/graduated.yaml (1.85) mt_ccap_income_eligible.py, mt_ccap_enrolled.py mt_ccap_income_eligible.yaml (Cases 1-6)
REQ-010 >85% SMI => not eligible income/income_limit_smi_rate.yaml (= 0.85) mt_ccap_income_eligible.py (hhs_smi) mt_ccap_income_eligible.yaml (Cases 10-11)
REQ-011 Countable income sources income/countable_income/sources.yaml mt_ccap_countable_income.py mt_ccap_countable_income.yaml
REQ-013 Payment = min(charge, rate) - copay, floor 0 mt_ccap.py mt_ccap.yaml, integration.yaml
REQ-014 State max rates (6 x 3 x 2) rates/provider_rates.yaml mt_ccap_max_rate.py mt_ccap_max_rate.yaml (18 cases)
REQ-015 Half/full-time rate distinction rates/provider_rates.yaml mt_ccap_care_time.py mt_ccap_max_rate.yaml
REQ-019 RCE / School-Age-Provider NA cells = 0 rates/provider_rates.yaml mt_ccap_max_rate.py mt_ccap_max_rate.yaml (Case 12)
REQ-020 Copay = max(GMI x %, $10) copayment/minimum.yaml (= 10) mt_ccap_copay.py mt_ccap_copay.yaml
REQ-021 Copay % sliding scale (0.5% -> 7.0%, floor reading) copayment/copay_rate.yaml mt_ccap_copay.py mt_ccap_copay.yaml (boundary cases)
REQ-022 TANF recipients flat $10 copay copayment/minimum.yaml mt_ccap_copay.py mt_ccap_copay.yaml (Case 6), integration.yaml (Case 4)
REQ-023 Graduated tier to 185% FPG at redetermination (non-TANF) income/fpg_limit/graduated.yaml mt_ccap_income_eligible.py (mt_ccap_enrolled) mt_ccap_income_eligible.yaml (Cases 4-6)
REQ-026 Non-TANF + TANF eligibility pathways mt_ccap_income_eligible.py, mt_ccap_eligible.py mt_ccap_eligible.yaml (Case 8)

All 20 in-scope requirements have parameter/variable/test coverage.

* REQ-005: the work-requirement waiver for a parent in full-time school (including a teen in high school/HiSET) is modeled via the is_full_time_student waiver, plus the incarcerated-parent waiver in two-parent ("intact") families via is_incarcerated. The teen-parent "may be treated as a separate household" / under-20 specifics are not modeled (entity structure).

Not Modeled

These features are documented limitations — we don't track the underlying inputs at the moment:

REQ What Why excluded
REQ-005 (sub) Teen parent treated as a separate household; under-20 specifics No teen-parent household-split input (the work-requirement waiver itself is modeled)
REQ-012 Entry-level income floor = TANF GMI + $1 Entry-vs-redetermination income floor not tracked; bracket math is driven by % FPG
REQ-016 Full monthly authorization when attendance >=85% No per-day attendance input; assumes full-month authorization
REQ-017 Extended-care multipliers (12-18h = 1.25x, >18h = 1.5x) No daily-hours-in-care input at that granularity
REQ-018 No school-hours care for age 6+ as of Sept 10 No school-hours-care / school-calendar input
REQ-023 (timing) Graduated-tier redetermination timing (12-month period / only-at-redetermination) We proxy applicant-vs-redetermination with the mt_ccap_enrolled input, but not the 12-month eligibility clock
REQ-024 Funding-limited priority / waitlist categories Priority affects waitlist ordering, not benefit calc
REQ-025 Presumptive eligibility (30 days) No application-date / presumptive-period state
REQ-026 (sub-pathways) Tribal / Tribal-TANF / CFSD-referral eligibility categories No tribal-enrollment / CFSD-referral input
REQ (activity) Part-time student + 40/mo work pathway; "least hours outside the home" two-parent nuance; "paid legal labor / minimum wage" earnings condition Part-time-school status not tracked; covered via the meets_ccdf_activity_test fallback input. Activity test checks hours only, not whether the work is paid at minimum wage
REQ-015 (derivation) Auto-classification of half- vs full-time by daily hours No per-day-hours-in-care input; care_time is a bare input defaulting to FULL_TIME

⚠️ Regulatory Note — FPG threshold sources (reviewers please confirm)

Eligibility uses ARM 37.80.202(1)-(2): initial 150% FPG, graduated 185% FPG (non-TANF, at redetermination). The published Sliding Fee Scale (eff. 07-01-2025) shows higher operational ceilings — a standard table running to 185% FPG ("MAX ENTRY") and a graduated table to 200% FPG ("EXIT"). We use the sliding-fee scale only for the copay percentages, and the ARM rule text for the income-eligibility limits. Reviewers should confirm which source governs eligibility (the ARM rule text vs. the operational scale), since the two differ by ~35 FPG points.

Documented Assumptions

  • Applicant vs redetermination via mt_ccap_enrolled (default = applicant): the 150% (initial) vs 185% (graduated) split from ARM 37.80.202(1)-(2) is selected by this input. Households that don't set it — including all microdata — are treated as first-time applicants at the 150% limit. TANF families are categorically eligible regardless.
  • Copay bracket = floor reading: each labeled FPG% is the bottom of its co-pay tier (per the scale footnote "co-payments listed are minimums and correspond to the lowest level for each income range"), so the 1.0% tier covers 105% up to 115% FPG, etc. Thresholds use the labeled % directly with no +0.0001 offset.
  • Age-group month boundaries (Infant/Toddler 0-35 mo, Preschool 36-71 mo, School Age 72+ mo): the Provider Rates PDF gives no month cutoffs. The Infant/Toddler (36 mo) cutoff is a documented assumption; the Preschool/School-Age (72 mo) cutoff follows ARM 37.80.102 (school-age = 6th birthday). Documented in the mt_ccap_child_age_category docstring.
  • Child age limits 13 / special-needs 19: CCDF defaults; ARM defers to the policy manual for the exact figures.
  • care_time defaults to FULL_TIME: there is no per-day-hours-in-care input, so half-time must be set explicitly.
  • Activity hours use weekly_hours_worked_before_lsr (converted to monthly via 52/12), so the activity gate is stable under labor-supply responses.
  • tanf excluded from countable-income sources: avoids a childcare <-> TANF circular dependency. TANF families are instead handled via the is_tanf_enrolled categorical pathway plus the flat $10 copay branch.

Test plan

  • 118 tests pass locally (unit + integration + edge cases)
  • CI passes

Files Added

policyengine_us/parameters/gov/states/mt/dphhs/ccap/
├── age_group/months.yaml
├── copayment/copay_rate.yaml
├── copayment/minimum.yaml
├── eligibility/activity_hours/single_parent.yaml
├── eligibility/activity_hours/two_parent.yaml
├── eligibility/child_age_limit.yaml
├── eligibility/special_needs_child_age_limit.yaml
├── income/countable_income/sources.yaml
├── income/fpg_limit/initial.yaml
├── income/fpg_limit/graduated.yaml
├── income/income_limit_smi_rate.yaml
└── rates/provider_rates.yaml

policyengine_us/variables/gov/states/mt/dphhs/ccap/
├── mt_ccap.py
├── mt_ccap_care_time.py
├── mt_ccap_child_age_category.py
├── mt_ccap_copay.py
├── mt_ccap_countable_income.py
├── mt_ccap_max_rate.py
├── mt_ccap_provider_type.py
├── mt_child_care_subsidies.py
└── eligibility/
    ├── mt_ccap_activity_eligible.py
    ├── mt_ccap_eligible.py
    ├── mt_ccap_eligible_child.py
    ├── mt_ccap_enrolled.py
    └── mt_ccap_income_eligible.py

policyengine_us/tests/policy/baseline/gov/states/mt/dphhs/ccap/
├── integration.yaml
├── mt_ccap.yaml
├── mt_ccap_activity_eligible.yaml
├── mt_ccap_child_age_category.yaml
├── mt_ccap_copay.yaml
├── mt_ccap_countable_income.yaml
├── mt_ccap_eligible.yaml
├── mt_ccap_eligible_child.yaml
├── mt_ccap_income_eligible.yaml
├── mt_ccap_max_rate.yaml
└── mt_child_care_subsidies.yaml

Federal-registration edits (2 files):

  • policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml — added mt_child_care_subsidies to the adds list
  • policyengine_us/programs.yaml — added the MT Best Beginnings state_implementations entry under the federal CCDF program (variable mt_child_care_subsidies, parameter prefix gov.states.mt.dphhs.ccap)

12 parameters, 13 variables, 11 tests (118 test cases).

🤖 Generated with Claude Code

hua7450 and others added 2 commits June 17, 2026 09:23
Scaffolding commit for the Montana Child Care Assistance Program
implementation. Adds changelog fragment.

Issue: PolicyEngine#8661

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…olicyEngine#8661)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (47cb26b) to head (9854f3e).
⚠️ Report is 10 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##              main     #8662    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files            3        13    +10     
  Lines           47       198   +151     
==========================================
+ Hits            47       198   +151     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

hua7450 and others added 4 commits June 17, 2026 10:55
Apply two-parent both-full-time-students activity waiver (CC 2-3); add
45 CFR 98.20 child-age citation; fix CC 2-6 page anchor; clean parameter
descriptions; add two-parent FT-student regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
C1 (critical): correct the preschool/school-age provider-rate boundary from
60 to 72 months per ARM 37.80.102 (school-age begins at the 6th birthday).
Age-5 children at child care centers were placed in the cheaper school-age
cell, understating the max rate by ~$110/mo full-time. Adds an ARM 37.80.102
reference plus age-5 -> PRESCHOOL / age-6 -> SCHOOL_AGE and CENTER-rate tests.

S1/S2: document that the graduated 185-200% FPG band is recipient-only
("must already be on the Non-TANF program ... at redetermination"), so the
flat 200% ceiling over-grants new applicants (modeling limitation, no
CCAP-enrollment input); annotate the ARM-150/185 vs operational-scale-185/200
divergence.

S3: note the 85% SMI ceiling is operational (45 CFR 98.20(a)(2), not ARM) and
add an SMI-cap isolation test (binds before 200% FPG only at large household
sizes).

S4: replace the incorrect ARM 37.80.201 child-age citation with
45 CFR 98.20(a)(1)(i) (under 13) and (a)(1)(ii) (under 19, special needs).

S5: document the unmodeled activity waivers (incarcerated/pre-release,
teen-parent, disabled-parent, part-time-student+40hr).

S6: reconcile the sliding-fee-scale vintage (2016-11-01 structure vs 2025
values) across the income/copay parameter files.

No parameter values changed except the age-group boundary threshold. Adds
4 test cases; all 113 MT CCAP tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Activity (mt_ccap_activity_eligible):
- Drive the work-hour test off weekly_hours_worked_before_lsr so eligibility
  is independent of labor-supply response.
- Add meets_ccdf_activity_test as a fallback for approved activities not
  individually modeled (part-time student + 40 hrs, job search, training).
- Model the disability (is_disabled) and intact-family incarceration
  (is_incarcerated) waivers per CC 2-3: a waived parent drops a two-parent
  family to the single-parent 60-hour standard; all parents waived means no
  work requirement.

Copay (copay_rate, mt_ccap_copay):
- Read the Best Beginnings sliding fee scale as a floor (each labeled % FPG is
  the tier floor, per the scale footnote), matching the source table; replaces
  the prior +0.0001/ceiling reading that overcharged several bands.

Tests: rename work-hours inputs to weekly_hours_worked_before_lsr across the
CCAP suite; add disabled / incarcerated / CCDF-fallback activity cases;
de-brittle the FPG-boundary copay cases. All 119 MT CCAP tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…into mt-ccap

# Conflicts:
#	policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml
#	policyengine_us/programs.yaml
@hua7450 hua7450 marked this pull request as ready for review June 21, 2026 22:01
hua7450 and others added 3 commits June 21, 2026 18:04
Replace the flat 200% FPG ceiling with the ARM rule structure: non-TANF first-time applicants eligible below 150% FPG (initial, sec (1)); non-TANF continuing recipients at annual redetermination up to 185% FPG (graduated, sec (2)), selected by the new mt_ccap_enrolled input (default applicant); TANF families remain categorically income-eligible. The 85% SMI overlay is retained (now binds only at very large household sizes). The published copay sliding scale is unchanged, but its tiers above 185% FPG are unreachable for eligible families. 118 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ARM 37.80.202(1)-(2) grants initial eligibility for income below 150% FPG and graduated eligibility below 185% FPG. Use strict < for the FPG comparison so a non-TANF household exactly at its cap fails the income test. The 85% SMI overlay stays <= (45 CFR 98.20(a)(2): does not exceed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Fix stale 60-mo Preschool/School-Age boundary in the mt_ccap_child_age_category
  docstring; the running code and age_group/months.yaml correctly use the 72-mo
  cutoff per ARM 37.80.102 (school-age = 6th birthday). Docs-only; no calc change.
- Add the official rules.mt.gov citation alongside the Cornell LII mirror for the
  150%/185% FPG income limits (initial.yaml, graduated.yaml).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hua7450 hua7450 requested a review from PavelMakarchuk June 22, 2026 01:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Montana Child Care Assistance Program (Best Beginnings Child Care Scholarship)

1 participant