Skip to content

Add Iowa TANF Program#7171

Merged
hua7450 merged 36 commits intoPolicyEngine:mainfrom
llennemann:ia-tanf
Feb 13, 2026
Merged

Add Iowa TANF Program#7171
hua7450 merged 36 commits intoPolicyEngine:mainfrom
llennemann:ia-tanf

Conversation

@llennemann
Copy link
Collaborator

@llennemann llennemann commented Jan 14, 2026

Summary

Implements Iowa's Family Investment Program (FIP), the state's TANF cash assistance program.

Closes #7163
Closes #6645

Regulatory Authority

Income Eligibility Tests

Iowa FIP uses a three-step income eligibility process for applicants and a two-step process for continuing recipients:

Test 1: Gross Income Test (All)

Test 2: Net Income Test (Applicants Only)

  • Net income < Standard of Need
  • Net income = Gross income - 20% earned income deduction
  • Source: IAC 441-41.27(2)(a)

Test 3: Countable Income Test (All)

  • Countable income < Payment Standard
  • Countable income applies both 20% earned income deduction AND 58% work incentive disregard
  • Source: IAC 441-41.27(2)(c)

Income Deductions & Exemptions

Deduction Rate Applies To Source
Earned Income Deduction 20% Gross earned income IAC 441-41.27(2)(a)
Work Incentive Disregard 58% Income after 20% deduction IAC 441-41.27(2)(c)

Income Standards

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

Source: IAC 441-41.28(2)

Resource Limits

Status Limit Source
Applicant $2,000 IAC 441-41.26(1)(e)
Recipient $5,000 IAC 441-41.26(1)(e)

Benefit Calculation

Benefit = Payment Standard - Countable Income

Where:

  • Countable Income = (Gross Earned × 0.8 × 0.42) + Gross Unearned

Source: IAC 441-41.27(2)

Historical Note

Iowa's FIP payment standards have remained unchanged since at least January 1997 (source: 1998 Green Book Table 7-8). The work incentive disregard was increased from 50% to 58% effective August 1, 2007.

llennemann and others added 12 commits January 14, 2026 17:25
Starting implementation of Iowa TANF (Family Investment Program).
Documentation and parallel development will follow.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Schedule of Living Costs for Iowa FIP (Family Investment Program):
- Main parameter with family sizes 1-10
- Additional amount for families larger than 10

Per 441 IAC 41.28(239B), effective 7/1/2025.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Schedule of Basic Needs for Iowa FIP:
- Main parameter with family sizes 1-10
- Additional amount for families larger than 10

Per 441 IAC 41.28(239B), effective 7/1/2025.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add FIP income parameters:
- 20% earned income deduction rate
- 58% work incentive disregard rate
- 185% gross income limit (percent of standard of need)

Per 441 IAC 41.27(239B), effective 7/1/2025.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add FIP resource limits:
- Applicant families: $2,000
- Recipient families: $5,000

Per 441 IAC 41.26(239B).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add FIP variables:
- ia_tanf_standard_of_need: Schedule of Living Costs by family size
- ia_tanf_payment_standard: Schedule of Basic Needs by family size
- ia_tanf_eligible: Overall eligibility combining demographic and income tests

Per 441 IAC 41.27(239B) and 41.28(239B).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add FIP income test variables:
- ia_tanf_income_eligible: Combined income eligibility
- ia_tanf_gross_income_eligible: Test 1 (185% of standard of need)
- ia_tanf_net_income_eligible: Test 2 (after 20% deduction)
- ia_tanf_payment_standard_eligible: Test 3 (after work incentive)

Per 441 IAC 41.27(239B).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add FIP income source parameters:
- Earned income sources (employment, self-employment)
- Unearned income sources (social security, SSI, unemployment, etc.)

Add FIP income variables:
- ia_tanf_gross_earned_income: Total earned income
- ia_tanf_gross_unearned_income: Total unearned income
- ia_tanf_gross_income: Combined gross income
- ia_tanf_countable_income: Net income after 20% deduction and 58% work incentive

Per 441 IAC 41.27(239B).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add main ia_tanf variable that calculates the FIP benefit amount:
- Benefit = Payment Standard - Countable Income
- Eligible households get max(payment_standard - countable_income, 0)

Per 441 IAC 41.28(239B).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add test cases for ia_tanf:
- Unit tests for benefit calculation
- Integration test based on documentation example (family of 3, $800/month)
- Integration test for gross income limit failure

Per 441 IAC 41.27(239B) and 41.28(239B).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Apply black formatting to ia_tanf_net_income_eligible.py

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@codecov
Copy link

codecov bot commented Jan 19, 2026

Codecov Report

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

Additional details and impacted files
@@             Coverage Diff              @@
##             main     #7171       +/-   ##
============================================
+ Coverage   73.03%   100.00%   +26.96%     
============================================
  Files        3819        12     -3807     
  Lines       55013       165    -54848     
  Branches      274         0      -274     
============================================
- Hits        40177       165    -40012     
+ Misses      14815         0    -14815     
+ Partials       21         0       -21     
Flag Coverage Δ
unittests 100.00% <100.00%> (+26.96%) ⬆️

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.

llennemann and others added 7 commits January 19, 2026 04:42
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactored Iowa TANF implementation to use FIP (Family Investment Program)
naming convention which is the official state program name. Added 11 tests
covering unit tests, integration tests with various income scenarios,
and edge cases including large families and non-Iowa states.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add individual test files for each Iowa FIP variable following the
Arizona TANF pattern from PR PolicyEngine#7150:

- ia_fip_eligible.yaml (8 tests)
- ia_fip_income_eligible.yaml (8 tests)
- ia_fip_payment_standard.yaml (8 tests)
- ia_fip_standard_of_need.yaml (8 tests)
- ia_fip_countable_income.yaml (8 tests)
- ia_fip_gross_income.yaml (6 tests)
- ia_fip_gross_earned_income.yaml (7 tests)
- ia_fip_gross_unearned_income.yaml (10 tests)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@llennemann llennemann marked this pull request as ready for review January 21, 2026 17:09
@llennemann llennemann requested a review from hua7450 January 21, 2026 17:17
@llennemann llennemann self-assigned this Jan 21, 2026
@llennemann
Copy link
Collaborator Author

Dates for parameters values in Iowa TANF payment values 2017, 2018, 2019 #6645.

@hua7450 Should I add Iowa TANF to the state level aggregation level? in tanf.py
Also, for the immigration check, the Iowa State TANF plan states that "Each member of the eligible group must be a citizen or qualified alien." Does the immigration eligibility look right to you?

@PavelMakarchuk
Copy link
Collaborator

PR Review - Iowa Family Investment Program (FIP/TANF) Implementation

🔴 Critical Issues (Must Fix Before Merge)

None identified. The implementation correctly follows Iowa Administrative Code regulations.


🟡 Should Address

1. Missing Dedicated Test Files

Two variables with formulas lack dedicated unit test files:

  • ia_fip_resource_eligible - Only tested indirectly via ia_fip_eligible.yaml
  • ia_fip_countable_earned_income - Only tested indirectly via ia_fip_countable_income.yaml

Action: Create dedicated test files for these variables.

2. Missing Boundary Tests at Exact Thresholds

The implementation uses <= and < comparisons that need boundary testing:

Threshold Current Tests Missing Test
Applicant resource limit ($2,000) Above limit only Exactly $2,000, exactly $2,001
Recipient resource limit ($5,000) Above limit only Exactly $5,000, exactly $5,001
185% gross income limit Above limit only Exactly at threshold
Net income = standard of need Above only Exactly equal (should fail with <)
Countable = payment standard Above only Exactly equal (should fail with <)

3. Reference Format Issues

Several parameter files have inline comments in href fields:

# Current (unconventional):
href: https://hhs.iowa.gov/media/17445/download?inline#page=7 # (3)

# Should be:
- title: Iowa TANF State Plan 2025, Section (3)
  href: https://hhs.iowa.gov/media/17445/download?inline#page=7

Files affected: work_incentive_disregard.yaml, max_unit_size.yaml, payment_standard/*.yaml, resources/*.yaml

4. Missing Page Anchors on PDF References

Files: resources/applicant_limit.yaml, resources/recipient_limit.yaml

  • IAC PDF links missing #page=XX anchors

5. Description Typo

File: need_standard/additional.yaml

  • "families larger than than the max" → "families larger than the max"

🟢 Suggestions

  1. Family size 11+ value verification: The large family integration test doesn't explicitly verify the calculated payment/need standard values. Add tests that verify $865 + $87 = $952/month for size 11.

  2. Period consistency: ia_fip_payment_standard.py and ia_fip_standard_of_need.py use period for spm_unit_size - consider period.this_year for consistency with count variables.

  3. Cliff effect test: Add an integration test showing benefit dropping to $0 at the exact payment standard threshold.


✅ What's Implemented Correctly

Component Verification
Three-step income eligibility ✓ Gross (185% SoN) → Net (< SoN) → Countable (< PS)
20% earned income deduction ✓ Applied to all earned income
58% work incentive disregard ✓ Applied after 20% deduction
Applicant vs recipient distinction ✓ Different tests and resource limits
Need standard (sizes 1-10) ✓ $365-$1,724/month + $173/additional
Payment standard (sizes 1-10) ✓ $183-$865/month + $87/additional
Resource limits ✓ $2,000 applicant, $5,000 recipient
Benefit formula max(payment_standard - countable, 0)
No hard-coded values ✓ All values from parameters
Variable naming ✓ All use ia_fip_* prefix
Pattern usage ✓ Correct adds, add(), max_(), where()
Federal eligibility reuse ✓ Uses is_demographic_tanf_eligible

Validation Summary

Check Result
Regulatory Accuracy ✅ Implementation matches IAC 441-41
Reference Quality ⚠️ Minor format issues (inline comments, missing anchors)
Code Patterns ⚠️ Missing 2 dedicated test files
Test Coverage ⚠️ Missing boundary tests at exact thresholds
CI Status ✅ All checks passing

Three-Step Income Eligibility Verified

The implementation correctly handles Iowa's unique three-step income test:

  1. Gross Income Test: gross_income ≤ 185% × standard_of_need
  2. Net Income Test (applicants only): (gross - 20%) < standard_of_need
  3. Countable Income Test: (gross × 0.80 × 0.42) + unearned < payment_standard

Recipients skip Test 2, applicants must pass all three.


Test Coverage: 68 Tests Passing

File Tests
ia_fip.yaml 11
ia_fip_countable_income.yaml 8
ia_fip_eligible.yaml 8
ia_fip_gross_income.yaml 6
ia_fip_income_eligible.yaml 11
ia_fip_payment_standard.yaml 8
ia_fip_standard_of_need.yaml 8
integration.yaml 8

Manual Calculation Verification

Scenario 2 (Family of 2, $800/month earned):

  • Standard of need: $719/month
  • Payment standard: $361/month
  • Gross income limit: $719 × 1.85 = $1,330.15

Test 1: $800 ≤ $1,330.15 ✓
Test 2: $800 × 0.80 = $640 < $719 ✓
Test 3: $640 × 0.42 = $268.80 < $361 ✓
Benefit: $361 - $268.80 = $92.20


Next Steps

To auto-fix issues: /fix-pr 7171

Or address manually:

  1. Create ia_fip_resource_eligible.yaml and ia_fip_countable_earned_income.yaml test files
  2. Add boundary tests at exact resource and income thresholds
  3. Move inline comments from href fields to title fields
  4. Fix "than than" typo in need_standard/additional.yaml

🤖 Generated with Claude Code - Complete Review Plugin

hua7450 and others added 4 commits February 2, 2026 15:15
- Update all parameter effective dates from 2017-10-27 to 2017-01-01
- Rename ia_fip_resource_eligible to ia_fip_resources_eligible
- Add #page=1 anchor to resource limit PDF references
- Fix typo in need_standard/additional.yaml description
- Create eligibility/ folder and move eligibility variables
- Break down ia_fip_income_eligible into sub-components:
  - ia_fip_gross_income_eligible (Test 1)
  - ia_fip_net_income_eligible (Test 2)
  - ia_fip_countable_income_eligible (Test 3)
- Add comprehensive test files for new variables
- Remove unnecessary test files for adds-only variables

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@hua7450
Copy link
Collaborator

hua7450 commented Feb 9, 2026

Temporary close.

@hua7450 hua7450 closed this Feb 9, 2026
@hua7450 hua7450 reopened this Feb 12, 2026
@hua7450 hua7450 mentioned this pull request Feb 12, 2026
@PavelMakarchuk
Copy link
Collaborator

PR Review: Iowa Family Investment Program (FIP/TANF)

🔴 Critical (Must Fix)

No critical issues found. The implementation correctly reflects Iowa's FIP regulations, all parameter values match IAC 441-41, and CI passes with 100% diff coverage.

🟡 Should Address

  1. Incorrect effective dates on all parameters: All 11 parameter files use 2017-01-01 as the effective date. Per the PR's own historical note, payment standards have been unchanged since at least January 1997 (1998 Green Book Table 7-8), and the work incentive disregard was set to 58% effective August 1, 2007. Parameter effective dates should reflect when the policy value took effect, not a generic start date. Consider using 1997-01-01 for standards and 2007-08-01 for the work incentive disregard. For historical completeness, the prior 50% work incentive disregard value could also be included.

  2. Period access for spm_unit_size: In ia_fip_standard_of_need.py and ia_fip_payment_standard.py, spm_unit_size (a YEAR variable) is accessed with period in a MONTH formula. Best practice (per Ohio's oh_owf_payment_standard.py reference implementation) is to use period.this_year:

    people = spm_unit("spm_unit_size", period.this_year)
  3. Missing dedicated test files: No unit test files for ia_fip_resources_eligible or ia_fip_countable_earned_income. These variables have conditional logic (applicant vs recipient limits; sequential 20% + 58% deductions) that warrants isolated testing. The existing ia_fip_eligible.yaml partially covers resources, and ia_fip_countable_income_eligible.yaml partially covers earned income deductions, but dedicated files would improve debuggability.

  4. Missing boundary tests at exact thresholds: No tests where income is exactly at the 185% gross income limit, resources are exactly at $2,000/$5,000 limits, or countable income equals the payment standard. These boundary conditions are important for verifying <= vs < comparisons.

🟢 Suggestions

  1. Person naming convention: Integration tests use descriptive names (parent, child1) while unit tests use person1, person2. Consider standardizing to person1, person2 per PolicyEngine testing conventions (or vice versa for readability -- either is fine as long as it's consistent).

  2. Parameter description formatting: Some parameter descriptions include extra explanatory text (e.g., "for the first income eligibility test", "or the schedule of living costs"). Per PolicyEngine parameter patterns, descriptions should follow the format [State] [verb] [category] to [this X] under the [Full Program Name] program. without additional explanation.

  3. Historical work incentive disregard value: The PR notes the disregard was 50% before August 2007. Consider adding this historical entry:

    values:
      1997-01-01: 0.50
      2007-08-01: 0.58

Validation Summary

Check Result
Regulatory Accuracy ✅ All income tests, deduction rates, standards, and resource limits match IAC 441-41
Reference Quality ✅ All parameters have references with specific IAC sections and page anchors
Code Patterns ✅ No hard-coded values, correct adds/add() usage, proper defined_for
Test Coverage ⚠️ 67 test cases across 8 files -- good overall, but missing boundary tests and isolated resource/earned income tests
CI Status ✅ All checks passing, 100% diff coverage

Highlights

  • Excellent PR description with regulatory citations, income calculation walkthrough, and historical context
  • Correct three-step vs two-step income test logic for applicants vs continuing recipients (Cases 9-11 in ia_fip_income_eligible.yaml)
  • Good use of federal baseline variables (tanf_gross_earned_income, is_demographic_tanf_eligible) instead of unnecessary state wrappers
  • Well-structured integration tests with inline calculation comments explaining each step
  • All manual calculation verifications pass (8 scenarios checked)

Next Steps

To auto-fix issues: /fix-pr 7171

Or address manually and re-request review.

@hua7450 hua7450 self-requested a review February 13, 2026 16:46
@hua7450 hua7450 merged commit 26b20d3 into PolicyEngine:main Feb 13, 2026
9 checks passed
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 Iowa TANF Iowa TANF payment values 2017, 2018, 2019

3 participants