Skip to content

Implement Georgia CCAP (Childcare and Parent Services - CAPS)#7958

Open
hua7450 wants to merge 20 commits into
PolicyEngine:mainfrom
hua7450:ga-ccap
Open

Implement Georgia CCAP (Childcare and Parent Services - CAPS)#7958
hua7450 wants to merge 20 commits into
PolicyEngine:mainfrom
hua7450:ga-ccap

Conversation

@hua7450
Copy link
Copy Markdown
Collaborator

@hua7450 hua7450 commented Apr 9, 2026

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

  • Initial eligibility: gross applicable income <= 50% State Median Income (Appendix A; Policy Manual §8.3)
  • Ongoing/redetermination: gross applicable income <= 85% SMI (Appendix A; CCDF Plan §2.5.5)
  • Modeled via ga_caps_enrolled flag: new applicants use 50% SMI threshold; enrolled families use 85% SMI

Income Sources

13 countable income types (Policy Manual §8.4):

# CAPS Income Type PolicyEngine Variable
1 Gross wages/salary (incl. commissions, cash bonuses) employment_income
2 Net self-employment income self_employment_income
3 Unemployment compensation unemployment_compensation
4 Worker's compensation workers_compensation
5 Alimony alimony_income
6 Child support (regular/ongoing) child_support_received
7 Veteran's benefits veterans_benefits
8 Capital gains capital_gains
9 Rental income rental_income
10 Dividends (regular/ongoing) dividend_income
11 Retirement/pension pension_income
12 Social Security retirement social_security_retirement
13 Base pay for military personnel military_basic_pay

Listed 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):

sum_max_monthly  = sum_over_eligible_children(ga_caps_maximum_weekly_benefit) * 52/12
base_monthly     = min(spm_unit_pre_subsidy_childcare_expenses_monthly, sum_max_monthly)
net_base         = max(base_monthly - ga_caps_family_fee, 0)
weighted_bonus_rate = sum(max_weekly * quality_bonus_rate) / sum(max_weekly)
ga_caps          = net_base * (1 + weighted_bonus_rate)

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):

Zone Provider Infant FT/wk Toddler FT/wk Preschool FT/wk School FT/wk
1 Center $260 $248 $221 $185
1 Family $199 $188 $180 $156
2 Center $165 $160 $150 $140
2 Family $145 $140 $135 $135
3 Center $130 $125 $120 $115
3 Family $120 $110 $105 $94

(Informal rates = Family rates. Part-time daily and before/after school weekly rates also included.)

Family fee tiers (Appendix D):

Income-to-FPL Ratio Fee Rate
<= 10% 0% (no fee)
> 10% to 50% 3% of income
> 50% to 100% 5% of income
> 100% 7% of income (federal cap)
  • Fee is per-family, not per-child
  • Weekly fee = floor(annual_income * rate / 52), converted to monthly
  • Fee waived (§ 9.5.1) for minor parents (age <= 17), children in DFCS custody, or income <= 10% FPL

Quality Rated add-ons (CCDF Plan §4.3.3):

  • 2-star: 5% bonus on net base payment
  • 3-star: 10% bonus on net base payment

Requirements Coverage

REQ Description Parameter Variable Test
REQ-001 Georgia residency defined_for=StateCode.GA all variables integration.yaml Case 7
REQ-002 Child age <= 12 age_threshold/child.yaml (13) ga_caps_eligible_child eligible_child.yaml Cases 1-3
REQ-003 Disabled child age <= 17 age_threshold/disabled_child.yaml (17) ga_caps_eligible_child eligible_child.yaml Cases 4-6
REQ-004 Child citizenship (INA/45 CFR 98.20) federal is_ccdf_immigration_eligible_child ga_caps_eligible_child eligible_child.yaml Cases 7-8, 16
REQ-008 Initial income <= 50% SMI income/smi_rate/initial_eligibility.yaml (0.5) ga_caps_income_eligible income_eligible.yaml Cases 1-2, 7-8
REQ-009 Ongoing income <= 85% SMI income/smi_rate/ongoing_eligibility.yaml (0.85) ga_caps_income_eligible income_eligible.yaml Cases 3-5, 9-10
REQ-010 Very low income priority (50% FPL) Captured by fee tier (REQ-025/REQ-030) ga_caps_family_fee family_fee.yaml Cases 2, 7
REQ-011 Activity: 24 hrs/week activity_requirements/weekly_hours.yaml (24) ga_caps_activity_eligible activity_eligible.yaml Cases 1-13 (Case 13 verifies CCDF fallback)
REQ-012 Asset test ($1M) federal is_ccdf_asset_eligible ga_caps_eligible eligible.yaml Case 4
REQ-013 13 countable income sources income/countable_income/sources.yaml ga_caps_countable_income income_eligible.yaml Case 15
REQ-014 Excluded income types Implicit (omitted from sources) ga_caps_countable_income income tests
REQ-015 4-week annualization method Implicit (PE uses annual income) -- --
REQ-016 Family unit composition SPMUnit entity all SPM-unit variables all SPM-unit tests
REQ-017 3 geographic zones (county-based) zone_1_counties.yaml, zone_2_counties.yaml ga_caps_zone zone.yaml Cases 1-7
REQ-018 Provider type (Center/Family/Informal) enum GACAPSProviderType ga_caps_provider_type maximum_weekly_benefit.yaml Cases 1-9
REQ-019 4 child age groups age_group/*.yaml thresholds ga_caps_age_group age_group.yaml Cases 1-7
REQ-020 Care type (FT/PT/Before-After) enum GACAPSCareType ga_caps_care_type maximum_weekly_benefit.yaml Cases 10-18
REQ-021 108-cell rate table rates/center.yaml, family.yaml, informal.yaml ga_caps_maximum_weekly_benefit maximum_weekly_benefit.yaml (18 cases)
REQ-022 Subsidy = min(max, expenses) - fee, with QR bonus -- ga_caps ga_caps.yaml, integration.yaml
REQ-023 Quality Rated add-on (5%/10%) quality_rated/bonus_rate.yaml ga_caps, ga_caps_quality_rating ga_caps.yaml Cases 2-4
REQ-024 Family fee is per-family -- (SPMUnit entity) ga_caps_family_fee family_fee.yaml
REQ-025 Fee tiers by FPL ratio (4 tiers) family_fee/rate.yaml ga_caps_family_fee family_fee.yaml Cases 1-4, 8-13
REQ-026 Weekly fee = floor(income * rate / 52) -- ga_caps_family_fee family_fee.yaml
REQ-027 Max copay cap 7% family_fee/rate.yaml top bracket ga_caps_family_fee family_fee.yaml Case 1
REQ-028 Fee waiver: DFCS custody -- ga_caps_family_fee (is_in_foster_care) family_fee.yaml Case 19
REQ-029 Fee waiver: minor parents <= 17 family_fee/minor_parent_age.yaml (17) ga_caps_family_fee family_fee.yaml Cases 6, 14
REQ-030 Fee waiver: income <= 10% FPL family_fee/rate.yaml tier 1 (0%) ga_caps_family_fee family_fee.yaml Cases 2, 7-8
REQ-038 Income limits from SMI/FPL smi_rate/*.yaml + hhs_smi ga_caps_income_eligible income_eligible.yaml Cases 12-14

Not Modeled

What Source Why Excluded
REQ-005: Immunization requirement Policy Manual §6 Administrative verification, not a financial variable
REQ-006: Proof of identity Policy Manual §6 Administrative verification, not a financial variable
REQ-007: Priority group membership Policy Manual §7 Complex categorical; group 13 is catch-all so effectively all eligible families qualify
REQ-031: Registration fee ($65/child) Policy Manual §10 One-time administrative cost, not recurring subsidy
REQ-032: 12-month eligibility period Policy Manual Time-based administrative rule; PE models point-in-time eligibility
REQ-033: Fee protection (no mid-period increases) Policy Manual Time-based administrative rule; requires temporal state tracking
REQ-034: Graduated phase-out Policy Manual Captured by entry vs. ongoing thresholds (REQ-008/REQ-009)
REQ-035: Age transition timing (Monday after birthday) Policy Manual §10 Intra-month timing; PE uses annual/monthly periods
REQ-036: Disability negotiated rate Policy Manual §10 Case-by-case administrative decision, no standard formula
REQ-037: 15% QR discount removal Policy Manual Already removed (10/06/2025), before our effective date
Per-child lesser-of (state max vs published rate) Policy Manual §9.6.1 PolicyEngine does not track per-child provider published rates; cap applied at SPMUnit total (same pattern as RI/MA/CO childcare)
Variable Schedule Scholarship (VSS) Policy Manual §10 Combines B&A, FT, and PT rates dynamically; collapsed to a single dominant care type
Military allotments Policy Manual §8.4 No matching PolicyEngine variable

Files Added

parameters/gov/states/ga/decal/caps/
  age_threshold/child.yaml
  age_threshold/disabled_child.yaml
  age_group/toddler_min.yaml
  age_group/preschool_min.yaml
  age_group/school_age_min.yaml
  activity_requirements/weekly_hours.yaml
  income/smi_rate/initial_eligibility.yaml
  income/smi_rate/ongoing_eligibility.yaml
  income/countable_income/sources.yaml
  family_fee/rate.yaml
  family_fee/minor_parent_age.yaml
  quality_rated/bonus_rate.yaml
  zone_1_counties.yaml
  zone_2_counties.yaml
  zone_3_counties.yaml
  rates/center.yaml
  rates/family.yaml
  rates/informal.yaml

variables/gov/states/ga/decal/caps/
  ga_caps.py
  ga_caps_enrolled.py
  ga_child_care_subsidies.py
  eligibility/ga_caps_eligible.py
  eligibility/ga_caps_eligible_child.py
  eligibility/ga_caps_income_eligible.py
  eligibility/ga_caps_activity_eligible.py
  income/ga_caps_countable_income.py
  copay/ga_caps_family_fee.py
  payment/ga_caps_zone.py
  payment/ga_caps_provider_type.py
  payment/ga_caps_care_type.py
  payment/ga_caps_age_group.py
  payment/ga_caps_quality_rating.py
  payment/ga_caps_maximum_weekly_benefit.py

tests/policy/baseline/gov/states/ga/decal/caps/
  integration.yaml
  ga_caps.yaml
  eligibility/ga_caps_eligible.yaml
  eligibility/ga_caps_eligible_child.yaml
  eligibility/ga_caps_income_eligible.yaml
  eligibility/ga_caps_activity_eligible.yaml
  copay/ga_caps_family_fee.yaml
  payment/ga_caps_zone.yaml
  payment/ga_caps_age_group.yaml
  payment/ga_caps_maximum_weekly_benefit.yaml

programs.yaml — Georgia registered under CCDF state_implementations

Verification

  • Reimbursement rates verified against Appendix C (108/108 cells match, 600 DPI confirmed)
  • Income limits verified against Appendix A (50% SMI / 85% SMI thresholds — Appendix A supersedes CCDF Plan §2.2.4's outdated 40%)
  • Family fee tiers verified against Appendix D (4 FPL brackets, "above X%" boundary semantics with 0.0001 shift)
  • Quality Rated add-ons verified against CCDF Plan §4.3.3 (5%/10% rates)
  • Zone county assignments verified against Appendix C zone map (14 Zone 1 + 46 Zone 2 counties match)
  • CI passes

Test Plan

  • 10 test files covering eligibility, income, fees, rates, zones, integration (_edge.yaml files merged into canonical counterparts per testing-patterns skill)
  • Activity-eligibility tests pin meets_ccdf_activity_test: false to isolate the GA-specific 24-hour rule from the federal CCDF fallback
  • All 127 GA CAPS tests pass locally
  • CI passes

hua7450 and others added 4 commits April 8, 2026 23:36
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
Copy link
Copy Markdown

codecov Bot commented Apr 9, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (7078494) to head (ac7b73e).
⚠️ Report is 14 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##              main     #7958    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files            1        15    +14     
  Lines           16       255   +239     
==========================================
+ Hits            16       255   +239     
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 Sentry.
📢 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 7 commits April 9, 2026 01:20
- 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>
@hua7450 hua7450 marked this pull request as ready for review May 14, 2026 22:27
@hua7450 hua7450 marked this pull request as draft May 14, 2026 22:37
hua7450 and others added 4 commits May 14, 2026 18:43
… 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>
@hua7450 hua7450 requested a review from PavelMakarchuk May 20, 2026 05:17
@hua7450 hua7450 marked this pull request as ready for review May 20, 2026 05:17
Copy link
Copy Markdown
Collaborator

@PavelMakarchuk PavelMakarchuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

  1. Default zone overstates reimbursement for 3 GA countiespolicyengine_us/variables/gov/states/ga/decal/caps/payment/ga_caps_zone.py:29 defaults unmapped GA counties to GACAPSZone.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 the select default to GACAPSZone.ZONE_3 (the residual "rest of state" zone). The gap is documented in parameters/gov/states/ga/decal/caps/zone_3_counties.yaml lines 100-101 but the default isn't aligned with that documentation.

  2. social_security_dependents incorrectly counted as incomeparameters/gov/states/ga/decal/caps/income/countable_income/sources.yaml line 17 lists social_security_dependents under countable income, and tests/.../income/ga_caps_countable_income.yaml Case 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." The social_security_dependents variable 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: remove social_security_dependents from sources.yaml and flip Case 8 to assert exclusion (parallel to existing Case 9 for social_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=34
    • variables/gov/states/ga/decal/caps/eligibility/ga_caps_eligible_child.py: Manual #page=29#page=30
    • variables/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), matching family_fee/minor_parent_age.yaml
  • PR body inconsistency — "12 countable income sources" vs sources.yaml has 14 — the PR-body "Income Sources" table omits social_security_retirement and social_security_dependents. After dropping social_security_dependents (per Critical #2), the yaml will have 13 sources; the PR body should be reconciled and a row added for social_security_retirement.
  • variables/gov/states/ga/decal/caps/ga_caps_enrolled.py missing default_value = False — input-only bool variable. Framework defaults to False, so behavior is correct, but explicit default_value is the convention and improves discoverability.
  • 108-cell rate matrix only ~17% sampled in teststests/.../payment/ga_caps_maximum_weekly_benefit.yaml and 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.yaml list. 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 three zone_*_counties.yaml lists.
  • 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 / 7 boundary test in ga_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 in is_ccdf_asset_eligible, but a pin would prevent silent drift.
  • No base_subsidy = 0 with non-NONE quality rating casega_caps.yaml Case 1 exercises zero base with NONE rating; the multiplicative bonus on net_base = 0 is 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_spouseeligibility/ga_caps_activity_eligible.py:15 and copay/ga_caps_family_fee.py:21 identify "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 modeledeligibility/ga_caps_eligible_child.py:19-22 documents the omission. Forced by data availability; no fix needed.
  • PR description omits zone_3_counties.yaml from 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.py missing reference field (cosmetic) — a one-line link to CAPS Manual §8.3.1/§8.3.2 would aid traceability.
  • income/ga_caps_countable_income.py could widen reference to pages 49-50 — §8.4.3 child-earnings exclusion (implemented via is_adult filter) is on p.50.
  • Add ga_caps_countable_income to 1-2 integration cases' output blocks to tighten the audit trail.

Investigated and Cleared (NOT real issues — highlight as strengths)

  1. No sources/ or lessons/agent-lessons.md regression at repo root (unlike PR #8208 from the same author).
  2. No _edge.yaml test leftovers — confirmed merged into canonical counterparts per testing-patterns skill.
  3. No federal helper duplicationis_ccdf_immigration_eligible_child, is_ccdf_asset_eligible, meets_ccdf_activity_test consumed directly from federal definitions.
  4. No spm_unit_benefits.py wiring neededga_child_care_subsidies aggregator 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 modify spm_unit_benefits.py (those edits were for non-CCAP variables).
  5. County zone classification fully parameter-driven — no hard-coded county lists in Python.
  6. 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).
  7. All 4 fee tiers + 3 waivers match Appendix D and Manual §9.5.1 verbatim. Boundary semantics (0.0001 strict-inequality) explicitly tested in Cases 7, 8, 10, 11, 12, 13, 16, 17, 18.
  8. 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.
  9. Period access correct throughout (period.this_year for demographics/bools, period for flows; verified across all 9 formula variables).
  10. 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).
  11. 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.
  12. 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.
  13. No hard-coded numeric values in formulas — constants MONTHS_IN_YEAR, WEEKS_IN_YEAR used; bracket scales handle lookups.
  14. Aggregator entity / defined_for / adds patterns 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.py default (change to ZONE_3), drop social_security_dependents from sources.yaml and flip Case 8, fix 4 page-anchor off-by-ones, reconcile PR-body income source list.
  • To auto-fix: /fix-pr 7958

hua7450 and others added 3 commits May 31, 2026 11:18
…hors

- Default unmapped GA counties to Zone 3 (residual) instead of Zone 1,
  fixing ~2x reimbursement overstatement for Ben Hill/Johnson/Toombs
  (Appendix C zone map)
- Exclude social_security_dependents from countable income per CAPS
  Manual §8.4.2 (SSA disability/survivors); flip countable income Case 8
  to assert exclusion
- Fix 4 Policy Manual page anchors: §6.8.1 page 33->34, §6.4.1 page
  29->30, §9.5.1 page 54->55

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hua7450
Copy link
Copy Markdown
Collaborator Author

hua7450 commented Jun 1, 2026

Thanks for the thorough review, @PavelMakarchuk! All addressed in bb50a17.

Critical fixes

  1. Zone default → Zone 3. Changed the select default (and the variable's default_value) in ga_caps_zone.py from ZONE_1 to ZONE_3, so Ben Hill, Johnson, Toombs, and any county not yet in the enum now fall to the residual "rest of state" zone instead of the highest-cost zone — fixing the ~2× reimbursement overstatement. Also updated the now-stale "— default" annotation in the zone test comment.

  2. social_security_dependents excluded. Removed it from income/countable_income/sources.yaml per Manual §8.4.2 (SSA disability/survivors), and flipped ga_caps_countable_income.yaml Case 8 to assert exclusion (output 0), paralleling Case 9 for social_security_disability.

Page anchors — fixed all four off-by-ones:

  • §6.8.1 #page=33 → 34 (weekly_hours.yaml, ga_caps_activity_eligible.py)
  • §6.4.1 #page=29 → 30 (age_threshold/child.yaml, age_threshold/disabled_child.yaml, ga_caps_eligible_child.py)
  • §9.5.1 #page=54 → 55 (ga_caps_family_fee.py)

PR body — reconciled the income-source count (now 13) and added the social_security_retirement row.

On ga_caps_enrolled's default_value: left it off, since the framework already defaults bool inputs to False — happy to add the explicit form if you'd prefer it.

The remaining test-coverage suggestions (rate-matrix sampling, unlisted-county fallback case, mixed-tier QR path, boundary pins) are noted — let me know if you'd like those in this PR or a follow-up.

@hua7450 hua7450 requested review from PavelMakarchuk June 1, 2026 13:33
Copy link
Copy Markdown
Collaborator

@PavelMakarchuk PavelMakarchuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Program Review — PR #7958 (Georgia CAPS, new program)

Repository: PolicyEngine/policyengine-us
Author: ziming
Program: Georgia Childcare and Parent Services (CAPS), DECAL, CCDF-funded
Year: 2026 (effective 3/2/2026)
Scope: 19 parameters, 14 variables, 10 YAML test files (127 cases), programs.yaml registry entry

Source Documents

🔴 Critical (Must Fix)

None.

CI is 26/26 PASS. No hard-coded values, no missing references, no incorrect formulas, no real value mismatches against source PDFs (108/108 rate cells confirmed, 14+46 zone counties confirmed, 9 family-fee parameters confirmed, 5 eligibility parameters confirmed).

🟡 Should Address

Regulatory accuracy

  1. CAPS → labor-supply → CAPS circularity in policyengine_us/variables/gov/states/ga/decal/caps/eligibility/ga_caps_activity_eligible.py: the activity test reads post-LSR weekly hours. Switch to weekly_hours_worked_before_lsr to break the feedback loop, mirroring the established SNAP labor-supply pattern.
  2. Period mismatch on policyengine_us/parameters/gov/states/ga/decal/caps/activity_requirements/weekly_hours.yaml: declared period: year but the value represents a weekly threshold (24h/wk). Should be period: eternity (matches how other weekly-threshold parameters are encoded).
  3. social_security_retirement countable-income scope (income/countable_income/sources.yaml): confirm this variable already captures survivor-insurance payments as required by CAPS Policy Manual §8.4.1 glossary (line 855). If not, add a survivor-benefits source or extend the variable's scope.

References (page anchors / scope)

  1. age_threshold/child.yaml & age_threshold/disabled_child.yaml cite Policy Manual #page=30, but §6.4 content is on printed/PDF page 29. Update anchors.
  2. activity_requirements/weekly_hours.yaml cites #page=34, but §6.8 heading and the 24-hour value are on printed page 33. Update anchor.
  3. 3 single-page-PDF references missing #page=1income/smi_rate/initial_eligibility.yaml, income/smi_rate/ongoing_eligibility.yaml, family_fee/rate.yaml. Add anchors for consistency.
  4. family_fee/minor_parent_age.yaml cites "§9.5", but the corroborating sub-clause is §9.5.1. Tighten the citation.
  5. Parameter count discrepancy: PR description claims 19 parameters; diff shows 18. Possibly an asset-limit parameter was dropped (CAPS relies on federal is_ccdf_asset_eligible). Clarify in PR body.

Code / parameters

  1. ga_caps.py:49-53 numpy division-warning suppression should mirror the pattern in ga_caps_family_fee.py:31-36 (use np.errstate(divide='ignore', invalid='ignore') with explicit np.where masking). Cosmetic but consistent.

Document source choice

  1. Disabled-child age boundary: CAPS Policy Manual §6.4.1 sets age 17; CCDF State Plan §2.2.1(b)(i) (page 19) sets age 18. PR picked 17 (more restrictive, more recent). This is defensible — ask author to add a one-line comment in age_threshold/disabled_child.yaml noting the source choice and conflict so future maintainers don't "fix" it to 18.

Test gaps (high priority)

  1. Multi-child different QR ratings (e.g., 2-star + 3-star siblings) — exercises the weighted Quality Rated bonus formula across children.
  2. §8.4.2 excluded-income types — verify TANF / SSI / LIHEAP / cash gifts are excluded from ga_caps_countable_income.
  3. Same-household zone swap — same household run through Zones 1, 2, 3 to confirm rate table is wired correctly to ga_caps_zone.
  4. Division-safe path: case where sum_max_weekly = 0 (e.g., no eligible children / zero rate) — confirms ga_caps.py does not raise and returns 0.
  5. End-to-end aggregation wiring: ga_capsga_child_care_subsidieschild_care_subsidieshousehold_state_benefits. Currently relies on individual unit tests; add an integration test that asserts non-zero flow at each level.

🟢 Suggestions

  • Description-template conformance on age_threshold/child.yaml and age_threshold/disabled_child.yaml (use the standard "The maximum age …" template).
  • ga_caps_family_fee.py: idiomatic np.where() style (already correct; only a polish suggestion).
  • Document the Quality Rated per-child default-NONE approximation — when QR rating is unknown, treated as no bonus. Add a brief docstring comment so users understand the conservative default.
  • Rate-table coverage gaps in tests: add Family Preschool, Informal Infant/Toddler, and Zone-3 Center FT cases to cover currently-untested cells.
  • Add a VSS (variable special support / very-special-services) collapse test if those flags are intended to be supported.

PDF Audit Summary

Category Count
Confirmed correct against PDFs 130+ (108 rate cells, 14 Zone-1 + 46 Zone-2 counties, 9 fee params, 5 eligibility)
Real value mismatches 0
Mismatches investigated and cleared (MONTH/YEAR auto-conversion in ga_caps_income_eligible) 1 — false positive (PolicyEngine auto-divides YEAR-defined flow variables in MONTH formulas; identical pattern in ma_ccfa_income_eligible.py; boundary tests at $1 increments confirm correctness)
Source-conflict items (Policy Manual §6.4.1 age 17 vs CCDF Plan §2.2.1(b)(i) age 18) 1 — author chose more restrictive; document inline
Missing-feature gaps 0 PR-blocking (3 Zone-3 counties — Ben Hill, Johnson, Toombs — missing from PE-US county enum; already documented with inline comment, not a blocker)
Defensible "Not Modeled" exclusions All — DFCS-custody waiver implemented via is_in_foster_care; verify against full §9.5.1 text (low priority)

Validation Summary

Check Result
Regulatory accuracy 0 critical, 3 should-fix
Reference quality 0 critical, 5 should-fix (page anchors + §9.5.1 scope + parameter-count discrepancy)
Code patterns 0 critical, 2 polish items
Test coverage 5 high-priority gaps, several lower-priority suggestions
PDF value audit 0 real mismatches (108/108 rates, 14+46 zones, 9 fees, 5 eligibility); 1 false-positive cleared; 1 source-conflict (disabled age)
CI 26/26 PASS

Verified Correct (Highlights)

  • 108/108 reimbursement rate cells match Appendix C exactly (3 zones × 3 provider types × 4 age groups × 3 care types).
  • All 14 Zone-1 counties and all 46 Zone-2 counties match the Appendix C zone map exactly.
  • 9 family-fee parameters match Appendix D exactly.
  • 5 eligibility parameters match Policy Manual + Appendix A.
  • Federal CCDF helpers (is_ccdf_asset_eligible, is_ccdf_immigration_eligible_child, meets_ccdf_activity_test) correctly wired — no reinvention.
  • ga_caps_enrolled parallels the established sibling pattern (ma_ccfa_enrolled, ri_ccap_enrolled).
  • Regulatory agent numerically traced integration Case 1 ($30K employment → $173.33 monthly family fee) and verified end-to-end correctness.

Review Severity: APPROVE (with should-fix items)

No critical blockers. Should-fix items are quality polish (period metadata, page anchors, circularity hardening, test coverage). Recommend the author address the should-fix list in a follow-up commit before merge; suggestions can be deferred.

hua7450 and others added 2 commits June 2, 2026 15:47
…ations

- Read weekly_hours_worked_before_lsr in activity test to break the
  CAPS -> net income -> labor supply response -> hours -> CAPS loop
  (mirrors SNAP); update test inputs to match
- weekly_hours.yaml period: year -> week (weekly-hours threshold)
- ga_caps.py: use np.divide(out=, where=) for the Quality Rated bonus
  rate, matching ga_caps_family_fee.py division-warning suppression
- Fix page anchors against the Policy Manual PDF: weekly_hours and
  activity_eligible -> page 33 (6.8.1); child age -> page 29 (6.4.1);
  disabled_child kept at page 30 (6.4.3); tighten 6.4/9.5 citations
- Document disabled-child age source conflict (Manual 6.4.3 = 17 vs
  CCDF 2.2.1(b)(i) = 18; follow Manual)

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

# Conflicts:
#	policyengine_us/programs.yaml
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.

Implement Georgia CCAP (Childcare and Parent Services - CAPS)

2 participants