From 084685c061d2fe96f5dba5be193de14469f4b0e3 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 16:36:49 -0400 Subject: [PATCH 1/6] Fix the 2020 unemployment compensation exclusion (IRC 85(c)) - Compare taxable_uc_agi, which already leaves out unemployment compensation, with the $150,000 cutoff instead of subtracting the compensation from it a second time. - Exclude up to $10,200 of each person's own compensation, so each spouse on a joint return excludes up to $10,200 (worksheet lines 8 and 9). - Keep a dependent's compensation on the dependent's own return: the tax unit's taxable compensation sums only members who are not dependents, and a dependent's exclusion is tested on a new dependent_taxable_uc_agi. Co-Authored-By: Claude Opus 5.5 --- changelog.d/fix-uc-exclusion-2020.fixed.md | 1 + .../exemption/amount.yaml | 13 +- .../exemption/cutoff.yaml | 10 +- .../dependent_taxable_uc_agi.yaml | 67 ++++ ...nit_taxable_unemployment_compensation.yaml | 92 +++-- .../taxable_unemployment_compensation.yaml | 332 +++++++++++++++++- .../dependent_taxable_uc_agi.py | 46 +++ ..._unit_taxable_unemployment_compensation.py | 19 +- .../unemployment_insurance/taxable_uc_agi.py | 27 +- .../taxable_unemployment_insurance.py | 46 ++- 10 files changed, 590 insertions(+), 63 deletions(-) create mode 100644 changelog.d/fix-uc-exclusion-2020.fixed.md create mode 100644 policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.yaml create mode 100644 policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.py diff --git a/changelog.d/fix-uc-exclusion-2020.fixed.md b/changelog.d/fix-uc-exclusion-2020.fixed.md new file mode 100644 index 00000000000..81abfe0902c --- /dev/null +++ b/changelog.d/fix-uc-exclusion-2020.fixed.md @@ -0,0 +1 @@ +Fixed the 2020 unemployment compensation exclusion: the $150,000 test no longer subtracts the compensation twice, each spouse on a joint return excludes up to $10,200 of their own compensation, and a dependent's compensation is excluded on the dependent's own return instead of using the filers' exclusion. diff --git a/policyengine_us/parameters/gov/irs/unemployment_compensation/exemption/amount.yaml b/policyengine_us/parameters/gov/irs/unemployment_compensation/exemption/amount.yaml index e26a94f6b66..708b70dc87f 100644 --- a/policyengine_us/parameters/gov/irs/unemployment_compensation/exemption/amount.yaml +++ b/policyengine_us/parameters/gov/irs/unemployment_compensation/exemption/amount.yaml @@ -1,7 +1,14 @@ -description: Unemployment Insurance exemption amount -metadata: - unit: currency-USD +description: The IRS excludes up to this amount of the unemployment compensation each person received from gross income, for each spouse on a joint return, when adjusted gross income is under the cutoff. values: 2013-01-01: 0 2020-01-01: 10_200 2021-01-01: 0 +metadata: + unit: currency-USD + period: year + label: Unemployment compensation exclusion amount per recipient + reference: + - title: 26 U.S. Code § 85(c)(1) - Special rule for 2020 + href: https://www.law.cornell.edu/uscode/text/26/85#c_1 + - title: 2020 Instructions for Form 1040 (rev. 4-2021), Unemployment Compensation Exclusion Worksheet, lines 8 and 9 + href: https://www.irs.gov/pub/irs-prior/i1040gi--2020.pdf#page=88 diff --git a/policyengine_us/parameters/gov/irs/unemployment_compensation/exemption/cutoff.yaml b/policyengine_us/parameters/gov/irs/unemployment_compensation/exemption/cutoff.yaml index ca7a83e4906..eac52054675 100644 --- a/policyengine_us/parameters/gov/irs/unemployment_compensation/exemption/cutoff.yaml +++ b/policyengine_us/parameters/gov/irs/unemployment_compensation/exemption/cutoff.yaml @@ -1,4 +1,4 @@ -description: Unemployment Insurance exemption cutoff +description: The IRS allows the unemployment compensation exclusion when adjusted gross income, figured without unemployment compensation, is under this amount. HEAD_OF_HOUSEHOLD: 2013-01-01: 0 2020-01-01: 150_000 @@ -21,7 +21,13 @@ SURVIVING_SPOUSE: 2021-01-01: 0 metadata: propagate_metadata_to_children: true - label: Unemployment compensation exemption cutoff + label: Unemployment compensation exclusion cutoff + period: year breakdown: - filing_status unit: currency-USD + reference: + - title: 26 U.S. Code § 85(c) - Special rule for 2020 + href: https://www.law.cornell.edu/uscode/text/26/85#c + - title: 2020 Instructions for Form 1040 (rev. 4-2021), Unemployment Compensation Exclusion Worksheet, lines 6 and 7 + href: https://www.irs.gov/pub/irs-prior/i1040gi--2020.pdf#page=88 diff --git a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.yaml b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.yaml new file mode 100644 index 00000000000..98bb5021d75 --- /dev/null +++ b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.yaml @@ -0,0 +1,67 @@ +# A dependent's IRC 85(c)(2) adjusted gross income on their own return: line 6 +# of the 2020 Unemployment Compensation Exclusion Worksheet (Instructions for +# Form 1040, rev. 4-2021, p. 88), figured with the dependent's own income. +- name: Case 1, the dependent's own income less their own adjustments, without the compensation. + period: 2020 + input: + people: + person1: + age: 45 + employment_income: 50_000 + person2: + age: 19 + is_full_time_student: true + employment_income: 12_000 + early_withdrawal_penalty: 100 + unemployment_compensation: 4_000 + person3: + age: 43 + tax_units: + tax_unit: + members: [person1, person3, person2] + marital_units: + marital_unit: + members: [person1, person3] + households: + household: + members: [person1, person3, person2] + state_code: TX + output: + # Line 1: 12,000 of wages. Line 5: 100. Line 6: 11,900. The head and + # spouse are not dependents and are tested on the tax unit's return. + is_tax_unit_dependent: [false, true, false] + dependent_taxable_uc_agi: [0, 11_900, 0] + +- name: Case 2, the dependent's Social Security is taxable on the full compensation. + period: 2020 + input: + people: + person1: + age: 45 + employment_income: 50_000 + person2: + age: 19 + is_full_time_student: true + employment_income: 30_000 + social_security_survivors: 10_000 + unemployment_compensation: 6_000 + person3: + age: 43 + tax_units: + tax_unit: + members: [person1, person3, person2] + marital_units: + marital_unit: + members: [person1, person3] + households: + household: + members: [person1, person3, person2] + state_code: TX + output: + # Social Security Benefits Worksheet (p. 31), unmarried: line 3, 30,000 + # + 6,000 = 36,000; line 5, 36,000 + 5,000 = 41,000. Taxable: the lesser + # of 85% x (41,000 - 34,000) + 4,500 = 10,450 and 85% x 10,000 = 8,500. + # Exclusion worksheet line 6: 30,000 + 8,500 = 38,500. + is_tax_unit_dependent: [false, true, false] + dependent_taxable_social_security: [0, 8_500, 0] + dependent_taxable_uc_agi: [0, 38_500, 0] diff --git a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_taxable_unemployment_compensation.yaml b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_taxable_unemployment_compensation.yaml index bb05654b3f4..fd48121bc12 100644 --- a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_taxable_unemployment_compensation.yaml +++ b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_taxable_unemployment_compensation.yaml @@ -1,37 +1,52 @@ # 26 USC 85(c)(1) excludes up to $10,200 of 2020 unemployment compensation -# only if AGI (determined without regard to unemployment compensation) is -# strictly less than $150,000. -- name: No exclusion in 2020 when AGI over UC equals the $150,000 cutoff exactly +# only if AGI, determined without regard to section 85 and so without any +# unemployment compensation (85(c)(2)(B)), is strictly less than $150,000. +# 2020 Unemployment Compensation Exclusion Worksheet (Instructions for Form +# 1040, rev. 4-2021, p. 88), lines 6 and 7. +- name: Case 1, no exclusion when AGI without the compensation equals the cutoff. period: 2020 input: people: head: age: 40 - employment_income: 155_000 + employment_income: 150_000 unemployment_compensation: 5_000 tax_units: tax_unit: members: [head] filing_status: SINGLE - marital_units: - marital_unit: - members: [head] - families: - family: + households: + household: members: [head] - spm_units: - spm_unit: + state_code: TX + output: + # Line 6: 150,000 of wages. Line 7: $150,000 or more, so all of the + # compensation is taxable. + taxable_uc_agi: 150_000 + tax_unit_taxable_unemployment_compensation: 5_000 + +- name: Case 2, full exclusion when AGI without the compensation is one dollar below the cutoff. + period: 2020 + input: + people: + head: + age: 40 + employment_income: 149_999 + unemployment_compensation: 5_000 + tax_units: + tax_unit: members: [head] + filing_status: SINGLE households: household: members: [head] state_code: TX output: - # AGI over UC = 155,000 - 5,000 = 150,000, not below the cutoff, - # so all unemployment compensation is taxable. - tax_unit_taxable_unemployment_compensation: 5_000 + # Line 6: 149,999, under the cutoff. Line 8: 5,000. + taxable_uc_agi: 149_999 + tax_unit_taxable_unemployment_compensation: 0 -- name: Full exclusion in 2020 when AGI over UC is one dollar below the cutoff +- name: Case 3, the compensation itself does not count toward the cutoff. period: 2020 input: people: @@ -43,20 +58,45 @@ tax_unit: members: [head] filing_status: SINGLE + households: + household: + members: [head] + state_code: TX + output: + # Line 6: 154,999, the wages alone. Subtracting the 5,000 of + # compensation from it (149,999) would wrongly allow the exclusion. + taxable_uc_agi: 154_999 + tax_unit_taxable_unemployment_compensation: 5_000 + +- name: Case 4, the joint return sums each spouse's taxable compensation and leaves out a dependent's. + period: 2020 + input: + people: + head: + age: 45 + employment_income: 40_000 + unemployment_compensation: 15_000 + spouse: + age: 43 + unemployment_compensation: 12_000 + child: + age: 17 + unemployment_compensation: 11_000 + tax_units: + tax_unit: + members: [head, spouse, child] marital_units: marital_unit: - members: [head] - families: - family: - members: [head] - spm_units: - spm_unit: - members: [head] + members: [head, spouse] households: household: - members: [head] + members: [head, spouse, child] state_code: TX output: - # AGI over UC = 154,999 - 5,000 = 149,999, below the $150,000 cutoff, - # so unemployment compensation up to $10,200 is excluded. - tax_unit_taxable_unemployment_compensation: 0 + # Line 6: 40,000. Line 8: 10,200. Line 9: 10,200. Line 10: 20,400 of + # the couple's 27,000, so 6,600 is taxable on their return. The child's + # 11,000 (800 taxable after the child's own exclusion) is on the + # child's return. + taxable_unemployment_compensation: [4_800, 1_800, 800] + tax_unit_taxable_unemployment_compensation: 6_600 + adjusted_gross_income: 46_600 diff --git a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_compensation.yaml b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_compensation.yaml index 964a4f25cc0..47cb6def2c9 100644 --- a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_compensation.yaml +++ b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_compensation.yaml @@ -1,4 +1,16 @@ -- name: Taxable UC allocated to spouse when only spouse received UC +# Each person's taxable unemployment compensation is their own compensation +# less the part IRC 85(c) excludes on the return it is reported on. The 2020 +# cases follow the 2020 Unemployment Compensation Exclusion Worksheet +# (Instructions for Form 1040, rev. 4-2021, p. 88): +# lines 1-4: total income without unemployment compensation (Form 1040 +# lines 1-7, Schedule 1 lines 1-6 and 8) +# line 5: adjustments (Form 1040 line 10c) +# line 6: modified AGI = line 4 - line 5 +# line 7: no exclusion when line 6 is $150,000 or more +# lines 8-9: compensation paid to you, and on a joint return to your +# spouse, each up to $10,200 +# line 10: exclusion = line 8 + line 9 +- name: Case 1, taxable compensation stays with the spouse who received it. period: 2025 input: people: @@ -27,7 +39,7 @@ output: taxable_unemployment_compensation: [0, 19_000] -- name: Taxable UC split in proportion to person-level UC +- name: Case 2, outside 2020 each spouse's compensation is fully taxable. period: 2025 input: people: @@ -56,7 +68,7 @@ output: taxable_unemployment_compensation: [5_000, 15_000] -- name: Zero UC produces zero allocation +- name: Case 3, no compensation means no taxable compensation. period: 2025 input: people: @@ -82,3 +94,317 @@ state_code: CA output: taxable_unemployment_compensation: [0] + +- name: Case 4, modified AGI of exactly 150,000 without the compensation allows no exclusion. + period: 2020 + input: + people: + person1: + age: 66 + taxable_pension_income: 150_000 + unemployment_compensation: 8_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MT + output: + # Worksheet line 1: Form 1040 line 4b pensions, 150,000; lines 2, 3 and + # 5: 0; line 6: 150,000. Line 7: 150,000 or more, so nothing is + # excluded. The compensation is not subtracted from line 6 again. + taxable_uc_agi: 150_000 + taxable_unemployment_compensation: [8_000] + tax_exempt_unemployment_compensation: [0] + tax_unit_taxable_unemployment_compensation: 8_000 + adjusted_gross_income: 158_000 + +- name: Case 5, modified AGI one dollar under 150,000 allows the exclusion. + period: 2020 + input: + people: + person1: + age: 66 + taxable_pension_income: 149_999 + unemployment_compensation: 8_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MT + output: + # Line 6: 149,999, under 150,000. Line 8: 8,000 (under 10,200). Line 10: + # 8,000, all of Schedule 1 line 7. + taxable_uc_agi: 149_999 + taxable_unemployment_compensation: [0] + tax_exempt_unemployment_compensation: [8_000] + tax_unit_taxable_unemployment_compensation: 0 + adjusted_gross_income: 149_999 + +- name: Case 6, each spouse on a joint return excludes up to 10,200 of their own compensation. + period: 2020 + input: + people: + person1: + age: 45 + employment_income: 60_000 + unemployment_compensation: 20_000 + person2: + age: 43 + unemployment_compensation: 5_000 + tax_units: + tax_unit: + members: [person1, person2] + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: TX + output: + # The example in the 2020 Form 1040 instructions (p. 87): "You were paid + # $20,000 of unemployment compensation and your spouse was paid $5,000. + # Report the $25,000 ... on line 7 and report $15,200 on line 8 as a + # negative amount." Line 6: 60,000. Line 8: min(20,000, 10,200) = + # 10,200. Line 9: min(5,000, 10,200) = 5,000. Line 10: 15,200. + filing_status: JOINT + taxable_uc_agi: 60_000 + taxable_unemployment_compensation: [9_800, 0] + tax_exempt_unemployment_compensation: [10_200, 5_000] + tax_unit_taxable_unemployment_compensation: 9_800 + adjusted_gross_income: 69_800 + +- name: Case 7, two spouses over 10,200 each exclude 10,200. + period: 2020 + input: + people: + person1: + age: 45 + unemployment_compensation: 20_000 + person2: + age: 43 + unemployment_compensation: 20_000 + tax_units: + tax_unit: + members: [person1, person2] + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: TX + output: + # Line 6: 0. Lines 8 and 9: 10,200 each. Line 10: 20,400 of 40,000. + taxable_uc_agi: 0 + taxable_unemployment_compensation: [9_800, 9_800] + tax_exempt_unemployment_compensation: [10_200, 10_200] + tax_unit_taxable_unemployment_compensation: 19_600 + adjusted_gross_income: 19_600 + +- name: Case 8, a dependent's compensation does not use the filers' exclusion. + period: 2020 + input: + people: + person1: + age: 45 + employment_income: 30_000 + person2: + age: 43 + unemployment_compensation: 8_000 + person3: + age: 20 + is_full_time_student: true + unemployment_compensation: 4_000 + tax_units: + tax_unit: + members: [person1, person2, person3] + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2, person3] + state_code: MT + output: + # The couple's worksheet: line 6, 30,000; line 8, 0; line 9, 8,000 (the + # spouse's own compensation); line 10, 8,000, so none of their 8,000 is + # taxable. The dependent's 4,000 is on the dependent's own return, where + # the dependent excludes all of it (own modified AGI 0). + is_tax_unit_dependent: [false, false, true] + taxable_uc_agi: 30_000 + dependent_taxable_uc_agi: [0, 0, 0] + taxable_unemployment_compensation: [0, 0, 0] + tax_exempt_unemployment_compensation: [0, 8_000, 4_000] + tax_unit_taxable_unemployment_compensation: 0 + adjusted_gross_income: 30_000 + +- name: Case 9, a dependent excludes up to 10,200 on their own return. + period: 2020 + input: + people: + person1: + age: 45 + employment_income: 30_000 + person2: + age: 43 + person3: + age: 20 + is_full_time_student: true + unemployment_compensation: 15_000 + tax_units: + tax_unit: + members: [person1, person2, person3] + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2, person3] + state_code: TX + output: + # The dependent's own worksheet: line 6, 0; line 8, min(15,000, 10,200) + # = 10,200; 4,800 is taxable on the dependent's return. None of it is on + # the filers' return. + is_tax_unit_dependent: [false, false, true] + taxable_unemployment_compensation: [0, 0, 4_800] + tax_exempt_unemployment_compensation: [0, 0, 10_200] + tax_unit_taxable_unemployment_compensation: 0 + adjusted_gross_income: 30_000 + +- name: Case 10, a dependent with modified AGI of 150,000 excludes nothing. + period: 2020 + input: + people: + person1: + age: 45 + employment_income: 30_000 + unemployment_compensation: 5_000 + person2: + age: 43 + person3: + age: 20 + is_full_time_student: true + dividend_income: 150_000 + unemployment_compensation: 5_000 + tax_units: + tax_unit: + members: [person1, person2, person3] + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2, person3] + state_code: TX + output: + # The dependent's own worksheet: line 1, Form 1040 line 3b dividends, + # 150,000; line 6, 150,000, so the dependent excludes nothing. The + # filers' worksheet: line 6, 30,000 (the dependent's dividends are on + # the dependent's return); line 8, 5,000; nothing taxable. + is_tax_unit_dependent: [false, false, true] + taxable_uc_agi: 30_000 + dependent_taxable_uc_agi: [0, 0, 150_000] + taxable_unemployment_compensation: [0, 0, 5_000] + tax_exempt_unemployment_compensation: [5_000, 0, 0] + tax_unit_taxable_unemployment_compensation: 0 + adjusted_gross_income: 30_000 + +- name: Case 11, modified AGI counts Social Security made taxable by the full compensation. + period: 2020 + input: + people: + person1: + age: 66 + taxable_pension_income: 140_000 + social_security_retirement: 20_000 + unemployment_compensation: 10_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: TX + output: + # IRC 85(c)(2)(A): AGI after section 86. Social Security Benefits + # Worksheet (p. 31) line 3 includes the full compensation: 140,000 + + # 10,000 = 150,000; line 5: 150,000 + 10,000 (half the benefits) = + # 160,000, so 85% of the benefits, 17,000, is taxable. Exclusion + # worksheet line 1: 140,000 + 17,000 = 157,000 = line 6, 150,000 or + # more, so nothing is excluded. + tax_unit_taxable_social_security: 17_000 + taxable_uc_agi: 157_000 + taxable_unemployment_compensation: [10_000] + tax_unit_taxable_unemployment_compensation: 10_000 + adjusted_gross_income: 167_000 + +- name: Case 12, adjustments to income reduce modified AGI. + period: 2020 + input: + people: + person1: + age: 40 + employment_income: 150_400 + early_withdrawal_penalty: 500 + unemployment_compensation: 5_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: TX + output: + # Line 4: 150,400. Line 5: Schedule 1 line 15 penalty on early + # withdrawal of savings, 500. Line 6: 149,900, under 150,000. Line 8: + # 5,000. + taxable_uc_agi: 149_900 + taxable_unemployment_compensation: [0] + adjusted_gross_income: 149_900 + +- name: Case 13, the exclusion ends after 2020. + period: 2021 + input: + people: + person1: + age: 40 + employment_income: 30_000 + unemployment_compensation: 8_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: TX + output: + taxable_unemployment_compensation: [8_000] + tax_exempt_unemployment_compensation: [0] + tax_unit_taxable_unemployment_compensation: 8_000 + +- name: Case 14, a net repayment is not excluded. + period: 2020 + input: + people: + person1: + age: 40 + employment_income: 30_000 + unemployment_compensation: -500 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: TX + output: + # Only compensation received can be excluded, so the exempt amount is + # never negative. + taxable_unemployment_compensation: [-500] + tax_exempt_unemployment_compensation: [0] + adjusted_gross_income: 30_000 diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.py b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.py new file mode 100644 index 00000000000..64468c4dbc9 --- /dev/null +++ b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.py @@ -0,0 +1,46 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.irs.income.taxable_income.adjusted_gross_income.irs_gross_income.social_security.dependent_taxable_ss_magi import ( + dependent_income_and_deductions, +) + + +class dependent_taxable_uc_agi(Variable): + value_type = float + entity = Person + label = ( + "Dependent's adjusted gross income for the unemployment compensation exclusion" + ) + unit = USD + documentation = """ + The adjusted gross income of IRC 85(c)(2), figured on a dependent's own + return: adjusted gross income after taxable Social Security and the + dependent's own above-the-line deductions, without any unemployment + compensation. It is taxable_uc_agi for a dependent, whose income + irs_gross_income leaves off the tax unit's return. + """ + definition_period = YEAR + defined_for = "is_tax_unit_dependent" + reference = ( + "https://www.law.cornell.edu/uscode/text/26/85#c_2", + # 2020 Instructions for Form 1040 (rev. 4-2021), Unemployment + # Compensation Exclusion Worksheet, lines 1 through 6. + "https://www.irs.gov/pub/irs-prior/i1040gi--2020.pdf#page=88", + ) + + def formula(person, period, parameters): + # The dependent's own income, with unemployment compensation in full + # and without Social Security, and their own above-the-line + # deductions. Of the deductions that list leaves out (IRC 86(b)(2)), + # IRC 85(c)(2)(A) applies sections 135, 137 and 221, but none of them + # is the dependent's: the model records the section 135 and 137 + # exclusions for the filer (gov.irs.ald.filer_amounts_recorded_on_ + # dependents), and IRC 221(c) denies a dependent the student loan + # interest deduction. + income, deductions = dependent_income_and_deductions(person, period, parameters) + # IRC 85(c)(2)(B): without regard to section 85, so without the + # compensation (worksheet line 2 leaves out Schedule 1, line 7). + income -= max_(0, person("unemployment_compensation", period)) + # IRC 85(c)(2)(A): after section 86 (worksheet line 1 includes Form + # 1040, line 6b). + income += person("dependent_taxable_social_security", period) + return income - add(person, period, deductions) diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_taxable_unemployment_compensation.py b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_taxable_unemployment_compensation.py index 9cbaae0d4ff..661a0770ce2 100644 --- a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_taxable_unemployment_compensation.py +++ b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_taxable_unemployment_compensation.py @@ -6,19 +6,12 @@ class tax_unit_taxable_unemployment_compensation(Variable): entity = TaxUnit label = "Taxable unemployment compensation" unit = USD - documentation = "Unemployment compensation included in AGI." + documentation = ( + "Unemployment compensation included in AGI: the taxable unemployment " + "compensation of the members who are not dependents. A dependent's " + "compensation is on the dependent's own return." + ) definition_period = YEAR reference = "https://www.law.cornell.edu/uscode/text/26/85" - def formula(tax_unit, period, parameters): - ui = parameters(period).gov.irs.unemployment_compensation - uc_amount = tax_unit("tax_unit_unemployment_compensation", period) - agi = tax_unit("taxable_uc_agi", period) - agi_over_uc = agi - uc_amount - filing_status = tax_unit("filing_status", period) - uc_excluded = where( - agi_over_uc < ui.exemption.cutoff[filing_status], - min_(uc_amount, ui.exemption.amount), - 0, - ) - return uc_amount - uc_excluded + formula = sum_among_non_dependents("taxable_unemployment_compensation") diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_uc_agi.py b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_uc_agi.py index 20045f03cf3..1da3faf0b9e 100644 --- a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_uc_agi.py +++ b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_uc_agi.py @@ -4,16 +4,33 @@ class taxable_uc_agi(Variable): value_type = float entity = TaxUnit - label = "Taxable unemployment compensation for SS adjusted gross income" + label = "Adjusted gross income for the unemployment compensation exclusion" unit = USD - documentation = "Income used to determine taxability of unemployment compensation." + documentation = ( + "The adjusted gross income IRC 85(c) compares with the cutoff: " + "adjusted gross income after taxable Social Security and the " + "above-the-line deductions, without any unemployment compensation " + "(IRC 85(c)(2)). It is line 6 of the 2020 Unemployment Compensation " + "Exclusion Worksheet." + ) definition_period = YEAR - reference = "https://www.law.cornell.edu/uscode/text/26/85" + reference = ( + "https://www.law.cornell.edu/uscode/text/26/85#c_2", + # 2020 Instructions for Form 1040 (rev. 4-2021), Unemployment + # Compensation Exclusion Worksheet, lines 1 through 6. + "https://www.irs.gov/pub/irs-prior/i1040gi--2020.pdf#page=88", + ) def formula(tax_unit, period, parameters): irs = parameters(period).gov.irs gross_income_sources = irs.gross_income.sources - income_sources_without_ss = [ + # IRC 85(c)(2)(B): without regard to section 85, so without any + # unemployment compensation. Taxable Social Security, the IRA + # deduction and the student loan interest and tuition and fees + # deductions, which this counts (85(c)(2)(A)), are figured with all + # of it (IRC 86(b)(2)(A), 219(g)(3)(A)(ii), 221(b)(2)(C); 2020 + # Instructions for Form 1040, p. 87, line 7 caution). + income_sources_without_uc = [ income_source for income_source in gross_income_sources if income_source != "taxable_unemployment_compensation" @@ -21,7 +38,7 @@ def formula(tax_unit, period, parameters): gross_income = 0 person = tax_unit.members not_dependent = ~person("is_tax_unit_dependent", period) - for source in income_sources_without_ss: + for source in income_sources_without_uc: # Add positive values only - losses are deducted later. gross_income += not_dependent * max_(0, add(person, period, [source])) gross_income = tax_unit.sum(gross_income) diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_insurance.py b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_insurance.py index 707baf719c0..44c02a8539c 100644 --- a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_insurance.py +++ b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_insurance.py @@ -6,18 +6,42 @@ class taxable_unemployment_compensation(Variable): entity = Person label = "Taxable unemployment compensation" unit = USD + documentation = ( + "Unemployment compensation a person received less the part IRC 85(c) " + "excludes from gross income on the return it is reported on: the tax " + "unit's return for the head and spouse, the dependent's own return " + "for a dependent." + ) definition_period = YEAR + reference = ( + "https://www.law.cornell.edu/uscode/text/26/85", + # 2020 Instructions for Form 1040 (rev. 4-2021), Unemployment + # Compensation Exclusion Worksheet, Schedule 1, line 8. + "https://www.irs.gov/pub/irs-prior/i1040gi--2020.pdf#page=88", + ) def formula(person, period, parameters): - # The taxable amount of unemployment compensation is decided at the tax - # unit level, but gross income (which contains taxable UI) is person-level. - # Allocate the tax unit's taxable UC to each person in proportion to their - # unemployment_compensation, so that per-person AGI reflects the actual - # recipient (required by states with combined-return optimization). - tax_unit_taxable_uc = person.tax_unit( - "tax_unit_taxable_unemployment_compensation", period + p = parameters(period).gov.irs.unemployment_compensation.exemption + received = person("unemployment_compensation", period) + # IRC 85(c)(1) tests the adjusted gross income of the return the + # compensation is on. Members who are not dependents are on the tax + # unit's return, as in irs_gross_income. + filing_status = person.tax_unit("filing_status", period) + filer_agi = person.tax_unit("taxable_uc_agi", period) + filer_eligible = filer_agi < p.cutoff[filing_status] + # A dependent's compensation is on the dependent's own return, filed + # separately if they live with their spouse and single otherwise + # (a dependent can't file jointly or claim dependents). + lives_with_spouse = person("dependent_lives_with_spouse", period) + dependent_cutoff = where( + lives_with_spouse, p.cutoff["SEPARATE"], p.cutoff["SINGLE"] ) - person_uc = person("unemployment_compensation", period) - tax_unit_uc = person.tax_unit.sum(person_uc) - share = where(tax_unit_uc > 0, person_uc / tax_unit_uc, 0) - return tax_unit_taxable_uc * share + dependent_agi = person("dependent_taxable_uc_agi", period) + dependent_eligible = dependent_agi < dependent_cutoff + is_dependent = person("is_tax_unit_dependent", period) + eligible = where(is_dependent, dependent_eligible, filer_eligible) + # Each person excludes up to the amount of the compensation they + # received, so on a joint return each spouse does (worksheet lines 8 + # and 9). A net repayment is not excluded. + excluded = eligible * min_(max_(0, received), p.amount) + return received - excluded From 1bce3dfe6af673fde9a1754d5f37eb01e93edc9a Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 16:46:40 -0400 Subject: [PATCH 2/6] Add property tests for the 2020 unemployment compensation exclusion Hypothesis batches of single, joint, joint-with-dependent and single-parent tax units near the $150,000 cutoff check: per-person bounds, the cutoff on the filers' and each dependent's own return, a differential between taxable_uc_agi and AGI less the taxable compensation, that dependents' compensation never moves the filers' return, and spouse symmetry; and that nothing is excluded in 2021. Co-Authored-By: Claude Opus 5.5 --- ...yment_compensation_exclusion_invariants.py | 285 ++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 policyengine_us/tests/core/test_unemployment_compensation_exclusion_invariants.py diff --git a/policyengine_us/tests/core/test_unemployment_compensation_exclusion_invariants.py b/policyengine_us/tests/core/test_unemployment_compensation_exclusion_invariants.py new file mode 100644 index 00000000000..10745b44693 --- /dev/null +++ b/policyengine_us/tests/core/test_unemployment_compensation_exclusion_invariants.py @@ -0,0 +1,285 @@ +"""Invariants for the 2020 unemployment compensation exclusion, IRC 85(c). + +IRC 85(c)(1): for a taxable year beginning in 2020, a taxpayer whose adjusted +gross income is less than $150,000 excludes up to $10,200 of the unemployment +compensation they received, "or, in the case of a joint return, received by +each spouse". IRC 85(c)(2): that adjusted gross income is figured after +section 86 and without regard to section 85, so without any unemployment +compensation (2020 Unemployment Compensation Exclusion Worksheet, line 6). +A dependent's compensation is on the dependent's own return. + +Hypothesis draws batches of tax units (single, joint, joint with a child or +student dependent, single parent) with income near the $150,000 cutoff. Each +drawn unit appears three times in one vectorized 2020 simulation: as drawn, +with its dependents' compensation set to zero, and with the head's and +spouse's compensation swapped. A 2021 simulation of the drawn units checks +that the exclusion ends. For every person and tax unit: + +1. Bounds: the exempt part of each person's compensation is between zero and + the lesser of what they received and $10,200, and zero in 2021. +2. Cutoff: the head's and spouse's compensation is exempt only when the tax + unit's `taxable_uc_agi` is under $150,000, a dependent's only when their + own `dependent_taxable_uc_agi` is, and then each person's exempt part is + the lesser of their own compensation and $10,200. +3. Differential: `taxable_uc_agi` equals adjusted gross income less the + taxable compensation on the return, floored at zero. The model figures + AGI without the compensation once from gross income sources and once, + here, from AGI itself; the two must agree, so the compensation is left + out exactly once. +4. Return boundary: the tax unit's taxable compensation is the sum over its + head and spouse, and dependents' compensation never changes the filers' + taxable compensation, `taxable_uc_agi` or AGI. +5. Symmetry: swapping the head's and spouse's compensation swaps their + taxable compensation and leaves the return's total unchanged. +""" + +import numpy as np +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +from policyengine_us import Simulation + +CUTOFF = 150_000 +AMOUNT = 10_200 +TOLERANCE = dict(rtol=1e-6, atol=0.01) + +PERSON_OUTPUTS = [ + "unemployment_compensation", + "taxable_unemployment_compensation", + "tax_exempt_unemployment_compensation", + "is_tax_unit_dependent", + "dependent_taxable_uc_agi", +] +TAX_UNIT_OUTPUTS = [ + "taxable_uc_agi", + "tax_unit_taxable_unemployment_compensation", + "adjusted_gross_income", +] +VARIANTS = ["drawn", "no_dependent_uc", "swapped"] + +# Amounts that land on and around the cutoff and the exclusion cap. +money = st.one_of( + st.just(0), + st.integers(1, 200_000), + st.sampled_from([CUTOFF - 1, CUTOFF, CUTOFF + 1]), +) +compensation = st.one_of( + st.just(0), + st.integers(1, 30_000), + st.sampled_from([AMOUNT - 1, AMOUNT, AMOUNT + 1]), +) + + +@st.composite +def adults(draw): + age = draw(st.integers(25, 80)) + return { + "age": age, + "employment_income": draw(money), + "taxable_pension_income": draw(st.sampled_from([0, 20_000, 140_000])), + "social_security_retirement": draw(st.sampled_from([0, 20_000])) + if age >= 62 + else 0, + "early_withdrawal_penalty": draw(st.sampled_from([0, 500])), + "unemployment_compensation": draw(compensation), + } + + +@st.composite +def dependents(draw, students_allowed): + # Qualifying children: their income never decides whether they are + # dependents, so zeroing their compensation keeps the tax unit's shape. + student = students_allowed and draw(st.booleans()) + return { + "age": draw(st.integers(19, 23)) if student else draw(st.integers(0, 17)), + "is_full_time_student": student, + "employment_income": draw(st.sampled_from([0, 8_000])), + "dividend_income": draw(st.sampled_from([0, 160_000])), + "unemployment_compensation": draw(compensation), + } + + +@st.composite +def tax_units(draw): + kind = draw(st.sampled_from(["single", "joint", "joint_child", "parent"])) + head = draw(adults()) + spouse = draw(adults()) if kind.startswith("joint") else None + # A single parent's adult student would be taken for a spouse. + children = ( + [draw(dependents(students_allowed=kind == "joint_child"))] + if kind in ("joint_child", "parent") + else [] + ) + return {"head": head, "spouse": spouse, "children": children} + + +def _variant(unit, variant): + adults_ = [dict(unit["head"])] + ([dict(unit["spouse"])] if unit["spouse"] else []) + children = [dict(child) for child in unit["children"]] + if variant == "no_dependent_uc": + for child in children: + child["unemployment_compensation"] = 0 + if variant == "swapped" and len(adults_) == 2: + first, second = adults_ + first["unemployment_compensation"], second["unemployment_compensation"] = ( + second["unemployment_compensation"], + first["unemployment_compensation"], + ) + return adults_, children + + +def _situation(units, year, variants): + """Each variant holds every drawn unit, in the same order, so a person's + position within a variant is the same in all of them.""" + people, tax_units_, marital_units, households = {}, {}, {}, {} + for variant in variants: + for i, unit in enumerate(units): + adults_, children = _variant(unit, variant) + key = f"{variant}_{i}" + adult_names = [f"{key}_adult{j}" for j in range(len(adults_))] + child_names = [f"{key}_child{j}" for j in range(len(children))] + for name, inputs in zip(adult_names + child_names, adults_ + children): + people[name] = {k: {year: v} for k, v in inputs.items()} + members = adult_names + child_names + tax_units_[key] = {"members": members} + marital_units[key] = {"members": adult_names} + for name in child_names: + marital_units[name] = {"members": [name]} + households[key] = {"members": members, "state_code": {year: "TX"}} + return { + "people": people, + "tax_units": tax_units_, + "marital_units": marital_units, + "households": households, + } + + +def _couples(units): + """Positions, within a variant, of each joint unit's two adults.""" + pairs, position = [], 0 + for unit in units: + if unit["spouse"]: + pairs.append((position, position + 1)) + position += 1 + bool(unit["spouse"]) + len(unit["children"]) + return np.array(pairs, dtype=int).reshape(-1, 2), position + + +def _run(units, year, variants): + sim = Simulation(situation=_situation(units, year, variants)) + run = { + name: np.asarray(sim.calculate(name, year)) + for name in PERSON_OUTPUTS + TAX_UNIT_OUTPUTS + } + run["tax_unit_index"] = sim.populations["tax_unit"].members_entity_id + return run + + +def _check_2020(units): + run = _run(units, 2020, VARIANTS) + received = run["unemployment_compensation"] + exempt = run["tax_exempt_unemployment_compensation"] + taxable = run["taxable_unemployment_compensation"] + dependent = run["is_tax_unit_dependent"] + filer = ~dependent + magi = run["taxable_uc_agi"] + + # 1. Bounds. + cap = np.minimum(np.maximum(received, 0), AMOUNT) + assert (exempt >= -TOLERANCE["atol"]).all() + assert (exempt <= cap + TOLERANCE["atol"]).all() + np.testing.assert_allclose(taxable + exempt, received, **TOLERANCE) + + # 2. Cutoff: the filers' return, and each dependent's own return. + filer_under = magi[run["tax_unit_index"]] < CUTOFF + dependent_under = run["dependent_taxable_uc_agi"] < CUTOFF + under = np.where(dependent, dependent_under, filer_under) + np.testing.assert_allclose(exempt, under * cap, **TOLERANCE) + + # 3. Differential: AGI without the compensation, two ways. + np.testing.assert_allclose( + magi, + np.maximum( + 0, + run["adjusted_gross_income"] + - run["tax_unit_taxable_unemployment_compensation"], + ), + **TOLERANCE, + ) + + # 4. Return boundary: the return sums the filers only, and dependents' + # compensation changes nothing on it. + np.testing.assert_allclose( + run["tax_unit_taxable_unemployment_compensation"], + np.bincount( + run["tax_unit_index"], weights=taxable * filer, minlength=len(magi) + ), + **TOLERANCE, + ) + pairs, people_per_variant = _couples(units) + n = len(units) + drawn, no_dependent_uc, swapped = ( + slice(k * n, (k + 1) * n) for k in range(len(VARIANTS)) + ) + for name in TAX_UNIT_OUTPUTS: + np.testing.assert_allclose( + run[name][no_dependent_uc], run[name][drawn], err_msg=name, **TOLERANCE + ) + people = [ + slice(k * people_per_variant, (k + 1) * people_per_variant) + for k in range(len(VARIANTS)) + ] + drawn_filer = filer[people[0]] + np.testing.assert_allclose( + taxable[people[1]][drawn_filer], taxable[people[0]][drawn_filer], **TOLERANCE + ) + + # 5. Symmetry between spouses. + np.testing.assert_allclose( + run["tax_unit_taxable_unemployment_compensation"][swapped], + run["tax_unit_taxable_unemployment_compensation"][drawn], + **TOLERANCE, + ) + if len(pairs): + for k in (0, 1): + # The swapped variant's adult k received the other adult's + # compensation, so is taxed on it as the other adult was. + np.testing.assert_allclose( + received[people[2]][pairs[:, k]], received[people[0]][pairs[:, 1 - k]] + ) + np.testing.assert_allclose( + taxable[people[2]][pairs[:, k]], + taxable[people[0]][pairs[:, 1 - k]], + **TOLERANCE, + ) + + +def _check_2021(units): + run = _run(units, 2021, ["drawn"]) + np.testing.assert_allclose(run["tax_exempt_unemployment_compensation"], 0) + np.testing.assert_allclose( + run["taxable_unemployment_compensation"], + run["unemployment_compensation"], + **TOLERANCE, + ) + + +# A batch's cost is mostly per-variable overhead, so each example is a large +# batch and there are few examples. +SETTINGS = dict( + max_examples=5, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) + + +@settings(**SETTINGS) +@given(st.lists(tax_units(), min_size=10, max_size=30)) +def test_exclusion_invariants_2020(units): + _check_2020(units) + + +@settings(**dict(SETTINGS, max_examples=2)) +@given(st.lists(tax_units(), min_size=10, max_size=30)) +def test_exclusion_ends_after_2020(units): + _check_2021(units) From eabaefd3e26f70d271043eef843f8908fd713dc0 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 16:55:32 -0400 Subject: [PATCH 3/6] Test that Indiana's UC deduction leaves out a dependent's compensation The tax unit's taxable unemployment compensation now sums only the head and spouse, in every year, so Indiana's deduction (IC 6-3-2-10) no longer deducts a dependent's compensation that is not in the filers' federal AGI. Co-Authored-By: Claude Opus 5.5 --- changelog.d/fix-uc-exclusion-2020.fixed.md | 2 +- ...n_unemployment_compensation_deduction.yaml | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/changelog.d/fix-uc-exclusion-2020.fixed.md b/changelog.d/fix-uc-exclusion-2020.fixed.md index 81abfe0902c..4d6c744368f 100644 --- a/changelog.d/fix-uc-exclusion-2020.fixed.md +++ b/changelog.d/fix-uc-exclusion-2020.fixed.md @@ -1 +1 @@ -Fixed the 2020 unemployment compensation exclusion: the $150,000 test no longer subtracts the compensation twice, each spouse on a joint return excludes up to $10,200 of their own compensation, and a dependent's compensation is excluded on the dependent's own return instead of using the filers' exclusion. +Fixed the 2020 unemployment compensation exclusion: the $150,000 test no longer subtracts the compensation twice, each spouse on a joint return excludes up to $10,200 of their own compensation, and a dependent's compensation is excluded on the dependent's own return instead of using the filers' exclusion. The tax unit's taxable unemployment compensation now leaves out dependents' compensation in every year, so Indiana's unemployment compensation deduction no longer deducts compensation that is not in the filers' federal AGI. diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/tax/income/in_unemployment_compensation_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/tax/income/in_unemployment_compensation_deduction.yaml index 20988c0e20b..632019a676a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/tax/income/in_unemployment_compensation_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/tax/income/in_unemployment_compensation_deduction.yaml @@ -7,3 +7,60 @@ tax_unit_taxable_unemployment_compensation: 3_000 output: in_unemployment_compensation_deduction: 2_000 + +- name: Case 2, a spouse's compensation in federal AGI is deductible. + period: 2024 + input: + people: + person1: + age: 45 + employment_income: 10_000 + person2: + age: 43 + unemployment_compensation: 5_000 + tax_units: + tax_unit: + members: [person1, person2] + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: IN + output: + # IC 6-3-2-10(a): federal AGI 15,000 less 18,000 is below zero, so the + # Indiana-taxable part is 0 and all 5,000 in federal AGI is deducted. + adjusted_gross_income: 15_000 + tax_unit_taxable_unemployment_compensation: 5_000 + in_unemployment_compensation_deduction: 5_000 + +- name: Case 3, a dependent's compensation is not in the filers' federal AGI, so it is not deducted. + period: 2024 + input: + people: + person1: + age: 45 + employment_income: 10_000 + person2: + age: 43 + person3: + age: 17 + unemployment_compensation: 5_000 + tax_units: + tax_unit: + members: [person1, person2, person3] + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2, person3] + state_code: IN + output: + # The dependent's 5,000 is on the dependent's own return, not in the + # filers' federal AGI of 10,000, so the filers deduct none of it. + is_tax_unit_dependent: [false, false, true] + adjusted_gross_income: 10_000 + tax_unit_taxable_unemployment_compensation: 0 + in_unemployment_compensation_deduction: 0 From a07010a7d4431d6ee9c14993c445b255432b75f5 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 20:43:49 -0400 Subject: [PATCH 4/6] Keep dependents' compensation off CA, RI and WI returns; net dependents' estate losses Address the independent review of #10175: - California's Schedule CA subtraction and Wisconsin's unemployment compensation subtraction now read tax_unit_taxable_unemployment_compensation, and Rhode Island adds back the new tax_unit_tax_exempt_unemployment_compensation, so a dependent's own-return amount no longer lands on the filers' return. - Add estate_income to the dependent helper's loss sources: limited_business_loss deducts estate and trust losses for filers, and the helper's own comment says it lists the sources loss_ald deducts. This reaches the dependent's IRC 86 and 85(c) modified AGIs and the dependent's IRA deduction. - Fix two form-line citations (Form 1040 line 5b, Schedule 1 line 17) and state that the differential invariant covers compensation that is not negative. Co-Authored-By: Claude Opus 5.5 --- changelog.d/fix-uc-exclusion-2020.fixed.md | 2 +- .../ca/tax/income/agi/subtractions.yaml | 3 +- .../tax/income/agi/additions/additions.yaml | 6 +- ...yment_compensation_exclusion_invariants.py | 7 +- .../dependent_taxable_ss_magi.yaml | 27 +++++++ .../ca/tax/income/ca_agi_subtractions.yaml | 75 +++++++++++++++++++ .../income/agi/additions/ri_additions.yaml | 70 +++++++++++++++++ ...unemployment_compensation_subtraction.yaml | 46 ++++++++++++ .../dependent_taxable_uc_agi.yaml | 34 +++++++++ .../taxable_unemployment_compensation.yaml | 4 +- .../dependent_taxable_ss_magi.py | 2 + ...it_tax_exempt_unemployment_compensation.py | 18 +++++ ...i_unemployment_compensation_subtraction.py | 4 +- 13 files changed, 289 insertions(+), 9 deletions(-) create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/ca_agi_subtractions.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/agi/additions/ri_additions.yaml create mode 100644 policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_tax_exempt_unemployment_compensation.py diff --git a/changelog.d/fix-uc-exclusion-2020.fixed.md b/changelog.d/fix-uc-exclusion-2020.fixed.md index 4d6c744368f..af2daca008a 100644 --- a/changelog.d/fix-uc-exclusion-2020.fixed.md +++ b/changelog.d/fix-uc-exclusion-2020.fixed.md @@ -1 +1 @@ -Fixed the 2020 unemployment compensation exclusion: the $150,000 test no longer subtracts the compensation twice, each spouse on a joint return excludes up to $10,200 of their own compensation, and a dependent's compensation is excluded on the dependent's own return instead of using the filers' exclusion. The tax unit's taxable unemployment compensation now leaves out dependents' compensation in every year, so Indiana's unemployment compensation deduction no longer deducts compensation that is not in the filers' federal AGI. +Fixed the 2020 unemployment compensation exclusion: the $150,000 test no longer subtracts the compensation twice, each spouse on a joint return excludes up to $10,200 of their own compensation, and a dependent's compensation is excluded on the dependent's own return instead of using the filers' exclusion. The tax unit's taxable unemployment compensation now leaves out dependents' compensation in every year, so Indiana's deduction, California's and Wisconsin's unemployment compensation subtractions and Rhode Island's add-back of the federally excluded amount count only the compensation on the filers' return. A dependent's own estate or trust loss now reduces the modified AGI of the dependent's own return. diff --git a/policyengine_us/parameters/gov/states/ca/tax/income/agi/subtractions.yaml b/policyengine_us/parameters/gov/states/ca/tax/income/agi/subtractions.yaml index afe1c819140..db164904db1 100644 --- a/policyengine_us/parameters/gov/states/ca/tax/income/agi/subtractions.yaml +++ b/policyengine_us/parameters/gov/states/ca/tax/income/agi/subtractions.yaml @@ -2,7 +2,8 @@ description: List of California AGI subtractions. values: 2021-01-01: - taxable_social_security - - taxable_unemployment_compensation + # The compensation in the filers' federal AGI; a dependent's is on their own return. + - tax_unit_taxable_unemployment_compensation - us_govt_interest - salt_refund_income diff --git a/policyengine_us/parameters/gov/states/ri/tax/income/agi/additions/additions.yaml b/policyengine_us/parameters/gov/states/ri/tax/income/agi/additions/additions.yaml index d2f47ef761a..e3cf44478a1 100644 --- a/policyengine_us/parameters/gov/states/ri/tax/income/agi/additions/additions.yaml +++ b/policyengine_us/parameters/gov/states/ri/tax/income/agi/additions/additions.yaml @@ -3,10 +3,12 @@ description: Rhode Island adds these items on federal adjusted gross income when values: 2021-01-01: - investment_in_529_plan # RIGL §44-30-12(4) - - tax_exempt_unemployment_compensation # RIGL §44-30-12(b)(6) + # The compensation on the filers' return; a dependent's is on their own. + - tax_unit_tax_exempt_unemployment_compensation # RIGL §44-30-12(b)(6) 2025-01-01: - investment_in_529_plan # RIGL §44-30-12(4) - - tax_exempt_unemployment_compensation # RIGL §44-30-12(b)(6) + # The compensation on the filers' return; a dependent's is on their own. + - tax_unit_tax_exempt_unemployment_compensation # RIGL §44-30-12(b)(6) - ri_section_179_expense_add_back # P.L. 119-21, H.R.1 (2025) - RI Schedule HR1 metadata: diff --git a/policyengine_us/tests/core/test_unemployment_compensation_exclusion_invariants.py b/policyengine_us/tests/core/test_unemployment_compensation_exclusion_invariants.py index 10745b44693..93fd8f6fa20 100644 --- a/policyengine_us/tests/core/test_unemployment_compensation_exclusion_invariants.py +++ b/policyengine_us/tests/core/test_unemployment_compensation_exclusion_invariants.py @@ -21,8 +21,11 @@ unit's `taxable_uc_agi` is under $150,000, a dependent's only when their own `dependent_taxable_uc_agi` is, and then each person's exempt part is the lesser of their own compensation and $10,200. -3. Differential: `taxable_uc_agi` equals adjusted gross income less the - taxable compensation on the return, floored at zero. The model figures +3. Differential, for compensation that is not negative (the draws never + are): `taxable_uc_agi` equals adjusted gross income less the taxable + compensation on the return, floored at zero. A net repayment is + different: `irs_gross_income` floors each person's negative taxable + compensation at zero, so it never reduces AGI. The model figures AGI without the compensation once from gross income sources and once, here, from AGI itself; the two must agree, so the compensation is left out exactly once. diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.yaml index f4eca3c333c..f1f4709af51 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.yaml @@ -170,3 +170,30 @@ state_code: TX output: dependent_taxable_ss_magi: [0, 24_000] + +- name: A dependent's own estate or trust loss reduces their modified AGI + # Schedule E Part III carries the loss to Schedule 1 line 5, which AGI + # includes (Pub. 915 Worksheet 1 line 3): 20,000 of wages less a 2,000 + # loss gives modified AGI of 18,000. + period: 2025 + input: + people: + parent: + age: 50 + employment_income: 80_000 + is_tax_unit_head: true + student: + age: 20 + is_full_time_student: true + is_tax_unit_dependent: true + employment_income: 20_000 + estate_income: -2_000 + tax_units: + tax_unit: + members: [parent, student] + households: + household: + members: [parent, student] + state_code: TX + output: + dependent_taxable_ss_magi: [0, 18_000] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/ca_agi_subtractions.yaml b/policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/ca_agi_subtractions.yaml new file mode 100644 index 00000000000..dc7b7339284 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/ca_agi_subtractions.yaml @@ -0,0 +1,75 @@ +# Schedule CA (540) subtracts the unemployment compensation in the filers' +# federal AGI (2020 and 2024 Schedule CA instructions, line 7). A dependent's +# compensation is on the dependent's own return. +- name: Case 1, the filer's taxable compensation is subtracted. + period: 2024 + input: + people: + person1: + age: 40 + employment_income: 30_000 + unemployment_compensation: 5_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: CA + output: + adjusted_gross_income: 35_000 + ca_agi_subtractions: 5_000 + ca_agi: 30_000 + +- name: Case 2, a dependent's compensation, not in the filer's federal AGI, is not subtracted. + period: 2024 + input: + people: + person1: + age: 45 + employment_income: 30_000 + is_tax_unit_head: true + person2: + age: 17 + is_tax_unit_dependent: true + unemployment_compensation: 5_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: CA + output: + adjusted_gross_income: 30_000 + ca_agi_subtractions: 0 + ca_agi: 30_000 + +- name: Case 3, a dependent's 2020 compensation taxable on their own return is not subtracted. + period: 2020 + input: + people: + person1: + age: 45 + employment_income: 30_000 + is_tax_unit_head: true + person2: + age: 20 + is_full_time_student: true + is_tax_unit_dependent: true + dividend_income: 150_000 + unemployment_compensation: 5_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: CA + output: + # The dependent's own modified AGI is 150,000, so the 5,000 is taxable + # on the dependent's federal return, not the filer's. + taxable_unemployment_compensation: [0, 5_000] + adjusted_gross_income: 30_000 + ca_agi_subtractions: 0 + ca_agi: 30_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/agi/additions/ri_additions.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/agi/additions/ri_additions.yaml new file mode 100644 index 00000000000..1c8f76aeb27 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/agi/additions/ri_additions.yaml @@ -0,0 +1,70 @@ +# RIGL 44-30-12(b)(6): Rhode Island counts all unemployment compensation as +# income, so the filers add back what IRC 85(c) excluded from their 2020 +# federal AGI (RI Division of Taxation, Advisory 2021-28). A dependent's +# compensation is on the dependent's own return. +- name: Case 1, the filer's federally excluded 2020 compensation is added back. + period: 2020 + input: + people: + person1: + age: 40 + employment_income: 30_000 + unemployment_compensation: 8_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: RI + output: + tax_exempt_unemployment_compensation: [8_000] + ri_additions: 8_000 + +- name: Case 2, a dependent's excluded compensation is not added to the filers' return. + period: 2020 + input: + people: + person1: + age: 45 + employment_income: 30_000 + is_tax_unit_head: true + person2: + age: 17 + is_tax_unit_dependent: true + unemployment_compensation: 5_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # The dependent excludes the 5,000 on their own return; it was never in + # the filer's federal AGI. + tax_exempt_unemployment_compensation: [0, 5_000] + ri_additions: 0 + +- name: Case 3, a dependent's excluded compensation stays off a return over the federal cutoff. + period: 2020 + input: + people: + person1: + age: 45 + employment_income: 160_000 + is_tax_unit_head: true + person2: + age: 17 + is_tax_unit_dependent: true + unemployment_compensation: 5_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + tax_exempt_unemployment_compensation: [0, 5_000] + ri_additions: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_unemployment_compensation_subtraction.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_unemployment_compensation_subtraction.yaml index ff13ab35a82..000273f6c91 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_unemployment_compensation_subtraction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_unemployment_compensation_subtraction.yaml @@ -39,3 +39,49 @@ state_code: WI output: wi_unemployment_compensation_subtraction: 0 + +- name: Case 5, a filer's own compensation on their return. + period: 2024 + input: + people: + person1: + age: 40 + employment_income: 12_000 + unemployment_compensation: 5_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: WI + output: + # Unemployment Compensation Worksheet: line 1, 5,000; line 2, 17,000; + # line 3, 12,000; line 7, 5,000; line 8, 2,500; line 9, 2,500; line 10, + # 5,000 - 2,500 = 2,500. + wi_unemployment_compensation_subtraction: 2_500 + +- name: Case 6, a dependent's compensation is on the dependent's own return. + period: 2024 + input: + people: + person1: + age: 45 + employment_income: 18_000 + is_tax_unit_head: true + person2: + age: 17 + is_tax_unit_dependent: true + unemployment_compensation: 5_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WI + output: + # Line 1 takes the compensation on federal Schedule 1 of this return, + # which has none. + tax_unit_taxable_unemployment_compensation: 0 + wi_unemployment_compensation_subtraction: 0 diff --git a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.yaml b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.yaml index 98bb5021d75..6a1066b2871 100644 --- a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.yaml +++ b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.yaml @@ -65,3 +65,37 @@ is_tax_unit_dependent: [false, true, false] dependent_taxable_social_security: [0, 8_500, 0] dependent_taxable_uc_agi: [0, 38_500, 0] + +- name: Case 3, an estate or trust loss reduces the dependent's own AGI below the cutoff. + period: 2020 + input: + people: + person1: + age: 45 + employment_income: 50_000 + person2: + age: 20 + is_full_time_student: true + dividend_income: 150_000 + estate_income: -1_000 + unemployment_compensation: 5_000 + person3: + age: 43 + tax_units: + tax_unit: + members: [person1, person3, person2] + marital_units: + marital_unit: + members: [person1, person3] + households: + household: + members: [person1, person3, person2] + state_code: TX + output: + # Line 1: Form 1040 line 3b dividends, 150,000. Line 2: Schedule 1 line + # 5, the Schedule E Part III loss, -1,000. Line 6: 149,000, under the + # cutoff, so the dependent excludes all 5,000. + is_tax_unit_dependent: [false, true, false] + dependent_taxable_uc_agi: [0, 149_000, 0] + taxable_unemployment_compensation: [0, 0, 0] + tax_exempt_unemployment_compensation: [0, 5_000, 0] diff --git a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_compensation.yaml b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_compensation.yaml index 47cb6def2c9..1ef556d6284 100644 --- a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_compensation.yaml +++ b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_compensation.yaml @@ -111,7 +111,7 @@ members: [person1] state_code: MT output: - # Worksheet line 1: Form 1040 line 4b pensions, 150,000; lines 2, 3 and + # Worksheet line 1: Form 1040 line 5b pensions, 150,000; lines 2, 3 and # 5: 0; line 6: 150,000. Line 7: 150,000 or more, so nothing is # excluded. The compensation is not subtracted from line 6 again. taxable_uc_agi: 150_000 @@ -360,7 +360,7 @@ members: [person1] state_code: TX output: - # Line 4: 150,400. Line 5: Schedule 1 line 15 penalty on early + # Line 4: 150,400. Line 5: Schedule 1 line 17 penalty on early # withdrawal of savings, 500. Line 6: 149,900, under 150,000. Line 8: # 5,000. taxable_uc_agi: 149_900 diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.py b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.py index 1b712f483cb..1326aeaaa99 100644 --- a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.py +++ b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.py @@ -11,6 +11,8 @@ "farm_operations_income", "farm_rent_income", "rental_income", + # Schedule E Part III estate and trust losses (limited_business_loss). + "estate_income", ] # Above-the-line deductions the model can attribute to one person, keyed by diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_tax_exempt_unemployment_compensation.py b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_tax_exempt_unemployment_compensation.py new file mode 100644 index 00000000000..cb80f4d0b2b --- /dev/null +++ b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_tax_exempt_unemployment_compensation.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class tax_unit_tax_exempt_unemployment_compensation(Variable): + value_type = float + entity = TaxUnit + label = "Tax-exempt unemployment compensation on the tax unit's return" + unit = USD + documentation = ( + "Unemployment compensation IRC 85(c) excludes from the AGI of the tax " + "unit's return: the tax-exempt unemployment compensation of the " + "members who are not dependents. A dependent's is excluded on the " + "dependent's own return." + ) + definition_period = YEAR + reference = "https://www.law.cornell.edu/uscode/text/26/85#c" + + formula = sum_among_non_dependents("tax_exempt_unemployment_compensation") diff --git a/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_unemployment_compensation_subtraction.py b/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_unemployment_compensation_subtraction.py index 051d59a80cf..1370f2a1063 100644 --- a/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_unemployment_compensation_subtraction.py +++ b/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_unemployment_compensation_subtraction.py @@ -14,7 +14,9 @@ class wi_unemployment_compensation_subtraction(Variable): defined_for = StateCode.WI def formula(tax_unit, period, parameters): - us_tuc = add(tax_unit, period, ["taxable_unemployment_compensation"]) + # Worksheet line 1: the compensation on this return. A dependent's is + # on the dependent's own return. + us_tuc = tax_unit("tax_unit_taxable_unemployment_compensation", period) us_agi = tax_unit("adjusted_gross_income", period) wi = parameters(period).gov.states.wi.tax.income p = wi.subtractions.unemployment_compensation.income_phase_out From 1bf37f4dc3d9148e994041069341600dc8ff5a78 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 22:24:59 -0400 Subject: [PATCH 5/6] Leave the CA, RI and WI unemployment lines to #10187 PolicyEngine/policyengine-us#10187 fixes the same three state lines (ca_agi_subtractions, ri_additions, wi_unemployment_compensation_subtraction) more broadly and has its own review, impact run and Axiom issues. Restore them to main here and drop tax_unit_tax_exempt_unemployment_compensation, which only Rhode Island used. #10175 should land after #10187, so the dependent routing never meets the old pooled state lines. Co-Authored-By: Claude Opus 5.5 --- changelog.d/fix-uc-exclusion-2020.fixed.md | 2 +- .../ca/tax/income/agi/subtractions.yaml | 3 +- .../tax/income/agi/additions/additions.yaml | 6 +- .../ca/tax/income/ca_agi_subtractions.yaml | 75 ------------------- .../income/agi/additions/ri_additions.yaml | 70 ----------------- ...unemployment_compensation_subtraction.yaml | 46 ------------ ...it_tax_exempt_unemployment_compensation.py | 18 ----- ...i_unemployment_compensation_subtraction.py | 4 +- 8 files changed, 5 insertions(+), 219 deletions(-) delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/ca_agi_subtractions.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/agi/additions/ri_additions.yaml delete mode 100644 policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_tax_exempt_unemployment_compensation.py diff --git a/changelog.d/fix-uc-exclusion-2020.fixed.md b/changelog.d/fix-uc-exclusion-2020.fixed.md index af2daca008a..7483ab4ceff 100644 --- a/changelog.d/fix-uc-exclusion-2020.fixed.md +++ b/changelog.d/fix-uc-exclusion-2020.fixed.md @@ -1 +1 @@ -Fixed the 2020 unemployment compensation exclusion: the $150,000 test no longer subtracts the compensation twice, each spouse on a joint return excludes up to $10,200 of their own compensation, and a dependent's compensation is excluded on the dependent's own return instead of using the filers' exclusion. The tax unit's taxable unemployment compensation now leaves out dependents' compensation in every year, so Indiana's deduction, California's and Wisconsin's unemployment compensation subtractions and Rhode Island's add-back of the federally excluded amount count only the compensation on the filers' return. A dependent's own estate or trust loss now reduces the modified AGI of the dependent's own return. +Fixed the 2020 unemployment compensation exclusion: the $150,000 test no longer subtracts the compensation twice, each spouse on a joint return excludes up to $10,200 of their own compensation, and a dependent's compensation is excluded on the dependent's own return instead of using the filers' exclusion. The tax unit's taxable unemployment compensation now leaves out dependents' compensation in every year, so Indiana's unemployment compensation deduction no longer deducts compensation that is not in the filers' federal AGI. A dependent's own estate or trust loss now reduces the modified AGI of the dependent's own return. diff --git a/policyengine_us/parameters/gov/states/ca/tax/income/agi/subtractions.yaml b/policyengine_us/parameters/gov/states/ca/tax/income/agi/subtractions.yaml index db164904db1..afe1c819140 100644 --- a/policyengine_us/parameters/gov/states/ca/tax/income/agi/subtractions.yaml +++ b/policyengine_us/parameters/gov/states/ca/tax/income/agi/subtractions.yaml @@ -2,8 +2,7 @@ description: List of California AGI subtractions. values: 2021-01-01: - taxable_social_security - # The compensation in the filers' federal AGI; a dependent's is on their own return. - - tax_unit_taxable_unemployment_compensation + - taxable_unemployment_compensation - us_govt_interest - salt_refund_income diff --git a/policyengine_us/parameters/gov/states/ri/tax/income/agi/additions/additions.yaml b/policyengine_us/parameters/gov/states/ri/tax/income/agi/additions/additions.yaml index e3cf44478a1..d2f47ef761a 100644 --- a/policyengine_us/parameters/gov/states/ri/tax/income/agi/additions/additions.yaml +++ b/policyengine_us/parameters/gov/states/ri/tax/income/agi/additions/additions.yaml @@ -3,12 +3,10 @@ description: Rhode Island adds these items on federal adjusted gross income when values: 2021-01-01: - investment_in_529_plan # RIGL §44-30-12(4) - # The compensation on the filers' return; a dependent's is on their own. - - tax_unit_tax_exempt_unemployment_compensation # RIGL §44-30-12(b)(6) + - tax_exempt_unemployment_compensation # RIGL §44-30-12(b)(6) 2025-01-01: - investment_in_529_plan # RIGL §44-30-12(4) - # The compensation on the filers' return; a dependent's is on their own. - - tax_unit_tax_exempt_unemployment_compensation # RIGL §44-30-12(b)(6) + - tax_exempt_unemployment_compensation # RIGL §44-30-12(b)(6) - ri_section_179_expense_add_back # P.L. 119-21, H.R.1 (2025) - RI Schedule HR1 metadata: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/ca_agi_subtractions.yaml b/policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/ca_agi_subtractions.yaml deleted file mode 100644 index dc7b7339284..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/ca_agi_subtractions.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# Schedule CA (540) subtracts the unemployment compensation in the filers' -# federal AGI (2020 and 2024 Schedule CA instructions, line 7). A dependent's -# compensation is on the dependent's own return. -- name: Case 1, the filer's taxable compensation is subtracted. - period: 2024 - input: - people: - person1: - age: 40 - employment_income: 30_000 - unemployment_compensation: 5_000 - tax_units: - tax_unit: - members: [person1] - households: - household: - members: [person1] - state_code: CA - output: - adjusted_gross_income: 35_000 - ca_agi_subtractions: 5_000 - ca_agi: 30_000 - -- name: Case 2, a dependent's compensation, not in the filer's federal AGI, is not subtracted. - period: 2024 - input: - people: - person1: - age: 45 - employment_income: 30_000 - is_tax_unit_head: true - person2: - age: 17 - is_tax_unit_dependent: true - unemployment_compensation: 5_000 - tax_units: - tax_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: CA - output: - adjusted_gross_income: 30_000 - ca_agi_subtractions: 0 - ca_agi: 30_000 - -- name: Case 3, a dependent's 2020 compensation taxable on their own return is not subtracted. - period: 2020 - input: - people: - person1: - age: 45 - employment_income: 30_000 - is_tax_unit_head: true - person2: - age: 20 - is_full_time_student: true - is_tax_unit_dependent: true - dividend_income: 150_000 - unemployment_compensation: 5_000 - tax_units: - tax_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: CA - output: - # The dependent's own modified AGI is 150,000, so the 5,000 is taxable - # on the dependent's federal return, not the filer's. - taxable_unemployment_compensation: [0, 5_000] - adjusted_gross_income: 30_000 - ca_agi_subtractions: 0 - ca_agi: 30_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/agi/additions/ri_additions.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/agi/additions/ri_additions.yaml deleted file mode 100644 index 1c8f76aeb27..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/agi/additions/ri_additions.yaml +++ /dev/null @@ -1,70 +0,0 @@ -# RIGL 44-30-12(b)(6): Rhode Island counts all unemployment compensation as -# income, so the filers add back what IRC 85(c) excluded from their 2020 -# federal AGI (RI Division of Taxation, Advisory 2021-28). A dependent's -# compensation is on the dependent's own return. -- name: Case 1, the filer's federally excluded 2020 compensation is added back. - period: 2020 - input: - people: - person1: - age: 40 - employment_income: 30_000 - unemployment_compensation: 8_000 - tax_units: - tax_unit: - members: [person1] - households: - household: - members: [person1] - state_code: RI - output: - tax_exempt_unemployment_compensation: [8_000] - ri_additions: 8_000 - -- name: Case 2, a dependent's excluded compensation is not added to the filers' return. - period: 2020 - input: - people: - person1: - age: 45 - employment_income: 30_000 - is_tax_unit_head: true - person2: - age: 17 - is_tax_unit_dependent: true - unemployment_compensation: 5_000 - tax_units: - tax_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: RI - output: - # The dependent excludes the 5,000 on their own return; it was never in - # the filer's federal AGI. - tax_exempt_unemployment_compensation: [0, 5_000] - ri_additions: 0 - -- name: Case 3, a dependent's excluded compensation stays off a return over the federal cutoff. - period: 2020 - input: - people: - person1: - age: 45 - employment_income: 160_000 - is_tax_unit_head: true - person2: - age: 17 - is_tax_unit_dependent: true - unemployment_compensation: 5_000 - tax_units: - tax_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: RI - output: - tax_exempt_unemployment_compensation: [0, 5_000] - ri_additions: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_unemployment_compensation_subtraction.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_unemployment_compensation_subtraction.yaml index 000273f6c91..ff13ab35a82 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_unemployment_compensation_subtraction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_unemployment_compensation_subtraction.yaml @@ -39,49 +39,3 @@ state_code: WI output: wi_unemployment_compensation_subtraction: 0 - -- name: Case 5, a filer's own compensation on their return. - period: 2024 - input: - people: - person1: - age: 40 - employment_income: 12_000 - unemployment_compensation: 5_000 - tax_units: - tax_unit: - members: [person1] - households: - household: - members: [person1] - state_code: WI - output: - # Unemployment Compensation Worksheet: line 1, 5,000; line 2, 17,000; - # line 3, 12,000; line 7, 5,000; line 8, 2,500; line 9, 2,500; line 10, - # 5,000 - 2,500 = 2,500. - wi_unemployment_compensation_subtraction: 2_500 - -- name: Case 6, a dependent's compensation is on the dependent's own return. - period: 2024 - input: - people: - person1: - age: 45 - employment_income: 18_000 - is_tax_unit_head: true - person2: - age: 17 - is_tax_unit_dependent: true - unemployment_compensation: 5_000 - tax_units: - tax_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: WI - output: - # Line 1 takes the compensation on federal Schedule 1 of this return, - # which has none. - tax_unit_taxable_unemployment_compensation: 0 - wi_unemployment_compensation_subtraction: 0 diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_tax_exempt_unemployment_compensation.py b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_tax_exempt_unemployment_compensation.py deleted file mode 100644 index cb80f4d0b2b..00000000000 --- a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/tax_unit_tax_exempt_unemployment_compensation.py +++ /dev/null @@ -1,18 +0,0 @@ -from policyengine_us.model_api import * - - -class tax_unit_tax_exempt_unemployment_compensation(Variable): - value_type = float - entity = TaxUnit - label = "Tax-exempt unemployment compensation on the tax unit's return" - unit = USD - documentation = ( - "Unemployment compensation IRC 85(c) excludes from the AGI of the tax " - "unit's return: the tax-exempt unemployment compensation of the " - "members who are not dependents. A dependent's is excluded on the " - "dependent's own return." - ) - definition_period = YEAR - reference = "https://www.law.cornell.edu/uscode/text/26/85#c" - - formula = sum_among_non_dependents("tax_exempt_unemployment_compensation") diff --git a/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_unemployment_compensation_subtraction.py b/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_unemployment_compensation_subtraction.py index 1370f2a1063..051d59a80cf 100644 --- a/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_unemployment_compensation_subtraction.py +++ b/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_unemployment_compensation_subtraction.py @@ -14,9 +14,7 @@ class wi_unemployment_compensation_subtraction(Variable): defined_for = StateCode.WI def formula(tax_unit, period, parameters): - # Worksheet line 1: the compensation on this return. A dependent's is - # on the dependent's own return. - us_tuc = tax_unit("tax_unit_taxable_unemployment_compensation", period) + us_tuc = add(tax_unit, period, ["taxable_unemployment_compensation"]) us_agi = tax_unit("adjusted_gross_income", period) wi = parameters(period).gov.states.wi.tax.income p = wi.subtractions.unemployment_compensation.income_phase_out From 9fde2d1ec4f45637df28b0af954c4a61a17893e2 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 23:44:51 -0400 Subject: [PATCH 6/6] Apply IRC 461(l) on the dependent's own return; keep taxable UC non-negative Address round 2 of the independent review of #10175: - dependent_income_and_deductions now limits a dependent's business losses (self-employment, farm, rental, partnership/S corporation and, since the last commit, estate and trust) to business income plus the IRC 461(l) threshold, as limited_business_loss does for the filers. The threshold is infinite while the limit is suspended (2018-2020), so the 2020 exclusion test keeps the whole loss. - taxable_unemployment_compensation is floored at zero. irs_gross_income counts positive amounts only, so a net repayment never reduced gross income; a negative taxable amount let CA, PA and MA subtract it anyway. The exempt part carries the repayment, as before this PR, which Wisconsin's homestead income reads. - The property test now draws net repayments, and the differential invariant holds for every input. Co-Authored-By: Claude Opus 5.5 --- ...yment_compensation_exclusion_invariants.py | 37 ++++++++++++------- .../dependent_taxable_ss_magi.yaml | 33 +++++++++++++++++ .../dependent_taxable_uc_agi.yaml | 31 ++++++++++++++++ .../taxable_unemployment_compensation.yaml | 32 +++++++++++++--- .../dependent_taxable_ss_magi.py | 31 +++++++++++++--- .../taxable_unemployment_insurance.py | 7 +++- 6 files changed, 144 insertions(+), 27 deletions(-) diff --git a/policyengine_us/tests/core/test_unemployment_compensation_exclusion_invariants.py b/policyengine_us/tests/core/test_unemployment_compensation_exclusion_invariants.py index 93fd8f6fa20..d32544ec140 100644 --- a/policyengine_us/tests/core/test_unemployment_compensation_exclusion_invariants.py +++ b/policyengine_us/tests/core/test_unemployment_compensation_exclusion_invariants.py @@ -15,17 +15,16 @@ spouse's compensation swapped. A 2021 simulation of the drawn units checks that the exclusion ends. For every person and tax unit: -1. Bounds: the exempt part of each person's compensation is between zero and - the lesser of what they received and $10,200, and zero in 2021. -2. Cutoff: the head's and spouse's compensation is exempt only when the tax - unit's `taxable_uc_agi` is under $150,000, a dependent's only when their - own `dependent_taxable_uc_agi` is, and then each person's exempt part is +1. Bounds: taxable compensation is never negative, and the exempt part + (compensation less taxable) is at most the lesser of what the person + received and $10,200. A net repayment is neither taxable nor excluded; + the exempt part carries it. Nothing is excluded in 2021. +2. Cutoff: the head's and spouse's compensation is excluded only when the + tax unit's `taxable_uc_agi` is under $150,000, a dependent's only when + their own `dependent_taxable_uc_agi` is, and then each person excludes the lesser of their own compensation and $10,200. -3. Differential, for compensation that is not negative (the draws never - are): `taxable_uc_agi` equals adjusted gross income less the taxable - compensation on the return, floored at zero. A net repayment is - different: `irs_gross_income` floors each person's negative taxable - compensation at zero, so it never reduces AGI. The model figures +3. Differential: `taxable_uc_agi` equals adjusted gross income less the + taxable compensation on the return, floored at zero. The model figures AGI without the compensation once from gross income sources and once, here, from AGI itself; the two must agree, so the compensation is left out exactly once. @@ -70,6 +69,8 @@ st.just(0), st.integers(1, 30_000), st.sampled_from([AMOUNT - 1, AMOUNT, AMOUNT + 1]), + # A net repayment. + st.integers(-2_000, -1), ) @@ -188,15 +189,18 @@ def _check_2020(units): # 1. Bounds. cap = np.minimum(np.maximum(received, 0), AMOUNT) - assert (exempt >= -TOLERANCE["atol"]).all() + assert (taxable >= 0).all() assert (exempt <= cap + TOLERANCE["atol"]).all() np.testing.assert_allclose(taxable + exempt, received, **TOLERANCE) + repayment = received < 0 + np.testing.assert_allclose(exempt[repayment], received[repayment]) # 2. Cutoff: the filers' return, and each dependent's own return. filer_under = magi[run["tax_unit_index"]] < CUTOFF dependent_under = run["dependent_taxable_uc_agi"] < CUTOFF under = np.where(dependent, dependent_under, filer_under) - np.testing.assert_allclose(exempt, under * cap, **TOLERANCE) + excluded = under * cap + np.testing.assert_allclose(taxable, np.maximum(0, received - excluded), **TOLERANCE) # 3. Differential: AGI without the compensation, two ways. np.testing.assert_allclose( @@ -258,12 +262,17 @@ def _check_2020(units): def _check_2021(units): run = _run(units, 2021, ["drawn"]) - np.testing.assert_allclose(run["tax_exempt_unemployment_compensation"], 0) + received = run["unemployment_compensation"] + # Nothing is excluded: all compensation is taxable, and only a net + # repayment is left in the exempt part. np.testing.assert_allclose( run["taxable_unemployment_compensation"], - run["unemployment_compensation"], + np.maximum(0, received), **TOLERANCE, ) + np.testing.assert_allclose( + run["tax_exempt_unemployment_compensation"], np.minimum(0, received) + ) # A batch's cost is mostly per-variable overhead, so each example is a large diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.yaml index f1f4709af51..8668b160dca 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.yaml @@ -197,3 +197,36 @@ state_code: TX output: dependent_taxable_ss_magi: [0, 18_000] + +- name: A dependent's business losses are limited by IRC 461(l) on their own return + # 2025 Form 461: business losses are deductible up to business income + # (none here) plus the $313,000 single threshold, so $313,000 of the + # $700,000 estate business loss is allowed. Modified AGI: 400,000 of + # dividends + 1,000 of wages - 313,000 = 88,000. With $20,000 of benefits + # the combined income of 98,000 is far over the adjusted base amount, so + # 85% of the benefits, 17,000, is taxable. + period: 2025 + input: + people: + parent: + age: 50 + employment_income: 80_000 + is_tax_unit_head: true + student: + age: 20 + is_full_time_student: true + is_tax_unit_dependent: true + employment_income: 1_000 + dividend_income: 400_000 + estate_income: -700_000 + social_security_survivors: 20_000 + tax_units: + tax_unit: + members: [parent, student] + households: + household: + members: [parent, student] + state_code: TX + output: + dependent_taxable_ss_magi: [0, 88_000] + dependent_taxable_social_security: [0, 17_000] diff --git a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.yaml b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.yaml index 6a1066b2871..4b4020dc626 100644 --- a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.yaml +++ b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/dependent_taxable_uc_agi.yaml @@ -99,3 +99,34 @@ dependent_taxable_uc_agi: [0, 149_000, 0] taxable_unemployment_compensation: [0, 0, 0] tax_exempt_unemployment_compensation: [0, 5_000, 0] + +- name: Case 4, the IRC 461(l) limit is suspended for 2020, so the whole loss counts. + period: 2020 + input: + people: + person1: + age: 45 + employment_income: 50_000 + person2: + age: 20 + is_full_time_student: true + dividend_income: 150_000 + estate_income: -200_000 + unemployment_compensation: 5_000 + person3: + age: 43 + tax_units: + tax_unit: + members: [person1, person3, person2] + marital_units: + marital_unit: + members: [person1, person3] + households: + household: + members: [person1, person3, person2] + state_code: TX + output: + # CARES Act section 2304 suspends the excess business loss limit through + # 2020. Line 6: 150,000 - 200,000 = -50,000, under the cutoff. + dependent_taxable_uc_agi: [0, -50_000, 0] + taxable_unemployment_compensation: [0, 0, 0] diff --git a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_compensation.yaml b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_compensation.yaml index 1ef556d6284..43479af7874 100644 --- a/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_compensation.yaml +++ b/policyengine_us/tests/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_compensation.yaml @@ -387,7 +387,7 @@ tax_exempt_unemployment_compensation: [0] tax_unit_taxable_unemployment_compensation: 8_000 -- name: Case 14, a net repayment is not excluded. +- name: Case 14, a net repayment is neither taxable nor excluded. period: 2020 input: people: @@ -403,8 +403,30 @@ members: [person1] state_code: TX output: - # Only compensation received can be excluded, so the exempt amount is - # never negative. - taxable_unemployment_compensation: [-500] - tax_exempt_unemployment_compensation: [0] + # irs_gross_income counts positive amounts only, so a net repayment + # never reduces gross income and none of it is taxable. The exempt + # amount carries it, as states that subtract repayments read it. + taxable_unemployment_compensation: [0] + tax_exempt_unemployment_compensation: [-500] + adjusted_gross_income: 30_000 + +- name: Case 15, a net repayment outside 2020 is not taxable either. + period: 2024 + input: + people: + person1: + age: 40 + employment_income: 30_000 + unemployment_compensation: -500 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: TX + output: + taxable_unemployment_compensation: [0] + tax_exempt_unemployment_compensation: [-500] + tax_unit_taxable_unemployment_compensation: 0 adjusted_gross_income: 30_000 diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.py b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.py index 1326aeaaa99..aa51a392aad 100644 --- a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.py +++ b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/dependent_taxable_ss_magi.py @@ -34,8 +34,9 @@ def dependent_income_and_deductions(person, period, parameters): """A dependent's own-return income before above-the-line deductions, and the person-level above-the-line deductions to subtract from it. - Income nets business losses and capital losses (within the IRC 1211(b) - limit) and leaves out Social Security, as IRC 86(b)(2) requires. + Income nets business losses (within the IRC 461(l) limit) and capital + losses (within the IRC 1211(b) limit) and leaves out Social Security, as + IRC 86(b)(2) requires. """ p = parameters(period).gov.irs sources = p.gross_income.sources @@ -49,7 +50,13 @@ def dependent_income_and_deductions(person, period, parameters): "capital_gains" in sources and "non_sch_d_capital_gains" in sources ) + # A dependent who lives with their spouse files separately; any other + # files as single. + lives_with_spouse = person("dependent_lives_with_spouse", period) + income = 0 + business_income = 0 + business_loss = 0 for source in sources: components = DEPENDENT_GROSS_INCOME_SOURCE_OVERRIDES.get(source, [source]) for component in components: @@ -57,14 +64,26 @@ def dependent_income_and_deductions(person, period, parameters): continue amount = add(person, period, [component]) if deduct_losses and component in BUSINESS_LOSS_SOURCES: - income += amount + business_income += max_(0, amount) + business_loss += max_(0, -amount) else: income += max_(0, amount) + if deduct_losses: + # IRC 461(l), as limited_business_loss applies it to the filers: + # business losses are deductible up to business income plus the + # threshold, which is infinite while the limit is suspended (2018 + # through 2020). + threshold = where( + lives_with_spouse, + p.ald.loss.max["SEPARATE"], + p.ald.loss.max["SINGLE"], + ) + income += business_income - min_(business_loss, business_income + threshold) + if "capital_gains" in sources: # IRC 1211(b): net capital losses are deductible up to the limit, # which is lower for a married individual filing separately. - lives_with_spouse = person("dependent_lives_with_spouse", period) capital_loss_limit = p.ald.loss.capital.max loss_limit = deduct_losses * where( lives_with_spouse, @@ -99,8 +118,8 @@ class dependent_taxable_ss_magi(Variable): relative gross income test, losses and above-the-line deductions reduce it. Above-the-line deductions the model records only for the tax unit (health savings account contributions) are not attributed to - dependents, and the IRC 461(l) excess business loss limit is not - applied. + dependents. The IRC 461(l) excess business loss limit applies to the + dependent's own business income and losses. """ definition_period = YEAR defined_for = "is_tax_unit_dependent" diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_insurance.py b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_insurance.py index 44c02a8539c..ef4957c3cba 100644 --- a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_insurance.py +++ b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_unemployment_insurance.py @@ -42,6 +42,9 @@ def formula(person, period, parameters): eligible = where(is_dependent, dependent_eligible, filer_eligible) # Each person excludes up to the amount of the compensation they # received, so on a joint return each spouse does (worksheet lines 8 - # and 9). A net repayment is not excluded. + # and 9). excluded = eligible * min_(max_(0, received), p.amount) - return received - excluded + # A net repayment adds nothing to gross income (irs_gross_income + # counts positive amounts only), so none of it is taxable; + # tax_exempt_unemployment_compensation carries it. + return max_(0, received - excluded)