Skip to content

Parameterize Head Start income eligibility: 100–130% FPG discretionary band and 2024 housing cost adjustment - #9291

Draft
PavelMakarchuk wants to merge 3 commits into
mainfrom
claude/pr-9274-review-he26r9
Draft

Parameterize Head Start income eligibility: 100–130% FPG discretionary band and 2024 housing cost adjustment#9291
PavelMakarchuk wants to merge 3 commits into
mainfrom
claude/pr-9274-review-he26r9

Conversation

@PavelMakarchuk

Copy link
Copy Markdown
Collaborator

Responds to a partner request on is_head_start_income_eligible (backs both head_start and early_head_start). Developed test-first: the reform tests were written and confirmed failing before the implementation.

What this does

Exposes two grantee-discretionary provisions of 45 CFR 1302.12 as reformable parameters. Both default to the statutory floor, so baseline behavior is unchanged — no partner contract tests are touched (the analytics_coverage suite pins is_head_start_income_eligible: false at ~100.3% FPG, inside the band, so a default change would be a partner-facing API change).

  1. gov.hhs.head_start.income_limit (default 1.0 × FPG) — §1302.12(c)(1)(i) statutory floor. §1302.12(d) lets grantees fill up to 35% of slots with families between 100% and 130% FPG; that slot-share cap is an enrollment-composition rule that can't be modeled at the household level, so the discretionary ceiling is represented by reforming this parameter to 1.3 (e.g., for screeners surfacing "possibly eligible with caveat").
  2. gov.hhs.head_start.housing_cost_adjustment (in_effect default false, income_share_threshold 0.3) — the 2024 final rule (89 FR 67720, Aug 21, 2024; effective October 2024) lets grantees deduct housing costs exceeding 30% of gross income when determining eligibility. Uses the existing housing_cost variable (rent, real estate taxes, HOA fees, mortgage payments, homeowners insurance), projected from the SPM unit.

Tests

  • New tests/policy/reform/test_head_start_income_eligibility.py: baseline floor holds at/just above FPG; baseline ignores housing costs; the band reform makes 120% and exactly 130% FPG eligible but not 135%; the housing reform deducts only the excess over 30% of gross income (19,200 ≤ 20,000 eligible; 23,200 > 20,000 not).
  • Baseline YAML guards pinning that both flexibilities are off by default.
  • Verified: Head Start baseline YAML suite (42 passed), partner contract suite (18 passed, unmodified), new reform tests (4 passed).

Draft caveats (why not ready for review yet)

  • The 30%-of-gross-income mechanics and the housing-cost definition in the 2024 rule (e.g., whether utilities count) could not be verified against the Federal Register/eCFR text from this environment (egress blocked); they follow the requesting partner's description and should be checked against the rule text before marking ready.
  • Whether the model's housing_cost component list matches the rule's definition needs the same verification.
  • Parameters are dated 2021-01-01 (matching the Head Start folder's model start) rather than the rule's October 2024 effective date, since the in_effect switch gates behavior; flagging for maintainer preference.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WHNW1s7kaFkksoyiTDoEkm


Generated by Claude Code

claude added 2 commits August 16, 2026 01:13
Expose two grantee-discretionary provisions of 45 CFR 1302.12 as
reformable parameters, both defaulting to the statutory floor so
baseline behavior (and partner contract tests) are unchanged:

- gov.hhs.head_start.income_limit (default 1.0): the 1302.12(d)
  discretionary band lets grantees serve families between 100% and
  130% of the poverty guidelines; reforms set this to 1.3. The 35%
  slot-share cap is an enrollment-composition rule that cannot be
  modeled at the household level.
- gov.hhs.head_start.housing_cost_adjustment (in_effect default
  false, income_share_threshold 0.3): the 2024 final rule
  (89 FR 67720, effective October 2024) lets grantees deduct housing
  costs exceeding 30% of gross income when determining eligibility.

Developed test-first: reform tests exercise both provisions, and
baseline YAML guards pin the unchanged default behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WHNW1s7kaFkksoyiTDoEkm
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WHNW1s7kaFkksoyiTDoEkm
@codecov

codecov Bot commented Aug 16, 2026

Copy link
Copy Markdown

Codecov Report

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

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #9291   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            1         1           
  Lines           22        16    -6     
  Branches         0         1    +1     
=========================================
- Hits            22        16    -6     
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.

…YAML

- Gate the housing cost adjustment behind a Python if on the scalar
  in_effect parameter (repo convention), so baseline runs never
  materialize the housing_cost dependency tree.
- Replace the pytest reform file with a YAML reform test using dotted
  parameter inputs: faster (no extra CountryTaxBenefitSystem builds),
  runs in the sharded YAML CI jobs, and counts toward coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WHNW1s7kaFkksoyiTDoEkm
@PavelMakarchuk
PavelMakarchuk requested a review from hua7450 August 16, 2026 05:04

@hua7450 hua7450 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for this. After reading the current eCFR text I want to restructure the approach a bit before this merges — three points.

1. Both flexibilities are current law, not reforms — they should be baseline toggles, not reform-only parameters

  • The 100–130% band is 45 CFR 1302.12(d): "A program may enroll an additional 35 percent of participants … whose incomes are below 130 percent of the poverty line."
  • The housing adjustment is in the CFR itself, not just the FR preamble — 45 CFR 1302.12(i)(1)(ii): "A program may make an adjustment to a family's gross income calculation … to account for excessive housing costs … (A) Determine if a family spends more than 30 percent of their total gross income on housing costs, as defined in part 1305; and (B) If applicable, reduce the total gross income by the amount spent on housing costs that exceed more than 30 percent."

Both are grantee-discretionary ("may"), so we shouldn't apply them universally in the microsim, but they're also not policy reforms, so gating them behind income_limit: 1.3 / in_effect: true reform edits (as this PR does) puts them in the wrong place — a screener shouldn't have to construct a reform to reach current law. Please instead model each as a baseline input variable on the SPM unit, default False, following the is_tanf_enrolled / takes_up_head_start_if_eligible pattern:

  • head_start_uses_discretionary_income_limit (bool, SPMUnit, YEAR, default False) → when true, use the 130% limit
  • head_start_applies_housing_cost_adjustment (bool, SPMUnit, YEAR, default False) → when true, deduct housing costs above 30% of gross income

Parameters become: income_limit/statutory.yaml = 1 (§1302.12(c)(1)(i)), income_limit/discretionary.yaml = 1.3 (§1302.12(d)), keep housing_cost_adjustment/income_share_threshold.yaml = 0.3 (§1302.12(i)(1)(ii)(A)), and drop housing_cost_adjustment/in_effect.yaml. The reform test file should become baseline tests that set the toggles per case.

2. Income base should be Head Start gross income per part 1305, not AGI

The pre-existing formula compares tax-unit adjusted_gross_income to FPG, but 45 CFR 1305.2 defines: "Income means gross income and only includes wages, business income, unemployment compensation, pension or annuity payments, gifts that exceed the threshold for taxable income, and military income (excluding [hostile-fire pay and BAH]) … it does not include refundable tax credits nor any forms of public assistance." Since the housing test in point 1 is 30% of that gross income, we need the right base. Please add a list parameter parameters/gov/hhs/head_start/income/sources.yaml (same shape as gov/hhs/tanf/cash/income/sources/earned.yaml):

- employment_income          # wages
- self_employment_income     # business income
- unemployment_compensation
- pension_income             # pension or annuity payments (taxable + tax-exempt)
- military_service_income    # military income; BAH/hostile-fire exclusion not separately modeled

and a head_start_gross_income variable that adds them, used by is_head_start_income_eligible. Gifts above the taxable threshold have no model variable — note that in the parameter comment. Interest, dividends, capital gains, rental, Social Security, alimony, and public assistance are excluded by the definition and should not be listed.

3. Entity

Part 1305 defines family as the persons in the household supported by the enrolling child's parents/guardians, which maps to the SPM unit better than the tax unit. The PR already reads housing_cost from the SPM unit while taking income from the tax unit, so for multi-tax-unit households the deduction is misattributed. Please move the whole comparison to the SPM unit (spm_unit_fpg, SPM-unit head_start_gross_income, SPM-unit toggles).

Happy to talk through any of this before you rewrite.

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.

3 participants