From 6f7e06e3047817e909cbd7b94668c3c76c945751 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 19:08:10 -0400 Subject: [PATCH 01/13] Count taxable employment disability benefits in federal gross income Adds tax_exempt_disability_benefits (IRC 104(a)(3)) and taxable_disability_benefits (IRC 105(a)) and lists the taxable part in gov.irs.gross_income.sources. State subtractions that remove disability income from federal AGI (VA, MT, LA, AR, SC, OH, CO) now read the taxable part; PA's rebate income adds only the exempt part. Co-Authored-By: Claude Opus 5.5 --- ...-disability-benefits-gross-income.fixed.md | 1 + .../gov/irs/gross_income/sources.yaml | 12 +++++++++- .../employment_sources.yaml | 2 +- .../gross_income/sources/individual.yaml | 8 +++---- .../income/gross_income/sources/joint.yaml | 8 +++---- .../subtractions/pension/income_sources.yaml | 4 ++-- .../oh/tax/income/deductions/deductions.yaml | 2 +- .../tax/income/subtractions/subtractions.yaml | 4 ++-- ...st_ar_gross_income_source_line_comments.py | 4 ++-- .../tests/core/test_uprating_series.py | 1 + .../la_disability_income_exemption_person.py | 4 ++-- .../mt_disability_income_exclusion_person.py | 2 +- .../pa_property_tax_or_rent_rebate_income.py | 3 ++- ...va_disability_income_subtraction_person.py | 2 +- .../person/general/disability_benefits.py | 6 ++++- .../general/tax_exempt_disability_benefits.py | 24 +++++++++++++++++++ .../general/taxable_disability_benefits.py | 24 +++++++++++++++++++ 17 files changed, 88 insertions(+), 23 deletions(-) create mode 100644 changelog.d/fix-disability-benefits-gross-income.fixed.md create mode 100644 policyengine_us/variables/household/income/person/general/tax_exempt_disability_benefits.py create mode 100644 policyengine_us/variables/household/income/person/general/taxable_disability_benefits.py diff --git a/changelog.d/fix-disability-benefits-gross-income.fixed.md b/changelog.d/fix-disability-benefits-gross-income.fixed.md new file mode 100644 index 00000000000..828a9c1eb1e --- /dev/null +++ b/changelog.d/fix-disability-benefits-gross-income.fixed.md @@ -0,0 +1 @@ +Count the taxable part of employment disability benefits in federal gross income (IRC 105(a)), with a new tax_exempt_disability_benefits input for benefits from plans the recipient paid for (IRC 104(a)(3)), and limit state disability subtractions to the taxable part. diff --git a/policyengine_us/parameters/gov/irs/gross_income/sources.yaml b/policyengine_us/parameters/gov/irs/gross_income/sources.yaml index af8391cacdf..d00f3b45950 100644 --- a/policyengine_us/parameters/gov/irs/gross_income/sources.yaml +++ b/policyengine_us/parameters/gov/irs/gross_income/sources.yaml @@ -17,8 +17,12 @@ values: - rental_income # Royalties included in rental income - dividend_income - - taxable_pension_income + - taxable_pension_income # Pension income includes annuities and endowment contracts + # Disability benefits from a plan paid for by the employer (§ 105(a)), + # on Form 1040 line 1h until minimum retirement age, then line 5. + # Benefits from a plan the recipient paid for are excluded (§ 104(a)(3)). + - taxable_disability_benefits - debt_relief # Income in respect of a decedent (§ 61(a)(13)) has no dedicated input; # IRD a beneficiary receives through an estate or trust (K-1 box 5) is @@ -49,6 +53,12 @@ metadata: href: https://www.law.cornell.edu/uscode/text/26/61 - title: 26 U.S. Code § 111 - Recovery of tax benefit items href: https://www.law.cornell.edu/uscode/text/26/111 + - title: 26 U.S. Code § 104(a)(3) - Amounts received through accident or health insurance + href: https://www.law.cornell.edu/uscode/text/26/104#a_3 + - title: 26 U.S. Code § 105(a) - Amounts attributable to employer contributions + href: https://www.law.cornell.edu/uscode/text/26/105#a + - title: IRS Publication 525 (2024), Sickness and Injury Benefits and Disability Pensions + href: https://www.irs.gov/pub/irs-prior/p525--2024.pdf#page=18 - title: 26 U.S. Code § 61(a)(14) - Income from an interest in an estate or trust href: https://www.law.cornell.edu/uscode/text/26/61#a_14 - title: 2024 Schedule 1 (Form 1040), line 5 - Rental real estate, royalties, partnerships, S corporations, trusts, etc. diff --git a/policyengine_us/parameters/gov/states/ar/tax/income/exemptions/retirement_or_disability_benefits/employment_sources.yaml b/policyengine_us/parameters/gov/states/ar/tax/income/exemptions/retirement_or_disability_benefits/employment_sources.yaml index 5db19b85c16..4376b043b6f 100644 --- a/policyengine_us/parameters/gov/states/ar/tax/income/exemptions/retirement_or_disability_benefits/employment_sources.yaml +++ b/policyengine_us/parameters/gov/states/ar/tax/income/exemptions/retirement_or_disability_benefits/employment_sources.yaml @@ -1,7 +1,7 @@ description: Arkansas exempts these employment-related retirement and disability benefits under the individual income tax retirement exemption program. values: 2021-01-01: - - disability_benefits + - taxable_disability_benefits - taxable_pension_income - taxable_401k_distributions - taxable_403b_distributions diff --git a/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/individual.yaml b/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/individual.yaml index 6c709962bc8..6e031dad59e 100644 --- a/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/individual.yaml +++ b/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/individual.yaml @@ -17,7 +17,7 @@ values: - taxable_roth_conversions # Line 16, or Lines 17A/17B after age 59 1/2 - military_retirement_pay # Line 17A/17B - taxable_pension_income # Line 17A/17B - - disability_benefits # Line 17A/17B + - taxable_disability_benefits # Line 17A/17B - rental_income # Line 18 - estate_income # Line 18 - farm_rent_income # Line 18, Form 4835 rent is reported on Schedule E @@ -42,7 +42,7 @@ values: - taxable_roth_conversions # Line 16, or Lines 18A/18B after age 59 1/2 - military_retirement_pay # Line 17 (Lines 17A/17B on the 2018 form) - taxable_pension_income # Line 18A/18B - - disability_benefits # Line 18A/18B + - taxable_disability_benefits # Line 18A/18B - rental_income # Line 19 - estate_income # Line 19 - farm_rent_income # Line 19, Form 4835 rent is reported on Schedule E @@ -61,7 +61,7 @@ values: - taxable_roth_conversions # Line 16, or Lines 18A/18B after age 59 1/2 - military_retirement_pay # Line 17 - taxable_pension_income # Line 18A/18B - - disability_benefits # Line 18A/18B + - taxable_disability_benefits # Line 18A/18B - rental_income # Line 19 - estate_income # Line 19 - farm_rent_income # Line 19, Form 4835 rent is reported on Schedule E @@ -83,7 +83,7 @@ values: - taxable_403b_distributions # Line 18A/18B - taxable_sep_distributions # Line 18A/18B - keogh_distributions # Line 18A/18B - - disability_benefits # Line 18A/18B + - taxable_disability_benefits # Line 18A/18B - rental_income # Line 19 - estate_income # Line 19 - farm_rent_income # Line 19, Form 4835 rent is reported on Schedule E diff --git a/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/joint.yaml b/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/joint.yaml index f5e8bf42c71..23479743ead 100644 --- a/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/joint.yaml +++ b/policyengine_us/parameters/gov/states/ar/tax/income/gross_income/sources/joint.yaml @@ -17,7 +17,7 @@ values: - taxable_roth_conversions # Line 16, or Lines 17A/17B after age 59 1/2 - military_retirement_pay # Line 17A/17B - taxable_pension_income # Line 17A/17B - - disability_benefits # Line 17A/17B + - taxable_disability_benefits # Line 17A/17B - rental_income # Line 18 - estate_income # Line 18 - farm_rent_income # Line 18, Form 4835 rent is reported on Schedule E @@ -42,7 +42,7 @@ values: - taxable_roth_conversions # Line 16, or Lines 18A/18B after age 59 1/2 - military_retirement_pay # Line 17 (Lines 17A/17B on the 2018 form) - taxable_pension_income # Line 18A/18B - - disability_benefits # Line 18A/18B + - taxable_disability_benefits # Line 18A/18B - rental_income # Line 19 - estate_income # Line 19 - farm_rent_income # Line 19, Form 4835 rent is reported on Schedule E @@ -61,7 +61,7 @@ values: - taxable_roth_conversions # Line 16, or Lines 18A/18B after age 59 1/2 - military_retirement_pay # Line 17 - taxable_pension_income # Line 18A/18B - - disability_benefits # Line 18A/18B + - taxable_disability_benefits # Line 18A/18B - rental_income # Line 19 - estate_income # Line 19 - farm_rent_income # Line 19, Form 4835 rent is reported on Schedule E @@ -83,7 +83,7 @@ values: - taxable_403b_distributions # Line 18A/18B - taxable_sep_distributions # Line 18A/18B - keogh_distributions # Line 18A/18B - - disability_benefits # Line 18A/18B + - taxable_disability_benefits # Line 18A/18B - rental_income # Line 19 - estate_income # Line 19 - farm_rent_income # Line 19, Form 4835 rent is reported on Schedule E diff --git a/policyengine_us/parameters/gov/states/co/tax/income/subtractions/pension/income_sources.yaml b/policyengine_us/parameters/gov/states/co/tax/income/subtractions/pension/income_sources.yaml index 8ac10e703f7..073b63b2e52 100644 --- a/policyengine_us/parameters/gov/states/co/tax/income/subtractions/pension/income_sources.yaml +++ b/policyengine_us/parameters/gov/states/co/tax/income/subtractions/pension/income_sources.yaml @@ -9,7 +9,7 @@ values: - taxable_sep_distributions - keogh_distributions - taxable_roth_conversions - - disability_benefits + - taxable_disability_benefits # In 2022 the taxable social security is calculated separately. 2022-01-01: - taxable_pension_income @@ -19,7 +19,7 @@ values: - taxable_sep_distributions - keogh_distributions - taxable_roth_conversions - - disability_benefits + - taxable_disability_benefits metadata: period: year unit: list diff --git a/policyengine_us/parameters/gov/states/oh/tax/income/deductions/deductions.yaml b/policyengine_us/parameters/gov/states/oh/tax/income/deductions/deductions.yaml index 55b555e02bc..29179ad539f 100644 --- a/policyengine_us/parameters/gov/states/oh/tax/income/deductions/deductions.yaml +++ b/policyengine_us/parameters/gov/states/oh/tax/income/deductions/deductions.yaml @@ -7,7 +7,7 @@ values: - oh_529_plan_deduction_person - pell_grant - oh_educator_expense_deduction_person - - disability_benefits + - taxable_disability_benefits - oh_unreimbursed_medical_care_expense_deduction_person - us_govt_interest_person - salt_refund_income diff --git a/policyengine_us/parameters/gov/states/sc/tax/income/subtractions/subtractions.yaml b/policyengine_us/parameters/gov/states/sc/tax/income/subtractions/subtractions.yaml index 8dd2790b80b..9350555a05e 100644 --- a/policyengine_us/parameters/gov/states/sc/tax/income/subtractions/subtractions.yaml +++ b/policyengine_us/parameters/gov/states/sc/tax/income/subtractions/subtractions.yaml @@ -2,7 +2,7 @@ description: South Carolina subtracts these sources from federal taxable income values: 2021-01-01: - salt_refund_income - - disability_benefits #include tax disability benefits + - taxable_disability_benefits - sc_net_capital_gain_deduction - sc_529_plan_deduction - us_govt_interest @@ -23,7 +23,7 @@ values: # H.4216 adds the SCIAD starting 2026 2026-01-01: - salt_refund_income - - disability_benefits + - taxable_disability_benefits - sc_net_capital_gain_deduction - sc_529_plan_deduction - us_govt_interest diff --git a/policyengine_us/tests/code_health/test_ar_gross_income_source_line_comments.py b/policyengine_us/tests/code_health/test_ar_gross_income_source_line_comments.py index 9bcafacd5aa..06cafba68ba 100644 --- a/policyengine_us/tests/code_health/test_ar_gross_income_source_line_comments.py +++ b/policyengine_us/tests/code_health/test_ar_gross_income_source_line_comments.py @@ -47,7 +47,7 @@ "taxable_roth_conversions": "16", "military_retirement_pay": "17A/17B", "taxable_pension_income": "17A/17B", - "disability_benefits": "17A/17B", + "taxable_disability_benefits": "17A/17B", "rental_income": "18", "estate_income": "18", "farm_rent_income": "18", @@ -71,7 +71,7 @@ "taxable_403b_distributions": "18A/18B", "taxable_sep_distributions": "18A/18B", "keogh_distributions": "18A/18B", - "disability_benefits": "18A/18B", + "taxable_disability_benefits": "18A/18B", "rental_income": "19", "estate_income": "19", "farm_rent_income": "19", diff --git a/policyengine_us/tests/core/test_uprating_series.py b/policyengine_us/tests/core/test_uprating_series.py index 7a673d48992..96ff535e2fd 100644 --- a/policyengine_us/tests/core/test_uprating_series.py +++ b/policyengine_us/tests/core/test_uprating_series.py @@ -46,6 +46,7 @@ # Wage-replacement benefits. "workers_compensation": EMPLOYMENT, "disability_benefits": EMPLOYMENT, + "tax_exempt_disability_benefits": EMPLOYMENT, "self_employed_pension_contributions_desired": SELF_EMPLOYMENT, # Components of capital gains. "long_term_capital_gains_on_collectibles": CAPITAL_GAINS, diff --git a/policyengine_us/variables/gov/states/la/tax/income/exempt_income/la_disability_income_exemption_person.py b/policyengine_us/variables/gov/states/la/tax/income/exempt_income/la_disability_income_exemption_person.py index 0e91fa77d63..7eb6348b785 100644 --- a/policyengine_us/variables/gov/states/la/tax/income/exempt_income/la_disability_income_exemption_person.py +++ b/policyengine_us/variables/gov/states/la/tax/income/exempt_income/la_disability_income_exemption_person.py @@ -12,8 +12,8 @@ class la_disability_income_exemption_person(Variable): def formula(person, period, parameters): p = parameters(period).gov.states.la.tax.income.exempt_income.disability - # The disability_benefits variable includes only taxable disability benefits. - disability_benefits = person("disability_benefits", period) + # Only disability income included in federal AGI can be exempted. + disability_benefits = person("taxable_disability_benefits", period) capped_disability_benefits = min_(disability_benefits, p.cap) is_head_or_spouse = person("is_tax_unit_head_or_spouse", period) total_disablity_exemption = capped_disability_benefits * is_head_or_spouse diff --git a/policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/mt_disability_income_exclusion_person.py b/policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/mt_disability_income_exclusion_person.py index 538f5958b75..f4a3bfb1ea7 100644 --- a/policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/mt_disability_income_exclusion_person.py +++ b/policyengine_us/variables/gov/states/mt/tax/income/subtractions/disability/mt_disability_income_exclusion_person.py @@ -12,4 +12,4 @@ class mt_disability_income_exclusion_person(Variable): def formula(person, period, parameters): p = parameters(period).gov.states.mt.tax.income.subtractions.disability_income - return min_(p.cap, person("disability_benefits", period)) + return min_(p.cap, person("taxable_disability_benefits", period)) diff --git a/policyengine_us/variables/gov/states/pa/tax/property/property_tax_or_rent_rebate/pa_property_tax_or_rent_rebate_income.py b/policyengine_us/variables/gov/states/pa/tax/property/property_tax_or_rent_rebate/pa_property_tax_or_rent_rebate_income.py index 1bd76724a54..5075b56eb23 100644 --- a/policyengine_us/variables/gov/states/pa/tax/property/property_tax_or_rent_rebate/pa_property_tax_or_rent_rebate_income.py +++ b/policyengine_us/variables/gov/states/pa/tax/property/property_tax_or_rent_rebate/pa_property_tax_or_rent_rebate_income.py @@ -60,7 +60,8 @@ def formula(tax_unit, period, parameters): "gambling_winnings", "alimony_income", "workers_compensation", - "disability_benefits", + # The taxable part is already in adjusted_gross_income. + "tax_exempt_disability_benefits", ], ) ) diff --git a/policyengine_us/variables/gov/states/va/tax/income/subtractions/va_disability_income_subtraction_person.py b/policyengine_us/variables/gov/states/va/tax/income/subtractions/va_disability_income_subtraction_person.py index bf06f572a97..699abc6e381 100644 --- a/policyengine_us/variables/gov/states/va/tax/income/subtractions/va_disability_income_subtraction_person.py +++ b/policyengine_us/variables/gov/states/va/tax/income/subtractions/va_disability_income_subtraction_person.py @@ -12,5 +12,5 @@ class va_disability_income_subtraction_person(Variable): def formula(person, period, parameters): p = parameters(period).gov.states.va.tax.income.subtractions.disability_income - subtractable = min_(person("disability_benefits", period), p.amount) + subtractable = min_(person("taxable_disability_benefits", period), p.amount) return subtractable * person("is_tax_unit_head_or_spouse", period) diff --git a/policyengine_us/variables/household/income/person/general/disability_benefits.py b/policyengine_us/variables/household/income/person/general/disability_benefits.py index fe525c274bf..c7d6b7624e8 100644 --- a/policyengine_us/variables/household/income/person/general/disability_benefits.py +++ b/policyengine_us/variables/household/income/person/general/disability_benefits.py @@ -6,6 +6,10 @@ class disability_benefits(Variable): entity = Person label = "disability benefits" unit = USD - documentation = "Disability benefits from employment (not Social Security), except for worker's compensation." + documentation = ( + "Disability benefits from employment (not Social Security), except for " + "worker's compensation. Includes both the taxable and the tax-exempt part; " + "see taxable_disability_benefits and tax_exempt_disability_benefits." + ) definition_period = YEAR uprating = "calibration.gov.irs.soi.employment_income" diff --git a/policyengine_us/variables/household/income/person/general/tax_exempt_disability_benefits.py b/policyengine_us/variables/household/income/person/general/tax_exempt_disability_benefits.py new file mode 100644 index 00000000000..05cd257a156 --- /dev/null +++ b/policyengine_us/variables/household/income/person/general/tax_exempt_disability_benefits.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class tax_exempt_disability_benefits(Variable): + value_type = float + entity = Person + label = "tax-exempt disability benefits" + unit = USD + documentation = ( + "The part of disability_benefits excluded from gross income: benefits " + "from a plan the recipient paid for with after-tax dollars, and the " + "recipient's share of a plan both they and their employer paid for " + "(IRC 104(a)(3), 105(a)). Premiums paid pre-tax through a cafeteria " + "plan count as paid by the employer, so benefits they buy are taxable. " + "Defaults to zero: benefits from employment are treated as coming from " + "a plan the employer paid for." + ) + definition_period = YEAR + uprating = "calibration.gov.irs.soi.employment_income" + reference = ( + "https://www.law.cornell.edu/uscode/text/26/104#a_3", + "https://www.law.cornell.edu/uscode/text/26/105#a", + "https://www.irs.gov/pub/irs-prior/p525--2024.pdf#page=18", + ) diff --git a/policyengine_us/variables/household/income/person/general/taxable_disability_benefits.py b/policyengine_us/variables/household/income/person/general/taxable_disability_benefits.py new file mode 100644 index 00000000000..987eb99bec0 --- /dev/null +++ b/policyengine_us/variables/household/income/person/general/taxable_disability_benefits.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class taxable_disability_benefits(Variable): + value_type = float + entity = Person + label = "taxable disability benefits" + unit = USD + documentation = ( + "The part of disability_benefits included in gross income: benefits " + "from a plan paid for by the employer, including disability pensions " + "(IRC 105(a)). Reported on Form 1040 line 1h until minimum retirement " + "age and as a pension on line 5 after it." + ) + definition_period = YEAR + reference = ( + "https://www.law.cornell.edu/uscode/text/26/105#a", + "https://www.irs.gov/pub/irs-prior/p525--2024.pdf#page=18", + ) + + def formula(person, period, parameters): + disability_benefits = person("disability_benefits", period) + tax_exempt = person("tax_exempt_disability_benefits", period) + return max_(0, disability_benefits - tax_exempt) From 409bf09fb7835250053b7c45fbf397bdbab56b8d Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 19:12:28 -0400 Subject: [PATCH 02/13] Test taxable disability benefits from Pub. 525's rules Co-Authored-By: Claude Opus 5.5 --- .../irs/income/dependent_gross_income.yaml | 25 +++ .../taxable_disability_benefits.yaml | 168 ++++++++++++++++++ .../is_qualifying_relative_dependent.yaml | 47 +++++ 3 files changed, 240 insertions(+) create mode 100644 policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/taxable_disability_benefits.yaml diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/dependent_gross_income.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/dependent_gross_income.yaml index e0af5604bfd..7e0614b3d4a 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/income/dependent_gross_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/dependent_gross_income.yaml @@ -410,3 +410,28 @@ # Gross income = 14,000 + 0 gains + 500 = 14,500. dependent_taxable_ss_magi: [0, 11_000] dependent_gross_income: [0, 14_500] + +- name: A dependent's disability benefits from an employer-paid plan are gross income. + period: 2024 + input: + people: + head: + age: 45 + is_tax_unit_head: true + employment_income: 50_000 + parent: + age: 62 + is_tax_unit_dependent: true + is_tax_unit_spouse: false + disability_benefits: 6_000 + tax_exempt_disability_benefits: 1_500 + tax_units: + tax_unit: + members: [head, parent] + households: + household: + members: [head, parent] + output: + # Only the part due to the employer's payments is gross income + # (IRC 105(a)): 6,000 - 1,500 = 4,500. + dependent_gross_income: [0, 4_500] diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/taxable_disability_benefits.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/taxable_disability_benefits.yaml new file mode 100644 index 00000000000..21fbcf7db21 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/taxable_disability_benefits.yaml @@ -0,0 +1,168 @@ +# IRS Pub. 525 (2024), page 18, Sickness and Injury Benefits and Disability +# Pensions: benefits from an accident or health plan paid for by the employer +# are income; if the employee paid the entire cost, none is; if both paid, +# only the part due to the employer's payments is (IRC 104(a)(3), 105(a)). + +- name: Benefits from a plan the employer paid for are gross income. + period: 2024 + input: + people: + person: + age: 45 + disability_benefits: 24_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + output: + taxable_disability_benefits: 24_000 + irs_gross_income: 24_000 + adjusted_gross_income: 24_000 + +- name: Benefits from a plan the employee paid the entire cost of are excluded. + period: 2024 + input: + people: + person: + age: 45 + disability_benefits: 24_000 + tax_exempt_disability_benefits: 24_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + output: + taxable_disability_benefits: 0 + irs_gross_income: 0 + adjusted_gross_income: 0 + +- name: When both paid for the plan, only the part due to the employer's payments is income. + period: 2024 + input: + people: + person: + age: 45 + # The employee's after-tax premiums bought 8,000 of the 20,000. + disability_benefits: 20_000 + tax_exempt_disability_benefits: 8_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + output: + # 20,000 - 8,000 = 12,000. + taxable_disability_benefits: 12_000 + irs_gross_income: 12_000 + adjusted_gross_income: 12_000 + +- name: An exempt part larger than the benefits leaves nothing taxable. + period: 2024 + input: + people: + person: + age: 45 + disability_benefits: 5_000 + tax_exempt_disability_benefits: 7_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + output: + taxable_disability_benefits: 0 + irs_gross_income: 0 + +- name: Each spouse's taxable part counts on a joint return. + period: 2024 + input: + people: + head: + age: 50 + is_tax_unit_head: true + disability_benefits: 18_000 + spouse: + age: 48 + is_tax_unit_spouse: true + disability_benefits: 10_000 + tax_exempt_disability_benefits: 10_000 + employment_income: 30_000 + tax_units: + tax_unit: + members: [head, spouse] + households: + household: + members: [head, spouse] + output: + taxable_disability_benefits: [18_000, 0] + irs_gross_income: [18_000, 30_000] + # 18,000 + 30,000 = 48,000. + adjusted_gross_income: 48_000 + +- name: Income tax on a single filer's employer-paid disability pension. + period: 2024 + input: + people: + person: + age: 45 + disability_benefits: 30_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + output: + adjusted_gross_income: 30_000 + # 30,000 - 14,600 standard deduction = 15,400. + taxable_income: 15_400 + # 10% x 11,600 + 12% x (15,400 - 11,600) = 1,160 + 456 = 1,616. + income_tax_before_credits: 1_616 + +- name: Taxable disability benefits count toward provisional income for Social Security. + period: 2024 + input: + people: + person: + age: 60 + social_security_disability: 20_000 + disability_benefits: 20_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + output: + # Provisional income = 20,000 + 0.5 x 20,000 = 30,000, between the + # 25,000 base and the 34,000 adjusted base for a single filer. + # Taxable benefits = min(0.5 x 20,000, 0.5 x (30,000 - 25,000)) = 2,500. + tax_unit_taxable_social_security: 2_500 + # 20,000 + 2,500 = 22,500. + adjusted_gross_income: 22_500 + +- name: Tax-exempt disability benefits do not count toward provisional income. + period: 2024 + input: + people: + person: + age: 60 + social_security_disability: 20_000 + disability_benefits: 20_000 + tax_exempt_disability_benefits: 20_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + output: + # Provisional income = 0.5 x 20,000 = 10,000 < 25,000. + tax_unit_taxable_social_security: 0 + adjusted_gross_income: 0 diff --git a/policyengine_us/tests/policy/baseline/household/demographic/person/is_qualifying_relative_dependent.yaml b/policyengine_us/tests/policy/baseline/household/demographic/person/is_qualifying_relative_dependent.yaml index d18a8460210..121a635f7a5 100644 --- a/policyengine_us/tests/policy/baseline/household/demographic/person/is_qualifying_relative_dependent.yaml +++ b/policyengine_us/tests/policy/baseline/household/demographic/person/is_qualifying_relative_dependent.yaml @@ -354,3 +354,50 @@ # for each parent, not below 4,400 for 2022. dependent_gross_income: [0, 5_100, 5_100] is_qualifying_relative_dependent: [false, false, false] + +- name: A parent whose employer-paid disability pension exceeds the gross income limit is not a qualifying relative. + period: 2024 + input: + people: + head: + age: 45 + is_tax_unit_head: true + employment_income: 50_000 + parent: + age: 62 + is_tax_unit_dependent: true + is_tax_unit_spouse: false + # Taxable under IRC 105(a), so over the $5,050 limit for 2024. + disability_benefits: 6_000 + tax_units: + tax_unit: + members: [head, parent] + households: + household: + members: [head, parent] + output: + is_qualifying_relative_dependent: [false, false] + +- name: A parent whose disability insurance they paid for themselves stays a qualifying relative. + period: 2024 + input: + people: + head: + age: 45 + is_tax_unit_head: true + employment_income: 50_000 + parent: + age: 62 + is_tax_unit_dependent: true + is_tax_unit_spouse: false + # Excluded under IRC 104(a)(3), so not gross income. + disability_benefits: 6_000 + tax_exempt_disability_benefits: 6_000 + tax_units: + tax_unit: + members: [head, parent] + households: + household: + members: [head, parent] + output: + is_qualifying_relative_dependent: [false, true] From b9d7f7c0a91386add3ef46cded89025167710fb6 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 19:18:54 -0400 Subject: [PATCH 03/13] Test that state disability subtractions read the taxable part Co-Authored-By: Claude Opus 5.5 --- .../states/ar/tax/income/ar_agi_indiv.yaml | 23 ++++++++++++++++++ ..._disability_benefits_exemption_person.yaml | 13 ++++++++++ .../pension/co_pension_subtraction_indv.yaml | 20 ++++++++++++++++ ...la_disability_income_exemption_person.yaml | 20 ++++++++++++++++ ...mt_disability_income_exclusion_person.yaml | 11 +++++++++ .../tax/income/deductions/oh_deductions.yaml | 22 +++++++++++++++++ ...pa_property_tax_or_rent_rebate_income.yaml | 24 +++++++++++++++++++ .../income/subtractions/sc_subtractions.yaml | 18 ++++++++++++++ .../va_disability_income_subtraction.yaml | 20 ++++++++++++++++ 9 files changed, 171 insertions(+) create mode 100644 policyengine_us/tests/policy/baseline/gov/states/oh/tax/income/deductions/oh_deductions.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/sc/tax/income/subtractions/sc_subtractions.yaml diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_agi_indiv.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_agi_indiv.yaml index c4c6ba6cd8c..2feecfbb789 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_agi_indiv.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/ar_agi_indiv.yaml @@ -64,3 +64,26 @@ ar_gross_income_indiv: 56_000 ar_capped_retirement_or_disability_benefits_exemption_person: 6_000 ar_agi_indiv: 50_000 + +- name: Only taxable disability benefits enter Arkansas gross income on line 18. + period: 2024 + input: + people: + person1: + irs_employment_income: 30_000 + disability_benefits: 10_000 + tax_exempt_disability_benefits: 7_000 + age: 50 + is_tax_unit_head: true + is_tax_unit_spouse: false + is_tax_unit_dependent: false + households: + household: + members: [person1] + state_code: AR + output: + # 30,000 + (10,000 - 7,000) = 33,000. + ar_gross_income_indiv: 33_000 + # The 3,000 is under the 6,000 cap and exempt in full. + ar_capped_retirement_or_disability_benefits_exemption_person: 3_000 + ar_agi_indiv: 30_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/exemptions/ar_retirement_or_disability_benefits_exemption_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/exemptions/ar_retirement_or_disability_benefits_exemption_person.yaml index 30ee8beec24..4da130dd74b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/exemptions/ar_retirement_or_disability_benefits_exemption_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/exemptions/ar_retirement_or_disability_benefits_exemption_person.yaml @@ -59,3 +59,16 @@ + +- name: Arkansas exemption counts only taxable disability benefits. + period: 2021 + input: + is_tax_unit_head_or_spouse: true + taxable_pension_income: 1_000 + age: 50 + disability_benefits: 4_000 + tax_exempt_disability_benefits: 1_500 + state_code: AR + output: + # 1,000 + (4,000 - 1,500) = 3,500. + ar_retirement_or_disability_benefits_exemption_person: 3_500 diff --git a/policyengine_us/tests/policy/baseline/gov/states/co/tax/income/subtractions/pension/co_pension_subtraction_indv.yaml b/policyengine_us/tests/policy/baseline/gov/states/co/tax/income/subtractions/pension/co_pension_subtraction_indv.yaml index 42a1ef07bbc..adfd98f3c1e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/co/tax/income/subtractions/pension/co_pension_subtraction_indv.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/co/tax/income/subtractions/pension/co_pension_subtraction_indv.yaml @@ -155,3 +155,23 @@ co_pension_subtraction_income: 15_000 co_pension_subtraction_indv: 15_000 + +- name: Only taxable disability benefits count toward the pension subtraction. + period: 2024 + input: + people: + person: + age: 60 + is_tax_unit_head: true + disability_benefits: 10_000 + tax_exempt_disability_benefits: 4_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: CO + output: + # 10,000 - 4,000 = 6,000. + co_pension_subtraction_income: 6_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/la/tax/income/exempt_income/la_disability_income_exemption_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/la/tax/income/exempt_income/la_disability_income_exemption_person.yaml index 30a93752b09..b500e55e340 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/la/tax/income/exempt_income/la_disability_income_exemption_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/la/tax/income/exempt_income/la_disability_income_exemption_person.yaml @@ -81,3 +81,23 @@ state_code: LA output: la_disability_income_exemption_person: [6_000] + +- name: Exemption is limited to the disability benefits included in federal AGI. + period: 2022 + input: + people: + person1: + is_tax_unit_head_or_spouse: true + disability_benefits: 8_000 + tax_exempt_disability_benefits: 4_000 + la_receives_blind_exemption: false + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: LA + output: + # min(8,000 - 4,000, 6,000 cap) = 4,000. + la_disability_income_exemption_person: 4_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/mt_disability_income_exclusion_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/mt_disability_income_exclusion_person.yaml index 7b4acc62111..8dfa12b9d19 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/mt_disability_income_exclusion_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/subtractions/mt_disability_income_exclusion_person.yaml @@ -25,3 +25,14 @@ output: mt_disability_income_exclusion_person: 5_000 + +- name: Eligible person's exclusion is limited to taxable disability income. + period: 2022 + input: + disability_benefits: 5_000 + tax_exempt_disability_benefits: 2_000 + mt_disability_income_exclusion_eligible_person: true + state_code: MT + output: + # 5,000 - 2,000 = 3,000, under the 5,200 cap. + mt_disability_income_exclusion_person: 3_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/income/deductions/oh_deductions.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/income/deductions/oh_deductions.yaml new file mode 100644 index 00000000000..42abd0b2256 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/income/deductions/oh_deductions.yaml @@ -0,0 +1,22 @@ +- name: Ohio deducts the disability benefits included in federal AGI. + period: 2024 + input: + people: + person: + age: 50 + disability_benefits: 10_000 + tax_exempt_disability_benefits: 4_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: OH + output: + # 10,000 - 4,000 = 6,000. + oh_deductions: 6_000 + adjusted_gross_income_person: 6_000 + # 6,000 federal AGI - 6,000 deduction = 0. Deducting the full 10,000 + # would take Ohio AGI below zero. + oh_agi_person: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/pa/tax/property/property_tax_or_rent_rebate/pa_property_tax_or_rent_rebate_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/pa/tax/property/property_tax_or_rent_rebate/pa_property_tax_or_rent_rebate_income.yaml index 5e60ce8d7b7..215eaa2fa27 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/pa/tax/property/property_tax_or_rent_rebate/pa_property_tax_or_rent_rebate_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/pa/tax/property/property_tax_or_rent_rebate/pa_property_tax_or_rent_rebate_income.yaml @@ -123,6 +123,9 @@ alimony_income: 2_000 workers_compensation: 3_000 disability_benefits: 4_000 + # Not in federal AGI (a policy the person paid for), so counted on + # line 11. A taxable part would be in adjusted_gross_income. + tax_exempt_disability_benefits: 4_000 tax_units: tax_unit: members: [person1] @@ -175,3 +178,24 @@ state_code: PA output: pa_property_tax_or_rent_rebate_income: 12_000 + +- name: Taxable disability benefits count once, through federal AGI. + period: 2025 + input: + people: + person1: + age: 65 + ssi: 0 + disability_benefits: 10_000 + tax_exempt_disability_benefits: 4_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: PA + output: + # Federal AGI holds the taxable 6,000 and line 11 the exempt 4,000. + adjusted_gross_income: 6_000 + pa_property_tax_or_rent_rebate_income: 10_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tax/income/subtractions/sc_subtractions.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tax/income/subtractions/sc_subtractions.yaml new file mode 100644 index 00000000000..9d33fac9a04 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tax/income/subtractions/sc_subtractions.yaml @@ -0,0 +1,18 @@ +- name: South Carolina subtracts the disability benefits included in federal taxable income. + period: 2024 + input: + people: + person: + age: 50 + disability_benefits: 30_000 + tax_exempt_disability_benefits: 12_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: SC + output: + # 30,000 - 12,000 = 18,000. + sc_subtractions: 18_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/subtractions/va_disability_income_subtraction.yaml b/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/subtractions/va_disability_income_subtraction.yaml index e1f5f9a42f7..86bfdd59a03 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/subtractions/va_disability_income_subtraction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/subtractions/va_disability_income_subtraction.yaml @@ -102,3 +102,23 @@ # $15,000 + $ 20,000(max) and ignore the dependent va_disability_income_subtraction: 35_000 + +- name: VA disability income subtraction is limited to the part included in federal AGI. + period: 2022 + input: + people: + person1: + disability_benefits: 15_000 + # Benefits from a policy the person paid for are not in federal AGI. + tax_exempt_disability_benefits: 9_000 + is_tax_unit_head: 1 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: VA + output: + # 15,000 - 9,000 = 6,000, under the 20,000 cap. + va_disability_income_subtraction: 6_000 From 285babb4a52bebcb234e813902de717595b2f86f Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 20:36:18 -0400 Subject: [PATCH 04/13] Default Schedule R disability income to taxable disability benefits total_disability_payments (IRC 22(c)(2)(B)(iii)) now defaults to taxable_disability_benefits for someone retired on permanent and total disability, with tests from the 2024 Schedule R instructions' examples. Co-Authored-By: Claude Opus 5.5 --- .../section_22_income.yaml | 91 +++++++++++++++++++ .../total_disability_payments.py | 19 +++- 2 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/section_22_income.yaml diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/section_22_income.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/section_22_income.yaml new file mode 100644 index 00000000000..b4df7aeba4e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/section_22_income.yaml @@ -0,0 +1,91 @@ +# 2024 Instructions for Schedule R (Form 1040), file pages 3-4: a qualified +# individual under 65 must have taxable disability income, paid under the +# employer's accident or health plan or pension plan and included in income +# as wages or payments instead of wages; the initial amount can't be more +# than that income. + +- name: Schedule R Example 1, joint filers with one spouse under 65 retired on disability. + period: 2024 + input: + people: + head: + age: 63 + is_tax_unit_head: true + retired_on_total_disability: true + disability_benefits: 4_000 + spouse: + age: 67 + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [head, spouse] + households: + household: + members: [head, spouse] + output: + total_disability_payments: [4_000, 0] + # Line 10: 7,500 (box 6). Line 11: 5,000 + 4,000 = 9,000. + # Line 12: min(7,500, 9,000) = 7,500. AGI 4,000 is under the 10,000 + # joint threshold, so nothing is phased out. + section_22_income: 7_500 + # 15% x 7,500. + elderly_disabled_credit_potential: 1_125 + +- name: Schedule R Example 2, single filer under 65 with $3,000 of taxable disability income. + period: 2024 + input: + people: + person: + age: 60 + retired_on_total_disability: true + disability_benefits: 3_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + output: + total_disability_payments: 3_000 + # Line 10: 5,000 (box 2). Line 11: 3,000. Line 12: 3,000. + section_22_income: 3_000 + # 15% x 3,000. + elderly_disabled_credit_potential: 450 + +- name: Disability benefits from insurance the filer paid for are not disability income for Schedule R. + period: 2024 + input: + people: + person: + age: 60 + retired_on_total_disability: true + disability_benefits: 3_000 + tax_exempt_disability_benefits: 3_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + output: + # Not included in income, so no taxable disability income on line 11. + total_disability_payments: 0 + section_22_income: 0 + +- name: Disability benefits of someone not retired on total disability are not Schedule R disability income. + period: 2024 + input: + people: + person: + age: 60 + retired_on_total_disability: false + disability_benefits: 3_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + output: + total_disability_payments: 0 + section_22_income: 0 diff --git a/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/total_disability_payments.py b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/total_disability_payments.py index a707d7f77c3..cd303518d1d 100644 --- a/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/total_disability_payments.py +++ b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/total_disability_payments.py @@ -6,5 +6,22 @@ class total_disability_payments(Variable): entity = Person label = "Disability (total) payments" unit = USD - documentation = "Wages (or payments in lieu thereof) paid to an individual for permanent and total disability" + documentation = ( + "Wages (or payments in lieu thereof) paid to an individual for permanent " + "and total disability. Defaults to the taxable disability benefits of " + "someone who retired on permanent and total disability: benefits from " + "an employer's accident or health plan or pension plan, included in " + "income as wages or payments instead of wages (IRC 22(c)(2)(B)(iii)). " + "Amounts received after the employer's mandatory retirement age are not " + "disability income; the model does not track that age." + ) definition_period = YEAR + reference = ( + "https://www.law.cornell.edu/uscode/text/26/22#c_2_B_iii", + "https://www.irs.gov/pub/irs-prior/i1040sr--2024.pdf#page=3", + ) + + def formula(person, period, parameters): + retired_on_total_disability = person("retired_on_total_disability", period) + taxable_disability_benefits = person("taxable_disability_benefits", period) + return retired_on_total_disability * taxable_disability_benefits From 0c4d9974a843bf197dd1c7da5e7eb1fe8351ff4e Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 02:51:33 -0400 Subject: [PATCH 05/13] Revert "Default Schedule R disability income to taxable disability benefits" This reverts commit 285babb4a52bebcb234e813902de717595b2f86f. --- .../section_22_income.yaml | 91 ------------------- .../total_disability_payments.py | 19 +--- 2 files changed, 1 insertion(+), 109 deletions(-) delete mode 100644 policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/section_22_income.yaml diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/section_22_income.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/section_22_income.yaml deleted file mode 100644 index b4df7aeba4e..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/section_22_income.yaml +++ /dev/null @@ -1,91 +0,0 @@ -# 2024 Instructions for Schedule R (Form 1040), file pages 3-4: a qualified -# individual under 65 must have taxable disability income, paid under the -# employer's accident or health plan or pension plan and included in income -# as wages or payments instead of wages; the initial amount can't be more -# than that income. - -- name: Schedule R Example 1, joint filers with one spouse under 65 retired on disability. - period: 2024 - input: - people: - head: - age: 63 - is_tax_unit_head: true - retired_on_total_disability: true - disability_benefits: 4_000 - spouse: - age: 67 - is_tax_unit_spouse: true - tax_units: - tax_unit: - members: [head, spouse] - households: - household: - members: [head, spouse] - output: - total_disability_payments: [4_000, 0] - # Line 10: 7,500 (box 6). Line 11: 5,000 + 4,000 = 9,000. - # Line 12: min(7,500, 9,000) = 7,500. AGI 4,000 is under the 10,000 - # joint threshold, so nothing is phased out. - section_22_income: 7_500 - # 15% x 7,500. - elderly_disabled_credit_potential: 1_125 - -- name: Schedule R Example 2, single filer under 65 with $3,000 of taxable disability income. - period: 2024 - input: - people: - person: - age: 60 - retired_on_total_disability: true - disability_benefits: 3_000 - tax_units: - tax_unit: - members: [person] - households: - household: - members: [person] - output: - total_disability_payments: 3_000 - # Line 10: 5,000 (box 2). Line 11: 3,000. Line 12: 3,000. - section_22_income: 3_000 - # 15% x 3,000. - elderly_disabled_credit_potential: 450 - -- name: Disability benefits from insurance the filer paid for are not disability income for Schedule R. - period: 2024 - input: - people: - person: - age: 60 - retired_on_total_disability: true - disability_benefits: 3_000 - tax_exempt_disability_benefits: 3_000 - tax_units: - tax_unit: - members: [person] - households: - household: - members: [person] - output: - # Not included in income, so no taxable disability income on line 11. - total_disability_payments: 0 - section_22_income: 0 - -- name: Disability benefits of someone not retired on total disability are not Schedule R disability income. - period: 2024 - input: - people: - person: - age: 60 - retired_on_total_disability: false - disability_benefits: 3_000 - tax_units: - tax_unit: - members: [person] - households: - household: - members: [person] - output: - total_disability_payments: 0 - section_22_income: 0 diff --git a/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/total_disability_payments.py b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/total_disability_payments.py index cd303518d1d..a707d7f77c3 100644 --- a/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/total_disability_payments.py +++ b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/total_disability_payments.py @@ -6,22 +6,5 @@ class total_disability_payments(Variable): entity = Person label = "Disability (total) payments" unit = USD - documentation = ( - "Wages (or payments in lieu thereof) paid to an individual for permanent " - "and total disability. Defaults to the taxable disability benefits of " - "someone who retired on permanent and total disability: benefits from " - "an employer's accident or health plan or pension plan, included in " - "income as wages or payments instead of wages (IRC 22(c)(2)(B)(iii)). " - "Amounts received after the employer's mandatory retirement age are not " - "disability income; the model does not track that age." - ) + documentation = "Wages (or payments in lieu thereof) paid to an individual for permanent and total disability" definition_period = YEAR - reference = ( - "https://www.law.cornell.edu/uscode/text/26/22#c_2_B_iii", - "https://www.irs.gov/pub/irs-prior/i1040sr--2024.pdf#page=3", - ) - - def formula(person, period, parameters): - retired_on_total_disability = person("retired_on_total_disability", period) - taxable_disability_benefits = person("taxable_disability_benefits", period) - return retired_on_total_disability * taxable_disability_benefits From 83183e75cc79016715c1644dfb39d56729d0753d Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 02:53:22 -0400 Subject: [PATCH 06/13] Exclude disability benefits from Pennsylvania taxable compensation Pennsylvania starts from federal gross income in the model, so the taxable disability benefits now in federal gross income need a PA subtraction: sick pay and disability benefits other than regular wages, including third-party insurer payments, and disability distributions are not taxable (61 Pa. Code 101.6(c)(1); 2024 PA-40 instructions pages 8 and 13). Co-Authored-By: Claude Opus 5.5 --- .../tax/income/nontaxable_income_sources.yaml | 8 ++++++ .../pa_total_taxable_income.yaml | 26 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/policyengine_us/parameters/gov/states/pa/tax/income/nontaxable_income_sources.yaml b/policyengine_us/parameters/gov/states/pa/tax/income/nontaxable_income_sources.yaml index e5270142c66..c129e29d75c 100644 --- a/policyengine_us/parameters/gov/states/pa/tax/income/nontaxable_income_sources.yaml +++ b/policyengine_us/parameters/gov/states/pa/tax/income/nontaxable_income_sources.yaml @@ -8,9 +8,17 @@ values: - taxable_social_security - us_govt_interest - salt_refund_income + # Sick pay and disability benefits other than regular wages, including + # third-party insurer payments, and disability distributions (61 Pa. + # Code 101.6(c)(1)). Regular sick leave pay is in employment income. + - taxable_disability_benefits metadata: unit: currency-USD label: PA nontaxable income sources reference: - title: 2021 Pennsylvania PIT Return Instructions (PA-40 IN) href: https://www.pa.gov/content/dam/copapwp-pagov/en/revenue/documents/formsandpublications/formsforindividuals/pit/documents/2021/2021_pa-40in.pdf#page=8 + - title: 61 Pa. Code § 101.6(c)(1) - Compensation excludes periodic sickness and disability payments other than regular wages + href: https://www.pacodeandbulletin.gov/Display/pacode?file=/secure/pacode/data/061/chapter101/s101.6.html + - title: "2024 Pennsylvania PIT Return Instructions (PA-40 IN), nontaxable sick pay and disability benefits and Code 3 disability distributions #page 8,13" + href: https://www.pa.gov/content/dam/copapwp-pagov/en/revenue/documents/formsandpublications/formsforindividuals/pit/documents/2024/2024_pa-40in.pdf#page=8 diff --git a/policyengine_us/tests/policy/baseline/gov/states/pa/tax/income/taxable_income/pa_total_taxable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/pa/tax/income/taxable_income/pa_total_taxable_income.yaml index 9e21cddcfb6..da3a50fb6cd 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/pa/tax/income/taxable_income/pa_total_taxable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/pa/tax/income/taxable_income/pa_total_taxable_income.yaml @@ -73,3 +73,29 @@ pa_total_taxable_income: 30_000 # 30,000 x 3.07% pa_income_tax_before_forgiveness: 921 + +- name: Disability benefits other than regular wages are not taxable compensation in Pennsylvania. + period: 2024 + input: + people: + person1: + age: 45 + employment_income: 40_000 + # Federally taxable: from a plan the employer paid for. + disability_benefits: 20_000 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: PA + output: + # Federal gross income: 40,000 wages + 20,000 disability benefits = + # 60,000. PA-40 instructions: sick pay and disability benefits, + # including third-party insurer payments, are not taxable unless they + # represent regular wages. 60,000 - 20,000 = 40,000. + irs_gross_income: 60_000 + pa_total_taxable_income: 40_000 + # 40,000 x 3.07% + pa_income_tax_before_forgiveness: 1_228 From 5651fbf9e3936e813271424868ce68804b142441 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 03:50:51 -0400 Subject: [PATCH 07/13] Count pre-retirement-age disability pensions as earned income; add state disability income exclusions - disability_benefits_before_minimum_retirement_age (input, default 0) and earned_disability_benefits feed EITC/ACTC earned income, a dependent's standard deduction and child and dependent care credit earnings (Pub. 596 p.8, Pub. 503 p.4). - permanent_disability_retirement_pay (retired on permanent and total disability) feeds new exclusions modelled on former IRC 105(d): Wisconsin Schedule 2440W, New York IT-221, Iowa IA 2440 (from 2023) and Indiana IT-2440 (code 602). Co-Authored-By: Claude Opus 5.5 --- .../age_limit.yaml | 12 ++++ .../disability_income_exclusion/cap.yaml | 12 ++++ .../reduction_threshold.yaml | 12 ++++ .../income/taxable_income/subtractions.yaml | 6 ++ .../in/tax/income/deductions/deductions.yaml | 9 +++ .../deductions/disability_retirement/cap.yaml | 12 ++++ .../reduction_threshold.yaml | 23 ++++++++ .../age_limit.yaml | 10 ++++ .../disability_income_exclusion/cap.yaml | 12 ++++ .../reduction_threshold.yaml | 12 ++++ .../tax/income/agi/subtractions/sources.yaml | 4 ++ .../disability_income/age_limit.yaml | 12 ++++ .../subtractions/disability_income/cap.yaml | 12 ++++ .../reduction_threshold.yaml | 12 ++++ .../wi/tax/income/subtractions/sources.yaml | 4 ++ .../tests/core/test_uprating_series.py | 1 + .../earned_income/eitc_earned_income.py | 3 + .../permanent_disability_retirement_pay.py | 30 ++++++++++ .../gov/irs/income/adjusted_earnings.py | 5 +- .../basic_standard_deduction.py | 5 +- .../ia_disability_income_exclusion.py | 40 +++++++++++++ .../in_disability_retirement_deduction.py | 40 +++++++++++++ .../income/deductions/in_other_deductions.py | 2 +- .../ny_disability_income_exclusion.py | 56 +++++++++++++++++++ .../wi_disability_income_exclusion.py | 38 +++++++++++++ ..._benefits_before_minimum_retirement_age.py | 21 +++++++ .../general/earned_disability_benefits.py | 26 +++++++++ 27 files changed, 428 insertions(+), 3 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/ia/tax/income/disability_income_exclusion/age_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/tax/income/disability_income_exclusion/cap.yaml create mode 100644 policyengine_us/parameters/gov/states/ia/tax/income/disability_income_exclusion/reduction_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/in/tax/income/deductions/disability_retirement/cap.yaml create mode 100644 policyengine_us/parameters/gov/states/in/tax/income/deductions/disability_retirement/reduction_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/age_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/cap.yaml create mode 100644 policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/reduction_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/wi/tax/income/subtractions/disability_income/age_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/wi/tax/income/subtractions/disability_income/cap.yaml create mode 100644 policyengine_us/parameters/gov/states/wi/tax/income/subtractions/disability_income/reduction_threshold.yaml create mode 100644 policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py create mode 100644 policyengine_us/variables/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.py create mode 100644 policyengine_us/variables/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.py create mode 100644 policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py create mode 100644 policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.py create mode 100644 policyengine_us/variables/household/income/person/general/disability_benefits_before_minimum_retirement_age.py create mode 100644 policyengine_us/variables/household/income/person/general/earned_disability_benefits.py diff --git a/policyengine_us/parameters/gov/states/ia/tax/income/disability_income_exclusion/age_limit.yaml b/policyengine_us/parameters/gov/states/ia/tax/income/disability_income_exclusion/age_limit.yaml new file mode 100644 index 00000000000..bfe9a0df248 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/tax/income/disability_income_exclusion/age_limit.yaml @@ -0,0 +1,12 @@ +description: Iowa allows the disability income exclusion to people who are under this age when the tax year ends. +values: + 2023-01-01: 65 +metadata: + unit: year + period: year + label: Iowa disability income exclusion age limit + reference: + - title: 2023 IA 2440 instructions, Who May Exclude Disability + href: https://revenue.iowa.gov/media/2750/download?inline=#page=2 + - title: 2024 IA 2440 instructions, Who May Exclude Disability + href: https://revenue.iowa.gov/media/4096/download?inline=#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/tax/income/disability_income_exclusion/cap.yaml b/policyengine_us/parameters/gov/states/ia/tax/income/disability_income_exclusion/cap.yaml new file mode 100644 index 00000000000..1b1bb09223e --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/tax/income/disability_income_exclusion/cap.yaml @@ -0,0 +1,12 @@ +description: Iowa limits the disability income exclusion to this amount per disabled person, $100 a week. +values: + 2023-01-01: 5_200 +metadata: + unit: currency-USD + period: year + label: Iowa disability income exclusion cap + reference: + - title: 2023 IA 2440 instructions, line 4 + href: https://revenue.iowa.gov/media/2750/download?inline=#page=2 + - title: 2024 IA 2440 instructions, line 4 + href: https://revenue.iowa.gov/media/4096/download?inline=#page=2 diff --git a/policyengine_us/parameters/gov/states/ia/tax/income/disability_income_exclusion/reduction_threshold.yaml b/policyengine_us/parameters/gov/states/ia/tax/income/disability_income_exclusion/reduction_threshold.yaml new file mode 100644 index 00000000000..cd164e66876 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ia/tax/income/disability_income_exclusion/reduction_threshold.yaml @@ -0,0 +1,12 @@ +description: Iowa reduces the disability income exclusion dollar for dollar by federal adjusted gross income above this amount. +values: + 2023-01-01: 15_000 +metadata: + unit: currency-USD + period: year + label: Iowa disability income exclusion reduction threshold + reference: + - title: 2023 IA 2440, line 4b + href: https://revenue.iowa.gov/media/2750/download?inline=#page=1 + - title: 2024 IA 2440, line 4b + href: https://revenue.iowa.gov/media/4096/download?inline=#page=1 diff --git a/policyengine_us/parameters/gov/states/ia/tax/income/taxable_income/subtractions.yaml b/policyengine_us/parameters/gov/states/ia/tax/income/taxable_income/subtractions.yaml index a4e6efa99de..489df1799ab 100644 --- a/policyengine_us/parameters/gov/states/ia/tax/income/taxable_income/subtractions.yaml +++ b/policyengine_us/parameters/gov/states/ia/tax/income/taxable_income/subtractions.yaml @@ -15,6 +15,8 @@ values: # Iowa Health Insurance Deduction # Iowa capital gains deduction - ia_529_plan_subtraction + # Schedule 1 line 19b, code h (IA 2440) + - ia_disability_income_exclusion 2024-01-01: # military_retirement_pay added in 2024. # Line 1B - us_govt_interest @@ -32,6 +34,8 @@ values: # Iowa Health Insurance Deduction # Iowa capital gains deduction - ia_529_plan_subtraction + # Schedule 1 line 19b, code h (IA 2440) + - ia_disability_income_exclusion metadata: unit: list @@ -42,5 +46,7 @@ metadata: href: https://revenue.iowa.gov/media/2746/download?inline - title: Iowa income tax law, 422.7 href: https://www.legis.iowa.gov/docs/code/422.7.pdf + - title: 2024 IA 2440 Iowa Disability Income Exclusion + href: https://revenue.iowa.gov/media/4096/download?inline=#page=1 - title: 2024 IA1040 Iowa Income Tax Return Instruction href: https://revenue.iowa.gov/media/4152/download?inline#page=61 diff --git a/policyengine_us/parameters/gov/states/in/tax/income/deductions/deductions.yaml b/policyengine_us/parameters/gov/states/in/tax/income/deductions/deductions.yaml index 8debf2504a8..6727676faf2 100644 --- a/policyengine_us/parameters/gov/states/in/tax/income/deductions/deductions.yaml +++ b/policyengine_us/parameters/gov/states/in/tax/income/deductions/deductions.yaml @@ -11,6 +11,7 @@ values: - in_nol - in_unemployment_compensation_deduction - in_other_deductions + - in_disability_retirement_deduction # IC 6-3-2-9 (code 602) - in_civil_service_annuity_deduction 2023-01-01: @@ -34,6 +35,8 @@ values: - in_unemployment_compensation_deduction # IC 6-3-2 - in_other_deductions + # IC 6-3-2-9 (code 602) + - in_disability_retirement_deduction # IC 6-3-2-4 (b) - military_basic_pay # IC 6-3-2-3.7 @@ -60,6 +63,8 @@ values: - in_unemployment_compensation_deduction # IC 6-3-2 - in_other_deductions + # IC 6-3-2-9 (code 602) + - in_disability_retirement_deduction # IC 6-3-2-4 (b) - military_basic_pay # IC 6-3-2-28 @@ -88,6 +93,8 @@ values: - in_unemployment_compensation_deduction # IC 6-3-2 - in_other_deductions + # IC 6-3-2-9 (code 602) + - in_disability_retirement_deduction # IC 6-3-2-4 (b) - military_basic_pay # IC 6-3-2-28 @@ -122,6 +129,8 @@ values: - in_unemployment_compensation_deduction # IC 6-3-2 - in_other_deductions + # IC 6-3-2-9 (code 602) + - in_disability_retirement_deduction # IC 6-3-2-4 (b) - military_basic_pay # IC 6-3-2-28 diff --git a/policyengine_us/parameters/gov/states/in/tax/income/deductions/disability_retirement/cap.yaml b/policyengine_us/parameters/gov/states/in/tax/income/deductions/disability_retirement/cap.yaml new file mode 100644 index 00000000000..c94fe9cd030 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/tax/income/deductions/disability_retirement/cap.yaml @@ -0,0 +1,12 @@ +description: Indiana limits the disability retirement deduction to this amount per disabled person, $100 a week. +values: + 2021-01-01: 5_200 +metadata: + unit: currency-USD + period: year + label: Indiana disability retirement deduction cap + reference: + - title: IC 6-3-2-9 + href: https://law.justia.com/codes/indiana/title-6/article-3/chapter-2/section-6-3-2-9/ + - title: Indiana Income Tax Information Bulletin 70, Computation of Disability Deduction + href: https://www.in.gov/dor/files/reference/ib70.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/in/tax/income/deductions/disability_retirement/reduction_threshold.yaml b/policyengine_us/parameters/gov/states/in/tax/income/deductions/disability_retirement/reduction_threshold.yaml new file mode 100644 index 00000000000..fabfccd50d5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/in/tax/income/deductions/disability_retirement/reduction_threshold.yaml @@ -0,0 +1,23 @@ +description: Indiana reduces the disability retirement deduction dollar for dollar by federal adjusted gross income above this amount, by filing status. +metadata: + propagate_metadata_to_children: true + period: year + unit: currency-USD + label: Indiana disability retirement deduction reduction threshold + reference: + - title: IC 6-3-2-9 + href: https://law.justia.com/codes/indiana/title-6/article-3/chapter-2/section-6-3-2-9/ + - title: Indiana Income Tax Information Bulletin 70, Computation of Disability Deduction, step 3 + href: https://www.in.gov/dor/files/reference/ib70.pdf#page=2 + breakdown: + - filing_status +SINGLE: + 2021-01-01: 15_000 +HEAD_OF_HOUSEHOLD: + 2021-01-01: 15_000 +JOINT: + 2021-01-01: 15_000 +SURVIVING_SPOUSE: + 2021-01-01: 15_000 +SEPARATE: + 2021-01-01: 7_500 diff --git a/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/age_limit.yaml b/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/age_limit.yaml new file mode 100644 index 00000000000..2f29a0d3af6 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/age_limit.yaml @@ -0,0 +1,10 @@ +description: New York allows the disability income exclusion to people who are under this age when the tax year ends. +values: + 2020-01-01: 65 +metadata: + unit: year + period: year + label: New York disability income exclusion age limit + reference: + - title: 2024 Instructions for Form IT-221, Who can exclude disability income + href: https://www.tax.ny.gov/pdf/2024/inc/it221i_2024.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/cap.yaml b/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/cap.yaml new file mode 100644 index 00000000000..58b6ae17538 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/cap.yaml @@ -0,0 +1,12 @@ +description: New York limits the disability income exclusion to this amount per disabled person, $100 a week. +values: + 2020-01-01: 5_200 +metadata: + unit: currency-USD + period: year + label: New York disability income exclusion cap + reference: + - title: N.Y. Tax Law § 612(c)(3-b) + href: https://www.nysenate.gov/legislation/laws/TAX/612 + - title: 2024 Instructions for Form IT-221, Limit on exclusion + href: https://www.tax.ny.gov/pdf/2024/inc/it221i_2024.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/reduction_threshold.yaml b/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/reduction_threshold.yaml new file mode 100644 index 00000000000..1bb9d1817d3 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/reduction_threshold.yaml @@ -0,0 +1,12 @@ +description: New York reduces the disability income exclusion dollar for dollar by federal adjusted gross income above this amount. +values: + 2020-01-01: 15_000 +metadata: + unit: currency-USD + period: year + label: New York disability income exclusion reduction threshold + reference: + - title: N.Y. Tax Law § 612(c)(3-b) + href: https://www.nysenate.gov/legislation/laws/TAX/612 + - title: 2024 Instructions for Form IT-221, Limit on exclusion + href: https://www.tax.ny.gov/pdf/2024/inc/it221i_2024.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/sources.yaml b/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/sources.yaml index 674a75e731a..d828df3c93e 100644 --- a/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/sources.yaml +++ b/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/sources.yaml @@ -5,6 +5,8 @@ values: - us_govt_interest - investment_in_529_plan - ny_pension_exclusion + # N.Y. Tax Law § 612(c)(3-b) / Form IT-221 (IT-225 S-124). + - ny_disability_income_exclusion - salt_refund_income # N.Y. Tax Law § 612(c)(3) / Form IT-201 Line 26: subtracts pensions paid by NY state, # local governments, or the federal government. Pensions from other states are not exempt. @@ -23,6 +25,8 @@ metadata: href: https://www.tax.ny.gov/pdf/2024/inc/it201i_2024.pdf#page=9 - title: 2024 NY Form IT-201, Line 25 (Taxable refunds, credits, or offsets of state and local income taxes) href: https://www.tax.ny.gov/pdf/2024/inc/it201_2024_fill_in.pdf#page=2 + - title: 2024 Instructions for Form IT-221, Disability Income Exclusion + href: https://www.tax.ny.gov/pdf/2024/inc/it221i_2024.pdf#page=1 - title: N.Y. Tax Law § 612(c)(7) href: https://newyork.public.law/laws/n.y._tax_law_section_612 - title: N.Y. Comp. Codes R. & Regs. tit. 20 § 112.3 diff --git a/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/disability_income/age_limit.yaml b/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/disability_income/age_limit.yaml new file mode 100644 index 00000000000..c63cd717f3b --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/disability_income/age_limit.yaml @@ -0,0 +1,12 @@ +description: Wisconsin allows the disability income exclusion to people under this age at the end of the year. +values: + 2021-01-01: 65 +metadata: + unit: year + period: year + label: Wisconsin disability income exclusion age limit + reference: + - title: 2022 Wisconsin Schedule 2440W instructions, Who Can Exclude Disability Income + href: https://www.revenue.wi.gov/TaxForms2022/2022-Schedule2440Wf.pdf#page=2 + - title: 2024 Wisconsin Schedule 2440W instructions, Who Can Exclude Disability Income + href: https://www.revenue.wi.gov/TaxForms2024/2024-Schedule2440Wf.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/disability_income/cap.yaml b/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/disability_income/cap.yaml new file mode 100644 index 00000000000..3033434ce1c --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/disability_income/cap.yaml @@ -0,0 +1,12 @@ +description: Wisconsin limits the disability income exclusion to this amount per disabled person, $100 a week. +values: + 2021-01-01: 5_200 +metadata: + unit: currency-USD + period: year + label: Wisconsin disability income exclusion cap + reference: + - title: 2022 Wisconsin Schedule 2440W, line 5 instructions + href: https://www.revenue.wi.gov/TaxForms2022/2022-Schedule2440Wf.pdf#page=3 + - title: 2024 Wisconsin Schedule 2440W, line 5 instructions + href: https://www.revenue.wi.gov/TaxForms2024/2024-Schedule2440Wf.pdf#page=3 diff --git a/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/disability_income/reduction_threshold.yaml b/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/disability_income/reduction_threshold.yaml new file mode 100644 index 00000000000..cf236adc5f6 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/disability_income/reduction_threshold.yaml @@ -0,0 +1,12 @@ +description: Wisconsin reduces the disability income exclusion dollar for dollar by adjusted gross income above this amount. +values: + 2021-01-01: 15_000 +metadata: + unit: currency-USD + period: year + label: Wisconsin disability income exclusion reduction threshold + reference: + - title: 2022 Wisconsin Schedule 2440W, line 5b + href: https://www.revenue.wi.gov/TaxForms2022/2022-Schedule2440Wf.pdf#page=1 + - title: 2024 Wisconsin Schedule 2440W, line 5b + href: https://www.revenue.wi.gov/TaxForms2024/2024-Schedule2440Wf.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/sources.yaml b/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/sources.yaml index 9f9d8a3984c..9da38e69a4b 100644 --- a/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/sources.yaml +++ b/policyengine_us/parameters/gov/states/wi/tax/income/subtractions/sources.yaml @@ -9,6 +9,7 @@ values: - us_govt_interest - wi_529_plan_deduction - salt_refund_income + - wi_disability_income_exclusion # Schedule SB, Schedule 2440W 2022-01-01: - wi_unemployment_compensation_subtraction - tax_unit_taxable_social_security @@ -17,6 +18,7 @@ values: - us_govt_interest - wi_529_plan_deduction - salt_refund_income + - wi_disability_income_exclusion # Schedule SB, Schedule 2440W metadata: unit: list @@ -32,5 +34,7 @@ metadata: href: https://www.revenue.wi.gov/TaxForms2022/2022-ScheduleSB-Inst.pdf - title: 2024 Wisconsin Form 1 Schedule SB instructions href: https://www.revenue.wi.gov/TaxForms2024/2024-ScheduleSB-Inst.pdf + - title: 2024 Wisconsin Schedule 2440W, Disability Income Exclusion + href: https://www.revenue.wi.gov/TaxForms2024/2024-Schedule2440Wf.pdf#page=1 - title: 2025 Wisconsin Form 1 Schedule SB instructions href: https://www.revenue.wi.gov/TaxForms2025/2025-ScheduleSB-inst.pdf diff --git a/policyengine_us/tests/core/test_uprating_series.py b/policyengine_us/tests/core/test_uprating_series.py index 96ff535e2fd..187cb13e944 100644 --- a/policyengine_us/tests/core/test_uprating_series.py +++ b/policyengine_us/tests/core/test_uprating_series.py @@ -47,6 +47,7 @@ "workers_compensation": EMPLOYMENT, "disability_benefits": EMPLOYMENT, "tax_exempt_disability_benefits": EMPLOYMENT, + "disability_benefits_before_minimum_retirement_age": EMPLOYMENT, "self_employed_pension_contributions_desired": SELF_EMPLOYMENT, # Components of capital gains. "long_term_capital_gains_on_collectibles": CAPITAL_GAINS, diff --git a/policyengine_us/variables/gov/irs/credits/earned_income/eitc_earned_income.py b/policyengine_us/variables/gov/irs/credits/earned_income/eitc_earned_income.py index 78714572f34..0a7e33c5322 100644 --- a/policyengine_us/variables/gov/irs/credits/earned_income/eitc_earned_income.py +++ b/policyengine_us/variables/gov/irs/credits/earned_income/eitc_earned_income.py @@ -28,6 +28,9 @@ def formula(tax_unit, period, parameters): "sstb_self_employment_income", "farm_operations_income", "partnership_self_employment_net_earnings", + # Taxable disability pensions before minimum retirement age + # (Form 1040 line 1h; Pub. 596). + "earned_disability_benefits", ] gross_earned_income = sum( tax_unit_non_dep_sum(source, tax_unit, period) diff --git a/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py new file mode 100644 index 00000000000..be52f132dd7 --- /dev/null +++ b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class permanent_disability_retirement_pay(Variable): + value_type = float + entity = Person + label = "permanent disability retirement pay" + unit = USD + documentation = ( + "Disability pay included in federal adjusted gross income of a person " + "who retired on disability and was permanently and totally disabled " + "when they retired: wages or payments in lieu of wages from an " + "employer's accident or health plan or pension plan. The larger of " + "total_disability_payments and taxable_disability_benefits, so the " + "same payments are not counted twice. State disability income " + "exclusions modelled on former IRC 105(d) apply to it." + ) + definition_period = YEAR + reference = ( + "https://www.irs.gov/pub/irs-prior/i1040sr--2024.pdf#page=3", + "https://www.revenue.wi.gov/TaxForms2024/2024-Schedule2440Wf.pdf#page=2", + ) + + def formula(person, period, parameters): + retired_on_total_disability = person("retired_on_total_disability", period) + disability_pay = max_( + person("total_disability_payments", period), + person("taxable_disability_benefits", period), + ) + return retired_on_total_disability * disability_pay diff --git a/policyengine_us/variables/gov/irs/income/adjusted_earnings.py b/policyengine_us/variables/gov/irs/income/adjusted_earnings.py index e59748efef8..946410b0c73 100644 --- a/policyengine_us/variables/gov/irs/income/adjusted_earnings.py +++ b/policyengine_us/variables/gov/irs/income/adjusted_earnings.py @@ -15,4 +15,7 @@ def formula(person, period, parameters): * p.employer_share * person("self_employment_tax", period) ) - return max_(0, person("earned_income", period) - adjustment) + # Disability pay reported as wages is earned income (Pub. 503 (2024), + # file page 4). + earnings = add(person, period, ["earned_income", "earned_disability_benefits"]) + return max_(0, earnings - adjustment) diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/deductions/standard_deduction/basic_standard_deduction.py b/policyengine_us/variables/gov/irs/income/taxable_income/deductions/standard_deduction/basic_standard_deduction.py index e3d3745bdc5..11daddb77f4 100644 --- a/policyengine_us/variables/gov/irs/income/taxable_income/deductions/standard_deduction/basic_standard_deduction.py +++ b/policyengine_us/variables/gov/irs/income/taxable_income/deductions/standard_deduction/basic_standard_deduction.py @@ -19,7 +19,10 @@ def formula(tax_unit, period, parameters): standard_deduction, max_( p.dependent.additional_earned_income - + tax_unit("tax_unit_earned_income", period), + + tax_unit("tax_unit_earned_income", period) + # Disability pensions reported on Form 1040 line 1h count + # as earned income on the worksheet (line 1z). + + tax_unit_non_dep_sum("earned_disability_benefits", tax_unit, period), p.dependent.amount, ), ) diff --git a/policyengine_us/variables/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.py b/policyengine_us/variables/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.py new file mode 100644 index 00000000000..505d7600fdb --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.py @@ -0,0 +1,40 @@ +from policyengine_us.model_api import * + + +class ia_disability_income_exclusion(Variable): + value_type = float + entity = TaxUnit + label = "Iowa disability income exclusion" + unit = USD + definition_period = YEAR + documentation = ( + "IA 2440, for retirees under 65 who retired on permanent and total " + "disability; Schedule 1 line 19b, code h, from 2023. The weekly $100 " + "limit is applied as an annual cap; the employer's mandatory " + "retirement age is not modelled." + ) + reference = ( + # PDF pages 1-2 + "https://revenue.iowa.gov/media/4096/download?inline=#page=1", + "https://www.legis.iowa.gov/docs/iac/rule/11-02-2022.701.302.22.pdf#page=1", + ) + defined_for = StateCode.IA + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.ia.tax.income.disability_income_exclusion + person = tax_unit.members + eligible = person("is_tax_unit_head_or_spouse", period) & ( + person("age", period) < p.age_limit + ) + disability_pay = person("permanent_disability_retirement_pay", period) + # Lines 1-3: each person's pay, at most $100 a week. + excludable = tax_unit.sum(eligible * min_(disability_pay, p.cap)) + # Line 4: reduced dollar for dollar by federal AGI above $15,000. + agi = tax_unit("adjusted_gross_income", period) + exclusion = max_(0, excludable - max_(0, agi - p.reduction_threshold)) + # A married person must file jointly unless the spouses did not live + # together at any time during the year. + filing_status = tax_unit("filing_status", period) + separate = filing_status == filing_status.possible_values.SEPARATE + lived_together = tax_unit("cohabitating_spouses", period) + return where(separate & lived_together, 0, exclusion) diff --git a/policyengine_us/variables/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.py b/policyengine_us/variables/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.py new file mode 100644 index 00000000000..a0e490a2a40 --- /dev/null +++ b/policyengine_us/variables/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.py @@ -0,0 +1,40 @@ +from policyengine_us.model_api import * + + +class in_disability_retirement_deduction(Variable): + value_type = float + entity = TaxUnit + label = "Indiana disability retirement deduction" + unit = USD + definition_period = YEAR + documentation = ( + "Schedule 2 code 602 (Schedule IT-2440), for people who retired on " + "disability and were permanently and totally disabled when they " + "retired. There is no age limit. The weekly $100 limit is applied as " + "an annual cap." + ) + reference = ( + "https://law.justia.com/codes/indiana/title-6/article-3/chapter-2/section-6-3-2-9/", + # PDF pages 1-2 + "https://www.in.gov/dor/files/reference/ib70.pdf#page=1", + ) + defined_for = StateCode.IN + + def formula(tax_unit, period, parameters): + p = ( + parameters(period) + .gov.states["in"] + .tax.income.deductions.disability_retirement + ) + person = tax_unit.members + head_or_spouse = person("is_tax_unit_head_or_spouse", period) + disability_pay = person("permanent_disability_retirement_pay", period) + # Steps 1-2: the individual's disability pay, at most $100 a week. + capped_pay = min_(disability_pay, p.cap) + # Steps 3-4: less federal AGI above $15,000 ($7,500 married filing + # separately), for each individual. + filing_status = tax_unit("filing_status", period) + agi = tax_unit("adjusted_gross_income", period) + reduction = max_(0, agi - p.reduction_threshold[filing_status]) + deduction = max_(0, capped_pay - person.tax_unit.project(reduction)) + return tax_unit.sum(head_or_spouse * deduction) diff --git a/policyengine_us/variables/gov/states/in/tax/income/deductions/in_other_deductions.py b/policyengine_us/variables/gov/states/in/tax/income/deductions/in_other_deductions.py index e3650257bea..df63c18ada9 100644 --- a/policyengine_us/variables/gov/states/in/tax/income/deductions/in_other_deductions.py +++ b/policyengine_us/variables/gov/states/in/tax/income/deductions/in_other_deductions.py @@ -7,6 +7,6 @@ class in_other_deductions(Variable): label = "Indiana other deductions" unit = USD definition_period = YEAR - documentation = "Other deductions available in Indiana including those for civil service annuities, disability retirement, government or civic group capital contributions, human services for Medicaid recipients, infrastructure fund gifts, indiana lottery winings annuity, Indiana partnership long-term care policy premiums, military retirement income or survivor's benefits, National Guard and reserve component members, Olympic/Paralymic medal winners, qualified patents income eemption, railroad unemployment and sickness benefits, repayment of previously taxed income deductions, COVID-related employee retention credit dissalowed expenses, and Indiana-only tax-exempt bonds." + documentation = "Other deductions available in Indiana including those for civil service annuities, government or civic group capital contributions, human services for Medicaid recipients, infrastructure fund gifts, indiana lottery winings annuity, Indiana partnership long-term care policy premiums, military retirement income or survivor's benefits, National Guard and reserve component members, Olympic/Paralymic medal winners, qualified patents income eemption, railroad unemployment and sickness benefits, repayment of previously taxed income deductions, COVID-related employee retention credit dissalowed expenses, and Indiana-only tax-exempt bonds." reference = "http://iga.in.gov/legislative/laws/2021/ic/titles/006#6-3-2" defined_for = StateCode.IN diff --git a/policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py b/policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py new file mode 100644 index 00000000000..fa8bfafd78f --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py @@ -0,0 +1,56 @@ +from policyengine_us.model_api import * + + +class ny_disability_income_exclusion(Variable): + value_type = float + entity = Person + label = "New York disability income exclusion" + unit = USD + definition_period = YEAR + documentation = ( + "Form IT-221, for people under 65 who retired on permanent and total " + "disability. The weekly $100 limit is applied as an annual cap; the " + "employer's mandatory retirement age is not modelled." + ) + reference = ( + "https://www.nysenate.gov/legislation/laws/TAX/612", + # PDF pages 1-2 + "https://www.tax.ny.gov/pdf/2024/inc/it221i_2024.pdf#page=1", + ) + defined_for = StateCode.NY + + def formula(person, period, parameters): + p = parameters( + period + ).gov.states.ny.tax.income.agi.subtractions.disability_income_exclusion + tax_unit = person.tax_unit + filing_status = tax_unit("filing_status", period) + separate = filing_status == filing_status.possible_values.SEPARATE + # A married person filing separately qualifies only if the spouses + # lived apart all year. + filing_eligible = ~(separate & tax_unit("cohabitating_spouses", period)) + eligible = ( + person("is_tax_unit_head_or_spouse", period) + & (person("age", period) < p.age_limit) + & filing_eligible + ) + disability_pay = eligible * person( + "permanent_disability_retirement_pay", period + ) + # Lines 1-10: each person's pay at most $100 a week, reduced dollar + # for dollar by federal AGI above $15,000. + excludable = tax_unit.sum(min_(disability_pay, p.cap)) + agi = tax_unit("adjusted_gross_income", period) + exclusion = max_(0, excludable - max_(0, agi - p.reduction_threshold)) + # Line 11: spouses share it in proportion to their disability pay. + total_pay = tax_unit.sum(disability_pay) + share = np.divide( + disability_pay, + total_pay, + out=np.zeros_like(total_pay), + where=total_pay > 0, + ) + # IT-221 also limits each person's disability plus pension exclusion + # to $20,000. It cannot bind: both exclude only income in federal + # AGI, and this exclusion is gone once that AGI reaches $20,200. + return exclusion * share diff --git a/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.py b/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.py new file mode 100644 index 00000000000..8375449057e --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.py @@ -0,0 +1,38 @@ +from policyengine_us.model_api import * + + +class wi_disability_income_exclusion(Variable): + value_type = float + entity = TaxUnit + label = "Wisconsin disability income exclusion" + unit = USD + definition_period = YEAR + documentation = ( + "Schedule 2440W, for retirees under 65 who retired on permanent and " + "total disability. The weekly $100 limit is applied as an annual cap; " + "the employer's mandatory retirement age is not modelled." + ) + reference = ( + "https://www.revenue.wi.gov/TaxForms2024/2024-Schedule2440Wf.pdf#page=1", + "https://www.revenue.wi.gov/TaxForms2024/2024-Schedule2440Wf.pdf#page=2", + "https://www.revenue.wi.gov/TaxForms2024/2024-Schedule2440Wf.pdf#page=3", + ) + defined_for = StateCode.WI + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.wi.tax.income.subtractions.disability_income + person = tax_unit.members + eligible = person("is_tax_unit_head_or_spouse", period) & ( + person("age", period) < p.age_limit + ) + disability_pay = person("permanent_disability_retirement_pay", period) + # Lines 1-4: each person's disability pay, at most $100 a week. + excludable = tax_unit.sum(eligible * min_(disability_pay, p.cap)) + # Line 5: reduced dollar for dollar by income above $15,000. + agi = tax_unit("adjusted_gross_income", period) + reduction = max_(0, agi - p.reduction_threshold) + exclusion = max_(0, excludable - reduction) + # A married claimant must file a joint return. + filing_status = tax_unit("filing_status", period) + separate = filing_status == filing_status.possible_values.SEPARATE + return where(separate, 0, exclusion) diff --git a/policyengine_us/variables/household/income/person/general/disability_benefits_before_minimum_retirement_age.py b/policyengine_us/variables/household/income/person/general/disability_benefits_before_minimum_retirement_age.py new file mode 100644 index 00000000000..e2e6a98dcb6 --- /dev/null +++ b/policyengine_us/variables/household/income/person/general/disability_benefits_before_minimum_retirement_age.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class disability_benefits_before_minimum_retirement_age(Variable): + value_type = float + entity = Person + label = "disability benefits before minimum retirement age" + unit = USD + documentation = ( + "Taxable benefits received under an employer's disability retirement " + "plan before the plan's minimum retirement age, reported as wages on " + "Form 1040 line 1h. They are earned income until that age. Railroad " + "retirement benefits, including disability benefits, are not. " + "Defaults to zero." + ) + definition_period = YEAR + uprating = "calibration.gov.irs.soi.employment_income" + reference = ( + "https://www.irs.gov/pub/irs-prior/p596--2024.pdf#page=8", + "https://www.irs.gov/pub/irs-prior/p525--2024.pdf#page=18", + ) diff --git a/policyengine_us/variables/household/income/person/general/earned_disability_benefits.py b/policyengine_us/variables/household/income/person/general/earned_disability_benefits.py new file mode 100644 index 00000000000..b7d38df567c --- /dev/null +++ b/policyengine_us/variables/household/income/person/general/earned_disability_benefits.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class earned_disability_benefits(Variable): + value_type = float + entity = Person + label = "disability benefits counted as earned income" + unit = USD + documentation = ( + "Taxable disability benefits that count as earned income: those " + "received under an employer's disability retirement plan before the " + "plan's minimum retirement age, limited to the benefits included in " + "gross income." + ) + definition_period = YEAR + reference = ( + "https://www.irs.gov/pub/irs-prior/p596--2024.pdf#page=8", + "https://www.irs.gov/pub/irs-prior/i1040gi--2024.pdf#page=25", + ) + + def formula(person, period, parameters): + before_minimum_retirement_age = person( + "disability_benefits_before_minimum_retirement_age", period + ) + taxable_disability_benefits = person("taxable_disability_benefits", period) + return min_(max_(0, before_minimum_retirement_age), taxable_disability_benefits) From 7f59b6aa7fdd58b9cfbcf6b832dabd24f5a34627 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 03:51:01 -0400 Subject: [PATCH 08/13] Correct the reason NY's combined limit cannot bind Co-Authored-By: Claude Opus 5.5 --- .../adjusted_gross_income/ny_disability_income_exclusion.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py b/policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py index fa8bfafd78f..54ea002b96c 100644 --- a/policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py +++ b/policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py @@ -51,6 +51,7 @@ def formula(person, period, parameters): where=total_pay > 0, ) # IT-221 also limits each person's disability plus pension exclusion - # to $20,000. It cannot bind: both exclude only income in federal - # AGI, and this exclusion is gone once that AGI reaches $20,200. + # to $20,000. It cannot bind: excluded pensions are in federal AGI, + # and this exclusion falls dollar for dollar with federal AGI above + # $15,000, so the two together stay under $15,000. return exclusion * share From dd3caa3139664465d503fe1b8d7da92c466c436a Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 03:53:46 -0400 Subject: [PATCH 09/13] Test earned-income disability pensions and the WI, NY, IA and IN disability exclusions Cases from the 2024 dependent standard deduction worksheet, Pub. 596, Pub. 503, Schedule 2440W, IT-221 Example 5, IA 2440 and Indiana Bulletin 70. Co-Authored-By: Claude Opus 5.5 --- .../earned_income/eitc_earned_income.yaml | 23 +++ .../permanent_disability_retirement_pay.yaml | 34 +++++ .../standard/basic_standard_deduction.yaml | 25 +++ .../ia_disability_income_exclusion.yaml | 61 ++++++++ .../in_disability_retirement_deduction.yaml | 88 +++++++++++ .../ny_disability_income_exclusion.yaml | 106 +++++++++++++ .../wi_disability_income_exclusion.yaml | 144 ++++++++++++++++++ .../general/earned_disability_benefits.yaml | 28 ++++ 8 files changed, 509 insertions(+) create mode 100644 policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/ny_disability_income_exclusion.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.yaml create mode 100644 policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_earned_income.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_earned_income.yaml index 8d76a04159c..6f229c13fb7 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_earned_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_earned_income.yaml @@ -382,3 +382,26 @@ output: filer_adjusted_earnings: 8000 amt_exemption: 18200 + +- name: A disability pension before minimum retirement age is earned income for the EITC + # Pub. 596 (2024), file page 8: taxable benefits from an employer's + # disability retirement plan are earned income until minimum retirement age. + period: 2024 + input: + people: + head: + age: 40 + disability_benefits: 10_000 + disability_benefits_before_minimum_retirement_age: 10_000 + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: TX + output: + eitc_earned_income: 10_000 + # No qualifying children: 7.65% x $8,260 = $632, and the $10,000 of AGI + # is under the $10,330 phase-out threshold. + eitc: 632 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml new file mode 100644 index 00000000000..420232f177a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml @@ -0,0 +1,34 @@ +- name: Taxable disability benefits of someone retired on permanent and total disability. + period: 2024 + input: + retired_on_total_disability: true + disability_benefits: 8_000 + tax_exempt_disability_benefits: 3_000 + output: + permanent_disability_retirement_pay: 5_000 + +- name: Disability pay entered as total disability payments is not counted twice. + period: 2024 + input: + retired_on_total_disability: true + disability_benefits: 8_000 + total_disability_payments: 8_000 + output: + permanent_disability_retirement_pay: 8_000 + +- name: Disability pay paid as wages and entered as total disability payments. + period: 2024 + input: + retired_on_total_disability: true + employment_income: 6_000 + total_disability_payments: 6_000 + output: + permanent_disability_retirement_pay: 6_000 + +- name: Someone who did not retire on disability has none. + period: 2024 + input: + retired_on_total_disability: false + disability_benefits: 8_000 + output: + permanent_disability_retirement_pay: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/deductions/standard/basic_standard_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/irs/deductions/standard/basic_standard_deduction.yaml index 483f073599a..97fba3f6c2e 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/deductions/standard/basic_standard_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/deductions/standard/basic_standard_deduction.yaml @@ -207,3 +207,28 @@ members: [head] output: basic_standard_deduction: 3_650 + +- name: A dependent filer's disability pension before minimum retirement age counts as earned income + # 2024 Form 1040 instructions, Standard Deduction Worksheet for Dependents: + # earned income starts from line 1z, which includes disability pensions + # reported on line 1h. max($1,300, $10,000 + $450) = $10,450, under the + # $14,600 single amount. + period: 2024 + input: + people: + head: + age: 30 + claimed_as_dependent_on_another_return: true + disability_benefits: 10_000 + disability_benefits_before_minimum_retirement_age: 10_000 + tax_units: + tax_unit: + members: [head] + filing_status: SINGLE + households: + household: + members: [head] + output: + basic_standard_deduction: 10_450 + taxable_income: 0 + income_tax_before_credits: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.yaml new file mode 100644 index 00000000000..387b82edbf4 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.yaml @@ -0,0 +1,61 @@ +# 2024 IA 2440: each person's disability pay at most $100 a week ($5,200), +# less federal AGI above $15,000; Schedule 1 line 19b, code h. + +- name: Exclusion reduced by federal AGI above $15,000. + period: 2024 + input: + people: + person: + age: 50 + retired_on_total_disability: true + disability_benefits: 10_000 + taxable_interest_income: 7_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: IA + output: + # Line 3: min(10,000, 5,200) = 5,200. Line 4c: 17,000 - 15,000 = 2,000. + ia_disability_income_exclusion: 3_200 + ia_subtractions_consolidated: 3_200 + +- name: A married person filing separately who lived with their spouse cannot take the exclusion. + period: 2024 + input: + people: + person: + age: 50 + retired_on_total_disability: true + disability_benefits: 5_000 + tax_units: + tax_unit: + members: [person] + filing_status: SEPARATE + cohabitating_spouses: true + households: + household: + members: [person] + state_code: IA + output: + ia_disability_income_exclusion: 0 + +- name: No exclusion at age 65. + period: 2024 + input: + people: + person: + age: 65 + retired_on_total_disability: true + disability_benefits: 5_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: IA + output: + ia_disability_income_exclusion: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.yaml new file mode 100644 index 00000000000..9bea1cf8339 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.yaml @@ -0,0 +1,88 @@ +# Indiana Income Tax Information Bulletin 70: disability pay at most $100 a +# week, less federal AGI above $15,000 ($7,500 married filing separately). + +- name: Deduction reduced by federal AGI above $15,000, with no age limit. + period: 2024 + input: + people: + person: + age: 67 + retired_on_total_disability: true + disability_benefits: 10_000 + taxable_interest_income: 8_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: IN + output: + # min(10,000, 5,200) - (18,000 - 15,000) = 2,200. + in_disability_retirement_deduction: 2_200 + +- name: Married filing separately uses a $7,500 threshold. + period: 2024 + input: + people: + person: + age: 50 + retired_on_total_disability: true + disability_benefits: 6_000 + taxable_interest_income: 3_000 + tax_units: + tax_unit: + members: [person] + filing_status: SEPARATE + households: + household: + members: [person] + state_code: IN + output: + # min(6,000, 5,200) - (9,000 - 7,500) = 3,700. + in_disability_retirement_deduction: 3_700 + +- name: Each spouse's deduction is reduced by the joint federal AGI above $15,000. + period: 2024 + input: + people: + head: + age: 60 + is_tax_unit_head: true + retired_on_total_disability: true + disability_benefits: 6_000 + spouse: + age: 58 + is_tax_unit_spouse: true + retired_on_total_disability: true + disability_benefits: 4_000 + taxable_interest_income: 6_000 + tax_units: + tax_unit: + members: [head, spouse] + households: + household: + members: [head, spouse] + state_code: IN + output: + # Federal AGI 16,000, 1,000 over $15,000. + # (5,200 - 1,000) + (4,000 - 1,000) = 7,200. + in_disability_retirement_deduction: 7_200 + +- name: No deduction without retirement on permanent and total disability. + period: 2024 + input: + people: + person: + age: 50 + retired_on_total_disability: false + disability_benefits: 5_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: IN + output: + in_disability_retirement_deduction: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/ny_disability_income_exclusion.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/ny_disability_income_exclusion.yaml new file mode 100644 index 00000000000..570a97f9399 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/ny_disability_income_exclusion.yaml @@ -0,0 +1,106 @@ +# 2024 Instructions for Form IT-221. + +- name: IT-221 Example 5, spouses share the exclusion in proportion to their disability pay. + period: 2024 + input: + people: + head: + age: 60 + is_tax_unit_head: true + retired_on_total_disability: true + disability_benefits: 6_000 + spouse: + age: 58 + is_tax_unit_spouse: true + retired_on_total_disability: true + disability_benefits: 4_000 + tax_units: + tax_unit: + members: [head, spouse] + households: + household: + members: [head, spouse] + state_code: NY + output: + # Line 10: min(6,000, 5,200) + min(4,000, 5,200) = 9,200, with federal + # AGI of 10,000 under $15,000. Line 11: 6,000 / 10,000 x 9,200 = 5,520 + # and 4,000 / 10,000 x 9,200 = 3,680. + ny_disability_income_exclusion: [5_520, 3_680] + +- name: Exclusion reduced by federal AGI above $15,000. + period: 2024 + input: + people: + person: + age: 50 + retired_on_total_disability: true + disability_benefits: 10_000 + taxable_interest_income: 7_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: NY + output: + # 5,200 - (17,000 - 15,000) = 3,200. + ny_disability_income_exclusion: 3_200 + +- name: A married person filing separately who lived with their spouse cannot take the exclusion. + period: 2024 + input: + people: + person: + age: 50 + retired_on_total_disability: true + disability_benefits: 5_000 + tax_units: + tax_unit: + members: [person] + filing_status: SEPARATE + cohabitating_spouses: true + households: + household: + members: [person] + state_code: NY + output: + ny_disability_income_exclusion: 0 + +- name: A married person filing separately who lived apart all year can take the exclusion. + period: 2024 + input: + people: + person: + age: 50 + retired_on_total_disability: true + disability_benefits: 5_000 + tax_units: + tax_unit: + members: [person] + filing_status: SEPARATE + cohabitating_spouses: false + households: + household: + members: [person] + state_code: NY + output: + ny_disability_income_exclusion: 5_000 + +- name: No exclusion at age 65. + period: 2024 + input: + people: + person: + age: 65 + retired_on_total_disability: true + disability_benefits: 5_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: NY + output: + ny_disability_income_exclusion: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.yaml new file mode 100644 index 00000000000..2d3b2ce6cc4 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.yaml @@ -0,0 +1,144 @@ +# 2024 Schedule 2440W: each person's disability pay at most $100 a week +# ($5,200 a year), less Form 1 line 3 income above $15,000. + +- name: Full exclusion for a retiree under 65 with $15,000 of income. + period: 2024 + input: + people: + person: + age: 45 + retired_on_total_disability: true + disability_benefits: 5_000 + taxable_interest_income: 10_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: WI + output: + adjusted_gross_income: 15_000 + # Line 4: min(5,000, 5,200) = 5,000. Line 5c: 15,000 - 15,000 = 0. + wi_disability_income_exclusion: 5_000 + wi_agi: 10_000 + +- name: Exclusion reduced by income above $15,000. + period: 2024 + input: + people: + person: + age: 50 + retired_on_total_disability: true + disability_benefits: 8_000 + taxable_interest_income: 10_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: WI + output: + # Line 4: min(8,000, 5,200) = 5,200. Line 5c: 18,000 - 15,000 = 3,000. + wi_disability_income_exclusion: 2_200 + +- name: Both spouses take the exclusion on a joint return. + period: 2024 + input: + people: + head: + age: 60 + is_tax_unit_head: true + retired_on_total_disability: true + disability_benefits: 6_000 + spouse: + age: 58 + is_tax_unit_spouse: true + retired_on_total_disability: true + disability_benefits: 4_000 + taxable_interest_income: 12_000 + tax_units: + tax_unit: + members: [head, spouse] + households: + household: + members: [head, spouse] + state_code: WI + output: + # Line 3: 5,200 + 4,000 = 9,200. Line 5c: 22,000 - 15,000 = 7,000. + wi_disability_income_exclusion: 2_200 + +- name: No exclusion at age 65. + period: 2024 + input: + people: + person: + age: 65 + retired_on_total_disability: true + disability_benefits: 5_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: WI + output: + wi_disability_income_exclusion: 0 + +- name: No exclusion without retirement on permanent and total disability. + period: 2024 + input: + people: + person: + age: 45 + retired_on_total_disability: false + disability_benefits: 5_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: WI + output: + wi_disability_income_exclusion: 0 + +- name: A married person filing separately cannot take the exclusion. + period: 2024 + input: + people: + person: + age: 45 + retired_on_total_disability: true + disability_benefits: 5_000 + tax_units: + tax_unit: + members: [person] + filing_status: SEPARATE + households: + household: + members: [person] + state_code: WI + output: + wi_disability_income_exclusion: 0 + +- name: Disability benefits from insurance the retiree paid for are not in federal AGI. + period: 2024 + input: + people: + person: + age: 45 + retired_on_total_disability: true + disability_benefits: 5_000 + tax_exempt_disability_benefits: 5_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: WI + output: + wi_disability_income_exclusion: 0 diff --git a/policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml b/policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml new file mode 100644 index 00000000000..7e0eda7d1ab --- /dev/null +++ b/policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml @@ -0,0 +1,28 @@ +- name: Only the taxable part of disability benefits can be earned income. + period: 2024 + input: + disability_benefits: 10_000 + # Benefits bought with the person's own after-tax premiums are not in + # gross income, so they cannot be earned income either. + tax_exempt_disability_benefits: 4_000 + disability_benefits_before_minimum_retirement_age: 10_000 + output: + taxable_disability_benefits: 6_000 + earned_disability_benefits: 6_000 + +- name: Disability benefits after minimum retirement age are not earned income. + period: 2024 + input: + disability_benefits: 10_000 + disability_benefits_before_minimum_retirement_age: 0 + output: + earned_disability_benefits: 0 + +- name: Disability pay reported as wages is earned income for the child and dependent care credit. + # Pub. 503 (2024), file page 4. + period: 2024 + input: + disability_benefits: 12_000 + disability_benefits_before_minimum_retirement_age: 12_000 + output: + adjusted_earnings: 12_000 From 3990a89ba182dc46494122f3b5a45d67c52dac1c Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 03:55:08 -0400 Subject: [PATCH 10/13] Update the changelog fragment Co-Authored-By: Claude Opus 5.5 --- changelog.d/fix-disability-benefits-gross-income.fixed.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/fix-disability-benefits-gross-income.fixed.md b/changelog.d/fix-disability-benefits-gross-income.fixed.md index 828a9c1eb1e..d89df774f0b 100644 --- a/changelog.d/fix-disability-benefits-gross-income.fixed.md +++ b/changelog.d/fix-disability-benefits-gross-income.fixed.md @@ -1 +1 @@ -Count the taxable part of employment disability benefits in federal gross income (IRC 105(a)), with a new tax_exempt_disability_benefits input for benefits from plans the recipient paid for (IRC 104(a)(3)), and limit state disability subtractions to the taxable part. +Count the taxable part of employment disability benefits in federal gross income (IRC 105(a)), with a new tax_exempt_disability_benefits input for benefits from plans the recipient paid for (IRC 104(a)(3)); count disability pensions received before minimum retirement age as earned income when entered; limit state disability subtractions to the taxable part; exclude disability benefits from Pennsylvania taxable compensation; and add the Wisconsin, New York, Iowa and Indiana disability income exclusions for people retired on permanent and total disability. From 6ec85c180a9ff958942f8c04b5e80e8ca5e68740 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 04:35:48 -0400 Subject: [PATCH 11/13] Address review: qualifying disability income input, married filers, NY limit, IRA and filing earned income - permanent_disability_retirement_pay reads the explicit total_disability_payments input (payments from a plan providing for disability retirement), limited to wages and taxable disability benefits in federal AGI. - WI and IA treat a separated spouse filing as head of household as married. - Restore New York's ,000 combined disability and pension limit, which binds when above-the-line deductions keep AGI low. - Disability pay treated as wages counts as IRA compensation and as earned income in the filing requirement's unearned-income test. Co-Authored-By: Claude Opus 5.5 --- .../combined_limit.yaml | 10 ++++ .../permanent_disability_retirement_pay.yaml | 22 +++++-- .../gov/irs/tax_unit_is_required_to_file.yaml | 19 +++++++ .../ia_disability_income_exclusion.yaml | 28 +++++++++ .../in_disability_retirement_deduction.yaml | 5 ++ .../ny_disability_income_exclusion.yaml | 34 +++++++++++ .../wi_disability_income_exclusion.yaml | 57 +++++++++++++++++++ .../general/earned_disability_benefits.yaml | 10 ++++ .../permanent_disability_retirement_pay.py | 29 ++++++---- .../gov/irs/tax_unit_is_required_to_file.py | 3 + .../ia_disability_income_exclusion.py | 17 ++++-- .../ny_disability_income_exclusion.py | 10 ++-- .../wi_disability_income_exclusion.py | 22 ++++--- .../expense/retirement/ira_compensation.py | 7 ++- 14 files changed, 239 insertions(+), 34 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/combined_limit.yaml diff --git a/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/combined_limit.yaml b/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/combined_limit.yaml new file mode 100644 index 00000000000..8f88f900781 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/tax/income/agi/subtractions/disability_income_exclusion/combined_limit.yaml @@ -0,0 +1,10 @@ +description: New York limits each person's disability income exclusion plus pension and annuity income exclusion to this amount. +values: + 2020-01-01: 20_000 +metadata: + unit: currency-USD + period: year + label: New York disability and pension exclusion combined limit + reference: + - title: "2024 Instructions for Form IT-221, Purpose of Form IT-221 and line 11 #page 1-2" + href: https://www.tax.ny.gov/pdf/2024/inc/it221i_2024.pdf#page=1 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml index 420232f177a..c46da23bef3 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml @@ -1,22 +1,22 @@ -- name: Taxable disability benefits of someone retired on permanent and total disability. +- name: Disability income of someone retired on permanent and total disability. period: 2024 input: retired_on_total_disability: true disability_benefits: 8_000 tax_exempt_disability_benefits: 3_000 + total_disability_payments: 5_000 output: permanent_disability_retirement_pay: 5_000 -- name: Disability pay entered as total disability payments is not counted twice. +- name: Disability benefits alone do not show the plan provides for disability retirement. period: 2024 input: retired_on_total_disability: true disability_benefits: 8_000 - total_disability_payments: 8_000 output: - permanent_disability_retirement_pay: 8_000 + permanent_disability_retirement_pay: 0 -- name: Disability pay paid as wages and entered as total disability payments. +- name: Disability pay paid as wages. period: 2024 input: retired_on_total_disability: true @@ -25,10 +25,22 @@ output: permanent_disability_retirement_pay: 6_000 +- name: Limited to disability pay included in federal AGI. + period: 2024 + input: + retired_on_total_disability: true + disability_benefits: 9_000 + tax_exempt_disability_benefits: 5_000 + total_disability_payments: 9_000 + output: + # Only 9,000 - 5,000 = 4,000 is in federal AGI. + permanent_disability_retirement_pay: 4_000 + - name: Someone who did not retire on disability has none. period: 2024 input: retired_on_total_disability: false disability_benefits: 8_000 + total_disability_payments: 8_000 output: permanent_disability_retirement_pay: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/tax_unit_is_required_to_file.yaml b/policyengine_us/tests/policy/baseline/gov/irs/tax_unit_is_required_to_file.yaml index 839bb09c946..fa7392212a6 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/tax_unit_is_required_to_file.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/tax_unit_is_required_to_file.yaml @@ -118,3 +118,22 @@ output: # $10,000 of gross income, under $15,750, and none of it is unearned. tax_unit_is_required_to_file: false + +- name: Disability pay treated as wages is earned income for the filing requirement + period: 2024 + input: + people: + head: + age: 40 + disability_benefits: 10_000 + disability_benefits_before_minimum_retirement_age: 10_000 + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + output: + # $10,000 of gross income, all earned, under the $14,600 single + # threshold, so no unearned income over the (a)(1)(C) amount either. + tax_unit_is_required_to_file: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.yaml b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.yaml index 387b82edbf4..40ebe61ba94 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.yaml @@ -9,6 +9,7 @@ age: 50 retired_on_total_disability: true disability_benefits: 10_000 + total_disability_payments: 10_000 taxable_interest_income: 7_000 tax_units: tax_unit: @@ -30,6 +31,7 @@ age: 50 retired_on_total_disability: true disability_benefits: 5_000 + total_disability_payments: 5_000 tax_units: tax_unit: members: [person] @@ -50,6 +52,7 @@ age: 65 retired_on_total_disability: true disability_benefits: 5_000 + total_disability_payments: 5_000 tax_units: tax_unit: members: [person] @@ -59,3 +62,28 @@ state_code: IA output: ia_disability_income_exclusion: 0 + +- name: A separated spouse filing as head of household who lived with their spouse cannot take the exclusion. + period: 2024 + input: + people: + head: + age: 45 + is_separated: true + retired_on_total_disability: true + disability_benefits: 5_000 + total_disability_payments: 5_000 + child: + age: 10 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [head, child] + cohabitating_spouses: true + households: + household: + members: [head, child] + state_code: IA + output: + filing_status: HEAD_OF_HOUSEHOLD + ia_disability_income_exclusion: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.yaml index 9bea1cf8339..6eb47e74f7e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.yaml @@ -9,6 +9,7 @@ age: 67 retired_on_total_disability: true disability_benefits: 10_000 + total_disability_payments: 10_000 taxable_interest_income: 8_000 tax_units: tax_unit: @@ -29,6 +30,7 @@ age: 50 retired_on_total_disability: true disability_benefits: 6_000 + total_disability_payments: 6_000 taxable_interest_income: 3_000 tax_units: tax_unit: @@ -51,11 +53,13 @@ is_tax_unit_head: true retired_on_total_disability: true disability_benefits: 6_000 + total_disability_payments: 6_000 spouse: age: 58 is_tax_unit_spouse: true retired_on_total_disability: true disability_benefits: 4_000 + total_disability_payments: 4_000 taxable_interest_income: 6_000 tax_units: tax_unit: @@ -77,6 +81,7 @@ age: 50 retired_on_total_disability: false disability_benefits: 5_000 + total_disability_payments: 5_000 tax_units: tax_unit: members: [person] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/ny_disability_income_exclusion.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/ny_disability_income_exclusion.yaml index 570a97f9399..fb7de164e4b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/ny_disability_income_exclusion.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/ny_disability_income_exclusion.yaml @@ -9,11 +9,13 @@ is_tax_unit_head: true retired_on_total_disability: true disability_benefits: 6_000 + total_disability_payments: 6_000 spouse: age: 58 is_tax_unit_spouse: true retired_on_total_disability: true disability_benefits: 4_000 + total_disability_payments: 4_000 tax_units: tax_unit: members: [head, spouse] @@ -35,6 +37,7 @@ age: 50 retired_on_total_disability: true disability_benefits: 10_000 + total_disability_payments: 10_000 taxable_interest_income: 7_000 tax_units: tax_unit: @@ -55,6 +58,7 @@ age: 50 retired_on_total_disability: true disability_benefits: 5_000 + total_disability_payments: 5_000 tax_units: tax_unit: members: [person] @@ -75,6 +79,7 @@ age: 50 retired_on_total_disability: true disability_benefits: 5_000 + total_disability_payments: 5_000 tax_units: tax_unit: members: [person] @@ -95,6 +100,7 @@ age: 65 retired_on_total_disability: true disability_benefits: 5_000 + total_disability_payments: 5_000 tax_units: tax_unit: members: [person] @@ -104,3 +110,31 @@ state_code: NY output: ny_disability_income_exclusion: 0 + +- name: The disability and pension exclusions together are limited to $20,000. + period: 2024 + input: + people: + person: + age: 60 + retired_on_total_disability: true + disability_benefits: 5_000 + total_disability_payments: 5_000 + taxable_private_pension_income: 20_000 + # Deductible alimony under a pre-2019 instrument keeps federal AGI low. + alimony_expense: 15_000 + divorce_year: 2015 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: NY + output: + # Federal AGI: 25,000 - 15,000 = 10,000, so line 10 is min(5,000, 5,200) + # = 5,000 with no reduction. The pension exclusion already uses the + # whole $20,000, leaving nothing for the disability exclusion. + adjusted_gross_income: 10_000 + ny_pension_exclusion: 20_000 + ny_disability_income_exclusion: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.yaml index 2d3b2ce6cc4..7c78c9427ba 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.yaml @@ -9,6 +9,7 @@ age: 45 retired_on_total_disability: true disability_benefits: 5_000 + total_disability_payments: 5_000 taxable_interest_income: 10_000 tax_units: tax_unit: @@ -31,6 +32,7 @@ age: 50 retired_on_total_disability: true disability_benefits: 8_000 + total_disability_payments: 8_000 taxable_interest_income: 10_000 tax_units: tax_unit: @@ -52,11 +54,13 @@ is_tax_unit_head: true retired_on_total_disability: true disability_benefits: 6_000 + total_disability_payments: 6_000 spouse: age: 58 is_tax_unit_spouse: true retired_on_total_disability: true disability_benefits: 4_000 + total_disability_payments: 4_000 taxable_interest_income: 12_000 tax_units: tax_unit: @@ -77,6 +81,7 @@ age: 65 retired_on_total_disability: true disability_benefits: 5_000 + total_disability_payments: 5_000 tax_units: tax_unit: members: [person] @@ -95,6 +100,7 @@ age: 45 retired_on_total_disability: false disability_benefits: 5_000 + total_disability_payments: 5_000 tax_units: tax_unit: members: [person] @@ -113,6 +119,7 @@ age: 45 retired_on_total_disability: true disability_benefits: 5_000 + total_disability_payments: 5_000 tax_units: tax_unit: members: [person] @@ -132,6 +139,7 @@ age: 45 retired_on_total_disability: true disability_benefits: 5_000 + total_disability_payments: 5_000 tax_exempt_disability_benefits: 5_000 tax_units: tax_unit: @@ -142,3 +150,52 @@ state_code: WI output: wi_disability_income_exclusion: 0 + +- name: A separated spouse filing as head of household is still married and cannot take the exclusion. + period: 2024 + input: + people: + head: + age: 45 + is_separated: true + retired_on_total_disability: true + disability_benefits: 5_000 + total_disability_payments: 5_000 + taxable_interest_income: 10_000 + child: + age: 10 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [head, child] + households: + household: + members: [head, child] + state_code: WI + output: + filing_status: HEAD_OF_HOUSEHOLD + wi_disability_income_exclusion: 0 + +- name: An unmarried head of household can take the exclusion. + period: 2024 + input: + people: + head: + age: 45 + retired_on_total_disability: true + disability_benefits: 5_000 + total_disability_payments: 5_000 + taxable_interest_income: 10_000 + child: + age: 10 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [head, child] + households: + household: + members: [head, child] + state_code: WI + output: + filing_status: HEAD_OF_HOUSEHOLD + wi_disability_income_exclusion: 5_000 diff --git a/policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml b/policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml index 7e0eda7d1ab..d6e6d35bd1b 100644 --- a/policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml +++ b/policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml @@ -26,3 +26,13 @@ disability_benefits_before_minimum_retirement_age: 12_000 output: adjusted_earnings: 12_000 + +- name: Disability pay treated as wages is compensation for IRA contributions. + # Pub. 4491 (Rev. 10-2025), file page 144. + period: 2024 + input: + age: 40 + disability_benefits: 20_000 + disability_benefits_before_minimum_retirement_age: 20_000 + output: + ira_compensation: 20_000 diff --git a/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py index be52f132dd7..7bdd0e398ea 100644 --- a/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py +++ b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py @@ -7,13 +7,16 @@ class permanent_disability_retirement_pay(Variable): label = "permanent disability retirement pay" unit = USD documentation = ( - "Disability pay included in federal adjusted gross income of a person " - "who retired on disability and was permanently and totally disabled " - "when they retired: wages or payments in lieu of wages from an " - "employer's accident or health plan or pension plan. The larger of " - "total_disability_payments and taxable_disability_benefits, so the " - "same payments are not counted twice. State disability income " - "exclusions modelled on former IRC 105(d) apply to it." + "Disability income included in federal adjusted gross income of a " + "person who retired on disability and was permanently and totally " + "disabled when they retired: total_disability_payments, the wages or " + "payments in lieu of wages from an employer's accident or health plan " + "or pension plan that provides for disability retirement. Payments " + "from a plan without disability retirement are not disability income, " + "so taxable_disability_benefits alone does not qualify. Limited to the " + "wages and taxable disability benefits in federal AGI. State " + "disability income exclusions modelled on former IRC 105(d) apply to " + "it." ) definition_period = YEAR reference = ( @@ -23,8 +26,12 @@ class permanent_disability_retirement_pay(Variable): def formula(person, period, parameters): retired_on_total_disability = person("retired_on_total_disability", period) - disability_pay = max_( - person("total_disability_payments", period), - person("taxable_disability_benefits", period), + disability_income = person("total_disability_payments", period) + # Line 1 of the state schedules: disability pay included in federal + # AGI, reported as wages or as taxable disability benefits. + included_in_agi = add( + person, period, ["irs_employment_income", "taxable_disability_benefits"] + ) + return retired_on_total_disability * max_( + 0, min_(disability_income, included_in_agi) ) - return retired_on_total_disability * disability_pay diff --git a/policyengine_us/variables/gov/irs/tax_unit_is_required_to_file.py b/policyengine_us/variables/gov/irs/tax_unit_is_required_to_file.py index 620cf3409ff..2657e18f2e9 100644 --- a/policyengine_us/variables/gov/irs/tax_unit_is_required_to_file.py +++ b/policyengine_us/variables/gov/irs/tax_unit_is_required_to_file.py @@ -55,9 +55,12 @@ def formula(tax_unit, period, parameters): "additional_standard_deduction", period ) # The section 911 exclusion covers earned income only. + # Disability pensions reported as wages before minimum retirement + # age are earned income. unearned_income = ( gross_income - add(tax_unit, period, ["earned_income"]) + - tax_unit_non_dep_sum("earned_disability_benefits", tax_unit, period) - section_911_exclusion ) unearned_income_over_threshold = unearned_income > unearned_income_threshold diff --git a/policyengine_us/variables/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.py b/policyengine_us/variables/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.py index 505d7600fdb..e9b5b7b91dc 100644 --- a/policyengine_us/variables/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.py +++ b/policyengine_us/variables/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.py @@ -32,9 +32,18 @@ def formula(tax_unit, period, parameters): # Line 4: reduced dollar for dollar by federal AGI above $15,000. agi = tax_unit("adjusted_gross_income", period) exclusion = max_(0, excludable - max_(0, agi - p.reduction_threshold)) - # A married person must file jointly unless the spouses did not live - # together at any time during the year. + # A person married at the end of the year must file jointly unless + # the spouses did not live together at any time during the year. + # That covers a separate return and a head of household return by a + # spouse who is separated but still married. filing_status = tax_unit("filing_status", period) - separate = filing_status == filing_status.possible_values.SEPARATE + status = filing_status.possible_values + separated = tax_unit.any( + person("is_tax_unit_head_or_spouse", period) + & person("is_separated", period) + ) + married_not_joint = (filing_status == status.SEPARATE) | ( + (filing_status != status.JOINT) & separated + ) lived_together = tax_unit("cohabitating_spouses", period) - return where(separate & lived_together, 0, exclusion) + return where(married_not_joint & lived_together, 0, exclusion) diff --git a/policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py b/policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py index 54ea002b96c..fbad7a5fead 100644 --- a/policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py +++ b/policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py @@ -50,8 +50,8 @@ def formula(person, period, parameters): out=np.zeros_like(total_pay), where=total_pay > 0, ) - # IT-221 also limits each person's disability plus pension exclusion - # to $20,000. It cannot bind: excluded pensions are in federal AGI, - # and this exclusion falls dollar for dollar with federal AGI above - # $15,000, so the two together stay under $15,000. - return exclusion * share + # Each person's disability and pension exclusions together are + # limited to $20,000; an unused part of a spouse's limit can't be used. + pension_exclusion = person("ny_pension_exclusion", period) + room = max_(0, p.combined_limit - pension_exclusion) + return min_(exclusion * share, room) diff --git a/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.py b/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.py index 8375449057e..690a8af86ac 100644 --- a/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.py +++ b/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.py @@ -12,11 +12,8 @@ class wi_disability_income_exclusion(Variable): "total disability. The weekly $100 limit is applied as an annual cap; " "the employer's mandatory retirement age is not modelled." ) - reference = ( - "https://www.revenue.wi.gov/TaxForms2024/2024-Schedule2440Wf.pdf#page=1", - "https://www.revenue.wi.gov/TaxForms2024/2024-Schedule2440Wf.pdf#page=2", - "https://www.revenue.wi.gov/TaxForms2024/2024-Schedule2440Wf.pdf#page=3", - ) + # PDF pages 1-3 + reference = "https://www.revenue.wi.gov/TaxForms2024/2024-Schedule2440Wf.pdf#page=1" defined_for = StateCode.WI def formula(tax_unit, period, parameters): @@ -32,7 +29,16 @@ def formula(tax_unit, period, parameters): agi = tax_unit("adjusted_gross_income", period) reduction = max_(0, agi - p.reduction_threshold) exclusion = max_(0, excludable - reduction) - # A married claimant must file a joint return. + # A claimant married at the end of the year must file a joint + # return: no separate return, and no head of household return by a + # spouse who is separated but still married. filing_status = tax_unit("filing_status", period) - separate = filing_status == filing_status.possible_values.SEPARATE - return where(separate, 0, exclusion) + status = filing_status.possible_values + separated = tax_unit.any( + person("is_tax_unit_head_or_spouse", period) + & person("is_separated", period) + ) + married_not_joint = (filing_status == status.SEPARATE) | ( + (filing_status != status.JOINT) & separated + ) + return where(married_not_joint, 0, exclusion) diff --git a/policyengine_us/variables/household/expense/retirement/ira_compensation.py b/policyengine_us/variables/household/expense/retirement/ira_compensation.py index a9eeff746ee..469328f4c56 100644 --- a/policyengine_us/variables/household/expense/retirement/ira_compensation.py +++ b/policyengine_us/variables/household/expense/retirement/ira_compensation.py @@ -16,10 +16,15 @@ class ira_compensation(Variable): "https://www.law.cornell.edu/uscode/text/26/219#f_1", "https://www.law.cornell.edu/uscode/text/26/401#c_2", "https://www.irs.gov/publications/p590a", + "https://www.irs.gov/pub/irs-pdf/p4491.pdf#page=144", ) def formula(person, period, parameters): - wages = person("irs_employment_income", period) + # Disability pay treated as wages before minimum retirement age is + # compensation (Pub. 4491 (Rev. 10-2025), file page 144). + wages = add( + person, period, ["irs_employment_income", "earned_disability_benefits"] + ) alimony = person("taxable_alimony_income", period) self_employment_earnings = ( add( From 9f2b50f12c62db83789f4427b0e1a95e363c0d1e Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 04:56:33 -0400 Subject: [PATCH 12/13] Define total_disability_payments as the taxable amount; count earned disability pay in Medicaid's filer test - total_disability_payments documents IRC 22(c)(2)(B)(iii): the taxable part of qualifying disability pay. permanent_disability_retirement_pay keeps the wages-plus-taxable-benefits limit only as a consistency check. - medicaid_person_is_required_to_file counts earned_disability_benefits as earned income. Co-Authored-By: Claude Opus 5.5 --- .../medicaid_person_is_required_to_file.yaml | 26 +++++++++++++++++++ .../permanent_disability_retirement_pay.yaml | 19 +++++++++++--- .../medicaid_person_is_required_to_file.py | 6 ++++- .../permanent_disability_retirement_pay.py | 23 ++++++++-------- .../total_disability_payments.py | 10 ++++++- 5 files changed, 67 insertions(+), 17 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/income/medicaid_person_is_required_to_file.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/income/medicaid_person_is_required_to_file.yaml index 045350b9415..ca98cb69e11 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/income/medicaid_person_is_required_to_file.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/income/medicaid_person_is_required_to_file.yaml @@ -107,3 +107,29 @@ members: [person1] output: medicaid_person_is_required_to_file: false + +- name: A dependent's disability pension before minimum retirement age is earned income for the filing threshold. + period: 2024 + input: + people: + parent: + age: 50 + is_tax_unit_head: true + employment_income: 25_000 + child: + age: 20 + is_tax_unit_dependent: true + disability_benefits: 10_000 + disability_benefits_before_minimum_retirement_age: 10_000 + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + output: + # Earned income 10,000 and no unearned income. Dependent standard + # deduction: max(1,300, 10,000 + 450) = 10,450, so gross income of + # 10,000 is under it and the dependent need not file. The parent's + # 25,000 of wages is over the 14,600 single amount. + medicaid_person_is_required_to_file: [true, false] diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml index c46da23bef3..729660f7871 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml @@ -25,17 +25,30 @@ output: permanent_disability_retirement_pay: 6_000 -- name: Limited to disability pay included in federal AGI. +- name: Only the taxable part of qualifying payments is disability income, whatever other wages there are. period: 2024 input: retired_on_total_disability: true + # Qualifying payments of 9,000, of which 5,000 came from premiums the + # retiree paid; only the 4,000 included in gross income is entered. disability_benefits: 9_000 tax_exempt_disability_benefits: 5_000 - total_disability_payments: 9_000 + total_disability_payments: 4_000 + # Unrelated wages. + employment_income: 1_000 output: - # Only 9,000 - 5,000 = 4,000 is in federal AGI. permanent_disability_retirement_pay: 4_000 +- name: Disability income entered without matching income in federal AGI is not counted. + period: 2024 + input: + retired_on_total_disability: true + disability_benefits: 6_000 + tax_exempt_disability_benefits: 6_000 + total_disability_payments: 6_000 + output: + permanent_disability_retirement_pay: 0 + - name: Someone who did not retire on disability has none. period: 2024 input: diff --git a/policyengine_us/variables/gov/hhs/medicaid/income/medicaid_person_is_required_to_file.py b/policyengine_us/variables/gov/hhs/medicaid/income/medicaid_person_is_required_to_file.py index d03c904be47..ce18b9d073d 100644 --- a/policyengine_us/variables/gov/hhs/medicaid/income/medicaid_person_is_required_to_file.py +++ b/policyengine_us/variables/gov/hhs/medicaid/income/medicaid_person_is_required_to_file.py @@ -18,7 +18,11 @@ def formula(person, period, parameters): standard = parameters(period).gov.irs.deductions.standard filing_requirement = parameters(period).gov.irs.income.filing_requirement gross_income = person("medicaid_irs_gross_income", period) - earned_income = person("earned_income", period) + # Disability pensions reported as wages before minimum retirement + # age are earned income. + earned_income = add( + person, period, ["earned_income", "earned_disability_benefits"] + ) unearned_income = gross_income - earned_income married = person.marital_unit.nb_persons() == 2 diff --git a/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py index 7bdd0e398ea..338f5e7273c 100644 --- a/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py +++ b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py @@ -7,16 +7,14 @@ class permanent_disability_retirement_pay(Variable): label = "permanent disability retirement pay" unit = USD documentation = ( - "Disability income included in federal adjusted gross income of a " - "person who retired on disability and was permanently and totally " - "disabled when they retired: total_disability_payments, the wages or " - "payments in lieu of wages from an employer's accident or health plan " - "or pension plan that provides for disability retirement. Payments " - "from a plan without disability retirement are not disability income, " - "so taxable_disability_benefits alone does not qualify. Limited to the " - "wages and taxable disability benefits in federal AGI. State " - "disability income exclusions modelled on former IRC 105(d) apply to " - "it." + "Disability income of a person who retired on disability and was " + "permanently and totally disabled when they retired: " + "total_disability_payments, the taxable wages or payments in lieu of " + "wages from an employer's plan that provides for disability " + "retirement. Payments from a plan without disability retirement are " + "not disability income, so taxable_disability_benefits alone does not " + "qualify. State disability income exclusions modelled on former IRC " + "105(d) apply to it." ) definition_period = YEAR reference = ( @@ -27,8 +25,9 @@ class permanent_disability_retirement_pay(Variable): def formula(person, period, parameters): retired_on_total_disability = person("retired_on_total_disability", period) disability_income = person("total_disability_payments", period) - # Line 1 of the state schedules: disability pay included in federal - # AGI, reported as wages or as taxable disability benefits. + # total_disability_payments is already the taxable amount; as a + # consistency check it cannot exceed the wages and taxable + # disability benefits it is reported in. included_in_agi = add( person, period, ["irs_employment_income", "taxable_disability_benefits"] ) diff --git a/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/total_disability_payments.py b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/total_disability_payments.py index a707d7f77c3..9d031f83e0a 100644 --- a/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/total_disability_payments.py +++ b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/total_disability_payments.py @@ -6,5 +6,13 @@ class total_disability_payments(Variable): entity = Person label = "Disability (total) payments" unit = USD - documentation = "Wages (or payments in lieu thereof) paid to an individual for permanent and total disability" + documentation = ( + "Disability income under IRC 22(c)(2)(B)(iii): wages or payments in lieu " + "of wages for a period of absence from work due to permanent and total " + "disability, from an employer's accident or health plan or pension plan " + "that provides for disability retirement, to the extent included in " + "gross income. Enter only the taxable part; it is also counted in " + "employment_income or taxable_disability_benefits." + ) + reference = "https://www.law.cornell.edu/uscode/text/26/22#c_2_B_iii" definition_period = YEAR From 2c76dd1df137eaba5453969b91ac51a9d6066685 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 04:59:52 -0400 Subject: [PATCH 13/13] Count earned disability pay in filer_adjusted_earnings Feeds the kiddie-tax AMT exemption and the federal-style IN, OK and WA credits. Co-Authored-By: Claude Opus 5.5 --- .../general/earned_disability_benefits.yaml | 17 +++++++++++++++++ .../gov/irs/income/filer_adjusted_earnings.py | 7 ++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml b/policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml index d6e6d35bd1b..845d1ce9d8f 100644 --- a/policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml +++ b/policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml @@ -36,3 +36,20 @@ disability_benefits_before_minimum_retirement_age: 20_000 output: ira_compensation: 20_000 + +- name: Disability pay treated as wages is filer earned income for federal-style credits. + period: 2024 + input: + people: + head: + age: 40 + disability_benefits: 10_000 + disability_benefits_before_minimum_retirement_age: 10_000 + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + output: + filer_adjusted_earnings: 10_000 diff --git a/policyengine_us/variables/gov/irs/income/filer_adjusted_earnings.py b/policyengine_us/variables/gov/irs/income/filer_adjusted_earnings.py index a64258b8386..151efa82ee1 100644 --- a/policyengine_us/variables/gov/irs/income/filer_adjusted_earnings.py +++ b/policyengine_us/variables/gov/irs/income/filer_adjusted_earnings.py @@ -28,8 +28,9 @@ def formula(tax_unit, period, parameters): excluded_wages = person("employment_income", period) - person( "irs_employment_income", period ) - adjusted = max_( - 0, person("earned_income", period) - excluded_wages - adjustment - ) + # Disability pensions reported as wages before minimum retirement + # age are earned income (Pub. 596). + earnings = add(person, period, ["earned_income", "earned_disability_benefits"]) + adjusted = max_(0, earnings - excluded_wages - adjustment) is_dependent = person("is_tax_unit_dependent", period) return tax_unit.sum(adjusted * ~is_dependent)