Implement Georgia CCAP (Childcare and Parent Services - CAPS)#7958
Implement Georgia CCAP (Childcare and Parent Services - CAPS)#7958hua7450 wants to merge 16 commits into
Conversation
Closes PolicyEngine#7957 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ine#7957) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7958 +/- ##
==========================================
Coverage 100.00% 100.00%
==========================================
Files 1 15 +14
Lines 13 255 +242
==========================================
+ Hits 13 255 +242
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
- Remove is_tax_unit_dependent from child eligibility (use age-based check only) - Exclude children's income from countable income (CAPS Manual §8.4.3) - Apply quality bonus to net base payment, not gross rate (CCDF Plan §4767) - Correct quality bonus effective date to 2024-09-29 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rewrite ga_caps.py formula with per-child min(state max, provider published rate); add ga_caps_provider_published_rate input variable (defaults to per-child share of spm_unit_pre_subsidy_childcare_expenses). Replace np.divide(out=..., where=...) workaround with idiomatic where(). - Fix income source: military_retirement_pay -> military_basic_pay; note military_allotments has no matching PolicyEngine variable. - Register ga_caps in programs.yaml under CCDF (coverage + state_implementations). - Replace 17 broken caps.decal.ga.gov reference URLs with working ones (0-CAPS_Policy-Manual.pdf and renamed appendix files). - Correct Policy Manual, Appendix C/D, and CCDF State Plan page anchors; CCDF State Plan now references working decal.ga.gov URL with §4.3.3 (was wrongly §4.3.2 / #page=110). - Merge integration_edge.yaml into integration.yaml (Cases 8-13). - Rename ga_caps_edge.yaml -> ga_caps.yaml; merge five other *_edge.yaml files into their canonical counterparts. - Pin meets_ccdf_activity_test=false in activity tests to isolate the GA-specific 24-hour rule from the federal CCDF fallback. - Remove duplicate-date entries in quality_rated/bonus_rate.yaml. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…blished_rate Reverts the per-child lesser-of attempt from review round 2: without per-child provider published rate data, the "even share of pre_subsidy expenses" default was just a derived value from spm_unit_pre_subsidy_childcare_expenses with no new information. Matches the SPMUnit-level pattern used by RI CCAP, MA CCFA, and CO CCAP. Keeps the idiomatic where(denom > 0, ...) fix from round 2 (replaces the np.divide(out=..., where=...) workaround for the weighted-average bonus rate). Per-child lesser-of with §9.6.1's exact regulatory semantics is now unmodeled — PolicyEngine doesn't track per-child provider published rates. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… fee cutoffs - Exempt disabled heads/spouses from the GA 24-hour activity gate per Policy Manual §6.8.1.8 (disabled parent counts as care provider). Previously, two-parent units with one disabled spouse failed the GA gate and relied on the federal CCDF fallback. Also tightens `sum(...) == 0` -> `~any(...)`. - Remove 0.0001 threshold shifts in family_fee/rate.yaml. The shifted thresholds (0.1001 / 0.5001 / 1.0001) created multi-dollar gaps where income just above 10% / 50% / 100% FPL incorrectly stayed in the lower bracket (e.g., a family of 2 with $2,165 income, which is 10.005% FPL, was charged $0 instead of 3%). Now uses exact 0.1 / 0.5 / 1.0 thresholds, matching how the rest of PE encodes FPL-percentage brackets. - Add tests: disabled-parent activity Cases 14-15; refactor family_fee Cases 7-13 to test "$1 above/below" boundary behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Program Review — Georgia CAPS (PR #7958)
Source Documents
- PDFs: CAPS Policy Manual (109pp), Appendix A income limits (1pp eff. 3/2/2026), Appendix C rates+zone map (2pp eff. 3/2/2026), Appendix D family fee chart (1pp eff. 3/2/2026), CCDF State Plan FFY 25-27 (388pp)
- Year: 2026 (effective 3/2/2026)
- Scope: New state program (48 files, 4,908 additions)
CI Status
All checks pass (codecov/patch + codecov/project both pass). 136/136 YAML tests pass locally.
Critical (Must Fix)
-
Default zone overstates reimbursement for 3 GA counties —
policyengine_us/variables/gov/states/ga/decal/caps/payment/ga_caps_zone.py:29defaults unmapped GA counties toGACAPSZone.ZONE_1(highest-cost zone). Per Appendix C page 2, Ben Hill, Johnson, and Toombs are Zone 3 counties, but they're absent from policyengine-us's county enum (policyengine_us/variables/household/demographic/geographic/county/county_enum.py, which holds 154 of 159 GA counties). With the current default, households in these 3 counties would receive Zone 1 rates (e.g.$260/wk infant FT) instead of Zone 3 rates ($130/wk) — a ~2x overstatement. Fix: change theselectdefault toGACAPSZone.ZONE_3(the residual "rest of state" zone). The gap is documented inparameters/gov/states/ga/decal/caps/zone_3_counties.yamllines 100-101 but the default isn't aligned with that documentation. -
social_security_dependentsincorrectly counted as income —parameters/gov/states/ga/decal/caps/income/countable_income/sources.yamlline 17 listssocial_security_dependentsunder countable income, andtests/.../income/ga_caps_countable_income.yamlCase 8 explicitly tests it as counted. CAPS Manual §8.4.2 (p.49) explicitly excludes "disability/survivors and SSI benefits received by the Social Security Administration." Thesocial_security_dependentsvariable covers SSDI-auxiliary and survivor benefits (in addition to OAS-auxiliary), and working-age recipients (e.g. Case 8's 30-year-old) overwhelmingly receive SSDI-auxiliary or survivor benefits — both unambiguously excluded by §8.4.2. Fix: removesocial_security_dependentsfromsources.yamland flip Case 8 to assert exclusion (parallel to existing Case 9 forsocial_security_disability).
Should Address
- Page-anchor off-by-ones (4 distinct citations, 6 files) — actual page content lives one page after the cited
#page=N:parameters/gov/states/ga/decal/caps/activity_requirements/weekly_hours.yaml: Manual#page=33→#page=34(§6.8.1)parameters/gov/states/ga/decal/caps/age_threshold/child.yaml: Manual#page=29→#page=30(§6.4.1)parameters/gov/states/ga/decal/caps/age_threshold/disabled_child.yaml: Manual#page=29→#page=30(§6.4.1)variables/gov/states/ga/decal/caps/eligibility/ga_caps_activity_eligible.py: Manual#page=33→#page=34variables/gov/states/ga/decal/caps/eligibility/ga_caps_eligible_child.py: Manual#page=29→#page=30variables/gov/states/ga/decal/caps/copay/ga_caps_family_fee.py: prefer#page=55(§9.5.1 waiver criteria) over current#page=54(§9.4 lead-in), matchingfamily_fee/minor_parent_age.yaml
- PR body inconsistency — "12 countable income sources" vs
sources.yamlhas 14 — the PR-body "Income Sources" table omitssocial_security_retirementandsocial_security_dependents. After droppingsocial_security_dependents(per Critical #2), the yaml will have 13 sources; the PR body should be reconciled and a row added forsocial_security_retirement. variables/gov/states/ga/decal/caps/ga_caps_enrolled.pymissingdefault_value = False— input-only bool variable. Framework defaults toFalse, so behavior is correct, but explicitdefault_valueis the convention and improves discoverability.- 108-cell rate matrix only ~17% sampled in tests —
tests/.../payment/ga_caps_maximum_weekly_benefit.yamland integration cases collectively touch ~18/108 cells. Critical missing combinations: Informal in Zone 1 or Zone 2 (only Zone 3 Informal tested); Family PART_TIME in Zone 1; Family BEFORE_AFTER_SCHOOL in any zone; INFANT × Family in Zone 2 or 3; TODDLER × Center in Zone 2 or 3. A 4–6 case addition would close the major gaps. - No test for unlisted-county Zone 3 fallback — all Zone 3 test cases use Appling, which is in the explicit
zone_3_counties.yamllist. The implicit-Zone-3-for-unlisted-counties branch (directly related to Critical #1) is never asserted. Add one case with a Georgia county not in any of the threezone_*_counties.yamllists. - Mixed-tier Quality Rated case untested for THREE_STAR + TWO_STAR — only NONE + TWO_STAR is covered (integration Case 8). The THREE_STAR + TWO_STAR mixed-tier weighted bonus path (effective rate strictly between 0.05 and 0.10) has no test.
- No
childcare_days_per_week = 0 / 7boundary test inga_caps_maximum_weekly_benefit.yaml. - No asset boundary case at exactly $1,000,000 / $1,000,001 in
ga_caps_eligible.yaml— Case 4 uses $1.5M (well above cap). The asset check is upstream inis_ccdf_asset_eligible, but a pin would prevent silent drift. - No
base_subsidy = 0with non-NONE quality rating case —ga_caps.yamlCase 1 exercises zero base withNONErating; the multiplicative bonus onnet_base = 0is never explicitly pinned with a non-NONE rating.
Suggestions
- School-age definition tension — Appendix C uses "6 years & older" for the rate tier; Manual defines "School Age" as "at least 5 by Sept 1". A 5-year-old "school age by Manual definition" would still be billed at preschool rates under current implementation. Matches Appendix C bracketing but worth a code comment in
payment/ga_caps_age_group.py. - Activity/minor-parent gates use
is_tax_unit_head_or_spouse—eligibility/ga_caps_activity_eligible.py:15andcopay/ga_caps_family_fee.py:21identify "the parent(s)" via tax-unit headship. SPM-unit composition can diverge (e.g. grandparent caregiver in same SPM but different tax unit). Matches VA CCSP precedent; not a blocker. - Manual §6.4.1 court-ordered-supervision path not modeled —
eligibility/ga_caps_eligible_child.py:19-22documents the omission. Forced by data availability; no fix needed. - PR description omits
zone_3_counties.yamlfrom the "Files Added" list (cosmetic — file is in the diff at lines 719-833). - Appendix A and Appendix D hrefs omit
#page=1(cosmetic — both are single-page PDFs). - Title precision — a few parameter titles cite a section header rather than the leaf subsection (e.g., "Section 8.4 (Applicable Income)" instead of "Section 8.4.1"); optional polish.
ga_caps_enrolled.pymissingreferencefield (cosmetic) — a one-line link to CAPS Manual §8.3.1/§8.3.2 would aid traceability.income/ga_caps_countable_income.pycould widen reference to pages 49-50 — §8.4.3 child-earnings exclusion (implemented viais_adultfilter) is on p.50.- Add
ga_caps_countable_incometo 1-2 integration cases' output blocks to tighten the audit trail.
Investigated and Cleared (NOT real issues — highlight as strengths)
- No
sources/orlessons/agent-lessons.mdregression at repo root (unlike PR #8208 from the same author). - No
_edge.yamltest leftovers — confirmed merged into canonical counterparts per testing-patterns skill. - No federal helper duplication —
is_ccdf_immigration_eligible_child,is_ccdf_asset_eligible,meets_ccdf_activity_testconsumed directly from federal definitions. - No
spm_unit_benefits.pywiring needed —ga_child_care_subsidiesaggregator follows the parameter-registry pattern (parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml+parameters/gov/household/household_state_benefits.yaml), avoiding hard-coded Python edits. This matches the 15-state CCAP pattern (AK, CA, CO, CT, DE, MA, ME, NE, VT, NH, PA, NJ, RI, SC, VA) — cleaner than WV/WA precedent which DID modifyspm_unit_benefits.py(those edits were for non-CCAP variables). - County zone classification fully parameter-driven — no hard-coded county lists in Python.
- All 12 income sources with PE variables match Manual §8.4.1 verbatim (14 yaml entries; 12 mappable + 2 SS variants where the dependents one is the §8.4.2 issue above).
- All 4 fee tiers + 3 waivers match Appendix D and Manual §9.5.1 verbatim. Boundary semantics (
0.0001strict-inequality) explicitly tested in Cases 7, 8, 10, 11, 12, 13, 16, 17, 18. - 108/108 rate cells match Appendix C (all 18 spot-checked cells across all 3 zones, all 3 provider types, all 4 age groups, all 3 care types). Informal = Family enforced correctly.
- Period access correct throughout (
period.this_yearfor demographics/bools,periodfor flows; verified across all 9 formula variables). - All 3 §9.5.1 family-fee waivers implemented and tested — minor parent (Case 6/14), DFCS custody (Case 19), ≤10% FPL (Cases 2/5/7/16).
- Appendix A SMI math hand-verified — GA FY2026 4-person SMI $110,736 × 0.50 = $55,368 (Appendix A row 4) and × 0.85 = $94,125.60 (Appendix A row 4). Size-1 adjustment (0.52) yields $57,583; ×0.50 = $28,792 and ×0.85 = $48,946 (Appendix A row 1). All match.
- Quality Rated add-on — 5%/10% rates and 2024-09-29 effective date verbatim from CCDF Plan §4.3.3 p.69; applied to net base payment (post-fee) per the same section.
- No hard-coded numeric values in formulas — constants
MONTHS_IN_YEAR,WEEKS_IN_YEARused; bracket scales handle lookups. - Aggregator entity /
defined_for/addspatterns all match precedent (CO CCAP, MA CCFA, RI CCAP).
PDF Audit Summary
| Topic | Cells Confirmed | Mismatches |
|---|---|---|
| Eligibility (5 params) | 5 | 0 |
| Income sources (12 of 14 Manual §8.4.1 bullets w/ PE variables) | 12 | 1 (social_security_dependents — §8.4.2) |
| Family fee tiers + waivers | 4 + 3 | 0 |
| Reimbursement rates (108-cell matrix) | 108 (18 spot-checked) | 0 |
| Zone county lists | 14 + 46 + 96 (3 missing from enum) | 0 listing errors; 3 enum gaps |
| Quality Rated bonus | 2 (5%/10%) | 0 |
Validation Summary
| Check | Result |
|---|---|
| Regulatory Accuracy | Strong; 1 material exclusion error (SS dependents) and 4 minor scope/style notes |
| Reference Quality | Clean; 4 page-anchor off-by-ones to fix |
| Code Patterns | PASS with minor; no critical regressions; no sources/ / lessons/ artifacts |
| Test Coverage | Strong (127 cases, all primary boundaries covered); rate matrix only 17% sampled |
| PDF Value Audit | 0 value mismatches across ~140 audited cells |
| CI Status | All passing (codecov/patch + codecov/project) |
Recommended Severity: COMMENT (close to APPROVE)
Rationale: Strong implementation with comprehensive coverage. Two material items to address before merge: (1) the unmapped-county default-to-ZONE_1 issue that overstates reimbursement for Ben Hill/Johnson/Toombs (~2x), trivially fixed by changing the select default to ZONE_3; and (2) social_security_dependents should be excluded per Manual §8.4.2. The remaining items are page-anchor off-by-ones, the PR-body income-source count reconciliation, and a handful of polish/test-gap items. No value mismatches found in the rate matrix, family fee tiers, SMI thresholds, Quality Rated bonus, zone county lists, or eligibility thresholds.
Next Steps
- Author: fix the
ga_caps_zone.pydefault (change toZONE_3), dropsocial_security_dependentsfromsources.yamland flip Case 8, fix 4 page-anchor off-by-ones, reconcile PR-body income source list. - To auto-fix:
/fix-pr 7958
Summary
Implements Georgia Childcare and Parent Services (CAPS) — the state's CCDF-funded child care subsidy program administered by the Department of Early Care and Learning (DECAL). Models eligibility (residency, child age/disability, immigration, income, activity, assets), a 108-cell reimbursement rate table (3 zones x 3 provider types x 4 age groups x 3 care types), income-based family fees with waivers, and Quality Rated provider add-ons.
Closes #7957
Regulatory Authority
Income Eligibility Tests
ga_caps_enrolledflag: new applicants use 50% SMI threshold; enrolled families use 85% SMIIncome Sources
12 countable income types (Policy Manual §8.4):
employment_incomeself_employment_incomeunemployment_compensationworkers_compensationalimony_incomechild_support_receivedveterans_benefitscapital_gainsrental_incomedividend_incomepension_incomemilitary_basic_payListed in §8.4 but no PolicyEngine variable: military allotments, lottery payments. Commissions and cash bonuses are folded into
employment_income.Excluded income (by omission from sources list): TANF, SSI, SSA disability/survivors, adoption supplements, LIHEAP, Census Bureau income, in-kind donations, tax refunds, cash gifts, disaster relief, relative care subsidy, GBI/UBI, AmeriCorps unearned income, DECAL stipends, income from children 17 or younger.
Benefit Calculation
Subsidy formula (Policy Manual §9.6, §10):
Matches the SPMUnit-level capping pattern used by RI CCAP, MA CCFA, and CO CCAP. Per §9.6.1's exact "per-child lesser-of state max and provider's published rate" is approximated at the SPMUnit level since PolicyEngine does not track per-child provider published rates.
Rate table — 3 zones x 3 provider types x 4 age groups x 3 care types = 108 cells (Appendix C):
(Informal rates = Family rates. Part-time daily and before/after school weekly rates also included.)
Family fee tiers (Appendix D):
Quality Rated add-ons (CCDF Plan §4.3.3):
Requirements Coverage
defined_for=StateCode.GAage_threshold/child.yaml(13)ga_caps_eligible_childage_threshold/disabled_child.yaml(17)ga_caps_eligible_childis_ccdf_immigration_eligible_childga_caps_eligible_childincome/smi_rate/initial_eligibility.yaml(0.5)ga_caps_income_eligibleincome/smi_rate/ongoing_eligibility.yaml(0.85)ga_caps_income_eligiblega_caps_family_feeactivity_requirements/weekly_hours.yaml(24)ga_caps_activity_eligibleis_ccdf_asset_eligiblega_caps_eligibleincome/countable_income/sources.yamlga_caps_countable_incomega_caps_countable_incomezone_1_counties.yaml,zone_2_counties.yamlga_caps_zoneGACAPSProviderTypega_caps_provider_typeage_group/*.yamlthresholdsga_caps_age_groupGACAPSCareTypega_caps_care_typerates/center.yaml,family.yaml,informal.yamlga_caps_maximum_weekly_benefitga_capsquality_rated/bonus_rate.yamlga_caps,ga_caps_quality_ratingga_caps_family_feefamily_fee/rate.yamlga_caps_family_feega_caps_family_feefamily_fee/rate.yamltop bracketga_caps_family_feega_caps_family_fee(is_in_foster_care)family_fee/minor_parent_age.yaml(17)ga_caps_family_feefamily_fee/rate.yamltier 1 (0%)ga_caps_family_feesmi_rate/*.yaml+hhs_smiga_caps_income_eligibleNot Modeled
Files Added
Verification
Test Plan
_edge.yamlfiles merged into canonical counterparts per testing-patterns skill)meets_ccdf_activity_test: falseto isolate the GA-specific 24-hour rule from the federal CCDF fallback