Skip to content

Integrate modeled state unemployment insurance into income flows - #9558

Merged
hua7450 merged 11 commits into
mainfrom
state-ui-income-flow-integration
Oct 13, 2026
Merged

hua7450 merged 11 commits into
mainfrom
state-ui-income-flow-integration

Conversation

@DTrim99

@DTrim99 DTrim99 commented Sep 21, 2026 •

Copy link
Copy Markdown
Collaborator

Supersedes #8303, whose original author (@daphnehanse11) has left PolicyEngine. @DTrim99 adopted it and rebased it onto current main (177 commits of drift).

What this does

This PR connects the modeled state unemployment insurance programs to every consumer of unemployment compensation.

  • New modeled_state_unemployment_compensation (Person/YEAR) sums the modeled state UI programs (al_ui, nj_unemployment_insurance, ny_ui, ok_ui, pa_uc and ut_ui) through a year-gated list, gov.states.household.modeled_state_unemployment_compensation. NJ UC was modeled on main after Draft: Integrate modeled state unemployment insurance into income flows #8303 was opened, so it was added during the rebase.
    • The year gate sets start years only. Each program enters in the first year of its verified_years in programs.yaml: OK 2022; AL, NJ and UT 2024; NY and PA 2025. Lists carry forward, so there is no end year.
    • Before its start year, a program's variable still computes but does not feed total_unemployment_compensation.
    • The empty 0000-01-01 base keeps early-year simulations (e.g., the 2010 AL SSP cases) from reaching state UI parameters that start later.
  • New total_unemployment_compensation (Person/YEAR) uses reported unemployment_compensation when it is nonzero, and the modeled amount otherwise. Every nonzero reported value, including a negative one, passes through exactly as on main. Nothing is counted twice.
  • Formula consumers. Every formula that read unemployment_compensation now reads total_unemployment_compensation:
    • the federal taxable-UC chain, dependent gross income, the tuition ALD and taxable SS MAGI;
    • the student loan interest ALD MAGI (student_loan_interest_ald_magi) and the IRA deduction MAGI (ira_219g_magi and ira_219g_taxable_social_security). Merges of main brought these in after this PR opened. Each figures MAGI without regard to section 85(c), so it counts all UC, reported or modeled;
    • SPM unit benefits, SNAP work registration, the AR Medicaid work requirement, CA Contra Costa GA and UT homeowner/renter relief;
    • the TAXSIM outputs and the household_benefits list.
  • Parameter-driven consumers. The PR swaps 118 list entries in 110 files under parameters/gov/ from the reported input: 117 now read total_unemployment_compensation and one, Virginia's, reads taxable_unemployment_compensation (see below). The hardcoded benefit lists in 4 contrib reforms (Tlaib ECPA and EDAA, BOOST, TX rebate) also use the total.
    • Among the migrated lists: SNAP unearned income (7 CFR 273.9(b)(2)(ii)), the shared TANF list (read by AL/NJ/NY/OK/PA/UT TANF), SSI, WIC, school meals, Head Start, HUD annual income, CBO social-insurance benefits, CCAP/CCDF lists, state TANF lists and state tax income lists.
    • Ten of those lists came in through merges of main after the first migration and are now migrated too: NY HEAP, NJ LIHEAP, IN EAP, KS LIEAP, KY LIHEAP, MD MEAP, MO Supplemental Aid to the Blind, MS LIHEAP, NC LIEAP and OR LIHEAP.
    • Each list names only the total (or, for Virginia, the taxable amount), never both a component and the total, so nothing is counted twice.
    • The reported input stays where it has to: input uprating (default_uprating, the 2025 Trustees reform's SOI tuple), the TAXSIM test generator, and the total's own formula.
    • No cycles: the six state UI formulas read only their own wage, week and hours inputs and demographics, so the total never depends on AGI and the MAGI formulas can read it.

Pre-existing fixes in files this PR touches (review round 3)

  • Virginia now subtracts taxable UC (Va. Code § 58.1-322.02(17)), as CA, DE and DC already do. The law subtracts UC "taxable pursuant to § 85", and federal AGI carries taxable UC, not the total. The previous list subtracted all UC.
    • Only tax year 2020 changes, because only in 2020 was part of UC federally tax-exempt. For a single filer with $50,000 of wages and $5,000 of UC, VA AGI goes from $45,000 to $50,000 and VA income tax from $1,767.78 to $2,055.28.
    • Tax year 2025 is unchanged, and so is every existing VA test (all are 2025).
  • Hawaii CCAP counts strike benefits (HAR 17-798.3-10(b)). The list claimed strike benefits were "captured via unemployment_compensation", but no UC variable includes them. $12,000 a year of strike benefits now gives $1,000 a month of countable income, not $0. strike_benefits is not in microdata, so aggregates do not move.
  • Tuition ALD reference. The two URLs in capped_qualified_tuition_expenses_ald lacked a separating comma, so Python joined them into one invalid string. The reference is now a tuple of two URLs.

Reported-zero rule

A reported nonzero amount (positive or negative) overrides modeled UI. A reported 0 is treated as not reported, because the formula cannot tell an explicit 0 from the default. To suppress modeled UI, leave the state UI wage and weeks inputs at 0. Microdata never populates those inputs, so aggregates are unaffected: there, total_unemployment_compensation == unemployment_compensation. A new microsimulation test now checks this.

Mode-conflict resolution (Option A)

@PavelMakarchuk's review on #8303 (changes requested) found that unemployment_compensation declared both uprating and adds. policyengine-core rejects that combination when the variable is registered, so the package failed to import. The fix, described in this comment:

  • unemployment_compensation stays the pure uprated survey input, unchanged, so future-year microsim uprating and CPS-reported values are unaffected;
  • the fallback variable above is added alongside it.

Tests

The PR now changes 23 test files. That is above the 8-file selective Quick Feedback limit (SELECTIVE_TEST_MAX_DIRECT_FILES), by choice: each migrated reader gets its regression cases in its own test file. Above the limit, Quick Feedback skips its selective run and coverage upload, so the full-suite jobs cover these changes.

  • Year gate:
    • AL: 2023 (al_ui = $3,850, but modeled, total, tax-unit and taxable UC = $0) and 2010 (modeled and total UC = $0, pinning the empty base).
    • NY 2024, PA 2024, UT 2023 and NJ 2023: each program computes but modeled and total UC = $0.
    • OK: its 2022 start year ($7,616 flows through to taxable UC) and 2021 (UC = $0).
  • Beyond SNAP:
    • modeled NY UI in SSI unearned income, federal and NY AGI ($7,982) and monthly TANF gross unearned income ($665.17);
    • modeled PA UC in taxable_ss_magi ($10,218);
    • adjusted_gross_income on each state's "feeds income flows" case (AL 103,850, NY 107,982 with ny_agi, OK 108,000, PA 110,218, UT 119,396).
  • Readers added by merges of main. Each modeled case has a reported-UC control with the same result:
    • PA 2025, $85,000 of wages, $2,500 of student loan interest and $10,218 of modeled UC: student_loan_interest_ald_magi $95,218 (was $85,000) and student_loan_interest_ald $797 (was $2,500);
    • PA 2025, $80,000 of wages and $10,218 of modeled UC: ira_219g_magi $90,218 (was $80,000);
    • PA 2025, $20,000 of wages, $20,000 of Social Security and $10,218 of modeled UC: ira_219g_taxable_social_security $9,785.30 (was $2,500). These two IRA variables had no test file named for them, so each now has one;
    • NY 2026, $7,982 of modeled UI: ny_heap_countable_income $7,980 after monthly flooring (was $0);
    • NJ 2026, $6,000 of modeled UI: nj_liheap_countable_income_person $6,000 (was $0);
    • IN EAP, KS LIEAP, KY LIHEAP, MD MEAP, MO SAB, MS LIHEAP, NC LIEAP and OR LIHEAP: none of these states has a modeled UI program, so each file gets a reported-UC control showing that UC still counts through the total.
  • Guards:
    • tests/code_health/test_unemployment_compensation_readers.py fails when a parameter list entry or a Python string constant names the raw unemployment_compensation. It reads text and syntax trees and does not import the model. An explicit allowlist covers uprating, the TAXSIM generator and the total's own formula, and a second check fails if an allowlisted file stops reading the raw input. Run against the previous head, it flags all 13 raw readers fixed here.
    • tests/microsimulation/test_microsim.py::test_default_dataset_has_no_modeled_state_unemployment_compensation asserts that modeled_state_unemployment_compensation is 0 for every person in the certified default build in 2025, the first year with all six programs. It computes only that variable over the full population and runs in the existing microsimulation job.
  • Reported values: a negative reported amount (−$1,000) passes through instead of modeled PA UC ($10,218). The existing explicit-zero case still falls back to modeled UI.
  • Pre-existing fixes: a VA 2020 case and an HI CCAP strike-benefits case.
  • Existing cases: earlier cases cover a low-income PA SNAP interaction, NJ, an asymmetric couple (one reported, one modeled) at annual and monthly periods, and the remaining formula consumers.
  • Wording fixes:
    • The 2020 tuition-cap case's comment now states the law: ARPA § 9042(b)(7) added § 85(c) to the § 222 MAGI definition, so $2,000 is the statutory cap.
    • The UT case is renamed to reflect what it covers (total and taxable UC).

Validation

  • SNAP before and after, for a PA single adult with no earnings and $10,218 of modeled UC, in January 2025:

    • SNAP unearned income goes from $0 to $851.50 (10,218 / 12), and SNAP from $292 to $228.
    • For a PA couple with $6,000 reported and $10,218 modeled, unearned income goes from $500 to $1,351.50 and SNAP from $536 to $247.
  • Local tests on this round: 201 passed, 0 failed.

    • The 13 changed reader YAML files: 138, including the student loan MAGI file (15), the two new IRA files (2 each), NY HEAP (7) and NJ LIHEAP (8).
    • total_unemployment_compensation.yaml (18), ira_phase_out.yaml (15) and student_loan_interest_ald.yaml (13).
    • The new code-health guard (4) and test_modified_agi_add_backs.py (13).
    • The new microsimulation guard was not run locally. It needs the full default dataset, so CI's microsimulation job runs it.
  • Local tests after merging current main (85 commits): 132 passed, 0 failed.

    • total_unemployment_compensation.yaml: 18/18. spm_unit_benefits.yaml: 6/6.
    • AL/NY/OK/PA/UT UI integration suites: 64.
    • VA va_subtractions_person, va_agi_person and integration: 16.
    • HI CCAP countable income and integration: 16.
    • UT homeowner/renter relief: 12.

    Earlier rounds also ran the SNAP income folder (267), the full VA subtractions folder (61) and the 4 changed contrib reforms (30). No existing expected value moved.

  • Coverage. On an earlier head, codecov's "project" number compared selective Quick Feedback uploads (this PR's changed files against 4 unrelated files at base), not whole-repository coverage.

  • No partner contract test files were touched.

Deferred to follow-ups

axiom: n/a: routing reported unemployment compensation, or modeled AL/NJ/NY/OK/PA/UT unemployment insurance when none is reported, into the readers is a modeling change, not a change in law | Va. Code § 58.1-322.02(17) TheAxiomFoundation/rulespec-us#1756 queued | HAR § 17-798.3-10(b)(3)(B) TheAxiomFoundation/rulespec-us#1757 queued

🤖 Generated with Claude Code

https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH

Rebase of PR #8303 onto current main under new ownership (original
author has left PolicyEngine). Adds modeled_state_unemployment_compensation
(sums al_ui, nj_unemployment_insurance, ny_ui, ok_ui, pa_uc, ut_ui) and
total_unemployment_compensation (reported-wins fallback), repoints the
direct consumers of unemployment_compensation - including the
household_benefits parameter list - and extends the five state UI
integration suites with income-flow, reported-preservation, and
no-double-count cases.

Resolves the uprating/adds computation-mode conflict Pavel flagged on
#8303 via Option A: unemployment_compensation stays a pure uprated
survey input, so CPS-reported values and future-year uprating are
untouched and modeled UI reaches income flows only when no reported
amount is present. NJ UI, modeled on main after #8303 was opened, is
included in the modeled aggregate as part of the rebase.

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

codecov Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (909176a) to head (36192aa).
⚠️ Report is 442 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #9558   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         2    -2     
  Lines           76        26   -50     
  Branches         2         0    -2     
=========================================
- Hits            76        26   -50     
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.

@PavelMakarchuk PavelMakarchuk 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.

The new total UI variable is vectorized correctly, but the migration misses parameter-driven means tests. snap_unearned_income_person still reads unemployment_compensation from the SNAP unearned-income source list, so the new modeled benefit enters household resources without entering SNAP income. In the PR's Pennsylvania example, $10,218 of modeled UI with no reported UI contributes $0 rather than $851.50/month to that list. This was verified by tracing the formulas and source list, not by running a full SNAP simulation locally.

Please migrate applicable remaining raw-UI income consumers without double-counting or cycles, and add a low-income integration test that exercises the benefit interaction. SNAP's treatment is specified in 7 CFR 273.9(b)(2)(ii). Also resolve the two failing coverage checks; the actual hosted model suites pass, and the selective project-coverage comparison should not be presented as a whole-repository regression.

Nonblocking: clarify whether an explicitly reported zero should trigger modeled entitlement, and cover NJ, asymmetric household inputs, and monthly aggregation.

…sation

Per review: migrate every income-source list under parameters/gov/ (SNAP,
TANF, SSI, WIC, school meals, Head Start, HUD, CBO, CCAP, state tax lists
and the VA subtraction) and four contrib reform benefit lists from the
reported unemployment_compensation input to total_unemployment_compensation.
Document the reported-zero rule, fold two always-true source appends into
direct substitutions, and add low-income SNAP, NJ, asymmetric-household,
monthly and reported-zero tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
@DTrim99

DTrim99 commented Sep 23, 2026

Copy link
Copy Markdown
Collaborator Author

Fixes applied (02fec91): Pavel's review

Parameter-driven consumers migrated. Every - unemployment_compensation entry in an income-source list under parameters/gov/ now reads total_unemployment_compensation (106 entries in 99 files). So do the hardcoded benefit lists in 4 contrib reforms (Tlaib ECPA and EDAA, BOOST, TX rebate), which would otherwise show modeled UI as a spurious reform-vs-baseline loss.

  • Results change today (modeled UI is nonzero for AL/NJ/NY/OK/PA/UT residents with program inputs): SNAP unearned income, the shared TANF list (AL/NJ/NY/OK/PA/UT TANF), SSI, WIC, school meals, Head Start, HUD annual income, CBO social-insurance benefits, and those six states' CCAP and OK sales-tax-credit lists.
  • Consistency only, $0 effect today: the remaining CCAP, TANF, county GA and state tax lists. This includes Virginia's UC subtraction, which has to use the total now that federal AGI carries it.
  • Left on the reported input (13 references): the variable's own definition, uprating plumbing, TAXSIM and uprating input lists, a parameter prefix, and comments.
  • No double counting: each list names only the total, never a component or an AGI/UC aggregate.
  • No cycles: the six state UI formulas read only their own wage, week and hours inputs, weeks_unemployed and demographics. PA's spouse employment_income path is cut by the labor-supply measurement branches.

Low-income integration test. It uses your Pennsylvania example: $10,218 modeled, nothing reported, no earnings, January 2025. Under 7 CFR 273.9(b)(2)(ii):

Case SNAP unearned income, before → after Monthly SNAP, before → after
PA single $0 → $851.50 (10,218 / 12) $292 → $228
PA couple: head reported $6,000, spouse modeled $10,218 $500 → $1,351.50 $536 → $247
NJ single, 2024 ($3,380 modeled) $0 → $281.67 $291 → $265

Non-blocking items, all covered. The new household/income/person/total_unemployment_compensation.yaml has these cases:

  • New Jersey, yearly and monthly;
  • the asymmetric couple, yearly totals ([6,000, 10,218], tax unit 16,218) and the monthly SNAP aggregation above;
  • an explicit reported 0.

Reported zero. This is documented in total_unemployment_compensation: a reported amount above 0 overrides modeled UI, and a reported 0 counts as not reported, because the formula can't tell it from the default. To suppress modeled UI, leave the state UI wage and weeks inputs at 0. Microdata never populates those inputs, so aggregates are unchanged.

Coverage checks

  • codecov/patch missed 4 lines: taxsim_pui.py:15, taxsim_ui.py:15, the pre-2021 branch of capped_qualified_tuition_expenses_ald.py and ut_homeowner_renter_relief_nontaxable_income.py:24. The new file covers all four.
  • Branch coverage. The always-true if ... in gross_income_sources appends in the tuition ALD and taxable_ss_magi are now straight list substitutions: same sources, identical behavior, no untestable branch.
  • Local replay. Re-running Quick Feedback's coverage step gives 100% line and branch coverage on all 16 changed variable files. The PR now changes 7 test files directly, under the selective runner's cap of 8, so Quick Feedback still runs and uploads coverage.
  • codecov/project was not measuring the repository. Quick Feedback is the only job that uploads coverage, and it ran only the changed YAMLs against the changed variable files. The "100% → 73.72%" row compared this PR's 15 changed files with 4 unrelated files at base. I've added this to the PR description.

Also:

  • the stale ny_ui.py comment ("not yet wired") and the SNAP work-requirements README are fixed;
  • the changelog now names New Jersey and the means-tested programs.

Verification. Local runs: 457 passed, 0 failed, and no existing expected value moved:

  • new file: 11
  • spm_unit_benefits.yaml: 6
  • AL/NJ/NY/OK/PA/UT UI suites: 82
  • SNAP income folder: 267
  • VA subtractions: 61
  • the 4 changed contrib reforms: 30

ruff format and ruff check are clean. An independent validator pass came back clean, no partner test sets any state UI input, and no partner files were touched.

Sum modeled state UI through a year-gated parameter list so each program
counts from its first verified year. Before 2022 the list is empty, so
pre-2015 simulations (e.g. the 2010 Alabama SSP cases reached via SSI
unearned income) no longer reach state UI parameters that start later.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
@DTrim99

DTrim99 commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator Author

CI fix (3d57cdd): year-gate the modeled state UI programs

Failure: Full Suite - Baseline (states-shard-1) failed on 6 cases in al/dhr/ssp/integration.yaml, all at period 2010-01. With SSI's unearned-income list now reading total_unemployment_compensation, those cases reached al_ui. Alabama's UI parameters start in 2020, and parameters are backdated only to 2015, so the run raised ParameterNotFoundError: gov.states.al.dol.unemployment_insurance.eligibility[quarters_with_wages] ... 2010-01-01.

Fix: modeled_state_unemployment_compensation now sums a year-gated parameter list, gov.states.household.modeled_state_unemployment_compensation, instead of a fixed adds list. This follows the pattern of state_property_tax_credits.yaml. Each program is included from the first year its implementation is verified in programs.yaml:

From Programs
before 2022 none
2022 OK
2024 AL, NJ, OK, UT
2025 AL, NJ, NY, OK, PA, UT

Modeled UI is therefore zero in years no state program is verified, and simulations of earlier years never reach state UI parameters that start later. Every test in this PR that uses modeled UI falls inside those years, so no expected values change.

Verification:

  • al/dhr/ssp/integration.yaml: 19/19 passing locally (6 were failing).
  • This PR's UI suites (AL/NJ/NY/OK/PA/UT), the new total_unemployment_compensation.yaml and spm_unit_benefits.yaml: 488 passed, 0 failed.

@PavelMakarchuk

Copy link
Copy Markdown
Collaborator

Program Review

Source Documents

  • Sources: 7 CFR 273.9(b)(2)(ii); 26 U.S.C. 85, 86, 222; Va. Code § 58.1-322.02; program regulations cited in migrated lists (no PDF audit: no numeric values changed)
  • Year: 2022–2026 (modeled UI year-gated from 2022)
  • Scope: PR changes only (+ prior requests)
  • Reviewed head SHA: 3d57cdd
  • Mode: full

Branch Status

The branch is 3 commits ahead of and 83 commits behind main. A rebase is recommended before merge; the gap did not affect these findings.

Prior requests

Ask Status Evidence
P-ASK1: migrate parameter-driven consumers without double counting or cycles RESOLVED 108 entries in 100 list files, 6 entries in 4 contrib reforms and 13 formula consumers now read total_unemployment_compensation; no list or formula names both the input and the total, and traces show no cycles (see Verified correct).
P-ASK2: low-income integration test RESOLVED total_unemployment_compensation.yaml Case 1 (line 7): modeled PA UC gives SNAP unearned income of $851.50 and SNAP of $228 (down from $292). Cases 3 and 5 cover NJ ($265) and a couple ($247). All hand-checked.
P-ASK3: coverage-check framing RESOLVED codecov/patch and codecov/project pass at head. The PR body now describes the earlier project number as a selective-upload comparison, not whole-repository coverage.
Nonblocking: reported-zero rule RESOLVED Documented in total_unemployment_compensation.py:9-17 and the PR body; Case 6 (line 172) pins the fallback.
Nonblocking: NJ RESOLVED Cases 2 and 3 (lines 42, 69). NJ's own integration.yaml was not extended; the fallback is state-independent, so this is cosmetic.
Nonblocking: asymmetric household RESOLVED Case 4 (line 95) asserts [6_000, 10_218], a tax-unit total of 16,218 and the TAXSIM head/spouse split.
Nonblocking: monthly aggregation RESOLVED Cases 1, 3 and 5 run at 2025-01/2024-01 and assert the ÷12 values.

Critical (Must Fix)

None.

Should Address

A1. The year gate has no direct test. The gate in policyengine_us/parameters/gov/states/household/modeled_state_unemployment_compensation.yaml:8-22 was added in the last commit to fix a ParameterNotFoundError in the 2010 AL SSP cases, but every test asserts modeled UI only in an included year. Only those SSP cases guard the fix, implicitly, so moving NY into the 2024 block, moving AL into 2022 or dropping OK's 2022 entry would all pass CI. Add excluded-year cases to the state integration files: for example NY 2024 and AL 2023 asserting the program amount alongside modeled_state_unemployment_compensation: 0 and total_unemployment_compensation: 0, an early-year AL case asserting only the totals, and OK in its first included year (2022).

Suggestions

S1. State that the year gate sets start years only. The comment at modeled_state_unemployment_compensation.yaml:3-7 says to "extend a program's block when its verified years are extended", which implies an end year. List blocks carry forward, so al_ui (verified for 2024 only) counts in 2025+, pa_uc (verified for 2025 only) counts in 2026+, and all six count in 2027+. This matches the PR body ("from its first verified year") and standard carry-forward practice, so the behavior can stay; reword the comment to say no end year is enforced. It could also note that before a program's start year its variable still computes (e.g., pa_uc = $4,740 in 2024 with claim inputs) while total_unemployment_compensation stays $0. That is not a regression, since no state UI program fed income on main.

S2. Extend modeled-UI coverage beyond SNAP. The changelog names TANF and SSI, but only SNAP, the federal taxable-UC chain and the benefit aggregates are tested with modeled UI. One case each for tanf_gross_unearned_income and ssi_unearned_income (NY is simplest, having no dependent allowance), an adjusted_gross_income/state AGI assertion on the existing "feeds income flows" cases, and a modeled-path taxable_ss_magi case would catch a revert of the shared lists.

S3. Case 8's comment misstates the law. policyengine_us/tests/policy/baseline/household/income/person/total_unemployment_compensation.yaml:233-237 calls the $2,000 cap "not the statutory result". ARPA §9042(b)(7) (Pub. L. 117-2) inserted "85(c)" into the §222(b)(2)(C)(i) MAGI definition, so excluded 2020 UC counts in MAGI: $70,000 and a $2,000 cap is the statutory result. Reword the comment; the same holds for taxable_ss_magi under 26 U.S.C. 86(b)(2)(A).

S4. Case 7 cannot detect a revert of the UT consumer swap. The case at total_unemployment_compensation.yaml:190 asserts ut_homeowner_renter_relief_nontaxable_income: 0, which is also the result if the variable read the reported input, because modeled UT UI is fully taxable. Rename or re-comment it so it reads as coverage of total and taxable UC, not of the UT consumer.

S5. Negative reported UC is now dropped. where(reported > 0, reported, modeled) (policyengine_us/variables/household/income/person/total_unemployment_compensation.py:23) replaces a negative reported value with the modeled amount (usually $0); on main it flowed through. Survey values are non-negative, so impact is low, but pin this with a test, or use reported != 0 if negatives should pass through.

S6. Guard against modeled UI appearing in microdata. Modeled UI stays at $0 in microsim only because the state wage and quarter inputs are absent; weeks_unemployed is already populated. A microsim assertion that modeled_state_unemployment_compensation sums to 0 on the default dataset (or an explicit take-up input) would make any future imputation of those wages a deliberate choice rather than implicit 100% take-up for every unemployed respondent with no reported UC.

S7. Housekeeping. Update the PR body's "106 entries in 99 files" to 108 in 100, and its VA rationale ("federal AGI now carries the total"): federal AGI carries taxable UC. Rename the unemployment_compensation locals that hold the total in policyengine_us/variables/contrib/taxsim/taxsim_pui.py:15, taxsim_ui.py:15 and ut_homeowner_renter_relief_nontaxable_income.py:24. Optionally reword the new parameter's description (line 1): the programs sum to modeled UC, which applies only when no UC is reported.

Pre-existing issues (not introduced by this PR; non-blocking)

P1. Virginia subtracts total rather than taxable UC. policyengine_us/parameters/gov/states/va/tax/income/subtractions/subtractions.yaml:11 was renamed by this PR, but VA behavior is unchanged. Va. Code § 58.1-322.02(17) subtracts UC "taxable pursuant to § 85". The 2021 list back-fills to 2020, so for TY2020 VA AGI is understated by min(UC, $10,200). A single filer with $50,000 of wages and $5,000 of UC owes $1,767.78 instead of $2,055.27; P.D. 22-93 rules out this double benefit. The error recurs under any reform that restores the federal exclusion. Using taxable_unemployment_compensation, as CA, DE and DC do, fixes it on a line this PR already edits.

P2. SC TANF counts taxable UC. policyengine_us/parameters/gov/states/sc/tanf/income/unearned.yaml:17. The manual's Sources of Income chart counts UC as unearned income with no tax carve-out, so in 2020 UC under the §85(c) cap is ignored. For a parent and child with $6,000 a year of UC, sc_tanf is $237.59 a month, versus $68.99 when gross UC counts. Use total_unemployment_compensation. The same list also uses taxable_social_security, but the manual counts gross SSA benefits.

P3. HI CCAP omits strike benefits. policyengine_us/parameters/gov/states/hi/bessd/ccap/income/countable_income/sources.yaml:33 says strike benefits are "captured via unemployment_compensation", but neither UC variable includes strike_benefits. HAR 17-798.3-10(b)(3)(B) counts them. With $12,000 of strike benefits, hi_ccap_countable_income is $0. Add - strike_benefits and delete the comment.

P4. Malformed reference. policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/capped_qualified_tuition_expenses_ald.py:16-20 has no comma between its two URL strings, so Python joins them into one invalid URL.

Investigated and cleared

  • 2020 §222 and §86 MAGI. Counting §85(c)-excluded UC in the tuition-deduction and Social Security MAGIs is correct under ARPA §9042(b)(2) and (b)(7). Head and merge base agree; for a 2020 test household, for example, taxable_ss_magi is $25,000 and taxable_social_security is $5,350.
  • Early-year parameter access. The empty 0000-01-01 base keeps pre-2022 simulations (the AL SSP 2010 cases) from reaching state UI parameters; states-shard-1 passes.
  • PA UC and labor-supply responses. pa_uc_has_dependent_spouse.py:27 reads post-LSR employment_income. The re-entry guard in labor_supply_behavioral_response.py:39-42 prevents recursion, and a baseline-plus-LSR run on a married PA couple completed. Reading employment_income_before_lsr would remove the edge (optional follow-up).
  • Partner tests. Eight partner files send unemployment_compensation: 0 with no state UI wage inputs, so the total falls back to $0. The Household API Partners check passes.

Verified correct

  • Migrated lists. 100 files, by family: CCAP/CCDF 47, TANF 14, CA local GA 10, state tax 9, WIC/school meals/Head Start/early education 5, SSI 2, SNAP 1, HUD 1, other 11. Every change is a 1:1 swap (108 +, 108 -), and each program counts UC under its income rules.

  • No remaining raw-UI consumers that should have migrated. A word-bounded grep of the whole tree at head (all file types) finds the raw token only in:

    • the input definition and the reported branch of the total;
    • uprating and calibration paths, and parameter-node names;
    • the TAXSIM input list, and comments.

    Taxable and tax-exempt UC now derive from the total, so their consumers (CA/DE/DC/MT/WI/IN/RI and others) follow automatically.

  • No double counting. A parser over every YAML values: list and Python list literal found no list containing both the input and the total, or the total and a component. UC enters household_net_income once and spm_unit_net_income once.

  • No cycles. Dependency traces show no UI variable reaches the total, AGI, benefits or taxes. Full-household runs in all six states computed taxes, SNAP, TANF, SSI, WIC, school meals, Head Start, HUD, CCAP and net income without a cycle error.

  • Symmetry. Modeled UI and the same amount entered as reported UC gave identical results on 21 downstream variables in all six states.

  • Mode conflict resolved. unemployment_compensation is unchanged from the merge base: an input with uprating, no adds and no formula. Neither new variable declares uprating, and smoke-import passes on Python 3.11–3.14.

  • Modeled UI cannot switch on in current microdata. Three checks confirm this:

    • The populace 2024 person table contains none of the state UI wage, quarter or claim inputs.
    • A populace microsim for 2024–2026 found 0 records with nonzero modeled UI, and max |total − reported| = $0. Weighted UC is unchanged at $28.596B, $31.956B and $35.911B.
    • CPS-like households in all six states with weeks_unemployed and earnings, but no wage inputs, returned $0.
  • Year-gate start years match the first verified_years year in programs.yaml: OK 2022; AL, NJ and UT 2024; NY and PA 2025.

  • Expected values. Twelve expected values in the new and extended tests match hand calculations from the parameters at head, including SNAP of $228, $265 and $247 and spm_unit_benefits of $13,065.

  • CI and housekeeping. CI passes 37/37, 0 partner test files are touched, and the changelog fragment is a top-level .added.md file.

Validation Summary

Check Result
Regulatory Accuracy Pass: modeled UI counts wherever reported UC counts (26 U.S.C. 85; 7 CFR 273.9(b)(2)(ii); program income rules); 0 issues introduced
Reference Quality Pass: no reference or #page lines changed; 1 test comment misstates the law (S3)
Code Patterns Pass: vectorized, no hard-coded values, entities consistent
Formatting Pass: Lint passes; changelog fragment present
Test Coverage 1 gap to address (A1); 4 coverage suggestions (S2, S4, S5, S6)
PDF Value Audit Skipped (no numeric values changed)
CI Status Passing (37/37)

Review Severity: COMMENT

All seven prior requests are resolved and there are no critical issues. A1 should be addressed before merge. The suggestions and pre-existing items are non-blocking; P1 and P3 are one-line fixes in files this PR already edits.

Next Steps

To auto-fix issues: run the fix-pr workflow for this PR.

@PavelMakarchuk PavelMakarchuk 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.

Re-review of 3d57cdd: full report here: #9558 (comment)

All three of my 9/23 requests are resolved, as are the non-blocking items. The migration covers 108 entries in 100 lists, 4 contrib reforms and 13 formulas. I found no remaining raw consumers, no double counting and no cycles. Modeled UI is $0 in populace 2024–2026, so aggregates are unaffected. No critical findings.

One should-address item:

  • A1: Add a test for a year before a state enters gov.states.household.modeled_state_unemployment_compensation, e.g. AL 2023 → 0. That pins the year gate directly; right now the ParameterNotFoundError fix is only covered indirectly by the AL SSP 2010 cases.

Suggestions and 4 pre-existing items (VA/SC 2020 taxable-UC handling, HI CCAP strike benefits) are in the report and are non-blocking.

@DTrim99
DTrim99 marked this pull request as ready for review September 29, 2026 14:27
DTrim99 and others added 2 commits September 29, 2026 12:42
…s through

Add year-gate tests for states before and after they enter the
modeled-UI list (AL 2023 and 2010, NY 2024, OK 2022, and PA/UT/NJ
excluded years), SSI/TANF and taxable-SS-MAGI flow tests, and treat any
nonzero reported unemployment compensation (including negative amounts)
as reported, as on main. Have Virginia subtract taxable UC, count strike
benefits in Hawaii child care, fix a reference comma, and clarify the
year-gate docs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
@DTrim99

DTrim99 commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator Author

Fixes applied (7e47d92): Pavel's re-review

A1, year-gate tests: the gate is now tested directly, not only through the Alabama SSP 2010 cases. New cases, all in files this PR already changes:

  • AL 2023: al_ui computes 3,850, but modeled, total, tax-unit and taxable UI are all 0, because AL enters the list in 2024.
  • AL 2010: modeled and total UI are 0. This pins the ParameterNotFoundError fix without asserting al_ui itself, which can't compute in 2010.
  • NY 2024: ny_ui is 7,982 with modeled and total 0; NY enters in 2025.
  • OK 2022: ok_ui = modeled = total = 7,616, on OK's first listed year with the 2022 $476 weekly cap.
  • Excluded years for PA, UT and NJ.

Suggestions:

  • S5: total_unemployment_compensation now treats any nonzero reported amount as reported (reported != 0), so a negative reported amount passes through as it does on main instead of falling back to modeled UI. A test covers it.
  • S2: new flow tests cover NY SSI unearned income (7,982), TANF gross unearned income (665.17/month) and PA taxable_ss_magi (10,218).
  • S1, S3, S4, S7:
    • the year-gate comment now says the list sets start years only;
    • the parameter description is reworded;
    • a test comment and a case name are fixed;
    • local variables in the TAXSIM and Utah files are renamed to say they hold the total.
  • P4: the missing comma in the tuition deduction reference is fixed.

Pre-existing items fixed here, in files this PR already edits:

  • P1, Virginia: Virginia's subtraction now uses taxable UC, which changes only 2020. The 2020 example's VA tax goes from $1,767.78 to $2,055.28; no 2025 Virginia test moves.
  • P3, Hawaii child care: strike benefits are now counted. $12,000 a year gives $1,000 a month of countable income.
  • A fixed changelog fragment covers both.

Deferred:

Verification: main merged cleanly; the branch was 85 behind and is now even. main added no new raw unemployment_compensation consumers. 132 targeted cases pass across the total-UC file, spm_unit_benefits, the AL/NY/OK/PA/UT UI suites, VA, HI child care and UT homeowner relief. The PR still directly changes 7 test files, under the cap of 8. ruff format is clean, and no partner tests were touched.

DTrim99 and others added 2 commits October 5, 2026 09:49
…nd SNAP UI paths

Resolve conflicts with main's restructured dependent gross income
(#9691) and SNAP months-of-receipt UI exemption (#9716): use main's
structure, reading total_unemployment_compensation (reported, or modeled
state UI when none is reported) in DEPENDENT_GROSS_INCOME_SOURCE_OVERRIDES
and unemployment_compensation_months.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
Main's #9716 limits the SNAP work-registration UI exemption to the months
of receipt (26 weeks -> 6 months), so outside those months the PA adults
in these cases hit the ABAWD time limit and 7 CFR 273.11(c)(2)(ii)
prorates their income. Update the two expectations with the arithmetic;
no code change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
DTrim99 added a commit that referenced this pull request Oct 5, 2026
Same expectation updates as #9558 (this branch carries #9558's modeled
state UI change): main's #9716 limits the SNAP work-registration UI
exemption to the months of receipt, so the PA adults hit the ABAWD time
limit outside them. No code change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
Resolve the Arkansas gross income source lists and the Michigan household
resources list against main's restructured lists, keeping
total_unemployment_compensation in place of unemployment_compensation.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
Main's code-health test pins the AR1000F line for every Arkansas gross
income source; the unemployment line (21 from 2018) now reads
total_unemployment_compensation.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
DTrim99 added a commit that referenced this pull request Oct 13, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH

@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.

[P2] Route the income consumers added on main through total unemployment compensation

There is one remaining integration gap: several consumers brought into this branch by later merges of main still read the reported-only unemployment_compensation input. They omit modeled state UI when no reported amount is supplied.

These are follow-up integrations for code added after this PR opened. In particular, NY HEAP (#9744) and NJ LIHEAP (#9745) merged on October 7 and 8 (Eastern), respectively, and entered this branch through its October 12 merge of main.

The remaining readers include:

  • student_loan_interest_ald_magi.py:37, ira_219g_magi.py:24, and ira_219g_taxable_social_security.py:32.
  • policyengine_us/parameters/gov/states/ny/otda/heap/income/sources/unearned.yaml:7.
  • policyengine_us/parameters/gov/states/nj/dca/liheap/income/sources/unearned.yaml:4.

Local reproductions using actual state-UI wage/week inputs show the effect:

Case Current result Expected result
PA 2025: $85,000 wages, $2,500 student-loan interest, $10,218 modeled UI MAGI $85,000; deduction $2,500 MAGI $95,218; deduction $797
PA 2025: $80,000 wages, $10,218 modeled UI IRA MAGI $80,000 IRA MAGI $90,218
NY 2026: $7,982 modeled UI HEAP countable income $0 $7,980 after monthly flooring
NJ 2026: $6,000 modeled UI LIHEAP person income $0 $6,000

The reported-UI controls produce the expected results. Please migrate these downstream readers to total_unemployment_compensation and add regression cases in the corresponding variable-named YAML files, while preserving the raw input inside the adapter and input-uprating code.

Validation: 88 changed-file cases passed; the independent cases produced five expected failures and four passing reported-UI controls. The affected runtime code and dependencies are unchanged on reviewed head 36192aabb31aa86e8341b666b03e9c3860952de1.

Thirteen readers that later merges of main brought in still read the
reported-only unemployment_compensation input, so they missed modeled state
UI when nothing was reported:

- the student loan interest ALD MAGI and the two IRA deduction MAGI
  formulas (ira_219g_magi, ira_219g_taxable_social_security), which now
  append total_unemployment_compensation. The total never reaches AGI, so
  there is no cycle;
- ten parameter source lists: NY HEAP, NJ LIHEAP, IN EAP, KS LIEAP,
  KY LIHEAP, MD MEAP, MO SAB, MS LIHEAP, NC LIEAP and OR LIHEAP.

Each reader gets regression cases in its own test file: a modeled-UI case
plus a reported-UI control where the state models UI (PA for the federal
MAGI formulas, NY, NJ), and a reported-UI control elsewhere. The two IRA
variables get new test files named for them.

Add a code-health guard that fails when a parameter list entry or a Python
string constant names the raw input, with an allowlist for uprating, the
TAXSIM generator and the total's own formula. Add a microsimulation guard
that modeled state UI is zero on the certified default build in 2025.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
@hua7450
hua7450 merged commit 50c68dd into main Oct 13, 2026
26 checks passed
@hua7450
hua7450 deleted the state-ui-income-flow-integration branch October 13, 2026 20:03
DTrim99 added a commit that referenced this pull request Oct 13, 2026
#9558 is merged. Drop its two changelog fragments, which main's release
already consumed, so this PR's diff is only the South Carolina TANF
change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
MaxGhenis added a commit that referenced this pull request Oct 14, 2026
#9558 merged, so income flows read total_unemployment_compensation
(reported UC, or modeled state UI when none is reported), and the
unemployment reader guard now requires it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hua7450 added a commit that referenced this pull request Oct 15, 2026
- S1: Merge blocker: the person source list reads the raw unemployment_compensation, so main's #9558 guard fails
- S2: Eight income sources and two smaller pieces of logic are not pinned by any test
- S3: Six parameter descriptions fall outside the house template
- REC-C: Federal 110%-of-poverty floor (coordinator recommendation C; not raised by David for GA)

Also applies the in-scope suggestions. Tests not run locally; CI validates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hua7450 added a commit that referenced this pull request Oct 15, 2026
- S1: Merge blocker from #9558: the unearned list reads the raw unemployment_compensation, so modeled ok_ui drops ou
- S2: Social Security counts net of Part B in the gross test; the OAC counts gross income and deducts the premium af
- S3: The medical deduction misses pretax payroll premiums (#10046) and reads is_disabled instead of the 7 CFR 271.2
- S4: Eight parameter descriptions are off the house template, and the student parameter misdescribes its scope
- S5: References: two missing page lists, a missing #page=1, and FY2025 limits dated and cited only from FY2026
- S6: farm_operations_income has no test that would fail if it were dropped

Also applies the in-scope suggestions. Tests not run locally; CI validates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hua7450 added a commit that referenced this pull request Oct 15, 2026
- S1: The unearned list reads the raw unemployment_compensation, so main's #9558 guard fails
- S2: Row G prints no Electric amount, but the PR pays $400 for electric heat in unsubsidized rent with no electric
- S3: Three pieces of logic have no test that fails when they break: excluded members' interest, 8 unearned sources
- S4: Six parameter descriptions fall outside the house template
- S5: Wrong rental anchor, Appendix H without page 2 and on two hosts, multi-page titles without page lists

Also applies the in-scope suggestions. Tests not run locally; CI validates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hua7450 added a commit that referenced this pull request Oct 15, 2026
- S1: Unearned list reads the raw unemployment_compensation (main's #9558 guard fails)
- S2: Regular cash help from family (financial_assistance) is excluded
- S3: Twelve parameter descriptions are off the house template (five have trailing sentences)
- S4: References: plan link without a page, incomplete page lists, rate parameters missing plan item 2.1

Also applies the in-scope suggestions. Tests not run locally; CI validates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hua7450 added a commit that referenced this pull request Oct 15, 2026
- S1: Unearned source list reads raw unemployment_compensation; main's #9558 guard fails
- S2: Premium deduction misses payroll (pretax) premiums (main #10046)
- S3: 2026 and 2027 pay the 2025 coefficients ($441 maximum) although the FY2026 matrix pays $31-$546
- S4: Size gate and NONE check are untested
- S5: Twelve parameter descriptions use off-template verbs
- S6: Wrong section label, two incomplete page lists, heat-in-rent branch lacks its E-4 citation
- REC-C: Coordinator recommendation C: federal 110% poverty floor (applies to Ohio from size 17)

Also applies the in-scope suggestions. Tests not run locally; CI validates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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