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..0f1818befd3 --- /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)); 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. Count only nontaxable disability benefits as an addition to federal AGI for Montana's elderly homeowner or renter credit. 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 c9705de6925..dd19f3cbf61 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 - partnership_s_corp_income # Line 18 - estate_income # Line 18 @@ -43,7 +43,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 - partnership_s_corp_income # Line 19 - estate_income # Line 19 @@ -63,7 +63,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 - partnership_s_corp_income # Line 19 - estate_income # Line 19 @@ -86,7 +86,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 - partnership_s_corp_income # Line 19 - estate_income # Line 19 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 c8583b5dd2e..811fe325ed5 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 - partnership_s_corp_income # Line 18 - estate_income # Line 18 @@ -43,7 +43,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 - partnership_s_corp_income # Line 19 - estate_income # Line 19 @@ -63,7 +63,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 - partnership_s_corp_income # Line 19 - estate_income # Line 19 @@ -86,7 +86,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 - partnership_s_corp_income # Line 19 - estate_income # Line 19 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/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/mt/tax/income/credits/elderly_homeowner_or_renter/gross_income_sources.yaml b/policyengine_us/parameters/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/gross_income_sources.yaml index f7369da0a8b..730271ed1c2 100644 --- a/policyengine_us/parameters/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/gross_income_sources.yaml +++ b/policyengine_us/parameters/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/gross_income_sources.yaml @@ -66,15 +66,13 @@ values: # (9)(a) counts all nontaxable income; a government-funded pilot is also # "any other government assistance" (Schedule 2EC line 16). - gi_cash_assistance - # Disability benefits from employment other than workers' compensation - # (2014-2023 instructions: "Disability benefits including, but not - # limited to, veteran's disability, SSI payments, and workers' - # compensation"; from 2024, Schedule 2EC line 1 for taxable sick pay and - # disability pay reported as wages, line 5 for a disability pension after - # minimum retirement age (IRS Pub. 525), otherwise line 15). The model - # leaves them out of federal AGI (irs_gross_income) and - # dependent_gross_income, so all of them count here, once. - - disability_benefits + # Only nontaxable employment disability benefits are added here. The + # taxable part is already in federal AGI or a dependent's own gross + # income. The 2014-2023 instructions list disability benefits among + # other income; from 2024, Schedule 2EC uses line 1 for taxable pay + # reported as wages, line 5 for a disability pension after minimum + # retirement age, and line 15 for nontaxable disability benefits. + - tax_exempt_disability_benefits # Unemployment compensation that neither federal AGI nor a dependent's # own gross income counts, such as the 2020 IRC 85(c) exclusion (2020 # line 8, "all items of income ... not reported on lines 1 through 7"; @@ -102,7 +100,7 @@ values: - tanf_person - workers_compensation - gi_cash_assistance - - disability_benefits + - tax_exempt_disability_benefits - mt_elderly_homeowner_or_renter_credit_unemployment_compensation_addback - mt_refundable_credits_before_renter_credit - mt_elderly_homeowner_or_renter_credit_received @@ -124,7 +122,7 @@ values: - tanf_person - workers_compensation - gi_cash_assistance - - disability_benefits + - tax_exempt_disability_benefits - mt_elderly_homeowner_or_renter_credit_unemployment_compensation_addback - mt_refundable_credits_before_renter_credit - mt_elderly_homeowner_or_renter_credit_received 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/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/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/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/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/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/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/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 3dc05f9dd9b..c4715375f0c 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", "partnership_s_corp_income": "18", "estate_income": "18", @@ -72,7 +72,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", "partnership_s_corp_income": "19", "estate_income": "19", diff --git a/policyengine_us/tests/core/test_disability_filing_invariants.py b/policyengine_us/tests/core/test_disability_filing_invariants.py new file mode 100644 index 00000000000..97df448dcf4 --- /dev/null +++ b/policyengine_us/tests/core/test_disability_filing_invariants.py @@ -0,0 +1,269 @@ +"""Differential properties for taxable disability and the filing worksheets. + +The merge review's seeded checks become Hypothesis batches, each calculated +in one simulation for 2024-2026 with a shared, unreformed system. YAML covers +the named households; this test checks independent worksheet references over +generated combinations of disability splits, wages, business profits/losses, +interest, claimability, age and blindness. It does not read model parameters +or calculated deductions to construct expected results. + +References: +- IRC 104(a)(3), 105(a): taxable disability is total less exempt benefits. +- Form 1040 line 1h and the Standard Deduction Worksheet for Dependents: + https://www.irs.gov/pub/irs-prior/i1040gi--2024.pdf + https://www.irs.gov/pub/irs-prior/i1040gi--2025.pdf +- Schedule SE, lines 4a, 4c and 12-13: 92.35% of business profit, the $400 + net-earnings threshold, 15.3% tax and half of that tax deductible. Drawn + wages plus business income stay below every year's Social Security cap: + https://www.irs.gov/pub/irs-prior/f1040sse--2024.pdf +- Publication 501 Table 2 (single dependents): + https://www.irs.gov/pub/irs-prior/p501--2024.pdf#page=4 + https://www.irs.gov/pub/irs-prior/p501--2025.pdf#page=4 +- 2026 amounts: Rev. Proc. 2025-32, section 4.14: + https://www.irs.gov/pub/irs-drop/rp-25-32.pdf#page=18 +- IRC 6012(f) for 2024-2025, and 6012(a)(1) for 2026. Claimable filers + retain the dependent worksheet in every year (decision d1395): + https://www.law.cornell.edu/uscode/text/26/6012 + +The Medicaid reference applies Table 2 to each person's gross and earned +income. The deduction worksheet additionally subtracts Schedule 1 line 15. +Elective deferrals are zero: the pre-existing worksheet/Medicaid treatment of +deferrals is review P3-4, reserved for a separate change. These properties +concern section 6012's income tests, not separate Schedule SE filing duties. +""" + +import numpy as np +from hypothesis import HealthCheck, given, seed, settings +from hypothesis import strategies as st + +from policyengine_us import Simulation +from policyengine_us.system import system as SYSTEM + +YEARS = (2024, 2025, 2026) +# Published single-filer amounts, independent of the model's parameter tree. +# Each tuple is (regular deduction, dependent floor, age/blindness addition). +AMOUNTS = { + 2024: (14_600, 1_300, 1_950), + 2025: (15_750, 1_350, 2_000), + 2026: (16_100, 1_350, 2_050), +} +EARNED_ADDITION = 450 + + +def filer(**inputs): + return { + "age": 40, + "is_blind": False, + "claimed_as_dependent_on_another_return": True, + "employment_income": 0, + "self_employment_income": 0, + "taxable_interest_income": 0, + "disability_benefits": 0, + "tax_exempt_disability_benefits": 0, + "disability_benefits_before_minimum_retirement_age": 0, + **inputs, + } + + +@st.composite +def filers(draw): + return filer( + age=draw(st.sampled_from([19, 40, 64, 65, 66, 80])), + is_blind=draw(st.booleans()), + claimed_as_dependent_on_another_return=draw(st.booleans()), + employment_income=draw(st.integers(0, 30_000)), + self_employment_income=draw( + st.one_of(st.just(0), st.integers(-10_000, 30_000)) + ), + taxable_interest_income=draw(st.integers(0, 5_000)), + disability_benefits=draw(st.integers(0, 30_000)), + # Overstated exemptions and negative/overstated before-retirement + # amounts exercise both floors and the earned-income cap. + tax_exempt_disability_benefits=draw(st.integers(0, 40_000)), + disability_benefits_before_minimum_retirement_age=draw( + st.integers(-5_000, 40_000) + ), + ) + + +ANCHORS = [ + filer( + disability_benefits=5_000, + disability_benefits_before_minimum_retirement_age=5_000, + ), + filer(disability_benefits=5_000), + filer(disability_benefits=5_000, tax_exempt_disability_benefits=6_000), + filer( + disability_benefits=5_000, + disability_benefits_before_minimum_retirement_age=-1, + ), + filer( + disability_benefits=5_000, + tax_exempt_disability_benefits=2_000, + disability_benefits_before_minimum_retirement_age=6_000, + ), + # H2: $6,000 business profit and $5,000 of earned disability. This also + # distinguishes Medicaid's Table 2 earnings from the deduction worksheet. + filer( + self_employment_income=6_000, + disability_benefits=7_000, + disability_benefits_before_minimum_retirement_age=5_000, + ), + filer(employment_income=2_000, self_employment_income=-5_000), + filer(employment_income=2_000, self_employment_income=-100), + # Schedule SE line 4a falls just below/above $400 at these profits. + # Wages put the worksheet above its floor so line 15 affects the result. + filer(employment_income=2_000, self_employment_income=433), + filer(employment_income=2_000, self_employment_income=434), + filer( + age=65, + is_blind=True, + disability_benefits=5_000, + tax_exempt_disability_benefits=500, + disability_benefits_before_minimum_retirement_age=3_500, + ), + filer( + is_blind=True, + claimed_as_dependent_on_another_return=False, + disability_benefits=17_000, + ), +] +# Disability income at the statutory threshold distinguishes strict > in +# 2024-2025 from >= for unclaimable filers in 2026, and exercises the earned +# cap of the dependent worksheet at equality. +for regular, _, _ in AMOUNTS.values(): + for claimed in (False, True): + ANCHORS.append( + filer( + claimed_as_dependent_on_another_return=claimed, + disability_benefits=regular, + disability_benefits_before_minimum_retirement_age=regular, + ) + ) + + +def simulate(people): + groups = { + entity: {} + for entity in ( + "tax_units", + "households", + "marital_units", + "spm_units", + "families", + ) + } + person_inputs = {} + for index, person in enumerate(people): + name = f"person_{index}" + inputs = {**person, "tax_unit_role_input": "HEAD"} + person_inputs[name] = { + variable: {year: value for year in YEARS} + for variable, value in inputs.items() + } + for entity, units in groups.items(): + units[name] = {"members": [name]} + if entity == "tax_units": + units[name]["filing_status"] = {year: "SINGLE" for year in YEARS} + elif entity == "households": + units[name]["state_code"] = {year: "TX" for year in YEARS} + return Simulation( + situation={"people": person_inputs, **groups}, tax_benefit_system=SYSTEM + ) + + +def reference(person, year): + """Paper-form arithmetic for a single person's section 6012 tests.""" + regular, floor, addition = AMOUNTS[year] + taxable = max( + 0, person["disability_benefits"] - person["tax_exempt_disability_benefits"] + ) + earned_disability = min( + taxable, max(0, person["disability_benefits_before_minimum_retirement_age"]) + ) + wages = person["employment_income"] + business = person["self_employment_income"] + interest = person["taxable_interest_income"] + gross = wages + max(0, business) + interest + taxable + earned = wages + business + earned_disability + unearned = interest + taxable - earned_disability + extra_count = int(person["age"] >= 65) + int(person["is_blind"]) + extra = addition * extra_count + + # Schedule SE lines 4a, 4c, 12 and 13, below the Social Security cap. + net_business = business * 0.9235 + line_15 = net_business * 0.153 / 2 if net_business >= 400 else 0 + worksheet_line_1 = max(0, earned - line_15) + worksheet_deduction = min(regular, max(floor, worksheet_line_1 + EARNED_ADDITION)) + claimed = person["claimed_as_dependent_on_another_return"] + basic = worksheet_deduction if claimed else regular + standard = basic + extra + + # A claimed dependent keeps the section 63(c)(5) worksheet and Table 2's + # unearned-income test. Otherwise 6012(f) includes blindness through 2025, + # and 6012(a)(1) in 2026 permits the age addition only, with >= at equality. + if claimed: + required = gross > standard or unearned > floor + extra + elif year <= 2025: + required = gross > standard + else: + required = gross >= regular + addition * int(person["age"] >= 65) + + # Table 2 has three distinct tests: unearned, earned and gross income. + # Business losses lower earned income but cannot reclassify wages or + # disability pensions as unearned income. + table_2_gross_limit = ( + max(floor, min(earned, regular - EARNED_ADDITION) + EARNED_ADDITION) + extra + ) + medicaid_required = ( + unearned > floor + extra + or earned > regular + extra + or gross > table_2_gross_limit + ) + return { + "taxable_disability_benefits": taxable, + "earned_disability_benefits": earned_disability, + "irs_gross_income": gross, + "basic_standard_deduction": basic, + "standard_deduction": standard, + "tax_unit_is_required_to_file": required, + "medicaid_person_is_required_to_file": medicaid_required, + } + + +@seed(20261007) +@settings( + max_examples=8, + deadline=None, + suppress_health_check=[HealthCheck.too_slow], +) +@given(drawn=st.lists(filers(), min_size=24, max_size=32)) +def test_disability_filing_worksheet_properties(drawn): + people = ANCHORS + drawn + simulation = simulate(people) + for year in YEARS: + expected = [reference(person, year) for person in people] + actual = {} + for variable in expected[0]: + actual[variable] = np.asarray(simulation.calculate(variable, year)) + values = np.asarray([row[variable] for row in expected]) + if values.dtype == bool: + np.testing.assert_array_equal( + actual[variable], values, err_msg=f"{year}: {variable}" + ) + else: + np.testing.assert_allclose( + actual[variable], + values, + rtol=0, + atol=0.01, + err_msg=f"{year}: {variable}", + ) + taxable = actual["taxable_disability_benefits"] + earned = actual["earned_disability_benefits"] + assert np.all((earned >= 0) & (earned <= taxable)) + for variable in ( + "tax_unit_is_required_to_file", + "medicaid_person_is_required_to_file", + ): + assert actual[variable].any() and not actual[variable].all() diff --git a/policyengine_us/tests/core/test_uprating_series.py b/policyengine_us/tests/core/test_uprating_series.py index 3b1447dc5e4..4ca3e841381 100644 --- a/policyengine_us/tests/core/test_uprating_series.py +++ b/policyengine_us/tests/core/test_uprating_series.py @@ -49,6 +49,8 @@ # Wage-replacement benefits. "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/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 94f2f9c5ef7..ec8fd341c06 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 @@ -145,3 +145,92 @@ members: [person1] output: medicaid_person_is_required_to_file: true + +- 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] + +# Positive-source gross income preserves the loss/deferral rules even +# when a disability pension is also earned income (Pub. 501, Table 2). +- name: Earned disability with a business loss does not become unearned Medicaid filing income + period: 2024 + input: + age: 20 + disability_benefits: 1300 + disability_benefits_before_minimum_retirement_age: 1300 + self_employment_income: -2000 + output: + medicaid_irs_gross_income: 1300 + medicaid_person_is_required_to_file: false +- name: Deferred wages do not hide unearned income alongside earned disability benefits + period: 2024 + input: + age: 20 + employment_income: 3000 + traditional_401k_contributions: 2000 + disability_benefits: 3000 + disability_benefits_before_minimum_retirement_age: 3000 + taxable_interest_income: 1500 + output: + medicaid_irs_gross_income: 5500 + medicaid_person_is_required_to_file: true + +- name: H3a, deferred wages and partially earned disability preserve the Medicaid unearned filing test + # Pub. 501 (2025), Table 2: positive gross wages are $4,000 - $2,500 = + # $1,500. Gross income $6,500 less $1,500 wages and $3,500 earned + # disability leaves $1,500 unearned, over $1,350. Using wages before + # deferrals to net earned income would incorrectly remove this excess. + period: 2025 + input: + age: 20 + employment_income: 4_000 + traditional_401k_contributions: 2_500 + disability_benefits: 5_000 + disability_benefits_before_minimum_retirement_age: 3_500 + output: + irs_employment_income: 1_500 + taxable_disability_benefits: 5_000 + earned_disability_benefits: 3_500 + medicaid_irs_gross_income: 6_500 + medicaid_person_is_required_to_file: true + +- name: H3b, deferred wages and fully earned disability do not require Medicaid filing + # All $5,000 is line 1h pay, leaving no unearned income. The dependent + # deduction used for this test is $4,000 + $5,000 + $450 = $9,450, + # above gross income $6,500. P3-4's wage-deferral worksheet treatment + # is pre-existing and reserved for a separate change. + period: 2025 + input: + age: 20 + employment_income: 4_000 + traditional_401k_contributions: 2_500 + disability_benefits: 5_000 + disability_benefits_before_minimum_retirement_age: 5_000 + output: + irs_employment_income: 1_500 + taxable_disability_benefits: 5_000 + earned_disability_benefits: 5_000 + medicaid_irs_gross_income: 6_500 + medicaid_person_is_required_to_file: false 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 c6b97d0bcd2..8a697202475 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 @@ -414,3 +414,26 @@ # No child cap from 2018; AMTI is below the 2022 phase-out start of 539,900. # amt_exemption = 75,900 - 0.25 * max(0, 200,000 - 539,900) = 75,900. amt_exemption: 75900 + +- 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..729660f7871 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.yaml @@ -0,0 +1,59 @@ +- 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 benefits alone do not show the plan provides for disability retirement. + period: 2024 + input: + retired_on_total_disability: true + disability_benefits: 8_000 + output: + permanent_disability_retirement_pay: 0 + +- name: Disability pay paid as wages. + 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: 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: 4_000 + # Unrelated wages. + employment_income: 1_000 + output: + 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: + 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/deductions/standard/basic_standard_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/irs/deductions/standard/basic_standard_deduction.yaml index 4099214070c..55633ed743d 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 @@ -285,3 +285,129 @@ # Worksheet earned income subtracts Schedule 1 line 15: # $3,000 - $3,000 x 0.9235 x 15.3% / 2 = $2,788.06; plus $450 = $3,238.06. basic_standard_deduction: 3238.06 + +- 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 + +# Worksheet: $10,000 disability + $3,000 business income - $211.94 +# deductible self-employment tax + $450 = $13,238.06 for either head label. +- name: 2025 joint return combines earned disability and net self-employment income when either spouse + can be claimed (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + disability_benefits: 10000 + disability_benefits_before_minimum_retirement_age: 10000 + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + self_employment_income: 3000 + tax_units: + tax_unit: + members: + - person_a + - person_b + filing_status: JOINT + households: + household: + members: + - person_a + - person_b + state_code: CA + output: + basic_standard_deduction: 13238.06 + absolute_error_margin: 0.01 +- name: 2025 joint return combines earned disability and net self-employment income when either spouse + can be claimed (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + self_employment_income: 3000 + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + disability_benefits: 10000 + disability_benefits_before_minimum_retirement_age: 10000 + tax_units: + tax_unit: + members: + - person_b + - person_a + filing_status: JOINT + households: + household: + members: + - person_b + - person_a + state_code: CA + output: + basic_standard_deduction: 13238.06 + absolute_error_margin: 0.01 + +- name: H2, the dependent worksheet combines earned disability with self-employment income net of deductible tax + # 2024 Form 1040 Standard Deduction Worksheet for Dependents: line 1h + # includes only the $5,000 before minimum retirement age. Schedule 1 + # line 15 is $6,000 x 0.9235 x 15.3% / 2 = $423.89. Worksheet line 1 is + # $6,000 + $5,000 - $423.89 = $10,576.11, plus $450 = $11,026.11. + # The remaining $2,000 of taxable disability is unearned. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + head: + age: 40 + claimed_as_dependent_on_another_return: true + self_employment_income: 6_000 + disability_benefits: 7_000 + disability_benefits_before_minimum_retirement_age: 5_000 + tax_units: + tax_unit: + members: [head] + filing_status: SINGLE + households: + household: + members: [head] + output: + taxable_disability_benefits: 7_000 + earned_disability_benefits: 5_000 + irs_gross_income: 13_000 + self_employment_tax_ald: 423.89 + basic_standard_deduction: 11_026.11 + standard_deduction: 11_026.11 + tax_unit_is_required_to_file: true 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/gov/irs/income/taxable_income/deductions/itemizing/charitable_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/itemizing/charitable_deduction.yaml index 562fe17e8ec..e91c3438dce 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/itemizing/charitable_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/itemizing/charitable_deduction.yaml @@ -425,5 +425,3 @@ # Total before floor = 30,000 + 20,000 + 10,000 = 60,000. # Floor (0.5% * 100,000 = 500) applies after ceilings: 60,000 - 500 = 59,500. charitable_deduction: 59_500 - - 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 2804058799c..f441bda36ee 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 @@ -573,3 +573,22 @@ # is $16,100 + $2,050 = $18,150 and would not require a return under (f). standard_deduction: 18_150 tax_unit_is_required_to_file: true + +- 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/irs/tax_unit_is_required_to_file_dependents.yaml b/policyengine_us/tests/policy/baseline/gov/irs/tax_unit_is_required_to_file_dependents.yaml index 17aff4458bf..f7ba92e3c6d 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/tax_unit_is_required_to_file_dependents.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/tax_unit_is_required_to_file_dependents.yaml @@ -641,3 +641,125 @@ taxable_interest_income: 600 output: tax_unit_is_required_to_file: false + +# IRC 105(a), 63(c)(5), 6012(a)(1)(C); Form 1040 line 1h is earned +# before minimum retirement age. Main's 2026 age-only rule still applies +# to a filer nobody can claim. +- name: 2024, a claimable filer with earned disability pension need not file + period: 2024 + input: + filing_status: SINGLE + age: 40 + claimed_as_dependent_on_another_return: true + disability_benefits: 10000 + disability_benefits_before_minimum_retirement_age: 10000 + output: + basic_standard_deduction: 10450 + tax_unit_is_required_to_file: false +- name: 2024, a claimable filer with unearned taxable disability benefits must file + period: 2024 + input: + filing_status: SINGLE + age: 40 + claimed_as_dependent_on_another_return: true + disability_benefits: 10000 + output: + basic_standard_deduction: 1300 + tax_unit_is_required_to_file: true +- name: 2026, taxable disability reaches the age-only filing threshold for a blind nondependent + period: 2026 + input: + filing_status: SINGLE + age: 40 + is_blind: true + disability_benefits: 16100 + output: + standard_deduction: 18150 + tax_unit_is_required_to_file: true +- name: 2026, a blind claimable filer keeps the earned disability dependent deduction + period: 2026 + input: + filing_status: SINGLE + age: 40 + is_blind: true + claimed_as_dependent_on_another_return: true + disability_benefits: 10000 + disability_benefits_before_minimum_retirement_age: 10000 + output: + basic_standard_deduction: 10450 + standard_deduction: 12500 + tax_unit_is_required_to_file: false + +- name: H1, a claimable spouse's unearned disability is not reduced by the other spouse's earned disability + # Pub. 501 (2025), Table 2 applies the unearned test to the claimable + # spouse's own income. The head's $2,500 of line 1h pay cannot offset the + # spouse's $1,500 of unearned disability, which exceeds $1,350. Gross + # income $5,000 is below the $3,950 + $1,600 blindness deduction. + period: 2025 + input: + people: + head: + age: 40 + is_tax_unit_head: true + is_tax_unit_spouse: false + is_blind: true + claimed_as_dependent_on_another_return: false + disability_benefits: 2_500 + disability_benefits_before_minimum_retirement_age: 2_500 + spouse: + age: 40 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true + employment_income: 1_000 + disability_benefits: 1_500 + tax_units: + tax_unit: + members: [head, spouse] + filing_status: JOINT + households: + household: + members: [head, spouse] + output: + irs_gross_income: [2_500, 2_500] + earned_disability_benefits: [2_500, 0] + basic_standard_deduction: 3_950 + standard_deduction: 5_550 + tax_unit_is_required_to_file: true + +- name: H1b, a claimable spouse's own line 1h disability is earned for the filing test + # With the spouse's $1,500 also reported on line 1h, neither spouse has + # unearned income. Joint worksheet earned income is $5,000, giving a + # $5,450 basic deduction and $7,050 with the head's blindness addition. + period: 2025 + input: + people: + head: + age: 40 + is_tax_unit_head: true + is_tax_unit_spouse: false + is_blind: true + claimed_as_dependent_on_another_return: false + disability_benefits: 2_500 + disability_benefits_before_minimum_retirement_age: 2_500 + spouse: + age: 40 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true + employment_income: 1_000 + disability_benefits: 1_500 + disability_benefits_before_minimum_retirement_age: 1_500 + tax_units: + tax_unit: + members: [head, spouse] + filing_status: JOINT + households: + household: + members: [head, spouse] + output: + irs_gross_income: [2_500, 2_500] + earned_disability_benefits: [2_500, 1_500] + basic_standard_deduction: 5_450 + standard_deduction: 7_050 + tax_unit_is_required_to_file: false 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/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..40ebe61ba94 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.yaml @@ -0,0 +1,89 @@ +# 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 + total_disability_payments: 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 + total_disability_payments: 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 + total_disability_payments: 5_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + 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 new file mode 100644 index 00000000000..6eb47e74f7e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/in/tax/income/deductions/in_disability_retirement_deduction.yaml @@ -0,0 +1,93 @@ +# 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 + total_disability_payments: 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 + total_disability_payments: 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 + 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: + 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 + total_disability_payments: 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/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/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_disability_and_unemployment.yaml b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_disability_and_unemployment.yaml index 9a474ec7a5a..9acc7082943 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_disability_and_unemployment.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/credits/elderly_homeowner_or_renter/mt_elderly_homeowner_or_renter_credit_disability_and_unemployment.yaml @@ -1,4 +1,4 @@ -# Employment disability benefits and unemployment compensation outside +# Nontaxable employment disability benefits and unemployment compensation outside # federal AGI in gross household income. § 15-30-2337(9)(a) counts federal # AGI "plus all nontaxable income". The 2014-2023 instructions list # "Disability benefits including, but not limited to, veteran's disability, @@ -16,6 +16,7 @@ age: 80 taxable_pension_income: 12_000 disability_benefits: 2_500 + tax_exempt_disability_benefits: 2_500 rent: 6_000 ssi: 0 tax_units: @@ -50,6 +51,7 @@ person2: age: 45 disability_benefits: 5_000 + tax_exempt_disability_benefits: 5_000 ssi: 0 tax_units: tax_unit1: @@ -85,6 +87,7 @@ person2: age: 64 disability_benefits: 4_000 + tax_exempt_disability_benefits: 4_000 ssi: 0 tax_units: tax_unit: @@ -118,6 +121,7 @@ person2: age: 45 disability_benefits: 7_000 + tax_exempt_disability_benefits: 7_000 ssi: 0 tax_units: tax_unit1: @@ -150,6 +154,7 @@ age: 64 taxable_pension_income: 16_000 disability_benefits: 6_000 + tax_exempt_disability_benefits: 6_000 real_estate_taxes: 1_300 ssi: 0 tax_units: @@ -334,3 +339,93 @@ mt_elderly_homeowner_or_renter_credit_net_household_income: 327.60 # Line 27 = 1_200 - 327.60 = 872.40; line 28 = 872.40; line 30 = 872.40. mt_elderly_homeowner_or_renter_credit: 872.40 + +# The following cases preserve Cases 1-3's total disability income while +# changing its tax treatment. Each parameter period must add only the +# nontaxable portion to federal AGI, so the credit remains unchanged. +- name: Case 11, 2016 fully taxable disability benefits count once through federal AGI. + period: 2016 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + taxable_pension_income: 12_000 + disability_benefits: 2_500 + tax_exempt_disability_benefits: 0 + rent: 6_000 + ssi: 0 + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_name: MT + output: + # Federal AGI already includes all 2_500 of disability benefits. + adjusted_gross_income_person: 14_500 + mt_elderly_homeowner_or_renter_credit_gross_household_income: 14_500 + mt_elderly_homeowner_or_renter_credit_net_household_income: 319.80 + mt_elderly_homeowner_or_renter_credit: 580.20 + +- name: Case 12, 2017 mixed disability benefits count each portion once for another household member. + period: 2017 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 72 + taxable_pension_income: 15_000 + real_estate_taxes: 1_200 + ssi: 0 + person2: + age: 45 + disability_benefits: 5_000 + tax_exempt_disability_benefits: 2_000 + ssi: 0 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + households: + household: + members: [person1, person2] + state_name: MT + output: + # The adult son's own federal AGI holds 3_000; only 2_000 is added. + adjusted_gross_income_person: [15_000, 3_000] + mt_elderly_homeowner_or_renter_credit_gross_household_income: [15_000, 5_000] + mt_elderly_homeowner_or_renter_credit_net_household_income: [685, 0] + mt_elderly_homeowner_or_renter_credit: [515, 0] + +- name: Case 13, 2023 mixed disability benefits count each portion once for a spouse. + period: 2023 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 66 + taxable_pension_income: 18_000 + real_estate_taxes: 1_000 + ssi: 0 + person2: + age: 64 + disability_benefits: 4_000 + tax_exempt_disability_benefits: 1_500 + ssi: 0 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_name: MT + output: + # Line 1 federal AGI 20_500; line 8 nontaxable disability 1_500; + # line 10 gross household income 22_000, as in Case 3. + adjusted_gross_income_person: [18_000, 2_500] + mt_elderly_homeowner_or_renter_credit_gross_household_income: [18_000, 4_000] + mt_elderly_homeowner_or_renter_credit_net_household_income: [394.80, 0] + mt_elderly_homeowner_or_renter_credit: [605.20, 0] 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/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..fb7de164e4b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/ny_disability_income_exclusion.yaml @@ -0,0 +1,140 @@ +# 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 + 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] + 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 + total_disability_payments: 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 + total_disability_payments: 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 + total_disability_payments: 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 + total_disability_payments: 5_000 + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + 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/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/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 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 7b8d46fb236..ec86404383c 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 @@ -129,6 +129,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] @@ -204,3 +207,25 @@ output: # PA-1000 Line 4: one-half of the State Supplementary Payment. pa_property_tax_or_rent_rebate_income: 3_835.8 + +- name: Taxable disability benefits count once, through federal AGI. + period: 2025 + input: + people: + person1: + age: 65 + ssi: 0 + pa_ssp: 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 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..7c78c9427ba --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.yaml @@ -0,0 +1,201 @@ +# 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 + total_disability_payments: 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 + total_disability_payments: 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 + 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: + 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 + total_disability_payments: 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 + total_disability_payments: 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 + total_disability_payments: 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 + total_disability_payments: 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 + +- 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/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] 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..845d1ce9d8f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/household/income/person/general/earned_disability_benefits.yaml @@ -0,0 +1,55 @@ +- 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 + +- 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 + +- 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/tests/test_mt_elderly_credit_nontaxable_income.py b/policyengine_us/tests/test_mt_elderly_credit_nontaxable_income.py index be9b2281fed..3090ca71bfc 100644 --- a/policyengine_us/tests/test_mt_elderly_credit_nontaxable_income.py +++ b/policyengine_us/tests/test_mt_elderly_credit_nontaxable_income.py @@ -5,10 +5,13 @@ nontaxable income", and (4) counts "all income received by all individuals of a household". 2024 Schedule 2EC line 14 counts "the total of unemployment compensation received during the year"; the 2014-2023 instructions list -disability benefits. The model leaves employment disability benefits out of -federal AGI, and in 2020 IRC 85(c) excluded up to 10_200 of unemployment -compensation from it. Federal AGI counts the taxable part of a filer's -compensation and a dependent's own gross income all of a dependent's. +disability benefits. The original grid specifies fully nontaxable employment +disability benefits. Additional cases split benefits between taxable and +exempt amounts, exercising federal AGI and a dependent's own gross income. +In 2020 IRC 85(c) excluded up to 10_200 of +unemployment compensation from federal AGI. Federal AGI counts the taxable +part of a filer's compensation and a dependent's own gross income all of a +dependent's. For a claimant aged 66 (taxable pension, unemployment compensation, disability benefits, property tax) living with one other adult (unemployment @@ -31,6 +34,9 @@ Table), lies between zero and the cap, and is zero at 45_000 or more. 3. More unemployment compensation or disability benefits never raise the credit while the refundable credits stay the same. +4. Holding total disability benefits fixed, fully taxable, half-exempt and + fully exempt benefits produce the same household income and credit in + every arrangement, with unchanged refundable credits. The YAML cases pin worked examples from each year's form. This test adds what they cannot: every arrangement and year at once against a reference @@ -110,6 +116,23 @@ MEMBER_DISABILITY, ) ] +# Keep the full original grid, and vary the taxable/exempt split in 18 +# additional households. These low-income cases retain the same refundable +# credits across splits, include both sides of the 2020 UC exclusion, and +# exercise claimant AGI, another filer's AGI and dependent gross income. +SPLIT_BASE_CASES = [ + c + for c in CASES + if c["pension"] == 12_000 + and c["claimant_uc"] == 6_000 + and c["member_uc"] == 12_000 + and c["claimant_disability"] + c["member_disability"] > 0 +] +SPLIT_CASES = [ + dict(c, exempt_fraction=fraction) + for c, fraction in itertools.product(SPLIT_BASE_CASES, (0, 0.5)) +] +ALL_CASES = CASES + SPLIT_CASES def build_situation(): @@ -117,14 +140,18 @@ def every_year(value): return {year: value for year in YEARS} people, tax_units, marital_units, households = {}, {}, {}, {} - for i, c in enumerate(CASES): + for i, c in enumerate(ALL_CASES): claimant, member = f"claimant_{i}", f"member_{i}" arrangement = c["arrangement"] + exempt_fraction = c.get("exempt_fraction", 1) people[claimant] = { "age": every_year(66), "taxable_pension_income": every_year(c["pension"]), "unemployment_compensation": every_year(c["claimant_uc"]), "disability_benefits": every_year(c["claimant_disability"]), + "tax_exempt_disability_benefits": every_year( + c["claimant_disability"] * exempt_fraction + ), "real_estate_taxes": every_year(PROPERTY_TAX), "ssi": every_year(0), "is_tax_unit_dependent": every_year(False), @@ -136,6 +163,9 @@ def every_year(value): "is_full_time_student": every_year(arrangement == "dependent"), "unemployment_compensation": every_year(c["member_uc"]), "disability_benefits": every_year(c["member_disability"]), + "tax_exempt_disability_benefits": every_year( + c["member_disability"] * exempt_fraction + ), "ssi": every_year(0), "is_tax_unit_dependent": every_year(arrangement == "dependent"), } @@ -214,7 +244,7 @@ def tolerance(amount): @pytest.mark.parametrize("year", YEARS) def test_each_amount_counts_once(results, year): r = results[year] - for i, c in enumerate(CASES): + for i, c in enumerate(ALL_CASES): expected = ( c["pension"] + c["claimant_uc"] @@ -231,7 +261,7 @@ def test_each_amount_counts_once(results, year): @pytest.mark.parametrize("year", YEARS) def test_credit_follows_the_schedule(results, year): r = results[year] - for i, c in enumerate(CASES): + for i, c in enumerate(ALL_CASES): ghi = float(r["gross_household_income"][i]) credit = float(r["credit"][i]) tol = tolerance(ghi) @@ -269,6 +299,22 @@ def test_more_income_never_raises_the_credit(results, year): assert compared > 0 +@pytest.mark.parametrize("year", YEARS) +def test_disability_taxability_does_not_change_the_credit(results, year): + r = results[year] + index = {tuple(sorted(c.items())): i for i, c in enumerate(ALL_CASES)} + for c in SPLIT_BASE_CASES: + exempt_index = index[tuple(sorted(c.items()))] + for exempt_fraction in (0, 0.5): + split = dict(c, exempt_fraction=exempt_fraction) + split_index = index[tuple(sorted(split.items()))] + for variable in ("refundable_credits", "gross_household_income", "credit"): + expected = r[variable][exempt_index] + assert r[variable][split_index] == pytest.approx( + expected, abs=tolerance(expected) + ), (year, split, variable) + + def test_worked_example(results): """2020 Elderly Homeowner/Renter Credit Schedule, own_return arrangement: the claimant's pension 12_000 and unemployment compensation 6_000, all 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 c5fec3109ad..f5b3d7f9796 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 @@ -26,7 +26,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 is gross income other than wages and self-employment # earnings (IRS Pub. 501, Table 2). Gross income counts each source's # positive amount, so subtract those sources' positive amounts: a @@ -34,6 +38,7 @@ def formula(person, period, parameters): earned_gross_income = 0 for source in EARNED_GROSS_INCOME_SOURCES: earned_gross_income += max_(0, person(source, period)) + earned_gross_income += person("earned_disability_benefits", period) unearned_income = max_(0, gross_income - earned_gross_income) married = person.marital_unit.nb_persons() == 2 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..338f5e7273c --- /dev/null +++ b/policyengine_us/variables/gov/irs/credits/elderly_and_disabled/permanent_disability_retirement_pay.py @@ -0,0 +1,36 @@ +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 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 = ( + "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_income = person("total_disability_payments", period) + # 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"] + ) + return retired_on_total_disability * max_( + 0, min_(disability_income, included_in_agi) + ) 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 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/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) 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 952da61a05f..9a6e4f56988 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 @@ -29,6 +29,9 @@ def formula(tax_unit, period, parameters): # deductible part of self-employment tax (Schedule 1, line 15). worksheet_earned_income = max_( 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) - tax_unit("self_employment_tax_ald", period), 0, ) 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 8fd7416bbb7..d63cc80d891 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 @@ -152,7 +152,15 @@ def formula(tax_unit, period, parameters): unearned_income = 0 for source in parameters(period).gov.irs.gross_income.sources: if source not in earned_income_sources: - unearned_income += max_(0, add(person, period, [source])) + source_income = add(person, period, [source]) + if source == "taxable_disability_benefits": + # Before minimum retirement age, disability pensions go + # on Form 1040 line 1h (included in worksheet line 1z). + # Only the remaining taxable disability pay is unearned. + source_income = source_income - person( + "earned_disability_benefits", period + ) + unearned_income += max_(0, source_income) p_standard = p.deductions.standard aged_or_blind_count = person("is_irs_aged", period).astype(int) + person( "is_blind", period 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..e9b5b7b91dc --- /dev/null +++ b/policyengine_us/variables/gov/states/ia/tax/income/subtractions/ia_disability_income_exclusion.py @@ -0,0 +1,49 @@ +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 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) + 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(married_not_joint & 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/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/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..fbad7a5fead --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/tax/income/adjusted_gross_income/ny_disability_income_exclusion.py @@ -0,0 +1,57 @@ +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, + ) + # 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/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 9776e65f27d..13dd8cab593 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 @@ -59,7 +59,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/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..690a8af86ac --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_disability_income_exclusion.py @@ -0,0 +1,44 @@ +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." + ) + # 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): + 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 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) + 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( 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/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) 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)