Implement Iowa Child Care Assistance Program (CCAP)#8612
Open
hua7450 wants to merge 7 commits into
Open
Conversation
Closes PolicyEngine#8611 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
) Full 3-tier CCDF child care subsidy: CCA (initial <=160%/200% FPL or 85% MFI), CCA Plus (ongoing <=225%), CCA Exit (ongoing <=250%/275%, state-funded). Benefit = min(provider charge, max rate ceiling) - copay per half-day unit, across a 5-provider x 3-age x 4-quality x Basic/SN rate matrix, with both copay mechanisms (sliding flat unit fee and CCA Exit %-of-cost). 28 params, 22 variables, 135 tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8612 +/- ##
============================================
+ Coverage 77.77% 100.00% +22.22%
============================================
Files 1 22 +21
Lines 9 404 +395
Branches 0 5 +5
============================================
+ Hits 7 404 +397
+ Misses 2 0 -2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- Fix citation 170.4(8)"d" -> 170.4(7)"d" (in-home care; no 170.4(8) exists) - Fix #page anchors on income exclusion / minor-age params (p.4/p.5) - Add ia_cca_has_special_needs_child unit test (was untested) - Use age-based child eligibility per IAC 170.2(1)"e"(3) (drop is_tax_unit_dependent) - Make ia_cca_max_rate provider selection explicit (no silent default) - Strip internal REQ- markers from tests; add ia_cca.yaml + matrix/negative-income cases Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The CCA/CCA Plus sliding-fee and CCA Exit fee-level lookups used sum(income > threshold), placing families whose income falls strictly between two thresholds one level too high (over-charging copay). The fee charts assign the level via "first row greater than income, use the row above" — each printed threshold is the inclusive floor of its level. Corrected both to max(sum(income >= threshold) - 1, 0). This makes CCA Exit Level A (33%) reachable. Recomputed affected copay/level/integration test expectations against the corrected logic. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Count SSI in countable income (excluded only in FIP-linked cases per IAC 441-170.2(1)"d"(25)-(26), which route through the income-exception path); drop tax_exempt_interest_income (already inside the interest_income umbrella) - Floor each person's net self-employment subtotal at zero per 170.2(1)"c"(1) (new self_employment_sources.yaml split) - Restrict the minor-earnings exclusions to non-head/spouse persons so a teen parent's own wages stay counted - Make ia_cca_exit_fee_level Person-level: the Basic vs Special Needs exit table is selected per child per the fee chart, and ia_cca_copay sums per-child percentages - Replace the count-based fee-level lookup with the chart's literal first-row-greater scan (the BB row sits below AA for family sizes 9-13, so the counting shortcut landed those sizes one level too high) - Fix need-for-service comment citations (170.2(2)"b"(3)/(9)/(6)-(7)), inverted threshold descriptions, and two page anchors - Tests: +15 cases (exit Levels C/D, mixed Basic/SN family, sliding-fee BB-window regressions, SSI/SE-loss/interest/teen-head countable income); boundary-test names corrected to actual offsets Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Count half-day units per day when the care schedule is known
(childcare_days_per_week / childcare_hours_per_day inputs): one unit
for a day of up to 5 hours, two units for a longer day, per
IAC 441-170.1 ("per 24-hour period") and 170.4(7)"a" (full-day rate =
2 half-day rates). Falls back to total-hours proration when only
weekly hours are reported, preserving existing test and microsim
behavior for hours-only inputs
- Apply the IAC 441-170.2(1)"a"(2) ceiling — min(225% FPL, 85% MFI) —
to the CCA Plus / CCA Exit copay-mechanism dispatch; the MFI cap
binds below 225% FPL at family sizes 10+ with current parameters
- Tests: +7 cases (part-day, full-day, 5-hour-boundary, 10-hour-day,
zero-hours schedules; size-10 dispatch on both sides of the MFI cap)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements Iowa Child Care Assistance (CCA / CCAP) in PolicyEngine — a 3-tier CCDF child care subsidy administered by Iowa HHS. The program covers initial applicants (CCA), already-enrolled families at redetermination (CCA Plus), and a state-funded transitional tier (CCA Exit). The benefit pays the provider's charge up to a published half-day-unit rate ceiling, minus a sliding family fee.
Closes #8611
Regulatory Authority
Current rates and thresholds took effect 2024-07-01 following HF2658 (2024 session), which raised reimbursement rates based on the 2023 Market Rate Survey.
Eligibility Tests
The program has a 3-tier income structure selected by the
ia_cca_enrolledboolean input (initial applicants vs. enrolled recipients at redetermination), mirroring the NJ CCAP initial-vs-ongoing pattern:ia_cca_enrolled = false)The 85% MFI cap reuses the federal
smi()lookup (likenj_ccap_smi); it binds on the initial tier and on the CCA Plus ceiling used for copay-mechanism dispatch, where it falls below 225% FPL only at family sizes 10+ (eligibility for enrolled families is governed by the uncapped a(3) Exit limits).Other tests:
meets_ccdf_activity_testfallback. Usesweekly_hours_worked_before_lsr(avoids the labor-supply cycle). Two-parent coinciding-hours is simplified to a per-parent gate.is_tanf_enrolledORreceives_or_needs_protective_servicesORis_in_foster_care). These paths also satisfy the need-for-service requirement through their qualifying condition: protective and foster care are themselves needs for service (170.2(2)"b"(3)/(9)), and FIP families qualify via employment with no minimum-hours requirement, education, or PROMISE JOBS participation (170.2(2)"b"(6)–(7)) — FIP enrollment serves as the proxy since we don't track PROMISE JOBS participation at the moment.defined_for = StateCode.IA.is_ccdf_immigration_eligible_child(5-year bar).Benefit Calculation
ia_cca_max_rate(max $/half-day-unit) ×ia_cca_monthly_units.childcare_hours_per_week > 0).ia_ccais defined at MONTH; the YEAR aggregatoria_child_care_subsidiessums the 12 monthly values and feeds the federalchild_care_subsidies.Rate matrix [5 provider types × 3 age groups × 4 quality tiers × Basic/Special-Needs]:
Age group (
ia_cca_age_group) is derived fromage(infant/toddler <3, preschool <5, school-age ≥5) with the_SNrow driven byis_disabled. Quality rating and provider type are enum inputs. The In-Home rate ($36.25/unit = Iowa minimum wage $7.25/hr × 5-hr unit) pays $0 unless 3+ children in the family require care.Copay (two mechanisms)
ia_cca_copaydispatches onia_cca_in_exit_tier(enrolled & income above the CCA Plus ceiling, min(225% FPL, 85% MFI)):copay/sliding_fee/): a flat $/half-day-unit fee. The level (A–BB, 28 levels) is a bracket lookup keyed by monthly countable income × family size (1–13+); the per-unit fee column varies by number of children in care (1 / 2 / 3+). The fee is assessed on a single child — the one receiving the most units of service.copay/exit/): a percentage of the cost of care charged per child (Level A=33%, B=45%, C=60%, D=60%). The Basic vs Special-Needs income-threshold table (Levels A–D) is selected per child from the child's own special-needs status (ia_cca_exit_fee_levelis Person-level, per the fee chart's "determine which table to use for each child" instruction), and the per-child fees are summed.Copay is $0 for the no-income-test population (FIP / protective / foster).
Requirements Coverage
33 of 33 in-scope requirements are covered (see
/tmp/ia-ccap-coverage-report.md).eligibility/child_age_limit.yaml,special_needs_age_limit.yamlia_cca_eligible_childia_cca_eligible_child.yamlia_cca_eligible_child(is_ccdf_immigration_eligible_child)ia_cca_eligible_child.yamldefined_for = StateCode.IAon all top-level varsstate_code: IA)income/fpl_rate/initial_basic.yaml,initial_special_needs.yamlia_cca_income_eligibleia_cca_income_eligible.yamlincome/smi_rate.yamlia_cca_smi,ia_cca_income_eligibleia_cca_smi.yaml,ia_cca_income_eligible.yamlincome/fpl_rate/plus_basic.yaml,exit_basic.yaml,exit_special_needs.yamlia_cca_income_eligibleia_cca_income_eligible.yamlia_cca_enrolled(input)ia_cca_income_eligible.yamlia_cca_income_exceptionia_cca_income_exception.yamleligibility/asset_limit.yamlia_cca_asset_eligibleia_cca_asset_eligible.yamlactivity_requirements/weekly_hours.yaml,weekly_hours_special_needs.yamlia_cca_activity_eligibleia_cca_activity_eligible.yamlia_cca_activity_eligibleia_cca_activity_eligible.yamlia_cca_eligibleia_cca_eligible.yamlpayment/hours_per_unit.yamlia_cca_monthly_unitsia_cca_monthly_units.yamlia_ccaintegration.yamlage_group/age_group.yamlia_cca_age_group,ia_cca_max_rateia_cca_age_group.yaml,ia_cca_max_rate.yamlia_cca_provider_type,ia_cca_quality_ratingia_cca_provider_type.yaml,ia_cca_quality_rating.yamlpayment/rates/licensed_center.yamlia_cca_max_rateia_cca_max_rate.yamlpayment/rates/child_dev_home_ab.yamlia_cca_max_rateia_cca_max_rate.yamlpayment/rates/child_dev_home_c.yamlia_cca_max_rateia_cca_max_rate.yamlpayment/rates/child_care_home_not_registered.yamlia_cca_max_rateia_cca_max_rate.yamlpayment/in_home_rate.yaml,in_home_min_children.yamlia_cca_max_rateia_cca_max_rate.yamlcopay/sliding_fee/unit_fee.yaml,income_thresholds.yamlia_cca_sliding_fee_level,ia_cca_copayia_cca_sliding_fee_level.yaml,ia_cca_copay.yamlcopay/exit/fee_pct.yaml,income_thresholds_basic.yaml,income_thresholds_special_needs.yamlia_cca_exit_fee_level,ia_cca_in_exit_tier,ia_cca_copayia_cca_exit_fee_level.yaml,ia_cca_in_exit_tier.yaml,ia_cca_copay.yamlia_cca_copay(income exception → 0)ia_cca_copay.yamlincome/countable_income/earned_sources.yaml,self_employment_sources.yaml,unearned_sources.yamlia_cca_countable_incomeia_cca_countable_income.yamlincome/minor_earnings_age.yaml,minor_student_age.yamlia_cca_countable_incomeia_cca_countable_income.yamlchild_care_subsidy_programs.yaml,programs.yamlia_child_care_subsidiesia_child_care_subsidies.yamlModeling Decisions & Limitations
These are explicit, neutral notes on where the model abstracts away from operational detail. We highlight them for reviewer scrutiny.
childcare_days_per_week/childcare_hours_per_dayinputs), units are counted per day — one unit for a day of up to 5 hours, two for a longer day — times days per week, annualized monthly (× 52/12); a full-time 5-day, 8-hour schedule yields ~43.3 units/month, consistent with the overview PDF's authorized-unit accounting (~40 units with 4-week months). We don't track authorized units at the moment, so when onlychildcare_hours_per_weekis reported the units fall back to total-hours proration (weekly hours × (52/12) / 5, ~34.67 units at 40 hrs/week), which understates units for schedules that aren't exact 5-hour blocks._SNrate/threshold rows and the 19-year age limit / 28-hour activity test are driven byis_disabled.Not Modeled (by design)
meets_ccdf_activity_testfallbackBackdating
Current era only — parameters start 2024-07-01 (HF2658 / 2023 Market Rate Survey). The pre-2024 era (IAC 5/4/22: initial limit 145% FPL, 28 hrs/week with no special-needs distinction, earlier rate tables, and a different sliding-fee start) differs materially and is deferred to a follow-up PR.
Review-fix round 3 (multi-agent review)
A five-dimension adversarially-verified review pass produced these fixes (commit
40e83a8): SSI counted in unearned income (the inline comment had inverted the rule), tax-exempt interest de-duplicated (theinterest_incomeumbrella already includes it), self-employment losses floored per 170.2(1)"c"(1), the minor-earnings exclusions gated to non-head/spouse persons, the CCA Exit Basic/SN table selected per child instead of family-wide, the fee-level lookup switched to the chart's literal first-row-greater scan (non-monotonic BB row, sizes 9–13), plus citation/description corrections and 15 new test cases (exit Levels C/D, mixed Basic/SN family, BB-window regressions, countable-income edge cases).Round 4 (commit
7711778) addressed two follow-up review findings: half-day units are now counted per day when the care schedule is known (one unit for a day of up to 5 hours, two for a longer day, per 170.1 and 170.4(7)"a"), with the hours-proration retained as the fallback for hours-only inputs; and the a(2) min(225% FPL, 85% MFI) CCA Plus ceiling is now applied at the copay-mechanism dispatch, where the MFI cap binds at family sizes 10+.Test plan
policyengine-core test policyengine_us/tests/policy/baseline/gov/states/ia/hhs/cca/ -c policyengine_us); review-fix round 3 added 15 cases whose expected values were independently recomputed by simulationmake formatclean (ruff format,ruff check)Files Added