Repository navigation
Integrate modeled state unemployment insurance into income flows - #9558
Conversation
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 Report✅ All modified and coverable lines are covered by tests. 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
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
PavelMakarchuk
left a comment
There was a problem hiding this comment.
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
Fixes applied (02fec91): Pavel's reviewParameter-driven consumers migrated. Every
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):
Non-blocking items, all covered. The new
Reported zero. This is documented in Coverage checks
Also:
Verification. Local runs: 457 passed, 0 failed, and no existing expected value moved:
|
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
CI fix (3d57cdd): year-gate the modeled state UI programsFailure: Fix:
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:
|
Program ReviewSource Documents
Branch StatusThe branch is 3 commits ahead of and 83 commits behind Prior requests
Critical (Must Fix)None. Should AddressA1. The year gate has no direct test. The gate in SuggestionsS1. State that the year gate sets start years only. The comment at 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 S3. Case 8's comment misstates the law. S4. Case 7 cannot detect a revert of the UT consumer swap. The case at S5. Negative reported UC is now dropped. 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; 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 Pre-existing issues (not introduced by this PR; non-blocking)P1. Virginia subtracts total rather than taxable UC. P2. SC TANF counts taxable UC. P3. HI CCAP omits strike benefits. P4. Malformed reference. Investigated and cleared
Verified correct
Validation Summary
Review Severity: COMMENTAll 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 StepsTo auto-fix issues: run the fix-pr workflow for this PR. |
PavelMakarchuk
left a comment
There was a problem hiding this comment.
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.
…-flow-integration
…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
Fixes applied (7e47d92): Pavel's re-reviewA1, 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:
Suggestions:
Pre-existing items fixed here, in files this PR already edits:
Deferred:
Verification: |
…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
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
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
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LqCGPgxDukji8Bhs57c5rH
hua7450
left a comment
There was a problem hiding this comment.
[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, andira_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
#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
#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>
- 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>
- 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>
- 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>
- 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>
- 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>
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.
modeled_state_unemployment_compensation(Person/YEAR) sums the modeled state UI programs (al_ui,nj_unemployment_insurance,ny_ui,ok_ui,pa_ucandut_ui) through a year-gated list,gov.states.household.modeled_state_unemployment_compensation. NJ UC was modeled onmainafter Draft: Integrate modeled state unemployment insurance into income flows #8303 was opened, so it was added during the rebase.verified_yearsinprograms.yaml: OK 2022; AL, NJ and UT 2024; NY and PA 2025. Lists carry forward, so there is no end year.total_unemployment_compensation.0000-01-01base keeps early-year simulations (e.g., the 2010 AL SSP cases) from reaching state UI parameters that start later.total_unemployment_compensation(Person/YEAR) uses reportedunemployment_compensationwhen it is nonzero, and the modeled amount otherwise. Every nonzero reported value, including a negative one, passes through exactly as onmain. Nothing is counted twice.unemployment_compensationnow readstotal_unemployment_compensation:student_loan_interest_ald_magi) and the IRA deduction MAGI (ira_219g_magiandira_219g_taxable_social_security). Merges ofmainbrought these in after this PR opened. Each figures MAGI without regard to section 85(c), so it counts all UC, reported or modeled;household_benefitslist.parameters/gov/from the reported input: 117 now readtotal_unemployment_compensationand one, Virginia's, readstaxable_unemployment_compensation(see below). The hardcoded benefit lists in 4 contrib reforms (Tlaib ECPA and EDAA, BOOST, TX rebate) also use the total.mainafter 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.default_uprating, the 2025 Trustees reform's SOI tuple), the TAXSIM test generator, and the total's own formula.Pre-existing fixes in files this PR touches (review round 3)
strike_benefitsis not in microdata, so aggregates do not move.capped_qualified_tuition_expenses_aldlacked 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_compensationdeclared bothupratingandadds. policyengine-core rejects that combination when the variable is registered, so the package failed to import. The fix, described in this comment:unemployment_compensationstays the pure uprated survey input, unchanged, so future-year microsim uprating and CPS-reported values are unaffected;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.al_ui= $3,850, but modeled, total, tax-unit and taxable UC = $0) and 2010 (modeled and total UC = $0, pinning the empty base).taxable_ss_magi($10,218);adjusted_gross_incomeon each state's "feeds income flows" case (AL 103,850, NY 107,982 withny_agi, OK 108,000, PA 110,218, UT 119,396).main. Each modeled case has a reported-UC control with the same result:student_loan_interest_ald_magi$95,218 (was $85,000) andstudent_loan_interest_ald$797 (was $2,500);ira_219g_magi$90,218 (was $80,000);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_heap_countable_income$7,980 after monthly flooring (was $0);nj_liheap_countable_income_person$6,000 (was $0);tests/code_health/test_unemployment_compensation_readers.pyfails when a parameter list entry or a Python string constant names the rawunemployment_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_compensationasserts thatmodeled_state_unemployment_compensationis 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.Validation
SNAP before and after, for a PA single adult with no earnings and $10,218 of modeled UC, in January 2025:
Local tests on this round: 201 passed, 0 failed.
total_unemployment_compensation.yaml(18),ira_phase_out.yaml(15) andstudent_loan_interest_ald.yaml(13).test_modified_agi_add_backs.py(13).Local tests after merging current
main(85 commits): 132 passed, 0 failed.total_unemployment_compensation.yaml: 18/18.spm_unit_benefits.yaml: 6/6.va_subtractions_person,va_agi_personandintegration: 16.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
sc/tanf/income/unearned.yaml). This is outside the diff and the Social Security half changes SC TANF in every year, so it is tracked in South Carolina TANF counts taxable UC and taxable Social Security instead of gross amounts #9677 and fixed in the stacked Count gross unemployment compensation and Social Security in South Carolina TANF #9687, which fixes both halves together.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