Skip to content

fix: include state tax refund income in federal gross income and exclude in conforming states - #9422

Open
jindal-git wants to merge 2 commits into
PolicyEngine:mainfrom
jindal-git:fix-9122-salt-refund-gross-income
Open

fix: include state tax refund income in federal gross income and exclude in conforming states#9422
jindal-git wants to merge 2 commits into
PolicyEngine:mainfrom
jindal-git:fix-9122-salt-refund-gross-income

Conversation

@jindal-git

Copy link
Copy Markdown
Contributor

Summary

Closes #9122.

State and local tax refund income (salt_refund_income, Form 1040 Schedule 1 Line 1 / IRC § 111) was previously omitted from irs_gross_income/sources.yaml. As a result:

  1. Federal Gross Income and AGI did not capture taxable state/local tax refunds.
  2. States starting from federal AGI/taxable income erroneously omitted refunds from the federal base, leading to distortions when state-level subtractions were applied (or double tax / unintended shifts).
  3. States conforming to federal AGI that should not tax prior-year state refunds require state-level subtractions/deductions so that federal inclusion does not artificially inflate state taxable income.

Changes

  1. Federal Gross Income & Variable Harmonization:

    • Added salt_refund_income to policyengine_us/parameters/gov/irs/gross_income/sources.yaml.
    • Harmonized salt_refund_last_year to aggregate adds = ["salt_refund_income"] and clarified documentation.
    • Added reference (IRC § 111) and documentation to salt_refund_income.
  2. State Subtractions & Deductions:

    • Added or activated salt_refund_income in subtractions/deductions across conforming states: CA, NY, PA, VA, GA, DC, CT, DE, HI, IL, MD, MI, MN, NC, NE, OH, OK, OR, RI, VT, WI, AZ, CO, IN, KY, ND, IA.
  3. Tests & Quality:

    • Added unit tests to policyengine_us/tests/policy/baseline/gov/irs/irs_gross_income.yaml (8 passed).
    • Added multi-state integration tests to policyengine_us/tests/policy/baseline/gov/irs/salt_refund_integration.yaml (5 passed).
    • Verified UT & CA state tax tests (3 passed).
    • Added changelog fragment changelog.d/fix-9122-salt-refund-gross-income.fixed.md.
    • Partner API contract tests under policyengine_us/tests/policy/baseline/partners/** remain completely untouched.
    • Code formatting verified with make format (ruff).

@anth-volk

Copy link
Copy Markdown
Contributor

Program review

Base repository: PolicyEngine/policyengine-us
PR number: 9422
Reviewed head SHA: 316e783
Merge base SHA: 8e212c1
Mode: full
Scope: changed behavior and affected dependencies
Source manifest: /private/tmp/policyengine-command-runs/75c2761f5079/pr-9422-review-sources.json
Review status: PARTIAL

Source Documents

Critical

C1 — Michigan subtracts refunds paid by other jurisdictions even though Michigan limits the subtraction to Michigan refunds (OPEN)

  • Location: policyengine_us/parameters/gov/states/mi/tax/income/subtractions.yaml:13 and :26; the broad input contract is in policyengine_us/variables/household/income/person/misc/salt_refund_income.py:7-11.
  • Trigger: A Michigan resident in tax year 2024 has $50,000 of employment income and a $2,000 federally taxable refund attributable entirely to income tax paid to another state, such as Ohio.
  • Observed: The PR treats the all-jurisdiction $2,000 salt_refund_income as a Michigan subtraction. A detached-snapshot calculation produced adjusted_gross_income = 52,000, mi_subtractions = 2,000, mi_taxable_income = 44,400, and mi_income_tax = 1,887.
  • Expected: Michigan Treasury limits this subtraction to “Michigan state and local income tax refunds to the extent included in AGI,” and Michigan Schedule 1 line 16 uses the same jurisdiction-specific wording. An Ohio refund must remain in Michigan income. With the same modeled exemption, taxable income should be $46,400 and Michigan tax $1,972, an $85 increase.
  • Impact: The PR understates Michigan taxable income by the taxable portion of refunds paid by other states or their localities, and understates 2024 tax by 4.25% of that amount until another boundary intervenes. The model cannot represent the correct distinction because salt_refund_income carries no paying-jurisdiction information.
  • Why introduced by this diff: Before the diff, Michigan did not subtract this broad variable. The new list entries route every state/local refund represented by the federal input through the Michigan-specific subtraction.
  • Required correction: Use a Michigan-specific input/derived variable for Michigan state and local refunds, or add a jurisdiction dimension that permits the subtraction to select only Michigan refunds. Do not use the undifferentiated all-jurisdiction input for this line.

Coordinator assessment: The exact previously executed command, inputs, outputs, and expected-value derivation were recovered without rerunning the calculation; see the Michigan diagnostic artifact.

Should Address

A1 — Existing salt_refund_last_year inputs no longer reach the new federal or Indiana paths (SHOULD ADDRESS) (OPEN)

  • Location: policyengine_us/variables/gov/local/tax/salt_refund_last_year.py:4-12; policyengine_us/parameters/gov/irs/gross_income/sources.yaml:33-34; policyengine_us/parameters/gov/states/in/tax/income/deductions/deductions.yaml:3-6 (and the later dated lists).
  • Trigger: A 2021-or-later situation supplies the existing TaxUnit input salt_refund_last_year, as the repository's Utah regression still does, rather than the new person input salt_refund_income. For example, an Indiana filer supplies salt_refund_last_year: 2_000 for 2024.
  • Expected: Either the existing supported input continues to feed affected federal/state calculations, or the pull request explicitly removes/migrates that input contract and adds a compatibility test documenting the breaking behavior.
  • Observed: The new relationship is one-way: salt_refund_last_year derives from salt_refund_income through adds. A direct input override of the aggregate does not populate its component. Federal gross income and Indiana deductions now consume only salt_refund_income, so they see zero in this case, while Utah still consumes salt_refund_last_year and sees 2,000. The existing test at policyengine_us/tests/policy/baseline/gov/states/ut/tax/income/taxable_income/ut_taxable_income.yaml:5 demonstrates that direct input of salt_refund_last_year remains part of the tested interface.
  • Impact: Existing household/API payloads using salt_refund_last_year produce state-dependent results after this change. Indiana loses the deduction it received before this diff, and the new federal inclusion is skipped. This is especially confusing because the class and test still accept the old input without an error.
  • Diff causality: This pull request adds the component-to-aggregate relationship, adds the component to federal gross income, and replaces Indiana's aggregate consumer with the component consumer, but adds no reverse mapping or migration guard.

A2 — Refund-specific tests do not cover the materially distinct changed state paths (SHOULD ADDRESS) (OPEN)

  • Location: policyengine_us/tests/policy/baseline/gov/irs/salt_refund_integration.yaml:1-45 compared with the 27 changed state parameter lists.
  • Trigger: A changed state list has an incorrect date, is not reachable from the final state base, or uses a base structure unlike California's federal-AGI path or Indiana's deduction aggregate.
  • Expected: Refund-specific cases for each materially distinct state-base structure, reaching a final state adjusted gross income, taxable income, or liability. State lists whose legal breadth or effective dates differ need their own cases.
  • Observed: The new file checks federal AGI, California AGI, Utah's pre-existing refund variable, Idaho AGI, and Indiana's intermediate in_deductions. Only California and Indiana are among the 27 changed state parameter files; Indiana does not reach final taxable income or liability. No new refund input reaches the changed paths for the other 25 states.
  • Impact: The tests can pass if one of those parameter lists is unreachable, dated incorrectly, or placed at the wrong stage. The passing pre-existing aggregate tests do not exercise the new source because their fixtures generally leave salt_refund_income at zero.
  • Diff causality: The diff changes 27 state parameter lists while adding only these five integration cases.

Suggestions

S1 — The two input descriptions disagree about whether the amount is taxable or total (SUGGESTION) (OPEN)

  • Location: policyengine_us/variables/household/income/person/misc/salt_refund_income.py:9-10; policyengine_us/variables/gov/local/tax/salt_refund_last_year.py:7-12; policyengine_us/parameters/gov/irs/gross_income/sources.yaml:33-34.
  • Trigger: A user reads the aggregate's new documentation (Total state and local tax refund income) or the federal list comment (State and local income tax refunds) and supplies the gross refund instead of the taxable portion described by salt_refund_income.
  • Expected: Every alias/comment states the same input contract, including that only the federally taxable portion is represented if that is the intended contract.
  • Observed: The component documentation says “Taxable ... refunds,” while the new aggregate documentation says “Total” and the federal comment omits the qualifier.
  • Impact: The conflicting metadata invites a materially larger federal gross-income input than §111 permits, even though the arithmetic itself consistently consumes the component.
  • Diff causality: All three descriptions are introduced or changed by this pull request.

Evidence Gaps

  • Official state-law verification remains incomplete for 21 changed jurisdictions: Arizona, California, Colorado, Connecticut, Delaware, Georgia, Hawaii, Iowa, Illinois, Indiana, Maryland, North Carolina, North Dakota, Nebraska, Oklahoma, Oregon, Pennsylvania, Rhode Island, Virginia, Vermont, and Wisconsin. For each, the review has not established whether the subtraction exists for every affected year and covers all jurisdictions or only the taxpayer's own state/localities.
  • Formula reachability, effective-date placement, and refund-specific final-output behavior remain unverified for the materially distinct changed state-base paths not covered by the new integration tests. Only California and Indiana are changed paths represented there, and Indiana is asserted only at an intermediate deduction aggregate.
  • Role checks incomplete: pr-9422-review-policy.md; see recovered report.
  • Role checks incomplete: pr-9422-review-code.md; see recovered report.

Notes

  • Federal inclusion is correct only under the revised input contract: salt_refund_income represents the taxable portion determined under IRC §111, not the gross Form 1099-G refund. This pull request does not calculate that taxable portion from prior-year deductions or the §164 limit.
  • No duplicate aggregation was found. salt_refund_last_year is consumed only by Utah, and no parameter list contains both refund variables.
  • D.C., Minnesota, Kentucky, Ohio, and New York official authorities supported the newly added category at the abstraction reviewed; Michigan produced the confirmed jurisdiction-scope defect.
  • The New York changed list should cite the current instruction line that supports the refund item rather than relying only on metadata for an unrelated existing subtraction.
  • The review exceeded the under-20-minute target because source acquisition continued past the configured five-minute budget and the combined test run occupied most of its nine-minute limit.

Validation Summary

At reviewed head 316e7832a180a99c0cf8476ec95573cdacb7ed98, 44 relevant YAML cases and 22 structural Python tests passed; the successful bounded command took 63.66 seconds and imported policyengine_us from the detached snapshot. A previously executed Michigan diagnostic showed federal AGI $52,000, Michigan subtractions $2,000, taxable income $44,400, and tax $1,887 for a $2,000 taxable Ohio refund; Michigan law implies no subtraction and $1,972 tax, an $85 understatement. GitHub reported no CI checks. Two downloaded official HTML sources passed checksum validation; additional official federal/state sources were read but not cached. No PDF layout issue required rendering.

Timing

setup seconds: 77.00s; scope seconds: 71.00s; parallel review seconds: 1087.00s; policy role seconds: 1077.00s; code role seconds: 1021.00s; adjudication seconds: 30.00s; consolidation cleanup seconds: 339.00s; elapsed seconds: 1556.00s

Review Severity

REQUEST_CHANGES. Open findings: 1 critical, 2 should address, 1 suggestions.

@jindal-git

Copy link
Copy Markdown
Contributor Author

Thank you for the detailed review! We have pushed updates in commit 5581f5b addressing findings A1, A2, and S1, and provided clarification below on C1:


Regarding C1 (Michigan out-of-state refunds):

PolicyEngine operates under a single-jurisdiction full-year resident model (household.state_code). PE explicitly does not support multi-state returns, part-year residency / mid-year moves, non-resident returns, or out-of-state income apportionment.

Under this single-state architecture:

  1. All income variables (employment_income, taxable_unemployment_compensation, tax_exempt_interest_income, salt_refund_income) are national and state-agnostic. For example, states with additions for out-of-state municipal bond interest (e.g., Illinois, Wisconsin) add tax_exempt_interest_income directly without requiring a state-by-state bond issuer dimension.
  2. For a full-year Michigan resident modeled in PolicyEngine, any prior-year state/local tax refund received is a Michigan refund. Under MCL 206.30(1)(c) and Form MI-1040 Schedule 1 Line 16, Michigan exempts Michigan state and local income tax refunds to the extent included in federal AGI.
  3. Omitting the subtraction in Michigan would cause 100% of modeled Michigan residents with state tax refunds to be erroneously double-taxed on their Michigan refunds.
  4. An out-of-state refund (e.g. an Ohio refund received by a Michigan resident) represents an out-of-state sourcing or part-year filing scenario, which is beyond PolicyEngine's single-state resident scope. Introducing a state-specific variable like mi_salt_refund_income or a jurisdiction dimension would break parity with every other income source in PE, break CPS/SOI microdata ingestion (where refunds have no state label), and create inconsistent UX where Michigan unexpectedly fails to subtract federal refunds.

A1 — Standardize on salt_refund_income and deprecate salt_refund_last_year:

  • Standardized all state refund inputs on the canonical Person-level input salt_refund_income.
  • Updated Utah (ut_state_tax_refund) to consume salt_refund_income directly.
  • Deprecated salt_refund_last_year with docstring deprecation notices while retaining read compatibility (adds = ["salt_refund_income"]).
  • Updated Utah regression tests and changelog documentation.

A2 — Comprehensive test coverage across all conforming states:

  • Expanded policyengine_us/tests/policy/baseline/gov/irs/salt_refund_integration.yaml to test all 27 conforming states (AZ, CA, CO, CT, DC, DE, GA, HI, IA, IL, IN, KY, MD, MI, MN, NC, ND, NE, NY, OH, OK, OR, PA, RI, UT, VA, VT, WI) and federal AGI. All 31 tests pass.

S1 — Harmonized "Taxable" terminology:

  • Aligned documentation across salt_refund_income.py, salt_refund_last_year.py, and parameters/gov/irs/gross_income/sources.yaml to consistently specify taxable state and local income tax refunds under IRC § 111 (Form 1040, Schedule 1, Line 1).

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.

State tax refunds (SALT refunds) not included in Federal Gross Income / Federal AGI, causing state subtraction distortions

2 participants