Skip to content

Conversation

@hua7450
Copy link
Collaborator

@hua7450 hua7450 commented Feb 9, 2026

Summary

Implements Iowa's Temporary Assistance for Needy Families (TANF) program, known as the Family Investment Program (FIP).

Closes #6645

Regulatory Authority

  • Iowa Code Chapter 239B
  • Iowa Administrative Code (IAC) 441, Chapters 40-46
  • Administered by the Iowa Department of Health and Human Services (HHS)

Income Eligibility Tests

Iowa uses a three-test income eligibility system:

Test 1: Gross Income Test

  • Total gross income must not exceed 185% of the Standard of Need
  • Applies to both applicants and recipients
  • Source: IAC 441-41.27(1)

Test 2: Net Income Test (Applicants Only)

  • Net income after 20% earned income deduction must be less than Standard of Need
  • Recipients skip this test (use is_tanf_enrolled to differentiate)
  • Source: IAC 441-41.27(2)

Test 3: Payment Standard Test

  • Countable income (after all applicable deductions) must be less than Payment Standard
  • Recipients receive the additional 58% work incentive disregard
  • Source: IAC 441-41.27(2)

Income Deductions & Exemptions

Deduction Rate/Amount Applies To Source
Earned income deduction 20% of gross earned income All IAC 441-41.27(2)"a"
Work incentive disregard 58% of remaining earned income Recipients only IAC 441-41.27(2)"c"
Child support disregard $50/month per eligible group All IAC 441-41.27(7)"u"

Income Standards (Effective July 1, 2025)

Persons 185% of SoN (Gross Test) Standard of Need (Net Test) Payment Standard (Benefit)
1 $675.25 $365 $183
2 $1,330.15 $719 $361
3 $1,570.65 $849 $426
4 $1,824.10 $986 $495
5 $2,020.20 $1,092 $548
6 $2,249.60 $1,216 $610
7 $2,469.75 $1,335 $670
8 $2,695.45 $1,457 $731
9 $2,915.60 $1,576 $791
10 $3,189.40 $1,724 $865
Each Addl +$320.05 +$173 +$87

Source: IAC 441-41.28

Benefit Calculation

Formula: Monthly Benefit = floor(max(Payment Standard - Countable Net Income, 0))

  • Countable earned income (applicants): Gross earned * (1 - 0.20)
  • Countable earned income (recipients): Gross earned * (1 - 0.20) * (1 - 0.58)
  • Countable unearned income: max(Gross unearned - $50 child support disregard, 0)
  • Monthly benefit rounded DOWN to whole dollar per IAC 441-45.27

Example: Recipient, family of 3, $800/month earned income

  1. Gross income test: $800 <= $1,570.65 (185% of $849) -- PASS
  2. Net income test: Skipped (recipient)
  3. 20% deduction: $800 * 0.20 = $160; After: $640
  4. 58% disregard: $640 * 0.58 = $371.20; Countable earned: $268.80
  5. Payment standard test: $268.80 < $426 -- PASS
  6. Benefit: floor($426 - $268.80) = floor($157.20) = $157

Example: Applicant, family of 3, $800/month earned income

  1. Gross income test: $800 <= $1,570.65 -- PASS
  2. 20% deduction: $800 * 0.80 = $640 (no 58% disregard for applicants)
  3. Net income test: $640 < $849 -- PASS
  4. Payment standard test: $640 >= $426 -- FAIL (ineligible)

Implementation Approach

Simplified -- Uses federal baseline variables for gross income (tanf_gross_earned_income, tanf_gross_unearned_income) and demographic/immigration eligibility (is_demographic_tanf_eligible, is_citizen_or_legal_immigrant). State-specific variables created for income standards, deductions, and benefit calculation.

Files Added

Parameters (13 files)

policyengine_us/parameters/gov/states/ia/hhs/tanf/
  income/
    child_support_disregard/amount.yaml
    earned_income_deduction/rate.yaml
    gross_income_limit/additional_person.yaml
    gross_income_limit/amount.yaml
    gross_income_limit/rate.yaml
    work_incentive_disregard/rate.yaml
  need_standard/additional_person.yaml
  need_standard/amount.yaml
  payment_standard/additional_person.yaml
  payment_standard/amount.yaml
  resources/applicant_limit.yaml
  resources/recipient_limit.yaml
  max_unit_size.yaml

Variables (10 files)

policyengine_us/variables/gov/states/ia/hhs/tanf/
  eligibility/
    ia_tanf_eligible.py
    ia_tanf_gross_income_eligible.py
    ia_tanf_net_income_eligible.py
  income/
    ia_tanf_countable_earned_income.py
    ia_tanf_countable_income.py
    ia_tanf_countable_unearned_income.py
  ia_tanf_gross_income_limit.py
  ia_tanf_need_standard.py
  ia_tanf_payment_standard.py
  ia_tanf.py

Tests (11 files, 113 test cases)

policyengine_us/tests/policy/baseline/gov/states/ia/hhs/tanf/
  ia_tanf.yaml (16 cases)
  ia_tanf_countable_earned_income.yaml (11 cases)
  ia_tanf_countable_income.yaml (8 cases)
  ia_tanf_countable_unearned_income.yaml (10 cases)
  ia_tanf_eligible.yaml (9 cases)
  ia_tanf_gross_income_eligible.yaml (9 cases)
  ia_tanf_gross_income_limit.yaml (8 cases)
  ia_tanf_need_standard.yaml (8 cases)
  ia_tanf_net_income_eligible.yaml (10 cases)
  ia_tanf_payment_standard.yaml (12 cases)
  integration.yaml (12 cases)

Test Results

  • 10 unit test files covering each variable individually
  • 1 integration test file with 12 end-to-end family scenarios
  • Edge cases: boundary conditions, sub-dollar rounding, applicant vs recipient contrast, family size overflow beyond 10
  • All 113 test cases passing

Known Simplifications

  1. $50 child support disregard: Applied to all unearned income, not just child support. This is a favorable simplification when no child support is received. Correctly isolating child support from tanf_gross_unearned_income would require additional variable decomposition.
  2. Resource limits: Parameterized ($2,000 applicants / $5,000 recipients per IAC 441-41.26(1)"e") but not enforced in the eligibility formula, consistent with other TANF implementations.
  3. Time limits: Iowa's 60-month lifetime limit cannot be tracked in PolicyEngine's single-period architecture.

References

hua7450 and others added 3 commits February 9, 2026 11:32
Starting implementation of Iowa TANF (Family Investment Program).
Documentation and parallel development will follow.
Implements Iowa's Family Investment Program (FIP) including:
- Income eligibility: gross income test (185% FPL) and net income test
- Income calculations: earned income deductions (20% work incentive + 58% earned income),
  unearned income with child support disregard
- Benefit calculation: payment standard minus countable income
- Need standard and payment standard schedules by family size
- Resource eligibility tests for applicants and recipients
- Comprehensive YAML tests including integration scenarios

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@codecov
Copy link

codecov bot commented Feb 9, 2026

Codecov Report

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

Additional details and impacted files
@@            Coverage Diff             @@
##              main     #7338    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files            1        10     +9     
  Lines           20       147   +127     
==========================================
+ Hits            20       147   +127     
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
Copy link
Collaborator Author

hua7450 commented Feb 9, 2026

PR Review

🔴 Critical (Must Fix)

  1. spm_unit_size accessed with wrong period in 3 files: ia_tanf_gross_income_limit.py:19, ia_tanf_need_standard.py:16, ia_tanf_payment_standard.py:16. All use spm_unit("spm_unit_size", period) but spm_unit_size has definition_period = YEAR and value_type = int. When accessed from a MONTH-period variable with just period, PolicyEngine divides the annual value by 12 in microsimulation — a 3-person household becomes 0.25. Must change to period.this_year. Newer TANF implementations (TN, NE, NJ, WY, CT, MS, KS, NM, WV) all use period.this_year. Unit tests pass only because they set spm_unit_size directly as input, bypassing the period conversion.

  2. $50 child support disregard applied to ALL unearned income (ia_tanf_countable_unearned_income.py:17): Per IAC 441-41.27(7)"u", the $50 exemption is specifically for "the first $50 of current monthly support obligation or voluntary support payment." The implementation subtracts $50 from total unearned income regardless of whether child support is received. A household with only pension income ($200/month, no child support) incorrectly gets a $50 disregard, understating countable unearned by $50 and inflating the benefit by up to $50/month. The PR description's "Known Simplifications" section acknowledges this, but it means households with no child support receive an incorrect benefit increase.

🟡 Should Address

  1. Orphaned resource limit parameters: resources/applicant_limit.yaml ($2,000) and resources/recipient_limit.yaml ($5,000) are defined but no ia_tanf_resources_eligible variable uses them, and ia_tanf_eligible does not check resource limits. Either implement the resource check, or remove the orphaned parameters to avoid confusion (consistent with other TANF implementations that intentionally omit resources).

  2. Unused gross_income_limit/rate.yaml parameter: The 185% rate parameter is never referenced by any variable. The gross income limit is computed from pre-calculated bracket amounts in gross_income_limit/amount.yaml. Either remove it (keep only as a reference note in the bracket file) or use it to compute limits dynamically as need_standard * rate.

  3. Net income test (Test 2) does not apply the $50 child support disregard (ia_tanf_net_income_eligible.py:25): Test 2 uses raw tanf_gross_unearned_income (no $50 disregard), while Test 3 uses ia_tanf_countable_unearned_income (with disregard). Per IAC 441-41.27(2), the net income calculation should include the same income deductions. Verify whether the $50 disregard should be applied in Test 2 as well.

  4. Immigration eligibility untested: ia_tanf_eligible.py:18 checks is_citizen_or_legal_immigrant, but no test sets a non-citizen immigration status. Every test implicitly passes this gate because the default is CITIZEN. Add at least one test with a non-citizen household to exercise this gate.

  5. Multi-earner households untested: All tests have a single earner. ia_tanf_countable_earned_income.py:15 uses add() to aggregate across persons, but this aggregation is never verified with two earners. Add a test with two working parents.

  6. Test period (2025-01) precedes parameter effective date (2025-07-01): All tests use period: 2025-01 but all parameters start at 2025-07-01. Tests pass because bracket parameters provide values regardless, but this is technically incorrect — the program isn't effective until July 2025. Consider updating test periods to 2025-07 or 2025-08, or adding earlier effective dates to parameters.

🟢 Suggestions

  1. Add a pregnant woman eligibility test: is_person_demographic_tanf_eligible includes pregnancy as a qualifying condition, but no test exercises this path in the Iowa context.

  2. Code style — intermediate variables in ia_tanf_eligible.py:25-27: payment_standard, countable_income, and benefit_positive are each used only once. Could be compressed, though the current form is readable for a 5-condition eligibility check.

  3. Reference format — Cornell Law URLs lack section anchors: All law.cornell.edu links point to the top of the regulation page. The titles correctly cite subsections (e.g., IAC 441-41.27(2)"a") but the URLs don't deep-link. Cornell Law may not support subsection anchors for Iowa Admin Code, so this may be unavoidable.

  4. Consider adding a secondary reference to the 5 files that only cite one source (child_support_disregard, earned_income_deduction, work_incentive_disregard, both resource limits`) for consistency with the other 8 files that cite two sources.


Validation Summary

Check Result
Regulatory Accuracy 1 issue (child support disregard scope)
Reference Quality All values corroborated ✅ (minor format items)
Code Patterns 2 issues (period handling, orphaned params)
Formatting (params & vars) Clean ✅
Test Coverage 113 cases, 3 gaps (immigration, multi-earner, pregnant)
CI Status All passing ✅

Overall Assessment

Strong implementation that correctly captures Iowa's three-test eligibility system, applicant/recipient distinction with is_tanf_enrolled, income deductions, and floor rounding. PR description is thorough and well-organized. The period.this_year fix is the highest priority as it will cause incorrect results in microsimulation.

Next Steps

To auto-fix issues: /fix-pr 7338

Or address manually and re-request review.

@hua7450
Copy link
Collaborator Author

hua7450 commented Feb 12, 2026

duplicate of #7171

@hua7450 hua7450 closed this Feb 12, 2026
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.

Iowa TANF payment values 2017, 2018, 2019

1 participant