diff --git a/changelog.d/claimable-filer-ri-sc-ut-vt-wv-wi.fixed.md b/changelog.d/claimable-filer-ri-sc-ut-vt-wv-wi.fixed.md new file mode 100644 index 00000000000..35b9bb42977 --- /dev/null +++ b/changelog.d/claimable-filer-ri-sc-ut-vt-wv-wi.fixed.md @@ -0,0 +1,7 @@ +Apply the Rhode Island, South Carolina, Utah, Vermont, West Virginia and Wisconsin rules for a filer who can be claimed as a dependent: dependent exemptions, deductions and child credits on such a return, the Wisconsin dependent standard deduction and $250 exemption, the West Virginia exemptions and family credit, the Rhode Island and Vermont claimant tests for property tax relief and the renter credit, and Wisconsin's care subtraction and credit expenses. + +Preserve claimable-filer counts and the dependent-claimant filing exception in the contributed Rhode Island, South Carolina, Utah, Vermont and West Virginia exemption reforms. Preserve the Rhode Island and Wisconsin filer counts under the state dependent exemption repeal. For West Virginia units without dependents, preserve the statutory $500 allowance per claimable filer in the baseline, contributed reform and repeal override; retain existing dependent allocation pending resolution. + +Exclude pretax payroll deductions from Wisconsin dependent standard deduction earnings on both tax paths. + +Use HUD zero-bedroom rents for zero-exemption Vermont renters in every stored fair market rent year (2021–2025). diff --git a/policyengine_us/parameters/gov/states/vt/tax/income/credits/renter/fair_market_rent.yaml b/policyengine_us/parameters/gov/states/vt/tax/income/credits/renter/fair_market_rent.yaml index 6ddecf03a2c..0dfc6f7cc62 100644 --- a/policyengine_us/parameters/gov/states/vt/tax/income/credits/renter/fair_market_rent.yaml +++ b/policyengine_us/parameters/gov/states/vt/tax/income/credits/renter/fair_market_rent.yaml @@ -1,12 +1,12 @@ -description: Vermont sets these fair market rent amounts, based on the county and household size. +description: Vermont sets these fair market rent amounts, based on the county and the number of bedrooms allowed by personal exemptions. metadata: propagate_metadata_to_children: true unit: currency-USD period: month breakdown: - - list(range(1,9)) + - list(range(0,9)) breakdown_labels: - - Household size + - Bedrooms (personal exemptions) label: Vermont fair market rent amount reference: # The values are derived from the renter credit computation tables which represent 10% of the @@ -43,9 +43,19 @@ metadata: href: https://www.huduser.gov/portal/datasets/fmr/fmr2022/FY22_FMRs.xlsx - title: HUD FY2021 Fair Market Rents href: https://www.huduser.gov/portal/datasets/fmr/fmr2021/FY21_4050_FMRs_rev.xlsx + - title: "HUD FY2021 Final Fair Market Rent Schedule #page 48-49" + href: https://www.huduser.gov/portal/datasets/fmr/fmr2021/FY2021-ScheduleB.pdf#page=48 + - title: "HUD FY2022 Fair Market Rent Schedule #page 48-50" + href: https://www.huduser.gov/portal/datasets/fmr/fmr2022/FY2022_FMR_Schedule.pdf#page=48 + - title: "HUD FY2023 Fair Market Rent Schedule #page 49-50" + href: https://www.huduser.gov/portal/datasets/fmr/fmr2023/FY2023_FMR_Schedule.pdf#page=49 + - title: "HUD FY2024 Fair Market Rent Schedule #page 51-52" + href: https://www.huduser.gov/portal/datasets/fmr/fmr2024/FY2024_FMR_Schedule.pdf#page=51 + - title: "HUD FY2025 Fair Market Rent Schedule #page 51-52" + href: https://www.huduser.gov/portal/datasets/fmr/fmr2025/FY2025_FMR_Schedule.pdf#page=51 # Each county's value is HUD's fair market rent for the fiscal year that includes # June 30 of the taxable year (FY2025 for 2025), for the county's HUD area, with -# household size n using the min(n, 4)-bedroom rent. Chittenden's 2,083 is the +# exemption count n using the min(n, 4)-bedroom rent. Chittenden's 2,083 is the # rent at which 10% x 12 reaches the $2,500 maximum the department applies to # the credit amount (2,500 / 1.2 = 2,083.33). # @@ -64,6 +74,104 @@ metadata: # - 2023 reconstruction: the average with the Burlington four-bedroom rent # (2,170) held to 2,083.33 (all 12 unadjusted give 1,913, not the published 1,904). # - 2025: the unrounded average (1,057.75 x 1.2 = 1,269.3, published 1,269). +# Zero-bedroom rents below are the published HUD 0 BR amounts. Franklin and +# Grand Isle use the unrounded arithmetic mean of all 12 Vermont HUD FMR areas, +# following the state-average rule in 6061(7)(C). This is the averaging convention +# that reproduces the department's unrounded 2025 rents. These zero-bedroom +# values are calculated from HUD schedules rather than department credit tables. +# The unrounded 12-area method is used in every year. It differs from the +# existing 1-4 bedroom reconstructions in 2021 and 2024 (whole-dollar rounding) +# and 2022 (Addison excluded). Applying those alternatives to zero bedrooms +# gives full-year credits of $883 either way in 2021, $919 versus $918 in 2022, +# and $1,172 versus $1,171 in 2024 (this method first); 2023 and 2025 agree. +# A 14-county average instead weights the Burlington area three times and +# gives a 2025 zero-bedroom credit of $1,273 versus this method's $1,209. +# Section 6061(7)(C) does not specify averaging weights or intermediate rounding. +0: + ADDISON_COUNTY_VT: + 2021-01-01: 751 + 2022-01-01: 779 + 2023-01-01: 842 + 2024-01-01: 1_017 + 2025-01-01: 1_096 + BENNINGTON_COUNTY_VT: + 2021-01-01: 710 + 2022-01-01: 763 + 2023-01-01: 849 + 2024-01-01: 936 + 2025-01-01: 936 + CALEDONIA_COUNTY_VT: + 2021-01-01: 708 + 2022-01-01: 741 + 2023-01-01: 810 + 2024-01-01: 899 + 2025-01-01: 905 + CHITTENDEN_COUNTY_VT: + 2021-01-01: 1_091 + 2022-01-01: 1_033 + 2023-01-01: 1_139 + 2024-01-01: 1_341 + 2025-01-01: 1_380 + ESSEX_COUNTY_VT: + 2021-01-01: 560 + 2022-01-01: 585 + 2023-01-01: 730 + 2024-01-01: 812 + 2025-01-01: 823 + FRANKLIN_COUNTY_VT: + 2021-01-01: 736.0833333333334 + 2022-01-01: 766 + 2023-01-01: 849.0833333333334 + 2024-01-01: 976.3333333333334 + 2025-01-01: 1_007.6666666666666 + GRAND_ISLE_COUNTY_VT: + 2021-01-01: 736.0833333333334 + 2022-01-01: 766 + 2023-01-01: 849.0833333333334 + 2024-01-01: 976.3333333333334 + 2025-01-01: 1_007.6666666666666 + LAMOILLE_COUNTY_VT: + 2021-01-01: 788 + 2022-01-01: 801 + 2023-01-01: 874 + 2024-01-01: 913 + 2025-01-01: 883 + ORANGE_COUNTY_VT: + 2021-01-01: 740 + 2022-01-01: 787 + 2023-01-01: 852 + 2024-01-01: 976 + 2025-01-01: 1_013 + ORLEANS_COUNTY_VT: + 2021-01-01: 592 + 2022-01-01: 638 + 2023-01-01: 706 + 2024-01-01: 831 + 2025-01-01: 845 + RUTLAND_COUNTY_VT: + 2021-01-01: 764 + 2022-01-01: 814 + 2023-01-01: 904 + 2024-01-01: 991 + 2025-01-01: 992 + WASHINGTON_COUNTY_VT: + 2021-01-01: 717 + 2022-01-01: 760 + 2023-01-01: 839 + 2024-01-01: 985 + 2025-01-01: 1_075 + WINDHAM_COUNTY_VT: + 2021-01-01: 697 + 2022-01-01: 734 + 2023-01-01: 803 + 2024-01-01: 976 + 2025-01-01: 1_020 + WINDSOR_COUNTY_VT: + 2021-01-01: 715 + 2022-01-01: 757 + 2023-01-01: 841 + 2024-01-01: 1_039 + 2025-01-01: 1_124 1: ADDISON_COUNTY_VT: 2021-01-01: 846 diff --git a/policyengine_us/parameters/gov/states/wv/tax/income/exemptions/base_personal.yaml b/policyengine_us/parameters/gov/states/wv/tax/income/exemptions/base_personal.yaml index ac4a5c8f5a7..25d6dd1304f 100644 --- a/policyengine_us/parameters/gov/states/wv/tax/income/exemptions/base_personal.yaml +++ b/policyengine_us/parameters/gov/states/wv/tax/income/exemptions/base_personal.yaml @@ -1,12 +1,14 @@ -description: West Virginia provides an income tax exemption of this value for tax units with no exemptions claimed. +description: West Virginia provides this personal income tax exemption for each individual who is claimable as a dependent on another return. values: 1987-01-01: 500 metadata: period: year unit: currency-USD - label: West Virginia personal exemption + label: West Virginia claimable filer personal exemption reference: + - title: 1988 West Virginia H.B. 4472, enacted personal exemptions, pages 9-10 + href: https://code.wvlegislature.gov/signed_bills/1988/1988-RS-HB4472-SUB%20ENR_signed.pdf#page=9 - title: West Virginia Personal Income Tax Forms And Instructions 2025 href: https://tax.wv.gov/Documents/PIT/2025/it140.PersonalIncomeTaxFormsAndInstructions.2025.pdf#page=26 - title: West Virginia Personal Income Tax Forms And Instructions 2024 diff --git a/policyengine_us/reforms/state_dependent_exemptions/repeal_state_dependent_exemptions.py b/policyengine_us/reforms/state_dependent_exemptions/repeal_state_dependent_exemptions.py index d05820bfb6b..1d3a51c7332 100644 --- a/policyengine_us/reforms/state_dependent_exemptions/repeal_state_dependent_exemptions.py +++ b/policyengine_us/reforms/state_dependent_exemptions/repeal_state_dependent_exemptions.py @@ -152,7 +152,10 @@ class ri_exemptions(Variable): def formula(tax_unit, period, parameters): p = parameters(period).gov.states.ri.tax.income.exemption - exemptions_count = tax_unit("head_spouse_count", period) + # Repeal removes dependents, preserving the baseline filer count. + exemptions_count = tax_unit( + "head_spouse_count_not_dependent_elsewhere", period + ) exemption_amount = exemptions_count * p.amount @@ -215,10 +218,26 @@ class wv_personal_exemption(Variable): def formula(tax_unit, period, parameters): p = parameters(period).gov.states.wv.tax.income.exemptions - tax_unit_size = tax_unit("head_spouse_count", period) - return where( - tax_unit_size == 0, p.base_personal, p.personal * tax_unit_size + own_exemptions = tax_unit( + "head_spouse_count_not_dependent_elsewhere", period + ) + # Repeal preserves each childless claimable filer's statutory $500. + # Leave dependent-present allocation unchanged pending resolution. + person = tax_unit.members + claimable_filers = tax_unit.sum( + person("is_tax_unit_head_or_spouse", period) + & person("claimable_as_dependent_on_another_return", period) ) + filer_allowances = ( + p.personal * own_exemptions + p.base_personal * claimable_filers + ) + childless_claimable = (tax_unit("tax_unit_dependents", period) == 0) & ( + claimable_filers > 0 + ) + ordinary_amount = where( + own_exemptions == 0, p.base_personal, p.personal * own_exemptions + ) + return where(childless_claimable, filer_allowances, ordinary_amount) class ca_exemptions(Variable): value_type = float @@ -373,7 +392,6 @@ def formula(tax_unit, period, parameters): ) return exempt_status.base[filing_status] + personal_exemptions_added - # Using head and spouse count instead of exemptions count class wi_base_exemption(Variable): value_type = float entity = TaxUnit @@ -392,7 +410,11 @@ class wi_base_exemption(Variable): def formula(tax_unit, period, parameters): # compute base exemption amount p = parameters(period).gov.states.wi.tax.income - return tax_unit("head_spouse_count", period) * p.exemption.base + # Repeal removes dependents, preserving the baseline filer count. + own_exemptions = tax_unit( + "head_spouse_count_not_dependent_elsewhere", period + ) + return own_exemptions * p.exemption.base class de_personal_credit(Variable): value_type = float diff --git a/policyengine_us/reforms/states/ri/exemption/ri_exemption_reform.py b/policyengine_us/reforms/states/ri/exemption/ri_exemption_reform.py index edd25e32b79..ecf00256286 100644 --- a/policyengine_us/reforms/states/ri/exemption/ri_exemption_reform.py +++ b/policyengine_us/reforms/states/ri/exemption/ri_exemption_reform.py @@ -16,7 +16,10 @@ def formula(tax_unit, period, parameters): person = tax_unit.members age = person("age", period) - is_dependent = person("is_tax_unit_dependent", period) + # Retain the baseline dependent taxpayer test and filing exception. + is_dependent = person("is_tax_unit_dependent", period) & ~person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) # Apply age limit if in effect if p.age_limit.in_effect: @@ -83,7 +86,10 @@ class ri_older_dependents_count(Variable): def formula(tax_unit, period, parameters): person = tax_unit.members - is_dependent = person("is_tax_unit_dependent", period) + # Retain the baseline dependent taxpayer test and filing exception. + is_dependent = person("is_tax_unit_dependent", period) & ~person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) total_dependents = tax_unit.sum(is_dependent) eligible_dependent_exemptions = tax_unit( "ri_eligible_dependents_count", period @@ -101,17 +107,13 @@ class ri_exemptions(Variable): def formula(tax_unit, period, parameters): p_base = parameters(period).gov.states.ri.tax.income.exemption - # Calculate personal exemptions base amount - filing_status = tax_unit("filing_status", period) - older_dependents = tax_unit("ri_older_dependents_count", period) - personal_exemptions = ( - where( - filing_status == filing_status.possible_values.JOINT, - 2, - 1, - ) - + older_dependents + # Preserve the baseline exclusion of claimable filers, even when + # the filing exception permits them to claim their dependents. + own_exemptions = tax_unit( + "head_spouse_count_not_dependent_elsewhere", period ) + older_dependents = tax_unit("ri_older_dependents_count", period) + personal_exemptions = own_exemptions + older_dependents personal_exemption_base = personal_exemptions * p_base.amount # Apply baseline phase-out to personal exemptions diff --git a/policyengine_us/reforms/states/sc/dependent_exemption/sc_dependent_exemption_reform.py b/policyengine_us/reforms/states/sc/dependent_exemption/sc_dependent_exemption_reform.py index ccb3db4039e..f227705ede8 100644 --- a/policyengine_us/reforms/states/sc/dependent_exemption/sc_dependent_exemption_reform.py +++ b/policyengine_us/reforms/states/sc/dependent_exemption/sc_dependent_exemption_reform.py @@ -21,7 +21,11 @@ def formula(tax_unit, period, parameters): period ).gov.states.sc.tax.income.deductions.dependent_exemption.amount person = tax_unit.members - is_dependent = person("is_tax_unit_dependent", period) + # Apply the dependent taxpayer test before either age path, + # preserving the claimant filing exception (IRC 152(b)(1)). + is_dependent = person("is_tax_unit_dependent", period) & ~person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) # Age gate: when in effect, only dependents under the chosen age # are re-priced to the reform amount; older dependents keep the # baseline exemption. Otherwise every dependent is re-priced, diff --git a/policyengine_us/reforms/states/ut/dependent_exemption/ut_dependent_exemption_reform.py b/policyengine_us/reforms/states/ut/dependent_exemption/ut_dependent_exemption_reform.py index 5e4ebc0dccc..da642d21052 100644 --- a/policyengine_us/reforms/states/ut/dependent_exemption/ut_dependent_exemption_reform.py +++ b/policyengine_us/reforms/states/ut/dependent_exemption/ut_dependent_exemption_reform.py @@ -33,7 +33,13 @@ def formula(tax_unit, period, parameters): return p.personal_exemption * total_dependents person = tax_unit.members age = person("age", period) - dependent = person("is_tax_unit_dependent", period) + # A return on which the filer (or, if joint, either spouse) can be + # claimed as a dependent has no dependents (IRC 152(b)(1)) outside + # the claimant filing exception, as in the baseline + # ut_total_dependents. + dependent = person("is_tax_unit_dependent", period) & ~person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) # Dependents under the age threshold (all dependents when the # age limit is off) take the contrib amount; older dependents # keep the baseline (uprated) personal-exemption amount. diff --git a/policyengine_us/reforms/states/vt/dependent_exemption/vt_dependent_exemption_reform.py b/policyengine_us/reforms/states/vt/dependent_exemption/vt_dependent_exemption_reform.py index 35ba6e2a210..69440c7d77b 100644 --- a/policyengine_us/reforms/states/vt/dependent_exemption/vt_dependent_exemption_reform.py +++ b/policyengine_us/reforms/states/vt/dependent_exemption/vt_dependent_exemption_reform.py @@ -15,7 +15,10 @@ def formula(tax_unit, period, parameters): person = tax_unit.members age = person("age", period) - is_dependent = person("is_tax_unit_dependent", period) + # Retain the baseline dependent taxpayer test and filing exception. + is_dependent = person("is_tax_unit_dependent", period) & ~person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) # Apply age limit if in effect if p.age_limit.in_effect: @@ -49,7 +52,11 @@ class vt_older_dependents_count(Variable): def formula(tax_unit, period, parameters): person = tax_unit.members - is_dependent = person("is_tax_unit_dependent", period) + # Mask the fallback too, so disallowed children cannot reappear + # as older dependents after the eligible count is reduced. + is_dependent = person("is_tax_unit_dependent", period) & ~person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) total_dependents = tax_unit.sum(is_dependent) eligible_dependent_exemptions = tax_unit( "vt_eligible_dependents_count", period diff --git a/policyengine_us/reforms/states/wv/dependent_exemption/wv_dependent_exemption_reform.py b/policyengine_us/reforms/states/wv/dependent_exemption/wv_dependent_exemption_reform.py index 933e8deed81..75739319d88 100644 --- a/policyengine_us/reforms/states/wv/dependent_exemption/wv_dependent_exemption_reform.py +++ b/policyengine_us/reforms/states/wv/dependent_exemption/wv_dependent_exemption_reform.py @@ -15,7 +15,10 @@ def formula(tax_unit, period, parameters): person = tax_unit.members age = person("age", period) - is_dependent = person("is_tax_unit_dependent", period) + # Retain the baseline dependent taxpayer test and filing exception. + is_dependent = person("is_tax_unit_dependent", period) & ~person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) # Apply age limit if in effect if p.age_limit.in_effect: @@ -49,7 +52,10 @@ class wv_older_dependents_count(Variable): def formula(tax_unit, period, parameters): person = tax_unit.members - is_dependent = person("is_tax_unit_dependent", period) + # Apply the same gate to the older-dependent fallback. + is_dependent = person("is_tax_unit_dependent", period) & ~person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) total_dependents = tax_unit.sum(is_dependent) eligible_dependent_exemptions = tax_unit( "wv_eligible_dependents_count", period @@ -67,22 +73,38 @@ class wv_personal_exemption(Variable): def formula(tax_unit, period, parameters): p_base = parameters(period).gov.states.wv.tax.income.exemptions - # Personal exemptions exclude the dependent portion (head + spouse + - # any over-age dependents that fall back to the personal count). - tax_unit_size = tax_unit("tax_unit_size", period) - dependents = tax_unit("tax_unit_dependents", period) - older_dependents = tax_unit("wv_older_dependents_count", period) - personal_count = tax_unit_size - dependents + older_dependents - personal_amount = where( - tax_unit_size == 0, - p_base.base_personal, - p_base.personal * personal_count, + # Count ordinary own exemptions separately from dependent eligibility. + own_exemptions = tax_unit( + "head_spouse_count_not_dependent_elsewhere", period ) + older_dependents = tax_unit("wv_older_dependents_count", period) + personal_count = own_exemptions + older_dependents + personal_amount = p_base.personal * personal_count # Add separated dependent exemption. dependent_exemption_amount = tax_unit("wv_dependent_exemption", period) - return personal_amount + dependent_exemption_amount + # Section 11-21-16(d) gives each claimable filer $500 in units + # without dependent members. Preserve existing allocation otherwise. + person = tax_unit.members + claimable_filers = tax_unit.sum( + person("is_tax_unit_head_or_spouse", period) + & person("claimable_as_dependent_on_another_return", period) + ) + filer_allowances = ( + p_base.personal * own_exemptions + + p_base.base_personal * claimable_filers + ) + childless_claimable = (tax_unit("tax_unit_dependents", period) == 0) & ( + claimable_filers > 0 + ) + exemptions = tax_unit("exemptions_count", period) + ordinary_amount = where( + exemptions == 0, + p_base.base_personal, + personal_amount + dependent_exemption_amount, + ) + return where(childless_claimable, filer_allowances, ordinary_amount) class reform(Reform): def apply(self): diff --git a/policyengine_us/tests/core/test_claimable_filer_ri_sc_ut_vt_wv_wi_invariants.py b/policyengine_us/tests/core/test_claimable_filer_ri_sc_ut_vt_wv_wi_invariants.py new file mode 100644 index 00000000000..ba9f165132d --- /dev/null +++ b/policyengine_us/tests/core/test_claimable_filer_ri_sc_ut_vt_wv_wi_invariants.py @@ -0,0 +1,173 @@ +"""Rhode Island, South Carolina, Utah, Vermont, West Virginia and Wisconsin +rules for a filer who can be claimed as a dependent. + +A return on which the filer (or, if joint, either spouse) can be claimed has +no dependents (IRC 152(b)(1)) unless the would-be claimant meets the filing +exception, so the dependent-based amounts below are zero on it. Claimant +rules that turn on an actual claim (RI property tax relief, VT renter credit) +and per-filer exemptions (WV, WI $250) test each spouse separately. + +For couples drawn by Hypothesis (claimable, actually claimed and filing +exception drawn per spouse) and a seeded population in these states: + +1. Swap invariance: each output is the same under either head/spouse + labelling. +2. Monotonicity: marking another filer as claimed never raises the amounts + in MONOTONE. Wisconsin homestead income and the West Virginia family + credit are left out by design: they rise when a dependent deduction or + exemption goes away. +3. Identities: the dependent-based amounts are zero on a return where the + Dependent Taxpayer Test applies; a return whose every filer is actually + claimed gets no RI relief or VT renter credit; and a childless West + Virginia return gets $500 per claimable filer and $2,000 per other filer. + Dependent-present West Virginia allocation retains the existing behavior. +""" + +import numpy as np +import pytest +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +from policyengine_us.tests.core.test_claimable_filer_federal_invariants import ( + check_monotone, + check_swap, +) +from policyengine_us.tests.core.test_dependent_elsewhere_head_spouse_swap_invariance import ( + CLAIM_PATTERNS, + _calc, + _crafted_cases, + _seeded_couples, + adults, + dependents, + money, +) + +STATES = ["RI", "SC", "UT", "VT", "WV", "WI"] +YEARS = [2021, 2023, 2025, 2026] +# Zero on a return where either filer can be claimed (IRC 152(b)(1)). +DEPENDENT_BASED = [ + "ri_child_tax_rebate", + "sc_dependent_exemption", + "sc_young_child_deduction", + "ut_total_dependents", + "ut_personal_exemption", + "ut_at_home_parent_credit_potential", + "vt_ctc", +] +MONOTONE = DEPENDENT_BASED + [ + "ri_property_tax_credit", + "vt_personal_exemptions", + "vt_renter_credit", + "wv_personal_exemption", + "wv_low_income_family_tax_credit_eligible", + "wv_low_income_family_tax_credit_fpg", + "wi_standard_deduction", + "wi_additional_exemption", + "wi_homestead_credit", + "wi_childcare_expense_subtraction", + "wi_childcare_expense_credit_potential", +] +OUTPUTS = MONOTONE + [ + "wv_low_income_family_tax_credit", + "wi_homestead_income", + "wi_retirement_income_exclusion_tax", + "state_income_tax", +] + + +@st.composite +def adults_with_retirement_income(draw): + # Exercise the positive Wisconsin retirement-exclusion path as well as + # earnings-only returns, without changing the other states' generators. + return { + **draw(adults()), + "taxable_pension_income": draw(money(40_000)), + "taxable_ira_distributions": draw(money(20_000)), + } + + +@st.composite +def couples(draw): + claimable = draw(st.sampled_from(CLAIM_PATTERNS)) + claimed = tuple(can and draw(st.booleans()) for can in claimable) + return { + "state": draw(st.sampled_from(STATES)), + "adults": [ + draw(adults_with_retirement_income()), + draw(adults_with_retirement_income()), + ], + "dependents": draw(st.lists(dependents(), max_size=2)), + "claimed": claimed, + "claimable": claimable, + "exception": tuple(not c and draw(st.booleans()) for c in claimed), + } + + +def _identities(sim, year): + no_dependents = ( + _calc( + sim, "head_or_spouse_is_dependent_elsewhere_without_filing_exception", year + ) + > 0 + ) + for name in DEPENDENT_BASED: + values = _calc(sim, name, year) + assert not values[no_dependents].any(), ( + f"{name} in {year} is positive on a return where the Dependent " + "Taxpayer Test applies" + ) + person_claimed = np.asarray( + sim.calculate("claimed_as_dependent_on_another_return", year, map_to="tax_unit") + ) + filers = np.asarray( + sim.calculate("is_tax_unit_head_or_spouse", year, map_to="tax_unit") + ) + every_filer_claimed = (person_claimed >= filers) & (filers > 0) + for name in ["ri_property_tax_credit", "vt_renter_credit"]: + assert not _calc(sim, name, year)[every_filer_claimed].any(), ( + f"{name} in {year} is positive when every filer is claimed" + ) + state = np.asarray(sim.populations["tax_unit"].household("state_code_str", year)) + dependent_count = _calc(sim, "tax_unit_dependents", year) + wv_childless = (state == "WV") & (dependent_count == 0) + own = _calc(sim, "head_spouse_count_not_dependent_elsewhere", year) + np.testing.assert_array_equal( + _calc(sim, "wv_personal_exemption", year)[wv_childless], + (2_000 * own + 500 * (filers - own))[wv_childless], + ) + wv_none = ( + (state == "WV") + & (dependent_count > 0) + & (_calc(sim, "exemptions_count", year) == 0) + ) + np.testing.assert_array_equal( + _calc(sim, "wv_personal_exemption", year)[wv_none], 500 + ) + + +@settings( + max_examples=2, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) +@given(st.sampled_from(YEARS), st.lists(couples(), min_size=6, max_size=12)) +def test_ri_sc_ut_vt_wv_wi_claimable_filer_rules_are_label_free(year, units): + check_swap(units, year, OUTPUTS, _identities) + + +@pytest.mark.parametrize("year", YEARS) +def test_ri_sc_ut_vt_wv_wi_claimable_filer_rules_seeded_population(year): + units = _seeded_couples(STATES, per_state=2) + _crafted_cases(STATES) + rng = np.random.default_rng(20261019) + for unit in units: + unit["adults"] = [ + { + **adult, + "taxable_pension_income": float(rng.choice([0, 8_000, 30_000])), + "taxable_ira_distributions": float(rng.choice([0, 4_000, 12_000])), + } + for adult in unit["adults"] + ] + check_swap(units, year, OUTPUTS, _identities) + check_monotone(units, year, MONOTONE, _identities) diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/credits/property_tax/ri_property_tax_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/credits/property_tax/ri_property_tax_credit.yaml index b9a19ddc96c..073f9801cb1 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/credits/property_tax/ri_property_tax_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/credits/property_tax/ri_property_tax_credit.yaml @@ -88,6 +88,9 @@ tax_unit_size: 1 real_estate_taxes: 2_000 rent: 0 - greater_age_head_spouse: 70 + # The claimant's own age now sets eligibility (R.I. Gen. Laws 44-33-3), + # so the income cutoff alone makes this filer ineligible. + age: 70 output: + ri_property_tax_credit_eligible: false ri_property_tax_credit: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/credits/property_tax/ri_property_tax_credit_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/credits/property_tax/ri_property_tax_credit_eligible.yaml index 4e50ae67af2..d2ea7dffe07 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/credits/property_tax/ri_property_tax_credit_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/credits/property_tax/ri_property_tax_credit_eligible.yaml @@ -1,59 +1,379 @@ - name: Head above minimum age, and disabled period: 2022 input: - state_code: RI - greater_age_head_spouse: 65 - head_is_disabled: true - spouse_is_disabled: false + people: + head: + age: 65 + is_disabled: true + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: RI output: ri_property_tax_credit_eligible: true -- name: Head above minimum age, not diabled +- name: Head above minimum age, not disabled period: 2022 input: - state_code: RI - greater_age_head_spouse: 65 - head_is_disabled: false - spouse_is_disabled: false + people: + head: + age: 65 + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: RI output: ri_property_tax_credit_eligible: true - name: Head disabled, not above minimum age period: 2022 input: - state_code: RI - greater_age_head_spouse: 64 - head_is_disabled: true - spouse_is_disabled: false + people: + head: + age: 64 + is_disabled: true + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: RI output: ri_property_tax_credit_eligible: true - + - name: Spouse above minimum age, not disabled period: 2021 input: - state_code: RI - greater_age_head_spouse: 65 - head_is_disabled: false - spouse_is_disabled: false + people: + head: + age: 64 + spouse: + age: 65 + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [head, spouse] + filing_status: JOINT + households: + household: + members: [head, spouse] + state_code: RI output: ri_property_tax_credit_eligible: true - name: Not above minimum age, not disabled period: 2021 input: - state_code: RI - greater_age_head_spouse: 64 - head_is_disabled: false - spouse_is_disabled: false + people: + head: + age: 64 + spouse: + age: 64 + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [head, spouse] + filing_status: JOINT + households: + household: + members: [head, spouse] + state_code: RI output: ri_property_tax_credit_eligible: false - name: Spouse disabled period: 2021 input: - state_code: RI - greater_age_head_spouse: 64 - head_is_disabled: false - spouse_is_disabled: true + people: + head: + age: 64 + spouse: + age: 64 + is_disabled: true + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [head, spouse] + filing_status: JOINT + households: + household: + members: [head, spouse] + state_code: RI + output: + ri_property_tax_credit_eligible: true + +- name: "2025 single filer who can be claimed as a dependent: property tax relief needs a claimant aged 65 or older or disabled who is not claimed as a dependent" + period: 2025 + input: + people: + filer: + age: 65 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: RI + output: + # R.I. Gen. Laws 44-33-3: the claimant does not include any person + # claimed as a dependent by any taxpayer. + ri_property_tax_credit_eligible: false + ri_property_tax_credit: 0 + +- name: "2025 joint return with one claimable spouse: property tax relief needs a claimant aged 65 or older or disabled who is not claimed as a dependent (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 65 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 65 + real_estate_taxes: 500 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: RI + output: + # The unclaimed spouse, aged 65, may be the claimant (household + # members choose who claims). Household income $0, so the + # threshold is $0; property tax $1,000 is capped at the 2025 + # maximum of $700. + ri_property_tax_credit_eligible: true + ri_property_tax_credit: 700 + +- name: "2025 joint return with one claimable spouse: property tax relief needs a claimant aged 65 or older or disabled who is not claimed as a dependent (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 65 + real_estate_taxes: 500 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 65 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + households: + household: + members: [person_b, person_a] + state_code: RI + output: + ri_property_tax_credit_eligible: true + ri_property_tax_credit: 700 + +- name: "2025 joint return with both spouses claimable: property tax relief needs a claimant aged 65 or older or disabled who is not claimed as a dependent" + period: 2025 + input: + people: + person_a: + age: 65 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 65 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: RI + output: + ri_property_tax_credit_eligible: false + ri_property_tax_credit: 0 + +- name: "2025 joint return with neither spouse claimable: property tax relief needs a claimant aged 65 or older or disabled who is not claimed as a dependent" + period: 2025 + input: + people: + person_a: + age: 65 + real_estate_taxes: 500 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 65 + real_estate_taxes: 500 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: RI + output: + # Same as above: min($1,000 - 0 x 3%, $700) = $700. + ri_property_tax_credit_eligible: true + ri_property_tax_credit: 700 + +- name: "2025 joint return where only the claimable spouse is 65 or older: property tax relief has no eligible claimant (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 65 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 40 + real_estate_taxes: 500 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: RI + output: + # The age test and the dependency test apply to the same claimant, + # so the claimed spouse's age does not qualify the other spouse. + ri_property_tax_credit_eligible: false + ri_property_tax_credit: 0 + +- name: "2025 joint return where only the claimable spouse is 65 or older: property tax relief has no eligible claimant (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 40 + real_estate_taxes: 500 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 65 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + households: + household: + members: [person_b, person_a] + state_code: RI + output: + ri_property_tax_credit_eligible: false + ri_property_tax_credit: 0 + +- name: "2025 joint return where the unclaimed spouse is disabled: property tax relief stays available (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 65 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 40 + is_disabled: true + real_estate_taxes: 500 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: RI + output: + # The disabled, unclaimed spouse is the claimant. + ri_property_tax_credit_eligible: true + ri_property_tax_credit: 700 + +- name: "2025 joint return where the unclaimed spouse is disabled: property tax relief stays available (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 40 + is_disabled: true + real_estate_taxes: 500 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 65 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + households: + household: + members: [person_b, person_a] + state_code: RI + output: + ri_property_tax_credit_eligible: true + ri_property_tax_credit: 700 + +- name: 2025 single filer aged 65 who can be claimed but is not claimed is a Rhode Island property tax relief claimant + period: 2025 + input: + people: + filer: + age: 65 + real_estate_taxes: 1000 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: RI output: + # 44-33-3 excludes a person "claimed as a dependent by any taxpayer": + # an actual claim. min($1,000 - $0, $700) = $700. ri_property_tax_credit_eligible: true + ri_property_tax_credit: 700 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/credits/rebates/ri_child_tax_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/credits/rebates/ri_child_tax_rebate.yaml index a69c04874f5..95f0cd279d6 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/credits/rebates/ri_child_tax_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/credits/rebates/ri_child_tax_rebate.yaml @@ -200,3 +200,168 @@ ri_refundable_credits: 250 # 1,000 before refundable credits - 250 refundable credits = 750. ri_income_tax: 750 + +- name: "2021 single filer who can be claimed as a dependent: the 2021 child tax rebate needs a child validly claimed as a dependent" + period: 2021 + input: + people: + filer: + age: 20 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + child: + age: 4 + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: RI + output: + # R.I. Gen. Laws 44-30-103: $250 for each child the taxpayer validly + # claimed as a dependent; under IRC 152(b)(1) a filer who can be + # claimed has no dependents. + ri_child_tax_rebate: 0 + +- name: "2021 joint return with one claimable spouse: the 2021 child tax rebate needs a child validly claimed as a dependent (the claimable spouse is the head)" + period: 2021 + input: + people: + person_a: + age: 20 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: RI + output: + # On a joint return either spouse being claimable leaves no + # dependents (Publication 501, Dependent Taxpayer Test). + ri_child_tax_rebate: 0 + +- name: "2021 joint return with one claimable spouse: the 2021 child tax rebate needs a child validly claimed as a dependent (the claimable spouse is the spouse)" + period: 2021 + input: + people: + person_b: + age: 20 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: RI + output: + ri_child_tax_rebate: 0 + +- name: "2021 joint return with both spouses claimable: the 2021 child tax rebate needs a child validly claimed as a dependent" + period: 2021 + input: + people: + person_a: + age: 20 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: RI + output: + ri_child_tax_rebate: 0 + +- name: "2021 joint return with neither spouse claimable: the 2021 child tax rebate needs a child validly claimed as a dependent" + period: 2021 + input: + people: + person_a: + age: 20 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: RI + output: + # One child aged 4: min(1, 3) x $250. + ri_child_tax_rebate: 250 + +# Publication 501 claimant filing exception restores the valid dependent. + +- name: 2021 claimable but unclaimed filer whose claimant meets the filing exception keeps the Rhode Island + child rebate + period: 2021 + input: + people: + filer: + age: 22 + employment_income: 8000 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: + age: 4 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: RI + output: + ri_child_tax_rebate: 250 diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tax/income/deductions/sc_young_child_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tax/income/deductions/sc_young_child_deduction.yaml index c7acead018f..09ba8177f9d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/sc/tax/income/deductions/sc_young_child_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tax/income/deductions/sc_young_child_deduction.yaml @@ -72,3 +72,138 @@ # Young child deduction requires child to be under age 6 (ineligible_age = 6) # Child age 6 does NOT qualify - must be younger than 6 sc_young_child_deduction: 0 + +- name: "2025 single filer who can be claimed as a dependent: no South Carolina young child deduction" + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + child: + age: 4 + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: SC + output: + # S.C. Code 12-6-1160 requires a dependent eligible for the South + # Carolina dependent exemption, which a claimable filer has none of. + sc_young_child_deduction: 0 + +- name: "2025 joint return with one claimable spouse: no South Carolina young child deduction (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: SC + output: + sc_young_child_deduction: 0 + +- name: "2025 joint return with one claimable spouse: no South Carolina young child deduction (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: SC + output: + sc_young_child_deduction: 0 + +- name: "2025 joint return with both spouses claimable: no South Carolina young child deduction" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: SC + output: + sc_young_child_deduction: 0 + +- name: "2025 joint return with neither spouse claimable (control): South Carolina young child deduction" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: SC + output: + # One dependent under 6 x $4,930 (2025). + sc_young_child_deduction: 4930 diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tax/income/exemptions/sc_dependent_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tax/income/exemptions/sc_dependent_exemption.yaml index 23771760581..5c8be843c2e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/sc/tax/income/exemptions/sc_dependent_exemption.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tax/income/exemptions/sc_dependent_exemption.yaml @@ -63,3 +63,166 @@ output: # 2025 dependent exemption amount is $4,930; 3 * $4,930 = $14,790. sc_dependent_exemption: 14_790 + +- name: "2025 single filer who can be claimed as a dependent: no South Carolina dependent exemption" + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + child: + age: 4 + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: SC + output: + # S.C. Code 12-6-1140(13) allows the exemption for dependents claimed + # under IRC 151 and 152; IRC 152(b)(1) leaves a claimable filer none. + sc_dependent_exemption: 0 + +- name: "2025 joint return with one claimable spouse: no South Carolina dependent exemption (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: SC + output: + # Either spouse being claimable leaves the joint return no + # dependents (Publication 501, Dependent Taxpayer Test). + sc_dependent_exemption: 0 + +- name: "2025 joint return with one claimable spouse: no South Carolina dependent exemption (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: SC + output: + sc_dependent_exemption: 0 + +- name: "2025 joint return with both spouses claimable: no South Carolina dependent exemption" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: SC + output: + sc_dependent_exemption: 0 + +- name: "2025 joint return with neither spouse claimable (control): South Carolina dependent exemption" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: SC + output: + # One dependent x $4,930 (2025). + sc_dependent_exemption: 4930 + +- name: 2025 single filer who can be claimed but whose would-be claimant meets the filing exception keeps the South Carolina dependent exemption + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 8000 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: + age: 4 + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: SC + output: + # Publication 501, Dependent Taxpayer Test: the bar does not apply when + # the would-be claimant is not required to file and files only for a + # refund. One child aged 4: $4,930 each. + sc_dependent_exemption: 4930 + sc_young_child_deduction: 4930 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/tax/income/credits/ut_at_home_parent_credit_potential.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/tax/income/credits/ut_at_home_parent_credit_potential.yaml new file mode 100644 index 00000000000..1ca288b7054 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/tax/income/credits/ut_at_home_parent_credit_potential.yaml @@ -0,0 +1,219 @@ +- name: "2025 single filer who can be claimed as a dependent: no Utah at-home parent credit" + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 2000 + claimed_as_dependent_on_another_return: true + newborn: + age: 0 + tax_units: + tax_unit: + members: [filer, newborn] + households: + household: + members: [filer, newborn] + state_code: UT + output: + # Utah Code 59-10-1005: the parent must claim the qualifying child as a + # dependent; under IRC 152(b)(1) a claimable filer has no dependents. + ut_at_home_parent_credit_potential: 0 + +- name: "2025 joint return with one claimable spouse: no Utah at-home parent credit (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 2000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 24 + employment_income: 4000 + is_tax_unit_head: false + is_tax_unit_spouse: true + newborn: + age: 0 + tax_units: + tax_unit: + members: [person_a, person_b, newborn] + filing_status: JOINT + households: + household: + members: [person_a, person_b, newborn] + state_code: UT + output: + # Either spouse being claimable leaves the joint return no dependents. + ut_at_home_parent_credit_potential: 0 + +- name: "2025 joint return with one claimable spouse: no Utah at-home parent credit (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 24 + employment_income: 4000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 22 + employment_income: 2000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + newborn: + age: 0 + tax_units: + tax_unit: + members: [person_b, person_a, newborn] + filing_status: JOINT + households: + household: + members: [person_b, person_a, newborn] + state_code: UT + output: + ut_at_home_parent_credit_potential: 0 + +- name: "2025 joint return with both spouses claimable: no Utah at-home parent credit" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 2000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 24 + employment_income: 4000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + newborn: + age: 0 + tax_units: + tax_unit: + members: [person_a, person_b, newborn] + filing_status: JOINT + households: + household: + members: [person_a, person_b, newborn] + state_code: UT + output: + ut_at_home_parent_credit_potential: 0 + +- name: "2025 joint return with neither spouse claimable (control): Utah at-home parent credit" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 2000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 24 + employment_income: 4000 + is_tax_unit_head: false + is_tax_unit_spouse: true + newborn: + age: 0 + tax_units: + tax_unit: + members: [person_a, person_b, newborn] + filing_status: JOINT + households: + household: + members: [person_a, person_b, newborn] + state_code: UT + output: + # One child under 1 x $100 x one parent earning $3,000 or less + # (the other parent earns $4,000); AGI $6,000 is under $50,000. + ut_at_home_parent_credit_potential: 100 + +- name: '2025 joint return with both spouses claimable: no Utah at-home parent credit (head and spouse + labels swapped)' + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 2000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + person_b: + age: 24 + employment_income: 4000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + newborn: + age: 0 + tax_units: + tax_unit: + members: [person_a, person_b, newborn] + filing_status: JOINT + households: + household: + members: [person_a, person_b, newborn] + state_code: UT + output: + ut_at_home_parent_credit_potential: 0 + +- name: '2025 joint return with neither spouse claimable (control): Utah at-home parent credit (head and + spouse labels swapped)' + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 2000 + is_tax_unit_head: false + is_tax_unit_spouse: true + person_b: + age: 24 + employment_income: 4000 + is_tax_unit_head: true + is_tax_unit_spouse: false + newborn: + age: 0 + tax_units: + tax_unit: + members: [person_a, person_b, newborn] + filing_status: JOINT + households: + household: + members: [person_a, person_b, newborn] + state_code: UT + output: + ut_at_home_parent_credit_potential: 100 + +- name: 2025 claimable but unclaimed filer whose claimant meets the filing exception keeps the Utah at-home + parent credit + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 2000 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: + age: 0 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: UT + output: + ut_at_home_parent_credit_potential: 100 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/tax/income/credits/ut_personal_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/tax/income/credits/ut_personal_exemption.yaml index 3e278e3e5a2..c9f16e5b851 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ut/tax/income/credits/ut_personal_exemption.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/tax/income/credits/ut_personal_exemption.yaml @@ -33,3 +33,143 @@ state_code: UT output: ut_personal_exemption: 5_406 # 1802 * 3 + +- name: "2025 single filer who can be claimed as a dependent: no Utah additional dependent for a child born this year" + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + newborn: + age: 0 + tax_units: + tax_unit: + members: [filer, newborn] + households: + household: + members: [filer, newborn] + state_code: UT + output: + # The birth-year dependent (59-10-1018(1)(g)) must also be a dependent + # of the return; IRC 152(b)(1) leaves a claimable filer none. + ut_personal_exemption_additional_dependents: 0 + ut_personal_exemption: 0 + +- name: "2025 joint return with one claimable spouse: no Utah additional dependent for a child born this year (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + newborn: + age: 0 + tax_units: + tax_unit: + members: [person_a, person_b, newborn] + filing_status: JOINT + households: + household: + members: [person_a, person_b, newborn] + state_code: UT + output: + ut_personal_exemption_additional_dependents: 0 + ut_personal_exemption: 0 + +- name: "2025 joint return with one claimable spouse: no Utah additional dependent for a child born this year (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + newborn: + age: 0 + tax_units: + tax_unit: + members: [person_b, person_a, newborn] + filing_status: JOINT + households: + household: + members: [person_b, person_a, newborn] + state_code: UT + output: + ut_personal_exemption_additional_dependents: 0 + ut_personal_exemption: 0 + +- name: "2025 joint return with both spouses claimable: no Utah additional dependent for a child born this year" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + newborn: + age: 0 + tax_units: + tax_unit: + members: [person_a, person_b, newborn] + filing_status: JOINT + households: + household: + members: [person_a, person_b, newborn] + state_code: UT + output: + ut_personal_exemption_additional_dependents: 0 + ut_personal_exemption: 0 + +- name: "2025 joint return with neither spouse claimable (control): Utah additional dependent for a child born this year" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + newborn: + age: 0 + tax_units: + tax_unit: + members: [person_a, person_b, newborn] + filing_status: JOINT + households: + household: + members: [person_a, person_b, newborn] + state_code: UT + output: + # (1 dependent + 1 additional dependent) x $2,111 = $4,222. + ut_personal_exemption_additional_dependents: 1 + ut_personal_exemption: 4222 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/tax/income/credits/ut_total_dependents.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/tax/income/credits/ut_total_dependents.yaml new file mode 100644 index 00000000000..c4366419ade --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/tax/income/credits/ut_total_dependents.yaml @@ -0,0 +1,166 @@ +- name: "2025 single filer who can be claimed as a dependent: no Utah dependents for the taxpayer credit" + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + child: + age: 2 + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: UT + output: + # Utah Code 59-10-1018 counts dependents for whom the claimant is + # entitled to an IRC 24 credit; under IRC 152(b)(1) a claimable filer + # has no dependents. + ut_total_dependents: 0 + ut_personal_exemption: 0 + +- name: "2025 joint return with one claimable spouse: no Utah dependents for the taxpayer credit (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 2 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: UT + output: + # Either spouse being claimable leaves the joint return no dependents. + ut_total_dependents: 0 + ut_personal_exemption: 0 + +- name: "2025 joint return with one claimable spouse: no Utah dependents for the taxpayer credit (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 2 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: UT + output: + ut_total_dependents: 0 + ut_personal_exemption: 0 + +- name: "2025 joint return with both spouses claimable: no Utah dependents for the taxpayer credit" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 2 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: UT + output: + ut_total_dependents: 0 + ut_personal_exemption: 0 + +- name: "2025 joint return with neither spouse claimable (control): Utah dependents for the taxpayer credit" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 2 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: UT + output: + # One dependent x $2,111 (2025). + ut_total_dependents: 1 + ut_personal_exemption: 2111 + +- name: 2025 single filer whose would-be claimant meets the filing exception keeps Utah dependents + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 8000 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: + age: 2 + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: UT + output: + # The federal credit for the child is allowed (Dependent Taxpayer Test + # exception), so the child is a qualifying dependent: 1 x $2,111. + ut_total_dependents: 1 + ut_personal_exemption: 2111 diff --git a/policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/credits/rent/vt_renter_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/credits/rent/vt_renter_credit.yaml index 6a063373d9a..f8c65d7e5c3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/credits/rent/vt_renter_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/credits/rent/vt_renter_credit.yaml @@ -146,6 +146,173 @@ output: vt_renter_credit: 1_692 +- name: "2025 single filer who can be claimed as a dependent: Vermont renter credit needs a claimant who is not claimed as a dependent and sizes rent by personal exemptions" + period: 2025 + input: + people: + filer: + age: 30 + employment_income: 1000 + rent: 12000 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: VT + county: CHITTENDEN_COUNTY_VT + output: + # 32 V.S.A. 6066(c)(2): the claimant may not be a person claimed as a + # dependent by any taxpayer. + vt_renter_credit: 0 + +- name: "2025 joint return with one claimable spouse: Vermont renter credit needs a claimant who is not claimed as a dependent and sizes rent by personal exemptions (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 500 + rent: 6000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 500 + rent: 6000 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: VT + county: CHITTENDEN_COUNTY_VT + output: + # The unclaimed spouse is the claimant. 6066(b)(2) sizes fair market + # rent by the number of personal exemptions: one. Income $1,000 is + # below the full-credit limit: round($1,476 x 12 x 10%) = $1,771. + vt_renter_credit: 1771 + +- name: "2025 joint return with one claimable spouse: Vermont renter credit needs a claimant who is not claimed as a dependent and sizes rent by personal exemptions (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 30 + employment_income: 500 + rent: 6000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + employment_income: 500 + rent: 6000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + households: + household: + members: [person_b, person_a] + state_code: VT + county: CHITTENDEN_COUNTY_VT + output: + vt_renter_credit: 1771 + +- name: "2025 joint return with both spouses claimable: Vermont renter credit needs a claimant who is not claimed as a dependent and sizes rent by personal exemptions" + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 500 + rent: 6000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 500 + rent: 6000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: VT + county: CHITTENDEN_COUNTY_VT + output: + vt_renter_credit: 0 + +- name: "2025 joint return with neither spouse claimable: Vermont renter credit needs a claimant who is not claimed as a dependent and sizes rent by personal exemptions" + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 500 + rent: 6000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 500 + rent: 6000 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: VT + county: CHITTENDEN_COUNTY_VT + output: + # Two exemptions: round($1,936 x 12 x 10%) = $2,323. + vt_renter_credit: 2323 + +- name: 2025 single renter who can be claimed but is not claimed keeps the Vermont renter credit + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 1000 + rent: 12000 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: VT + county: CHITTENDEN_COUNTY_VT + output: + # 6066(c)(2) bars a claimant "claimed as a dependent", an actual claim. + # A filer who can be claimed has no personal exemption; the fair market + # rent uses the zero-bedroom HUD schedule under 6066(b)(2): + # round($1,380 x 12 x 10%) = $1,656. + vt_renter_credit: 1656 + # Franklin and Grand Isle use the state-average fair market rent (32 V.S.A. # 6061(7)(C)). Expected values are the department's Renter Credit Website # Calculators (2022, 2023, 2025), recalculated in LibreOffice for each household: @@ -496,3 +663,327 @@ # Full limit 31,050 = HUD FY2021 extremely low-income limit (PE had 31,040). # Full credit: ROUND(2,083 x 12 x 0.1, 0) = ROUND(2,499.6, 0) = 2,500. vt_renter_credit: 2_500 + +- name: 2021 zero-exemption renter uses HUD zero-bedroom rents in all Vermont counties + period: 2021 + input: + state_code: + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + county: + - ADDISON_COUNTY_VT + - BENNINGTON_COUNTY_VT + - CALEDONIA_COUNTY_VT + - CHITTENDEN_COUNTY_VT + - ESSEX_COUNTY_VT + - FRANKLIN_COUNTY_VT + - GRAND_ISLE_COUNTY_VT + - LAMOILLE_COUNTY_VT + - ORANGE_COUNTY_VT + - ORLEANS_COUNTY_VT + - RUTLAND_COUNTY_VT + - WASHINGTON_COUNTY_VT + - WINDHAM_COUNTY_VT + - WINDSOR_COUNTY_VT + tax_unit_size: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + exemptions_count: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + vt_renter_credit_income: [5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000] + rent_is_shared_with_another_tax_unit: [false, false, false, false, false, false, false, false, false, false, false, false, false, false] + housing_assistance: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + rent: [12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000] + output: + # Each HUD monthly 0BR amount x 12 x 10%, rounded half up. + # Franklin and Grand Isle use the average of Vermont's 12 HUD areas. + vt_renter_credit: + - 901 # ADDISON_COUNTY_VT + - 852 # BENNINGTON_COUNTY_VT + - 850 # CALEDONIA_COUNTY_VT + - 1309 # CHITTENDEN_COUNTY_VT + - 672 # ESSEX_COUNTY_VT + - 883 # FRANKLIN_COUNTY_VT + - 883 # GRAND_ISLE_COUNTY_VT + - 946 # LAMOILLE_COUNTY_VT + - 888 # ORANGE_COUNTY_VT + - 710 # ORLEANS_COUNTY_VT + - 917 # RUTLAND_COUNTY_VT + - 860 # WASHINGTON_COUNTY_VT + - 836 # WINDHAM_COUNTY_VT + - 858 # WINDSOR_COUNTY_VT + +- name: 2022 zero-exemption renter uses HUD zero-bedroom rents in all Vermont counties + period: 2022 + input: + state_code: + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + county: + - ADDISON_COUNTY_VT + - BENNINGTON_COUNTY_VT + - CALEDONIA_COUNTY_VT + - CHITTENDEN_COUNTY_VT + - ESSEX_COUNTY_VT + - FRANKLIN_COUNTY_VT + - GRAND_ISLE_COUNTY_VT + - LAMOILLE_COUNTY_VT + - ORANGE_COUNTY_VT + - ORLEANS_COUNTY_VT + - RUTLAND_COUNTY_VT + - WASHINGTON_COUNTY_VT + - WINDHAM_COUNTY_VT + - WINDSOR_COUNTY_VT + tax_unit_size: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + exemptions_count: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + vt_renter_credit_income: [5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000] + rent_is_shared_with_another_tax_unit: [false, false, false, false, false, false, false, false, false, false, false, false, false, false] + housing_assistance: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + rent: [12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000] + output: + # Each HUD monthly 0BR amount x 12 x 10%, rounded half up. + # Franklin and Grand Isle use the average of Vermont's 12 HUD areas. + vt_renter_credit: + - 935 # ADDISON_COUNTY_VT + - 916 # BENNINGTON_COUNTY_VT + - 889 # CALEDONIA_COUNTY_VT + - 1240 # CHITTENDEN_COUNTY_VT + - 702 # ESSEX_COUNTY_VT + - 919 # FRANKLIN_COUNTY_VT + - 919 # GRAND_ISLE_COUNTY_VT + - 961 # LAMOILLE_COUNTY_VT + - 944 # ORANGE_COUNTY_VT + - 766 # ORLEANS_COUNTY_VT + - 977 # RUTLAND_COUNTY_VT + - 912 # WASHINGTON_COUNTY_VT + - 881 # WINDHAM_COUNTY_VT + - 908 # WINDSOR_COUNTY_VT + +- name: 2023 zero-exemption renter uses HUD zero-bedroom rents in all Vermont counties + period: 2023 + input: + state_code: + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + county: + - ADDISON_COUNTY_VT + - BENNINGTON_COUNTY_VT + - CALEDONIA_COUNTY_VT + - CHITTENDEN_COUNTY_VT + - ESSEX_COUNTY_VT + - FRANKLIN_COUNTY_VT + - GRAND_ISLE_COUNTY_VT + - LAMOILLE_COUNTY_VT + - ORANGE_COUNTY_VT + - ORLEANS_COUNTY_VT + - RUTLAND_COUNTY_VT + - WASHINGTON_COUNTY_VT + - WINDHAM_COUNTY_VT + - WINDSOR_COUNTY_VT + tax_unit_size: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + exemptions_count: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + vt_renter_credit_income: [5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000] + rent_is_shared_with_another_tax_unit: [false, false, false, false, false, false, false, false, false, false, false, false, false, false] + housing_assistance: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + rent: [12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000] + output: + # Each HUD monthly 0BR amount x 12 x 10%, rounded half up. + # Franklin and Grand Isle use the average of Vermont's 12 HUD areas. + vt_renter_credit: + - 1010 # ADDISON_COUNTY_VT + - 1019 # BENNINGTON_COUNTY_VT + - 972 # CALEDONIA_COUNTY_VT + - 1367 # CHITTENDEN_COUNTY_VT + - 876 # ESSEX_COUNTY_VT + - 1019 # FRANKLIN_COUNTY_VT + - 1019 # GRAND_ISLE_COUNTY_VT + - 1049 # LAMOILLE_COUNTY_VT + - 1022 # ORANGE_COUNTY_VT + - 847 # ORLEANS_COUNTY_VT + - 1085 # RUTLAND_COUNTY_VT + - 1007 # WASHINGTON_COUNTY_VT + - 964 # WINDHAM_COUNTY_VT + - 1009 # WINDSOR_COUNTY_VT + +- name: 2024 zero-exemption renter uses HUD zero-bedroom rents in all Vermont counties + period: 2024 + input: + state_code: + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + county: + - ADDISON_COUNTY_VT + - BENNINGTON_COUNTY_VT + - CALEDONIA_COUNTY_VT + - CHITTENDEN_COUNTY_VT + - ESSEX_COUNTY_VT + - FRANKLIN_COUNTY_VT + - GRAND_ISLE_COUNTY_VT + - LAMOILLE_COUNTY_VT + - ORANGE_COUNTY_VT + - ORLEANS_COUNTY_VT + - RUTLAND_COUNTY_VT + - WASHINGTON_COUNTY_VT + - WINDHAM_COUNTY_VT + - WINDSOR_COUNTY_VT + tax_unit_size: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + exemptions_count: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + vt_renter_credit_income: [5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000] + rent_is_shared_with_another_tax_unit: [false, false, false, false, false, false, false, false, false, false, false, false, false, false] + housing_assistance: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + rent: [12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000] + output: + # Each HUD monthly 0BR amount x 12 x 10%, rounded half up. + # Franklin and Grand Isle use the average of Vermont's 12 HUD areas. + vt_renter_credit: + - 1220 # ADDISON_COUNTY_VT + - 1123 # BENNINGTON_COUNTY_VT + - 1079 # CALEDONIA_COUNTY_VT + - 1609 # CHITTENDEN_COUNTY_VT + - 974 # ESSEX_COUNTY_VT + - 1172 # FRANKLIN_COUNTY_VT + - 1172 # GRAND_ISLE_COUNTY_VT + - 1096 # LAMOILLE_COUNTY_VT + - 1171 # ORANGE_COUNTY_VT + - 997 # ORLEANS_COUNTY_VT + - 1189 # RUTLAND_COUNTY_VT + - 1182 # WASHINGTON_COUNTY_VT + - 1171 # WINDHAM_COUNTY_VT + - 1247 # WINDSOR_COUNTY_VT + +- name: 2025 zero-exemption renter uses HUD zero-bedroom rents in all Vermont counties + period: 2025 + input: + state_code: + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + - VT + county: + - ADDISON_COUNTY_VT + - BENNINGTON_COUNTY_VT + - CALEDONIA_COUNTY_VT + - CHITTENDEN_COUNTY_VT + - ESSEX_COUNTY_VT + - FRANKLIN_COUNTY_VT + - GRAND_ISLE_COUNTY_VT + - LAMOILLE_COUNTY_VT + - ORANGE_COUNTY_VT + - ORLEANS_COUNTY_VT + - RUTLAND_COUNTY_VT + - WASHINGTON_COUNTY_VT + - WINDHAM_COUNTY_VT + - WINDSOR_COUNTY_VT + tax_unit_size: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + exemptions_count: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + vt_renter_credit_income: [5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000, 5_000] + rent_is_shared_with_another_tax_unit: [false, false, false, false, false, false, false, false, false, false, false, false, false, false] + housing_assistance: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + rent: [12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000, 12_000] + output: + # Each HUD monthly 0BR amount x 12 x 10%, rounded half up. + # Franklin and Grand Isle use the average of Vermont's 12 HUD areas. + vt_renter_credit: + - 1315 # ADDISON_COUNTY_VT + - 1123 # BENNINGTON_COUNTY_VT + - 1086 # CALEDONIA_COUNTY_VT + - 1656 # CHITTENDEN_COUNTY_VT + - 988 # ESSEX_COUNTY_VT + - 1209 # FRANKLIN_COUNTY_VT + - 1209 # GRAND_ISLE_COUNTY_VT + - 1060 # LAMOILLE_COUNTY_VT + - 1216 # ORANGE_COUNTY_VT + - 1014 # ORLEANS_COUNTY_VT + - 1190 # RUTLAND_COUNTY_VT + - 1290 # WASHINGTON_COUNTY_VT + - 1224 # WINDHAM_COUNTY_VT + - 1349 # WINDSOR_COUNTY_VT + +- name: 2025 Vermont renter income limits count both resident spouses when one spouse is claimed + period: 2025 + input: + people: + unclaimed_spouse: + age: 30 + rent: 6_000 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_spouse: + age: 30 + rent: 6_000 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [unclaimed_spouse, claimed_spouse] + filing_status: JOINT + vt_renter_credit_income: 62_000 + households: + household: + members: [unclaimed_spouse, claimed_spouse] + state_code: VT + county: CHITTENDEN_COUNTY_VT + output: + exemptions_count: 1 + tax_unit_size: 2 + # Resident-family income limits use two people; the fair market rent + # uses one personal exemption. The alternative of one-person income + # limits would deny the credit at this income. + vt_renter_credit: 270 diff --git a/policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/credits/vt_ctc.yaml b/policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/credits/vt_ctc.yaml index 757e825b1e3..8b766141910 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/credits/vt_ctc.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/credits/vt_ctc.yaml @@ -30,27 +30,57 @@ - name: Fully phases out at $175,000. 1000-20*(175000-125000)/1000 = 0 period: 2023 input: - state_code: VT - age: 5 - adjusted_gross_income: 175_000 + people: + parent: + age: 35 + child1: + age: 5 + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 175_000 + households: + household: + members: [parent, child1] + state_code: VT output: vt_ctc: 0 - name: Check we're not creating a negative value. period: 2023 input: - state_code: VT - age: 5 - adjusted_gross_income: 200_000 + people: + parent: + age: 35 + child1: + age: 5 + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 200_000 + households: + household: + members: [parent, child1] + state_code: VT output: vt_ctc: 0 - name: Halfway phased out at $150,000. 1000-20*(150000-125000)/1000 = 500 period: 2023 input: - state_code: VT - age: 5 - adjusted_gross_income: 150_000 + people: + parent: + age: 35 + child1: + age: 5 + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 150_000 + households: + household: + members: [parent, child1] + state_code: VT output: vt_ctc: 500 @@ -58,35 +88,261 @@ - name: S.51 - CTC includes 6-year-olds starting 2025 period: 2025 input: - state_code: VT - age: 6 - adjusted_gross_income: 50_000 + people: + parent: + age: 35 + child1: + age: 6 + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 50_000 + households: + household: + members: [parent, child1] + state_code: VT output: vt_ctc: 1_000 - name: S.51 - CTC still applies to 5-year-olds in 2025 period: 2025 input: - state_code: VT - age: 5 - adjusted_gross_income: 50_000 + people: + parent: + age: 35 + child1: + age: 5 + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 50_000 + households: + household: + members: [parent, child1] + state_code: VT output: vt_ctc: 1_000 - name: S.51 - CTC does not apply to 7-year-olds in 2025 period: 2025 input: - state_code: VT - age: 7 - adjusted_gross_income: 50_000 + people: + parent: + age: 35 + child1: + age: 7 + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 50_000 + households: + household: + members: [parent, child1] + state_code: VT output: vt_ctc: 0 - name: S.51 - CTC did not include 6-year-olds before 2025 period: 2024 input: - state_code: VT - age: 6 - adjusted_gross_income: 50_000 + people: + parent: + age: 35 + child1: + age: 6 + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 50_000 + households: + household: + members: [parent, child1] + state_code: VT + output: + vt_ctc: 0 + +- name: "2025 single filer who can be claimed as a dependent: no Vermont child tax credit" + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 2000 + claimed_as_dependent_on_another_return: true + child: + age: 2 + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: VT output: + # 32 V.S.A. 5830f requires entitlement to the federal child tax credit + # (waiving only the identification-number rules); IRC 152(b)(1) leaves + # a claimable filer no dependents and so no federal credit. vt_ctc: 0 + +- name: "2025 joint return with one claimable spouse: no Vermont child tax credit (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 1000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 1000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 2 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: VT + output: + # Either spouse being claimable leaves the joint return no dependents. + vt_ctc: 0 + +- name: "2025 joint return with one claimable spouse: no Vermont child tax credit (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 22 + employment_income: 1000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 22 + employment_income: 1000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 2 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: VT + output: + vt_ctc: 0 + +- name: "2025 joint return with both spouses claimable: no Vermont child tax credit" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 1000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 1000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 2 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: VT + output: + vt_ctc: 0 + +- name: "2025 joint return with neither spouse claimable (control): Vermont child tax credit" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 1000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 1000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 2 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: VT + output: + # One qualifying child aged 6 or under x $1,000; AGI $2,000 is below + # the $125,000 phase-out start. + vt_ctc: 1000 + +- name: 2025 a young household member who is not a dependent does not count for the Vermont child tax credit + period: 2025 + input: + people: + parent: + age: 30 + employment_income: 2000 + sibling: + age: 5 + is_tax_unit_dependent: false + tax_units: + tax_unit: + members: [parent, sibling] + households: + household: + members: [parent, sibling] + state_code: VT + output: + # 5830f counts qualifying children under IRC 152(c), who are dependents. + vt_ctc: 0 + +# IRC 152(b)(1) does not bar dependents under the claimant filing exception. + +- name: 2025 claimable but unclaimed filer whose claimant meets the filing exception keeps the Vermont + child tax credit + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 2000 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: + age: 2 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: VT + output: + vt_ctc: 1000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/exemptions/vt_personal_exemptions.yaml b/policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/exemptions/vt_personal_exemptions.yaml index 584f51e0e02..7cffbef37a2 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/exemptions/vt_personal_exemptions.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/exemptions/vt_personal_exemptions.yaml @@ -4,6 +4,7 @@ filing_status: JOINT head_is_dependent_elsewhere: true spouse_is_dependent_elsewhere: true + head_or_spouse_is_dependent_elsewhere_without_filing_exception: true tax_unit_count_dependents: 0 state_code: VT output: @@ -15,10 +16,12 @@ filing_status: JOINT head_is_dependent_elsewhere: true spouse_is_dependent_elsewhere: true + head_or_spouse_is_dependent_elsewhere_without_filing_exception: true tax_unit_count_dependents: 2 state_code: VT output: - vt_personal_exemptions: 9_000 # 2*4500 + # IRC 152(b)(1): a return with a claimable filer has no dependents. + vt_personal_exemptions: 0 - name: "Joint household, one claimable elsewhere, with no dependents" period: 2022 @@ -26,6 +29,7 @@ filing_status: JOINT head_is_dependent_elsewhere: true spouse_is_dependent_elsewhere: false + head_or_spouse_is_dependent_elsewhere_without_filing_exception: true tax_unit_count_dependents: 0 state_code: VT output: @@ -37,10 +41,12 @@ filing_status: JOINT head_is_dependent_elsewhere: true spouse_is_dependent_elsewhere: false + head_or_spouse_is_dependent_elsewhere_without_filing_exception: true tax_unit_count_dependents: 2 state_code: VT output: - vt_personal_exemptions: 13_500 # 3*4500 + # The unclaimed spouse only; IRC 152(b)(1) leaves the return no dependents. + vt_personal_exemptions: 4_500 # 1*4500 - name: "Joint household, neither claimable elsewhere, with no dependents" period: 2022 @@ -69,6 +75,7 @@ input: filing_status: SINGLE head_is_dependent_elsewhere: true + head_or_spouse_is_dependent_elsewhere_without_filing_exception: true tax_unit_count_dependents: 0 state_code: VT output: @@ -79,10 +86,12 @@ input: filing_status: SINGLE head_is_dependent_elsewhere: true + head_or_spouse_is_dependent_elsewhere_without_filing_exception: true tax_unit_count_dependents: 2 state_code: VT output: - vt_personal_exemptions: 9_000 # 2*4500 + # IRC 152(b)(1): a filer who can be claimed has no dependents. + vt_personal_exemptions: 0 - name: "Single household, not claimable elsewhere, with no dependents" period: 2022 @@ -143,3 +152,163 @@ state_code: VT output: vt_personal_exemptions: 13_050 # 3*4350 + +- name: "2025 single filer who can be claimed as a dependent: Vermont personal exemptions count only filers who cannot be claimed and, when none can be, the dependents" + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + child: + age: 4 + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: VT + output: + # 32 V.S.A. 5811(21)(C): no exemption for a dependent individual, and + # IRC 152(b)(1) leaves a claimable filer no dependents. + vt_personal_exemptions: 0 + +- name: "2025 joint return with one claimable spouse: Vermont personal exemptions count only filers who cannot be claimed and, when none can be, the dependents (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: VT + output: + # The unclaimed spouse's exemption only: 1 x $5,300. + vt_personal_exemptions: 5300 + +- name: "2025 joint return with one claimable spouse: Vermont personal exemptions count only filers who cannot be claimed and, when none can be, the dependents (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: VT + output: + vt_personal_exemptions: 5300 + +- name: "2025 joint return with both spouses claimable: Vermont personal exemptions count only filers who cannot be claimed and, when none can be, the dependents" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: VT + output: + vt_personal_exemptions: 0 + +- name: "2025 joint return with neither spouse claimable: Vermont personal exemptions count only filers who cannot be claimed and, when none can be, the dependents" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: VT + output: + # 3 exemptions x $5,300 (2025). + vt_personal_exemptions: 15900 + +- name: 2025 single filer who can be claimed but whose would-be claimant meets the filing exception gets Vermont dependent exemptions only + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 8000 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: + age: 4 + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: VT + output: + # No own exemption (the filer can be claimed); the child counts because + # the Dependent Taxpayer Test does not apply: 1 x $5,300. + vt_personal_exemptions: 5300 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_additional_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_additional_exemption.yaml index c97d3f5d799..6677c4c2e6f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_additional_exemption.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_additional_exemption.yaml @@ -1,25 +1,291 @@ - name: Aged head period: 2022 input: - age_head: 65 - state_code: WI + people: + head: + age: 65 + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: WI output: wi_additional_exemption: 250 - name: Aged head and aged spouse period: 2022 input: - age_head: 65 - age_spouse: 65 - state_code: WI + people: + head: + age: 65 + spouse: + age: 65 + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [head, spouse] + filing_status: JOINT + households: + household: + members: [head, spouse] + state_code: WI output: wi_additional_exemption: 500 - name: No aged head or aged spouse period: 2022 input: - age_head: 64 - age_spouse: 64 - state_code: WI + people: + head: + age: 64 + spouse: + age: 64 + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [head, spouse] + filing_status: JOINT + households: + household: + members: [head, spouse] + state_code: WI output: wi_additional_exemption: 0 + +- name: "2025 single filer who can be claimed as a dependent: Wisconsin $250 exemption for a filer aged 65 or older who cannot be claimed" + period: 2025 + input: + people: + filer: + age: 65 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: WI + output: + # Form 1 instructions, line 10b: no $250 exemption for a filer whom + # someone else can claim as a dependent. + wi_additional_exemption: 0 + +- name: "2025 joint return with one claimable spouse: Wisconsin $250 exemption for a filer aged 65 or older who cannot be claimed (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 65 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 65 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WI + output: + # Each spouse is tested separately: only the unclaimed spouse counts. + wi_additional_exemption: 250 + +- name: "2025 joint return with one claimable spouse: Wisconsin $250 exemption for a filer aged 65 or older who cannot be claimed (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 65 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 65 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + households: + household: + members: [person_b, person_a] + state_code: WI + output: + wi_additional_exemption: 250 + +- name: "2025 joint return with both spouses claimable: Wisconsin $250 exemption for a filer aged 65 or older who cannot be claimed" + period: 2025 + input: + people: + person_a: + age: 65 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 65 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WI + output: + wi_additional_exemption: 0 + +- name: "2025 joint return with neither spouse claimable: Wisconsin $250 exemption for a filer aged 65 or older who cannot be claimed" + period: 2025 + input: + people: + person_a: + age: 65 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 65 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WI + output: + # Two filers aged 65 or older x $250. + wi_additional_exemption: 500 + +- name: "2025 joint return where only the claimable spouse is 65 or older: no Wisconsin $250 exemption (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 65 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 40 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WI + output: + wi_additional_exemption: 0 + +- name: "2025 joint return where only the claimable spouse is 65 or older: no Wisconsin $250 exemption (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 40 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 65 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + households: + household: + members: [person_b, person_a] + state_code: WI + output: + wi_additional_exemption: 0 + +- name: 2025 single filer aged 65 who can be claimed but is not claimed gets no Wisconsin $250 exemption + period: 2025 + input: + people: + filer: + age: 65 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: WI + output: + # Line 10b requires the $700 exemption on line 10a, which a filer who + # can be claimed does not get whether or not anyone claims them. + wi_additional_exemption: 0 + +- name: 2025 joint return where one spouse aged 65 can be claimed but is not (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 65 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 65 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WI + output: + # Only the spouse who cannot be claimed gets $250. + wi_additional_exemption: 250 + +- name: 2025 joint return where one spouse aged 65 can be claimed but is not (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 65 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 65 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + households: + household: + members: [person_b, person_a] + state_code: WI + output: + wi_additional_exemption: 250 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_childcare_expense_credit_potential.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_childcare_expense_credit_potential.yaml new file mode 100644 index 00000000000..1b301608797 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_childcare_expense_credit_potential.yaml @@ -0,0 +1,102 @@ +# Disabled-adult care remains eligible when the filer can be claimed. +# The $2,000 childcare is excluded unless the filing exception applies +# or the child is incapable of self-care (IRC 21(b)(1)(B)). + +- name: 2025 claimable filer keeps adult care and only qualifying childcare + period: 2025 + absolute_error_margin: 0.01 + input: + people: + filer: + age: 22 + employment_income: 60000 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: false + child: + age: 4 + is_tax_unit_dependent: true + is_incapable_of_self_care: false + adult: + age: 30 + is_tax_unit_spouse: false + is_tax_unit_dependent: true + is_incapable_of_self_care: true + care_expenses: 1000 + tax_units: + tax_unit: + members: [filer, child, adult] + tax_unit_childcare_expenses: 2000 + households: + household: + members: [filer, child, adult] + state_code: WI + output: + wi_childcare_expense_credit_potential: 200.0 + +- name: 2025 filing exception filer keeps adult care and only qualifying childcare + period: 2025 + absolute_error_margin: 0.01 + input: + people: + filer: + age: 22 + employment_income: 60000 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: + age: 4 + is_tax_unit_dependent: true + is_incapable_of_self_care: false + adult: + age: 30 + is_tax_unit_spouse: false + is_tax_unit_dependent: true + is_incapable_of_self_care: true + care_expenses: 1000 + tax_units: + tax_unit: + members: [filer, child, adult] + tax_unit_childcare_expenses: 2000 + households: + household: + members: [filer, child, adult] + state_code: WI + output: + wi_childcare_expense_credit_potential: 600.0 + +- name: 2025 incapable child filer keeps adult care and only qualifying childcare + period: 2025 + absolute_error_margin: 0.01 + input: + people: + filer: + age: 22 + employment_income: 60000 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: false + child: + age: 4 + is_tax_unit_dependent: true + is_incapable_of_self_care: true + adult: + age: 30 + is_tax_unit_spouse: false + is_tax_unit_dependent: true + is_incapable_of_self_care: true + care_expenses: 1000 + tax_units: + tax_unit: + members: [filer, child, adult] + tax_unit_childcare_expenses: 2000 + households: + household: + members: [filer, child, adult] + state_code: WI + output: + wi_childcare_expense_credit_potential: 600.0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_childcare_expense_subtraction.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_childcare_expense_subtraction.yaml index fc6bfbf91c6..3feb4d685d5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_childcare_expense_subtraction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_childcare_expense_subtraction.yaml @@ -79,3 +79,106 @@ state_code: WI output: wi_childcare_expense_subtraction: 2_000 + +# Disabled-adult care remains eligible when the filer can be claimed. +# The $2,000 childcare is excluded unless the filing exception applies +# or the child is incapable of self-care (IRC 21(b)(1)(B)). + +- name: 2021 claimable filer keeps adult care and only qualifying childcare + period: 2021 + absolute_error_margin: 0.01 + input: + people: + filer: + age: 22 + employment_income: 60000 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: false + child: + age: 4 + is_tax_unit_dependent: true + is_incapable_of_self_care: false + adult: + age: 30 + is_tax_unit_spouse: false + is_tax_unit_dependent: true + is_incapable_of_self_care: true + care_expenses: 1000 + tax_units: + tax_unit: + members: [filer, child, adult] + tax_unit_childcare_expenses: 2000 + households: + household: + members: [filer, child, adult] + state_code: WI + output: + wi_childcare_expense_subtraction: 1000 + +- name: 2021 filing exception filer keeps adult care and only qualifying childcare + period: 2021 + absolute_error_margin: 0.01 + input: + people: + filer: + age: 22 + employment_income: 60000 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: + age: 4 + is_tax_unit_dependent: true + is_incapable_of_self_care: false + adult: + age: 30 + is_tax_unit_spouse: false + is_tax_unit_dependent: true + is_incapable_of_self_care: true + care_expenses: 1000 + tax_units: + tax_unit: + members: [filer, child, adult] + tax_unit_childcare_expenses: 2000 + households: + household: + members: [filer, child, adult] + state_code: WI + output: + wi_childcare_expense_subtraction: 3000 + +- name: 2021 incapable child filer keeps adult care and only qualifying childcare + period: 2021 + absolute_error_margin: 0.01 + input: + people: + filer: + age: 22 + employment_income: 60000 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: false + child: + age: 4 + is_tax_unit_dependent: true + is_incapable_of_self_care: true + adult: + age: 30 + is_tax_unit_spouse: false + is_tax_unit_dependent: true + is_incapable_of_self_care: true + care_expenses: 1000 + tax_units: + tax_unit: + members: [filer, child, adult] + tax_unit_childcare_expenses: 2000 + households: + household: + members: [filer, child, adult] + state_code: WI + output: + wi_childcare_expense_subtraction: 3000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_exemption.yaml index 96a1ec8eddb..17307b8dd1c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_exemption.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_exemption.yaml @@ -1,16 +1,32 @@ - name: WI exemption unit test 1 period: 2021 input: - exemptions_count: 5 - state_code: WI + people: + head: {} + tax_units: + tax_unit: + members: [head] + exemptions_count: 5 + households: + household: + members: [head] + state_code: WI output: wi_exemption: 5 * 700 - name: WI exemption unit test 2 period: 2022 input: - exemptions_count: 5 - age_head: 65 - state_code: WI + people: + head: + age: 65 + tax_units: + tax_unit: + members: [head] + exemptions_count: 5 + households: + household: + members: [head] + state_code: WI output: wi_exemption: 5 * 700 + 250 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_homestead_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_homestead_income.yaml index 744d7253c8a..a979963d4ac 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_homestead_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_homestead_income.yaml @@ -99,3 +99,206 @@ # loss_ald deducts each category's loss on its own, so AGI is 0 and the # add-back is the 5,000 non-SSTB loss. wi_homestead_income: 5_000 + +# Hold TANF at zero to isolate the $500 dependent deduction on wage income. + +- name: "2025 single filer who can be claimed as a dependent: no Wisconsin homestead $500 dependent deduction" + period: 2025 + input: + people: + filer: + age: 62 + employment_income: 10000 + real_estate_taxes: 1000 + claimed_as_dependent_on_another_return: true + child: + age: 4 + spm_units: + spm_unit: + members: [filer, child] + tanf: 0 + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: WI + output: + # The $500 deduction is for a dependent under IRC 152, and a claimant + # who can be claimed has none (IRC 152(b)(1)). The claimant, 62 or + # older, stays eligible: ($1,000 - ($10,000 - $8,060) x 8.785%) x 80%. + wi_homestead_income: 10000 + wi_homestead_credit: 663.6568 + +- name: "2025 joint return with one claimable spouse: no Wisconsin homestead $500 dependent deduction (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 62 + employment_income: 5000 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 62 + employment_income: 5000 + real_estate_taxes: 500 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + spm_units: + spm_unit: + members: [person_a, person_b, child] + tanf: 0 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: WI + output: + # Either spouse being claimable leaves the joint return no dependents. + wi_homestead_income: 10000 + wi_homestead_credit: 663.6568 + +- name: "2025 joint return with one claimable spouse: no Wisconsin homestead $500 dependent deduction (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 62 + employment_income: 5000 + real_estate_taxes: 500 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 62 + employment_income: 5000 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + spm_units: + spm_unit: + members: [person_b, person_a, child] + tanf: 0 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: WI + output: + wi_homestead_income: 10000 + wi_homestead_credit: 663.6568 + +- name: "2025 joint return with both spouses claimable: no Wisconsin homestead $500 dependent deduction" + period: 2025 + input: + people: + person_a: + age: 62 + employment_income: 5000 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 62 + employment_income: 5000 + real_estate_taxes: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + spm_units: + spm_unit: + members: [person_a, person_b, child] + tanf: 0 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: WI + output: + wi_homestead_income: 10000 + wi_homestead_credit: 663.6568 + +- name: "2025 joint return with neither spouse claimable (control): Wisconsin homestead $500 dependent deduction" + period: 2025 + input: + people: + person_a: + age: 62 + employment_income: 5000 + real_estate_taxes: 500 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 62 + employment_income: 5000 + real_estate_taxes: 500 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + spm_units: + spm_unit: + members: [person_a, person_b, child] + tanf: 0 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: WI + output: + # $10,000 - $500 = $9,500; ($1,000 - $1,440 x 8.785%) x 80% = $698.7968. + wi_homestead_income: 9500 + wi_homestead_credit: 698.7968 + +# $10,000 income less the restored $500 dependent deduction. + +- name: 2025 claimant filing exception preserves the Wisconsin homestead dependent deduction + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 10000 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: + age: 4 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: WI + spm_units: + spm_unit: + members: [filer, child] + tanf: 0 + output: + wi_homestead_income: 9500 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_retirement_income_exclusion_tax.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_retirement_income_exclusion_tax.yaml index 2ec7fa9cf4d..ee9f2d1e2cf 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_retirement_income_exclusion_tax.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_retirement_income_exclusion_tax.yaml @@ -219,3 +219,26 @@ # tax = 6,000 * 0.035 = 210. wi_retirement_income_exclusion_amount: 24_000 wi_retirement_income_exclusion_tax: 210 + +# $34,000 WI income - $24,000 exclusion - $4,450 dependent deduction +# - $0 exemption = $5,550, taxed at 3.5% = $194.25. Pension and IRA both qualify. + +- name: 2025 claimable but unclaimed retiree uses the dependent deduction on the positive retirement exclusion + path + period: 2025 + absolute_error_margin: 0.01 + input: + age: 70 + employment_income: 4000 + taxable_pension_income: 20000 + taxable_ira_distributions: 10000 + is_tax_unit_head: true + filing_status: SINGLE + state_code: WI + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + output: + wi_retirement_income_exclusion_amount: 24000 + wi_standard_deduction: 4450 + wi_exemption: 0 + wi_retirement_income_exclusion_tax: 194.25 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_standard_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_standard_deduction.yaml index 24ec29f0189..e3a7516b372 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_standard_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_standard_deduction.yaml @@ -97,3 +97,259 @@ # same amount through the 22.515% and 12% segments that meet at $58,827, # within $0.05 of the schedule. wi_standard_deduction: 13_960 - 0.12 * (70_000 - 20_120) + +- name: "2025 single filer who can be claimed as a dependent: Wisconsin standard deduction limited for a filer who can be claimed" + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 1000 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: WI + output: + # Wis. Stat. 71.05(22)(f): the lesser of the ordinary deduction and + # max($1,350, earned income + $450) = max($1,350, $1,000 + $450). + wi_standard_deduction: 1450 + +- name: "2025 joint return with one claimable spouse: Wisconsin standard deduction limited for a filer who can be claimed (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 500 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WI + output: + # Form 1 worksheet: applies if you or your spouse can be claimed; the + # couple's earned income is $1,000, so $1,450. + wi_standard_deduction: 1450 + +- name: "2025 joint return with one claimable spouse: Wisconsin standard deduction limited for a filer who can be claimed (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 22 + employment_income: 500 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 22 + employment_income: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + households: + household: + members: [person_b, person_a] + state_code: WI + output: + wi_standard_deduction: 1450 + +- name: "2025 joint return with both spouses claimable: Wisconsin standard deduction limited for a filer who can be claimed" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 500 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WI + output: + wi_standard_deduction: 1450 + +- name: "2025 joint return with neither spouse claimable: Wisconsin standard deduction limited for a filer who can be claimed" + period: 2025 + input: + people: + person_a: + age: 22 + employment_income: 500 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + employment_income: 500 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WI + output: + # Joint maximum at WI income $1,000: $25,110 (2025). + wi_standard_deduction: 25110 + +- name: 2025 single filer who cannot be claimed gets the full Wisconsin standard deduction + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 1000 + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: WI + output: + wi_standard_deduction: 13560 + +- name: 2025 single filer who can be claimed and has no earned income gets the Wisconsin dependent floor + period: 2025 + input: + people: + filer: + age: 20 + taxable_interest_income: 2000 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: WI + output: + # max($1,350, $0 + $450) = $1,350. + wi_standard_deduction: 1350 + +- name: "2021 single filer who can be claimed: Wisconsin dependent standard deduction" + period: 2021 + input: + people: + filer: + age: 20 + employment_income: 600 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: WI + output: + # 2021 Form 1 worksheet: max($1,100, $600 + $350) = $1,100. + wi_standard_deduction: 1100 + +- name: "2023 single filer who can be claimed: Wisconsin dependent standard deduction" + period: 2023 + input: + people: + filer: + age: 20 + employment_income: 3000 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: WI + output: + # 2023 Form 1 worksheet: max($1,250, $3,000 + $400) = $3,400. + wi_standard_deduction: 3400 + + +- name: Wisconsin dependent deduction uses wages included in Wisconsin income after pretax retirement contributions + period: 2025 + input: + people: + filer: + age: 22 + is_full_time_student: true + employment_income: 10_000 + traditional_401k_contributions: 5_000 + taxable_interest_income: 10_000 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + spm_units: + spm_unit: + members: [filer] + tanf: 0 + households: + household: + members: [filer] + state_code: WI + output: + # 2025 Form 1 dependent worksheet: WI-included earnings $5,000 + $450. + irs_employment_income: 5_000 + wi_agi: 15_000 + wi_standard_deduction: 5_450 + wi_taxable_income: 9_550 + +- name: Wisconsin caps an unclaimed but claimable filer's standard deduction + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 1_000 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: [filer] + spm_units: + spm_unit: + members: [filer] + tanf: 0 + households: + household: + members: [filer] + state_code: WI + output: + # Claimability, regardless of whether anyone actually claims the filer. + wi_standard_deduction: 1_450 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/tax/income/credits/liftc/wv_low_income_family_tax_credit_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/tax/income/credits/liftc/wv_low_income_family_tax_credit_eligible.yaml index 73a49c95403..d6bf9d58de2 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wv/tax/income/credits/liftc/wv_low_income_family_tax_credit_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/tax/income/credits/liftc/wv_low_income_family_tax_credit_eligible.yaml @@ -13,3 +13,147 @@ alternative_minimum_tax: 0 output: wv_low_income_family_tax_credit_eligible: true + +- name: "2025 single filer who can be claimed as a dependent: West Virginia low-income family tax credit uses the exemptions that may be claimed" + period: 2025 + input: + people: + filer: + age: 30 + employment_income: 16000 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: WV + output: + # W. Va. Code 11-21-22A: family size is the number of exemptions that + # may be legally claimed; with zero exemptions there is no credit. + wv_low_income_family_tax_credit_eligible: false + wv_low_income_family_tax_credit_potential: 0 + +- name: "2025 joint return with one claimable spouse: West Virginia low-income family tax credit uses the exemptions that may be claimed (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WV + output: + # Family size 1: 2025 FPG $15,650. Taxable income $16,000 - $2,500 = + # $13,500; tax $10,000 x 2.22% + $3,500 x 2.96% = $325.60. Income + # exceeds the FPG by $350, so the credit is 80%: $260.48. + wv_low_income_family_tax_credit_eligible: true + wv_low_income_family_tax_credit_fpg: 15650 + wv_personal_exemption: 2500 + wv_taxable_income: 13500 + wv_income_tax_before_non_refundable_credits: 325.6 + wv_low_income_family_tax_credit_potential: 260.48 + +- name: "2025 joint return with one claimable spouse: West Virginia low-income family tax credit uses the exemptions that may be claimed (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 30 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + households: + household: + members: [person_b, person_a] + state_code: WV + output: + wv_low_income_family_tax_credit_eligible: true + wv_low_income_family_tax_credit_fpg: 15650 + wv_personal_exemption: 2500 + wv_taxable_income: 13500 + wv_income_tax_before_non_refundable_credits: 325.6 + wv_low_income_family_tax_credit_potential: 260.48 + +- name: "2025 joint return with both spouses claimable: West Virginia low-income family tax credit uses the exemptions that may be claimed" + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WV + output: + wv_low_income_family_tax_credit_eligible: false + wv_low_income_family_tax_credit_potential: 0 + +- name: "2025 joint return with neither spouse claimable: West Virginia low-income family tax credit uses the exemptions that may be claimed" + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WV + output: + # Family size 2: $15,650 + $5,500 = $21,150. Taxable income $12,000; + # tax $222 + $2,000 x 2.96% = $281.20; income below the FPG: 100%. + wv_low_income_family_tax_credit_eligible: true + wv_low_income_family_tax_credit_fpg: 21150 + wv_income_tax_before_non_refundable_credits: 281.2 + wv_low_income_family_tax_credit_potential: 281.2 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/tax/income/exemptions/wv_personal_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/tax/income/exemptions/wv_personal_exemption.yaml index a41435eb495..19e20f23aff 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wv/tax/income/exemptions/wv_personal_exemption.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/tax/income/exemptions/wv_personal_exemption.yaml @@ -28,3 +28,351 @@ tax_unit_size: 2 output: wv_personal_exemption: 4_000 + +- name: "2025 single filer who can be claimed as a dependent: West Virginia personal exemption counts only exemptions that may be claimed" + period: 2025 + input: + people: + filer: + age: 30 + employment_income: 16000 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: WV + output: + # W. Va. Code 11-21-16 and IRC 151(d)(2): no exemption for a filer who + # can be claimed; section 11-21-16(d) grants that individual $500. + wv_personal_exemption: 500 + +- name: "2025 joint return with one claimable spouse: West Virginia personal exemption counts only exemptions that may be claimed (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WV + output: + # $2,000 for the nonclaimable spouse plus the claimable filer's $500. + wv_personal_exemption: 2500 + +- name: "2025 joint return with one claimable spouse: West Virginia personal exemption counts only exemptions that may be claimed (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 30 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + households: + household: + members: [person_b, person_a] + state_code: WV + output: + wv_personal_exemption: 2500 + +- name: "2025 joint return with both spouses claimable: West Virginia personal exemption counts only exemptions that may be claimed" + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WV + output: + # Section 11-21-16(d) grants each claimable spouse a $500 allowance. + wv_personal_exemption: 1000 + +- name: "2025 joint return with neither spouse claimable: West Virginia personal exemption counts only exemptions that may be claimed" + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: WV + output: + # Two exemptions x $2,000. + wv_personal_exemption: 4000 + +- name: "2025 joint return with one claimable spouse and a child: West Virginia personal exemption has no dependent exemption (the claimable spouse is the head)" + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: WV + output: + # IRC 152(b)(1): either spouse being claimable leaves the return no + # dependents; one exemption x $2,000 (the control below gets $6,000). + wv_personal_exemption: 2000 + +- name: "2025 joint return with one claimable spouse and a child: West Virginia personal exemption has no dependent exemption (the claimable spouse is the spouse)" + period: 2025 + input: + people: + person_b: + age: 30 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + employment_income: 8000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: WV + output: + wv_personal_exemption: 2000 + +- name: "2025 joint return with neither spouse claimable and a child: West Virginia personal exemption" + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 8000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 8000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 4 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: WV + output: + wv_personal_exemption: 6000 + +- name: 2025 single filer who can be claimed but whose would-be claimant meets the filing exception gets a West Virginia dependent exemption + period: 2025 + input: + people: + filer: + age: 22 + employment_income: 16000 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: + age: 4 + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: WV + output: + # No own exemption; one dependent exemption x $2,000, so no $500. + wv_personal_exemption: 2000 + +- name: WV statutory individual allowance - single claimable filer + period: 2025 + input: + people: + filer: + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: + - filer + filing_status: SINGLE + wv_agi: 30000 + wv_low_income_earned_income_exclusion: 0 + households: + household: + members: + - filer + state_code: WV + output: + wv_personal_exemption: 500 + wv_taxable_income: 29500 + +- name: WV statutory individual allowance - claimable head and nonclaimable spouse + period: 2025 + input: + people: + head: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: true + spouse: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: + - head + - spouse + filing_status: JOINT + wv_agi: 30000 + wv_low_income_earned_income_exclusion: 0 + households: + household: + members: + - head + - spouse + state_code: WV + output: + wv_personal_exemption: 2500 + wv_taxable_income: 27500 + +- name: WV statutory individual allowance - two claimable spouses + period: 2025 + input: + people: + head: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: true + spouse: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: + - head + - spouse + filing_status: JOINT + wv_agi: 30000 + wv_low_income_earned_income_exclusion: 0 + households: + household: + members: + - head + - spouse + state_code: WV + output: + wv_personal_exemption: 1000 + wv_taxable_income: 29000 + +- name: WV statutory individual allowance - nonclaimable head and claimable spouse + period: 2025 + input: + people: + head: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: false + spouse: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: + - head + - spouse + filing_status: JOINT + wv_agi: 30000 + wv_low_income_earned_income_exclusion: 0 + households: + household: + members: + - head + - spouse + state_code: WV + output: + wv_personal_exemption: 2500 + wv_taxable_income: 27500 diff --git a/policyengine_us/tests/policy/contrib/state_dependent_exemptions/repeal_state_dependent_exemptions.yaml b/policyengine_us/tests/policy/contrib/state_dependent_exemptions/repeal_state_dependent_exemptions.yaml index 2c9f3842667..da8bbe43114 100644 --- a/policyengine_us/tests/policy/contrib/state_dependent_exemptions/repeal_state_dependent_exemptions.yaml +++ b/policyengine_us/tests/policy/contrib/state_dependent_exemptions/repeal_state_dependent_exemptions.yaml @@ -151,3 +151,330 @@ output: # Baseline keeps the dependent add: 7,600 + 1 x 1,000 + 6,800 = 15,400. ma_income_tax_exemption_threshold: 15_400 + +- name: WV dependent exemption repeal - claimed filer with a child keeps the zero-exemption amount + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: WV}} + output: {wv_personal_exemption: 500} + +- name: WV dependent exemption repeal - claimed childless filer keeps the zero-exemption amount + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + tax_units: {tax_unit: {members: [parent], filing_status: SINGLE}} + households: {household: {members: [parent], state_name: WV}} + output: {wv_personal_exemption: 500} + +- name: WV dependent exemption repeal - unclaimed but claimable childless filer keeps the zero-exemption amount + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: {tax_unit: {members: [parent], filing_status: SINGLE}} + households: {household: {members: [parent], state_name: WV}} + output: {wv_personal_exemption: 500} + +- name: WI repeal - single filer claimed - baseline + period: 2025 + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: false + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_name: WI}} + output: + exemptions_count: 0 + wi_base_exemption: 0 + +- name: WI repeal - single filer claimed - reform + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_name: WI}} + output: + exemptions_count: 0 + wi_base_exemption: 0 + +- name: WI repeal - both joint filers claimed - baseline + period: 2025 + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: false + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + spouse: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + tax_units: {tax_unit: {members: [head, spouse], filing_status: JOINT}} + households: {household: {members: [head, spouse], state_name: WI}} + output: + exemptions_count: 0 + wi_base_exemption: 0 + +- name: WI repeal - both joint filers claimed - reform + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + spouse: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + tax_units: {tax_unit: {members: [head, spouse], filing_status: JOINT}} + households: {household: {members: [head, spouse], state_name: WI}} + output: + exemptions_count: 0 + wi_base_exemption: 0 + +- name: RI repeal - single filer claimed - baseline + period: 2025 + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: false + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + +- name: RI repeal - single filer claimed - reform + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + +- name: WI repeal - single filer unclaimed but claimable - baseline + period: 2025 + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: false + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_name: WI}} + output: + exemptions_count: 0 + wi_base_exemption: 0 + +- name: WI repeal - single filer unclaimed but claimable - reform + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_name: WI}} + output: + exemptions_count: 0 + wi_base_exemption: 0 + +- name: RI repeal - single filer unclaimed but claimable - baseline + period: 2025 + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: false + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + +- name: RI repeal - single filer unclaimed but claimable - reform + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + +- name: WV statutory individual allowance - single claimable filer + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + filer: + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: + - filer + filing_status: SINGLE + wv_agi: 30000 + wv_low_income_earned_income_exclusion: 0 + households: + household: + members: + - filer + state_code: WV + output: + wv_personal_exemption: 500 + wv_taxable_income: 29500 + +- name: WV statutory individual allowance - claimable head and nonclaimable spouse + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: true + spouse: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: + - head + - spouse + filing_status: JOINT + wv_agi: 30000 + wv_low_income_earned_income_exclusion: 0 + households: + household: + members: + - head + - spouse + state_code: WV + output: + wv_personal_exemption: 2500 + wv_taxable_income: 27500 + +- name: WV statutory individual allowance - two claimable spouses + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: true + spouse: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: + - head + - spouse + filing_status: JOINT + wv_agi: 30000 + wv_low_income_earned_income_exclusion: 0 + households: + household: + members: + - head + - spouse + state_code: WV + output: + wv_personal_exemption: 1000 + wv_taxable_income: 29000 + +- name: WV statutory individual allowance - nonclaimable head and claimable spouse + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: false + spouse: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: + - head + - spouse + filing_status: JOINT + wv_agi: 30000 + wv_low_income_earned_income_exclusion: 0 + households: + household: + members: + - head + - spouse + state_code: WV + output: + wv_personal_exemption: 2500 + wv_taxable_income: 27500 diff --git a/policyengine_us/tests/policy/contrib/states/ri/exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/ri/exemption_reform_test.yaml index 0349abe6f45..7afc6a0208b 100644 --- a/policyengine_us/tests/policy/contrib/states/ri/exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/ri/exemption_reform_test.yaml @@ -115,3 +115,295 @@ # Dependent exemption: $0 (set to $0 in reform) # Final: $0 + $0 = $0 ri_exemptions: 0 + +- name: RI exemption reform - young dependent of claimed filer - baseline + period: 2025 + input: + gov.contrib.states.ri.dependent_exemption.in_effect: false + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + +- name: RI exemption reform - young dependent of claimed filer - reform + period: 2025 + reforms: policyengine_us.reforms.states.ri.exemption.ri_exemption_reform.ri_exemption_reform + input: + gov.contrib.states.ri.dependent_exemption.in_effect: true + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + ri_eligible_dependents_count: 0 + ri_older_dependents_count: 0 + +- name: RI exemption reform - young dependent of unclaimed but claimable filer - baseline + period: 2025 + input: + gov.contrib.states.ri.dependent_exemption.in_effect: false + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + +- name: RI exemption reform - young dependent of unclaimed but claimable filer - reform + period: 2025 + reforms: policyengine_us.reforms.states.ri.exemption.ri_exemption_reform.ri_exemption_reform + input: + gov.contrib.states.ri.dependent_exemption.in_effect: true + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + ri_eligible_dependents_count: 0 + ri_older_dependents_count: 0 + +- name: RI exemption reform - older dependent of claimed filer - baseline + period: 2025 + input: + gov.contrib.states.ri.dependent_exemption.in_effect: false + gov.contrib.states.ri.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ri.dependent_exemption.age_limit.threshold: 18 + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + child: {age: 20, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + +- name: RI exemption reform - older dependent of claimed filer - reform + period: 2025 + reforms: policyengine_us.reforms.states.ri.exemption.ri_exemption_reform.ri_exemption_reform + input: + gov.contrib.states.ri.dependent_exemption.in_effect: true + gov.contrib.states.ri.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ri.dependent_exemption.age_limit.threshold: 18 + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + child: {age: 20, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + ri_eligible_dependents_count: 0 + ri_older_dependents_count: 0 + +- name: RI exemption reform - older dependent of unclaimed but claimable filer - baseline + period: 2025 + input: + gov.contrib.states.ri.dependent_exemption.in_effect: false + gov.contrib.states.ri.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ri.dependent_exemption.age_limit.threshold: 18 + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + child: {age: 20, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + +- name: RI exemption reform - older dependent of unclaimed but claimable filer - reform + period: 2025 + reforms: policyengine_us.reforms.states.ri.exemption.ri_exemption_reform.ri_exemption_reform + input: + gov.contrib.states.ri.dependent_exemption.in_effect: true + gov.contrib.states.ri.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.ri.dependent_exemption.age_limit.threshold: 18 + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + child: {age: 20, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + ri_eligible_dependents_count: 0 + ri_older_dependents_count: 0 + +- name: RI exemption reform - joint return with only head claimable - baseline + period: 2025 + input: + gov.contrib.states.ri.dependent_exemption.in_effect: false + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + spouse: + age: 22 + claimable_as_dependent_on_another_return: false + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [head, spouse, child], filing_status: JOINT}} + households: {household: {members: [head, spouse, child], state_name: RI}} + output: + exemptions_count: 1 + ri_exemptions: 5_100 + +- name: RI exemption reform - joint return with only head claimable - reform + period: 2025 + reforms: policyengine_us.reforms.states.ri.exemption.ri_exemption_reform.ri_exemption_reform + input: + gov.contrib.states.ri.dependent_exemption.in_effect: true + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + spouse: + age: 22 + claimable_as_dependent_on_another_return: false + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [head, spouse, child], filing_status: JOINT}} + households: {household: {members: [head, spouse, child], state_name: RI}} + output: + exemptions_count: 1 + ri_exemptions: 5_100 + +- name: RI exemption reform - joint return with only spouse claimable - baseline + period: 2025 + input: + gov.contrib.states.ri.dependent_exemption.in_effect: false + people: + head: + age: 22 + claimable_as_dependent_on_another_return: false + spouse: + age: 22 + claimable_as_dependent_on_another_return: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [head, spouse, child], filing_status: JOINT}} + households: {household: {members: [head, spouse, child], state_name: RI}} + output: + exemptions_count: 1 + ri_exemptions: 5_100 + +- name: RI exemption reform - joint return with only spouse claimable - reform + period: 2025 + reforms: policyengine_us.reforms.states.ri.exemption.ri_exemption_reform.ri_exemption_reform + input: + gov.contrib.states.ri.dependent_exemption.in_effect: true + people: + head: + age: 22 + claimable_as_dependent_on_another_return: false + spouse: + age: 22 + claimable_as_dependent_on_another_return: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [head, spouse, child], filing_status: JOINT}} + households: {household: {members: [head, spouse, child], state_name: RI}} + output: + exemptions_count: 1 + ri_exemptions: 5_100 + +- name: RI exemption reform - joint return with both filers claimable - baseline + period: 2025 + input: + gov.contrib.states.ri.dependent_exemption.in_effect: false + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + spouse: + age: 22 + claimable_as_dependent_on_another_return: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [head, spouse, child], filing_status: JOINT}} + households: {household: {members: [head, spouse, child], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + +- name: RI exemption reform - joint return with both filers claimable - reform + period: 2025 + reforms: policyengine_us.reforms.states.ri.exemption.ri_exemption_reform.ri_exemption_reform + input: + gov.contrib.states.ri.dependent_exemption.in_effect: true + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + spouse: + age: 22 + claimable_as_dependent_on_another_return: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [head, spouse, child], filing_status: JOINT}} + households: {household: {members: [head, spouse, child], state_name: RI}} + output: + exemptions_count: 0 + ri_exemptions: 0 + +- name: RI exemption reform - dependent claimant filing exception preserves child exemption - baseline + period: 2025 + input: + gov.contrib.states.ri.dependent_exemption.in_effect: false + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: RI}} + output: + exemptions_count: 1 + ri_exemptions: 5_100 + +- name: RI exemption reform - dependent claimant filing exception preserves child exemption - reform + period: 2025 + reforms: policyengine_us.reforms.states.ri.exemption.ri_exemption_reform.ri_exemption_reform + input: + gov.contrib.states.ri.dependent_exemption.in_effect: true + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: RI}} + output: + exemptions_count: 1 + ri_exemptions: 5_100 diff --git a/policyengine_us/tests/policy/contrib/states/sc/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/sc/dependent_exemption_reform_test.yaml index b9dd61a79e2..ef737773dc1 100644 --- a/policyengine_us/tests/policy/contrib/states/sc/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/sc/dependent_exemption_reform_test.yaml @@ -89,3 +89,67 @@ households: {household: {members: [parent, child1], state_name: SC}} # Dependent one year under the limit (12 < 13) is re-priced to the reform amount (0). output: {sc_dependent_exemption: 0} + +# IRC 152(b)(1) applies inside the reform as well as in the baseline. +- name: SC dependent exemption reform - claimed filer cannot claim a child at default parameters + period: 2025 + reforms: policyengine_us.reforms.states.sc.dependent_exemption.sc_dependent_exemption_reform.sc_dependent_exemption_reform + input: + gov.contrib.states.sc.dependent_exemption.in_effect: true + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: SC}} + output: {sc_dependent_exemption: 0} + +- name: SC dependent exemption reform - unclaimed but claimable filer cannot claim a child + period: 2025 + reforms: policyengine_us.reforms.states.sc.dependent_exemption.sc_dependent_exemption_reform.sc_dependent_exemption_reform + input: + gov.contrib.states.sc.dependent_exemption.in_effect: true + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: SC}} + output: {sc_dependent_exemption: 0} + +- name: SC dependent exemption reform - claimable filer cannot recover an older dependent exemption + period: 2025 + reforms: policyengine_us.reforms.states.sc.dependent_exemption.sc_dependent_exemption_reform.sc_dependent_exemption_reform + input: + gov.contrib.states.sc.dependent_exemption.in_effect: true + gov.contrib.states.sc.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.sc.dependent_exemption.age_limit.threshold: 13 + people: + parent: + age: 40 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + child: {age: 15, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: SC}} + output: {sc_dependent_exemption: 0} + +- name: SC dependent exemption reform - filing exception permits the child exemption + period: 2025 + reforms: policyengine_us.reforms.states.sc.dependent_exemption.sc_dependent_exemption_reform.sc_dependent_exemption_reform + input: + gov.contrib.states.sc.dependent_exemption.in_effect: true + people: + parent: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: SC}} + output: {sc_dependent_exemption: 4_930} diff --git a/policyengine_us/tests/policy/contrib/states/ut/dependent_exemption/ut_dependent_exemption.yaml b/policyengine_us/tests/policy/contrib/states/ut/dependent_exemption/ut_dependent_exemption.yaml index 49278857c1e..ad1e6ca70af 100644 --- a/policyengine_us/tests/policy/contrib/states/ut/dependent_exemption/ut_dependent_exemption.yaml +++ b/policyengine_us/tests/policy/contrib/states/ut/dependent_exemption/ut_dependent_exemption.yaml @@ -148,3 +148,141 @@ # in_effect is false, so the $0 amount does not apply: two dependents # at the uprated baseline amount. ut_personal_exemption: 4_318 + +- name: Reform in effect counts no dependents on a claimable filer's return (single filer) + period: 2026 + reforms: policyengine_us.reforms.states.ut.dependent_exemption.ut_dependent_exemption_reform + input: + gov.contrib.states.ut.dependent_exemption.in_effect: true + gov.contrib.states.ut.dependent_exemption.amount: 3_000 + people: + filer: + age: 20 + claimed_as_dependent_on_another_return: true + child1: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child1] + households: + household: + members: [filer, child1] + state_code: UT + output: + # IRC 152(b)(1): a filer who can be claimed has no dependents, as in the + # baseline ut_total_dependents. + ut_personal_exemption: 0 + +- name: Reform in effect counts no dependents when one joint spouse can be claimed (the claimable spouse is the spouse) + period: 2026 + reforms: policyengine_us.reforms.states.ut.dependent_exemption.ut_dependent_exemption_reform + input: + gov.contrib.states.ut.dependent_exemption.in_effect: true + gov.contrib.states.ut.dependent_exemption.amount: 3_000 + people: + person_b: + age: 22 + is_tax_unit_head: true + person_a: + age: 20 + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true + child1: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person_b, person_a, child1] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child1] + state_code: UT + output: + ut_personal_exemption: 0 + +- name: Reform in effect counts no dependents when one joint spouse can be claimed (the claimable spouse is the head) + period: 2026 + reforms: policyengine_us.reforms.states.ut.dependent_exemption.ut_dependent_exemption_reform + input: + gov.contrib.states.ut.dependent_exemption.in_effect: true + gov.contrib.states.ut.dependent_exemption.amount: 3_000 + people: + person_a: + age: 20 + is_tax_unit_head: true + claimed_as_dependent_on_another_return: true + person_b: + age: 22 + is_tax_unit_spouse: true + child1: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person_a, person_b, child1] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child1] + state_code: UT + output: + ut_personal_exemption: 0 + +- name: Reform in effect, neither spouse claimable (control) + period: 2026 + reforms: policyengine_us.reforms.states.ut.dependent_exemption.ut_dependent_exemption_reform + input: + gov.contrib.states.ut.dependent_exemption.in_effect: true + gov.contrib.states.ut.dependent_exemption.amount: 3_000 + people: + person_a: + age: 20 + is_tax_unit_head: true + person_b: + age: 22 + is_tax_unit_spouse: true + child1: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person_a, person_b, child1] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child1] + state_code: UT + output: + # One dependent at the reform amount (no age limit): $3,000. + ut_personal_exemption: 3_000 + +- name: Reform in effect, neither spouse claimable (control) (head and spouse labels swapped) + period: 2026 + reforms: policyengine_us.reforms.states.ut.dependent_exemption.ut_dependent_exemption_reform + input: + gov.contrib.states.ut.dependent_exemption.in_effect: true + gov.contrib.states.ut.dependent_exemption.amount: 3000 + people: + person_a: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + person_b: + age: 22 + is_tax_unit_spouse: false + is_tax_unit_head: true + child1: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person_a, person_b, child1] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child1] + state_code: UT + output: + ut_personal_exemption: 3000 diff --git a/policyengine_us/tests/policy/contrib/states/vt/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/vt/dependent_exemption_reform_test.yaml index e87d6f00982..36c9d083418 100644 --- a/policyengine_us/tests/policy/contrib/states/vt/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/vt/dependent_exemption_reform_test.yaml @@ -252,3 +252,80 @@ # VT income tax from 1,221.08 to 1,576.18 (about +355.10). output: vt_income_tax: 1576.18 + +# The dependent taxpayer test masks both reform and older-dependent paths. + +- name: VT dependent exemption reform - claimed filer cannot claim a child at default parameters + period: 2025 + reforms: policyengine_us.reforms.states.vt.dependent_exemption.vt_dependent_exemption_reform.vt_dependent_exemption_reform + input: + gov.contrib.states.vt.dependent_exemption.in_effect: true + people: + parent: + age: 40 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: VT}} + output: + vt_eligible_dependents_count: 0 + vt_older_dependents_count: 0 + vt_personal_exemptions: 0 + +- name: VT dependent exemption reform - unclaimed but claimable filer cannot claim a child + period: 2025 + reforms: policyengine_us.reforms.states.vt.dependent_exemption.vt_dependent_exemption_reform.vt_dependent_exemption_reform + input: + gov.contrib.states.vt.dependent_exemption.in_effect: true + people: + parent: + age: 40 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: VT}} + output: + vt_eligible_dependents_count: 0 + vt_older_dependents_count: 0 + vt_personal_exemptions: 0 + +- name: VT dependent exemption reform - claimable filer cannot recover an older dependent exemption + period: 2025 + reforms: policyengine_us.reforms.states.vt.dependent_exemption.vt_dependent_exemption_reform.vt_dependent_exemption_reform + input: + gov.contrib.states.vt.dependent_exemption.in_effect: true + gov.contrib.states.vt.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.vt.dependent_exemption.age_limit.threshold: 18 + people: + parent: + age: 40 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + child: {age: 20, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: VT}} + output: + vt_eligible_dependents_count: 0 + vt_older_dependents_count: 0 + vt_personal_exemptions: 0 + +- name: VT dependent exemption reform - filing exception permits the child exemption without an own exemption + period: 2025 + reforms: policyengine_us.reforms.states.vt.dependent_exemption.vt_dependent_exemption_reform.vt_dependent_exemption_reform + input: + gov.contrib.states.vt.dependent_exemption.in_effect: true + people: + parent: + age: 40 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: VT}} + output: + vt_eligible_dependents_count: 1 + vt_older_dependents_count: 0 + vt_personal_exemptions: 5_300 diff --git a/policyengine_us/tests/policy/contrib/states/wv/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/wv/dependent_exemption_reform_test.yaml index 69a598e05a0..13e9250e469 100644 --- a/policyengine_us/tests/policy/contrib/states/wv/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/wv/dependent_exemption_reform_test.yaml @@ -136,3 +136,289 @@ # exemption from $6,000 to $2,000 ($4,000 of taxable income added), raising WV # income tax from 1,787.10 to 1,964.70 (about +177.60). output: {wv_income_tax: 1964.70} + +# The dependent taxpayer test masks both reform and older-dependent paths. + +- name: WV dependent exemption reform - claimed filer cannot claim a child at default parameters + period: 2025 + reforms: policyengine_us.reforms.states.wv.dependent_exemption.wv_dependent_exemption_reform.wv_dependent_exemption_reform + input: + gov.contrib.states.wv.dependent_exemption.in_effect: true + people: + parent: + age: 40 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: WV}} + output: + wv_personal_exemption: 500 + wv_eligible_dependents_count: 0 + wv_older_dependents_count: 0 + +- name: WV dependent exemption reform - unclaimed but claimable filer cannot claim a child + period: 2025 + reforms: policyengine_us.reforms.states.wv.dependent_exemption.wv_dependent_exemption_reform.wv_dependent_exemption_reform + input: + gov.contrib.states.wv.dependent_exemption.in_effect: true + people: + parent: + age: 40 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: WV}} + output: + wv_personal_exemption: 500 + wv_eligible_dependents_count: 0 + wv_older_dependents_count: 0 + +- name: WV dependent exemption reform - claimable filer cannot recover an older dependent exemption + period: 2025 + reforms: policyengine_us.reforms.states.wv.dependent_exemption.wv_dependent_exemption_reform.wv_dependent_exemption_reform + input: + gov.contrib.states.wv.dependent_exemption.in_effect: true + gov.contrib.states.wv.dependent_exemption.age_limit.in_effect: true + gov.contrib.states.wv.dependent_exemption.age_limit.threshold: 18 + people: + parent: + age: 40 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: true + child: {age: 20, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: WV}} + output: + wv_personal_exemption: 500 + wv_eligible_dependents_count: 0 + wv_older_dependents_count: 0 + +- name: WV dependent exemption reform - filing exception permits the child exemption without an own exemption + period: 2025 + reforms: policyengine_us.reforms.states.wv.dependent_exemption.wv_dependent_exemption_reform.wv_dependent_exemption_reform + input: + gov.contrib.states.wv.dependent_exemption.in_effect: true + people: + parent: + age: 40 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child], filing_status: SINGLE}} + households: {household: {members: [parent, child], state_name: WV}} + output: + wv_personal_exemption: 2_000 + wv_eligible_dependents_count: 1 + wv_older_dependents_count: 0 + +- name: WV baseline - joint return with one claimable spouse and two children + period: 2025 + input: + people: + parent1: {age: 40, employment_income: 60_000} + parent2: + age: 38 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent1, parent2, child1, child2], filing_status: JOINT}} + households: {household: {members: [parent1, parent2, child1, child2], state_name: WV}} + output: + exemptions_count: 1 + wv_personal_exemption: 2_000 + +- name: WV dependent exemption reform - joint return with one claimable spouse and two children + period: 2025 + reforms: policyengine_us.reforms.states.wv.dependent_exemption.wv_dependent_exemption_reform.wv_dependent_exemption_reform + input: + gov.contrib.states.wv.dependent_exemption.in_effect: true + people: + parent1: {age: 40, employment_income: 60_000} + parent2: + age: 38 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent1, parent2, child1, child2], filing_status: JOINT}} + households: {household: {members: [parent1, parent2, child1, child2], state_name: WV}} + output: + exemptions_count: 1 + wv_personal_exemption: 2_000 + wv_eligible_dependents_count: 0 + wv_older_dependents_count: 0 + +- name: WV baseline - joint return with both spouses claimable and two children + period: 2025 + input: + people: + parent1: + age: 40 + employment_income: 60_000 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + parent2: + age: 38 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent1, parent2, child1, child2], filing_status: JOINT}} + households: {household: {members: [parent1, parent2, child1, child2], state_name: WV}} + output: + exemptions_count: 0 + wv_personal_exemption: 500 + +- name: WV dependent exemption reform - joint return with both spouses claimable and two children + period: 2025 + reforms: policyengine_us.reforms.states.wv.dependent_exemption.wv_dependent_exemption_reform.wv_dependent_exemption_reform + input: + gov.contrib.states.wv.dependent_exemption.in_effect: true + people: + parent1: + age: 40 + employment_income: 60_000 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + parent2: + age: 38 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent1, parent2, child1, child2], filing_status: JOINT}} + households: {household: {members: [parent1, parent2, child1, child2], state_name: WV}} + output: + exemptions_count: 0 + wv_personal_exemption: 500 + wv_eligible_dependents_count: 0 + wv_older_dependents_count: 0 + +- name: WV statutory individual allowance - single claimable filer + period: 2025 + reforms: policyengine_us.reforms.states.wv.dependent_exemption.wv_dependent_exemption_reform.wv_dependent_exemption_reform + input: + gov.contrib.states.wv.dependent_exemption.in_effect: true + gov.contrib.states.wv.dependent_exemption.amount: 0 + people: + filer: + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: + - filer + filing_status: SINGLE + wv_agi: 30000 + wv_low_income_earned_income_exclusion: 0 + households: + household: + members: + - filer + state_code: WV + output: + wv_personal_exemption: 500 + wv_taxable_income: 29500 + +- name: WV statutory individual allowance - claimable head and nonclaimable spouse + period: 2025 + reforms: policyengine_us.reforms.states.wv.dependent_exemption.wv_dependent_exemption_reform.wv_dependent_exemption_reform + input: + gov.contrib.states.wv.dependent_exemption.in_effect: true + gov.contrib.states.wv.dependent_exemption.amount: 0 + people: + head: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: true + spouse: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: + - head + - spouse + filing_status: JOINT + wv_agi: 30000 + wv_low_income_earned_income_exclusion: 0 + households: + household: + members: + - head + - spouse + state_code: WV + output: + wv_personal_exemption: 2500 + wv_taxable_income: 27500 + +- name: WV statutory individual allowance - two claimable spouses + period: 2025 + reforms: policyengine_us.reforms.states.wv.dependent_exemption.wv_dependent_exemption_reform.wv_dependent_exemption_reform + input: + gov.contrib.states.wv.dependent_exemption.in_effect: true + gov.contrib.states.wv.dependent_exemption.amount: 0 + people: + head: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: true + spouse: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: + - head + - spouse + filing_status: JOINT + wv_agi: 30000 + wv_low_income_earned_income_exclusion: 0 + households: + household: + members: + - head + - spouse + state_code: WV + output: + wv_personal_exemption: 1000 + wv_taxable_income: 29000 + +- name: WV statutory individual allowance - nonclaimable head and claimable spouse + period: 2025 + reforms: policyengine_us.reforms.states.wv.dependent_exemption.wv_dependent_exemption_reform.wv_dependent_exemption_reform + input: + gov.contrib.states.wv.dependent_exemption.in_effect: true + gov.contrib.states.wv.dependent_exemption.amount: 0 + people: + head: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: false + spouse: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: + - head + - spouse + filing_status: JOINT + wv_agi: 30000 + wv_low_income_earned_income_exclusion: 0 + households: + household: + members: + - head + - spouse + state_code: WV + output: + wv_personal_exemption: 2500 + wv_taxable_income: 27500 diff --git a/policyengine_us/variables/gov/states/ri/tax/income/credits/property_tax/ri_property_tax_credit_eligible.py b/policyengine_us/variables/gov/states/ri/tax/income/credits/property_tax/ri_property_tax_credit_eligible.py index a69dffa25c4..3294148b8a8 100644 --- a/policyengine_us/variables/gov/states/ri/tax/income/credits/property_tax/ri_property_tax_credit_eligible.py +++ b/policyengine_us/variables/gov/states/ri/tax/income/credits/property_tax/ri_property_tax_credit_eligible.py @@ -14,15 +14,19 @@ class ri_property_tax_credit_eligible(Variable): def formula(tax_unit, period, parameters): p = parameters(period).gov.states.ri.tax.income.credits.property_tax - # minimum age eligibility - greater_head_or_spouse_age = tax_unit("greater_age_head_spouse", period) - age_eligible = greater_head_or_spouse_age >= p.age_threshold - # disability eligibility - head_is_disabled = tax_unit("head_is_disabled", period) - spouse_is_disabled = tax_unit("spouse_is_disabled", period) - head_or_spouse_disabled = head_is_disabled | spouse_is_disabled + person = tax_unit.members + # R.I. Gen. Laws 44-33-3: the claimant is a homeowner or renter aged + # 65 or older or disabled, and "shall not mean or include any person + # claimed as a dependent by any taxpayer". Members of a household choose who + # claims, so either spouse may be the claimant, but the age or + # disability and the dependency test belong to the same person. + filer = person("is_tax_unit_head_or_spouse", period) + age_eligible = person("age", period) >= p.age_threshold + disabled = person("is_disabled", period) + claimed = person("claimed_as_dependent_on_another_return", period) + eligible_claimant = filer & (age_eligible | disabled) & ~claimed household_income = tax_unit("ri_property_tax_household_income", period) income_threshold = p.rate.one_person.thresholds[-1] # The tax form RI-1040H specifies the income of a household as a eligibility requirement household_income_eligible = household_income <= income_threshold - return (age_eligible | head_or_spouse_disabled) & household_income_eligible + return tax_unit.any(eligible_claimant) & household_income_eligible diff --git a/policyengine_us/variables/gov/states/ri/tax/income/credits/rebates/ri_child_tax_rebate.py b/policyengine_us/variables/gov/states/ri/tax/income/credits/rebates/ri_child_tax_rebate.py index 32313e54694..2536eef604d 100644 --- a/policyengine_us/variables/gov/states/ri/tax/income/credits/rebates/ri_child_tax_rebate.py +++ b/policyengine_us/variables/gov/states/ri/tax/income/credits/rebates/ri_child_tax_rebate.py @@ -18,7 +18,15 @@ def formula(tax_unit, period, parameters): dependent = person("is_tax_unit_dependent", period) p = parameters(period).gov.states.ri.tax.income.credits.child_tax_rebate age_eligibility = age <= p.limit.age - eligible_child = age_eligibility & dependent + # R.I. Gen. Laws 44-30-103(b)(1) pays the rebate for each child "whom + # the eligible taxpayer validly claims as a dependent" on the 2021 + # return. Under IRC 152(b)(1) a return on which the filer (or, if + # joint, either spouse) can be claimed as a dependent has none, unless + # the would-be claimant meets the filing exception (Publication 501). + filer_is_dependent = person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + eligible_child = age_eligibility & dependent & ~filer_is_dependent child_count = tax_unit.sum(eligible_child) capped_children = min_(child_count, p.limit.child) return capped_children * p.amount diff --git a/policyengine_us/variables/gov/states/sc/tax/income/deductions/sc_young_child_deduction.py b/policyengine_us/variables/gov/states/sc/tax/income/deductions/sc_young_child_deduction.py index 2e827e9eeea..c1dff53f03b 100644 --- a/policyengine_us/variables/gov/states/sc/tax/income/deductions/sc_young_child_deduction.py +++ b/policyengine_us/variables/gov/states/sc/tax/income/deductions/sc_young_child_deduction.py @@ -20,7 +20,19 @@ def formula(tax_unit, period, parameters): # Determine eligibility for each person in the tax unit. person = tax_unit.members meets_age_limit = person("age", period) < p.ineligible_age - eligible_dependent = meets_age_limit & person("is_tax_unit_dependent", period) + # Section 12-6-1160 requires a "dependent eligible for the South + # Carolina dependent exemption", which a return on which the filer (or, + # if joint, either spouse) can be claimed as a dependent has none of + # (IRC 152(b)(1), incorporated by Section 12-6-1140(13)), unless the + # would-be claimant meets the filing exception (Publication 501). + filer_is_dependent = person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + eligible_dependent = ( + meets_age_limit + & person("is_tax_unit_dependent", period) + & ~filer_is_dependent + ) # Count number of eligible people in the tax unit. total_eligible_dependents = tax_unit.sum(eligible_dependent) # Multiply by the amount per eligible dependent. diff --git a/policyengine_us/variables/gov/states/sc/tax/income/exemptions/sc_dependent_exemption.py b/policyengine_us/variables/gov/states/sc/tax/income/exemptions/sc_dependent_exemption.py index 77c51754adb..1a4a75cab4e 100644 --- a/policyengine_us/variables/gov/states/sc/tax/income/exemptions/sc_dependent_exemption.py +++ b/policyengine_us/variables/gov/states/sc/tax/income/exemptions/sc_dependent_exemption.py @@ -17,7 +17,16 @@ class sc_dependent_exemption(Variable): def formula(tax_unit, period, parameters): # Section 12-6-1140(13): a dependent exemption for every dependent. p = parameters(period).gov.states.sc.tax.income.deductions.dependent_exemption - # every dependent is eligible - dependents = tax_unit("tax_unit_dependents", period) + # Section 12-6-1140(13): "each dependent must meet the eligibility + # requirements of Section 151 and 152", and under IRC 152(b)(1) a + # return on which the filer (or, if joint, either spouse) can be + # claimed as a dependent has no dependents, unless the would-be + # claimant meets the filing exception (Publication 501). + filer_is_dependent = tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + dependents = where( + filer_is_dependent, 0, tax_unit("tax_unit_dependents", period) + ) # Multiply by the amount per exemption. return dependents * p.amount diff --git a/policyengine_us/variables/gov/states/ut/tax/income/credits/taxpayer_credit/ut_personal_exemption_additional_dependent_eligible.py b/policyengine_us/variables/gov/states/ut/tax/income/credits/taxpayer_credit/ut_personal_exemption_additional_dependent_eligible.py index bf3e43f098f..18d7646016b 100644 --- a/policyengine_us/variables/gov/states/ut/tax/income/credits/taxpayer_credit/ut_personal_exemption_additional_dependent_eligible.py +++ b/policyengine_us/variables/gov/states/ut/tax/income/credits/taxpayer_credit/ut_personal_exemption_additional_dependent_eligible.py @@ -13,4 +13,11 @@ def formula(person, period, parameters): is_dependent = person("is_tax_unit_dependent", period) birth_year = person("birth_year", period) born_this_year = birth_year == period.start.year - return is_dependent & born_this_year + # The additional dependent must also be a dependent of the return, and + # a return on which the filer (or, if joint, either spouse) can be + # claimed as a dependent has none (IRC 152(b)(1)), unless the would-be + # claimant meets the filing exception (Publication 501). + filer_is_dependent = person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + return is_dependent & born_this_year & ~filer_is_dependent diff --git a/policyengine_us/variables/gov/states/ut/tax/income/credits/taxpayer_credit/ut_total_dependents.py b/policyengine_us/variables/gov/states/ut/tax/income/credits/taxpayer_credit/ut_total_dependents.py index f9be89959c4..8949b0840ca 100644 --- a/policyengine_us/variables/gov/states/ut/tax/income/credits/taxpayer_credit/ut_total_dependents.py +++ b/policyengine_us/variables/gov/states/ut/tax/income/credits/taxpayer_credit/ut_total_dependents.py @@ -9,4 +9,17 @@ class ut_total_dependents(Variable): documentation = "Form TC-40, line 2c" definition_period = YEAR defined_for = StateCode.UT - adds = ["tax_unit_count_dependents"] + reference = "https://le.utah.gov/xcode/Title59/Chapter10/59-10-S1018.html" + + def formula(tax_unit, period, parameters): + # Utah Code 59-10-1018(1)(c) counts "qualifying dependents": those + # "with respect to whom the claimant is allowed to claim a tax credit + # under Section 24". Under IRC 152(b)(1) a return on which the filer + # (or, if joint, either spouse) can be claimed as a dependent has no + # dependents, and so no such credit, unless the would-be claimant + # meets the filing exception (Publication 501). + filer_is_dependent = tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + dependents = tax_unit("tax_unit_count_dependents", period) + return where(filer_is_dependent, 0, dependents) diff --git a/policyengine_us/variables/gov/states/ut/tax/income/credits/ut_at_home_parent_credit_potential.py b/policyengine_us/variables/gov/states/ut/tax/income/credits/ut_at_home_parent_credit_potential.py index 6e18a6211b7..235bb11ebde 100644 --- a/policyengine_us/variables/gov/states/ut/tax/income/credits/ut_at_home_parent_credit_potential.py +++ b/policyengine_us/variables/gov/states/ut/tax/income/credits/ut_at_home_parent_credit_potential.py @@ -18,7 +18,15 @@ def formula(tax_unit, period, parameters): age = person("age", period) is_dependent = person("is_tax_unit_dependent", period) p = parameters(period).gov.states.ut.tax.income.credits.at_home_parent - qualifying_child = (age < p.max_child_age) & is_dependent + # Utah Code 59-10-1005 requires that the parent claim the qualifying + # child as a dependent. Under IRC 152(b)(1) a return on which the filer + # (or, if joint, either spouse) can be claimed as a dependent has no + # dependents, unless the would-be claimant meets the filing exception + # (Publication 501). + filer_is_dependent = person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + qualifying_child = (age < p.max_child_age) & is_dependent & ~filer_is_dependent count_qualifying_children = tax_unit.sum(qualifying_child) # Multiply by each qualifying parent; they can claim it separately. diff --git a/policyengine_us/variables/gov/states/vt/tax/income/credits/ctc/vt_ctc.py b/policyengine_us/variables/gov/states/vt/tax/income/credits/ctc/vt_ctc.py index 6d58a34dfe1..4562395aa9c 100644 --- a/policyengine_us/variables/gov/states/vt/tax/income/credits/ctc/vt_ctc.py +++ b/policyengine_us/variables/gov/states/vt/tax/income/credits/ctc/vt_ctc.py @@ -11,11 +11,22 @@ class vt_ctc(Variable): defined_for = StateCode.VT def formula(tax_unit, period, parameters): - # Get age status of all people in the tax unit. + # 32 V.S.A. 5830f: a taxpayer entitled to a child tax credit under the + # laws of the United States (or who would be but for the taxpayer + # identification number requirements of IRC 24(e) and (h)(7)) gets the + # credit for each qualifying child under IRC 152(c) at or under the + # age limit. The identification waiver does not reach IRC 152(b)(1): + # a return on which the filer (or, if joint, either spouse) can be + # claimed as a dependent has no dependents and no federal credit, + # unless the would-be claimant meets the filing exception. person = tax_unit.members age = person("age", period) p = parameters(period).gov.states.vt.tax.income.credits.ctc - eligible = age <= p.age_limit + dependent = person("is_tax_unit_dependent", period) + filer_is_dependent = person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + eligible = (age <= p.age_limit) & dependent & ~filer_is_dependent count_eligible = tax_unit.sum(eligible) # Get maximum credit amount. max_credit = p.amount * count_eligible diff --git a/policyengine_us/variables/gov/states/vt/tax/income/credits/renter/vt_renter_credit.py b/policyengine_us/variables/gov/states/vt/tax/income/credits/renter/vt_renter_credit.py index 6284d0a2187..6c0c1c606bb 100644 --- a/policyengine_us/variables/gov/states/vt/tax/income/credits/renter/vt_renter_credit.py +++ b/policyengine_us/variables/gov/states/vt/tax/income/credits/renter/vt_renter_credit.py @@ -8,6 +8,7 @@ class vt_renter_credit(Variable): unit = USD definition_period = YEAR reference = ( + "https://legislature.vermont.gov/statutes/fullchapter/32/154", # 6066(b)(2), (c)(2) "https://law.justia.com/codes/vermont/2022/title-32/chapter-154/section-6066/", # b "https://tax.vermont.gov/sites/tax/files/documents/Income%20Booklet-2022.pdf#page=35", # the formula used in this file is based on the excel sheet provided on the official Vermont government website @@ -19,7 +20,16 @@ def formula(tax_unit, period, parameters): p = parameters(period).gov.states.vt.tax.income.credits.renter # get tax unit size and county. tax_unit_size = tax_unit("tax_unit_size", period) - county = tax_unit.household("county", period) + county = tax_unit.household("county_str", period) + # defined_for masks results after evaluation, so every row needs a + # valid Vermont county while indexing the state-only parameter tables. + in_vt = tax_unit.household("state_code_str", period) == "VT" + county = where(in_vt, county, "ADDISON_COUNTY_VT") + # 32 V.S.A. 6066(b)(2): the fair market rent is for "a number of + # bedrooms equal to the number of personal exemptions" under + # 5811(21)(C), which allows none for a filer who can be claimed as a + # dependent and no dependents on a return where either filer can be. + exemptions = clip(tax_unit("exemptions_count", period), 0, 8) # locate the values by family size and county full_credit_income_limit = p.income_limit_ami.thirty_percent[tax_unit_size][ county @@ -27,7 +37,7 @@ def formula(tax_unit, period, parameters): partial_credit_income_limit = p.income_limit_ami.fifty_percent[tax_unit_size][ county ] - fmr = p.fair_market_rent[tax_unit_size][county] + fmr = p.fair_market_rent[exemptions][county] # The department rounds the credit amount to whole dollars, half up, # before applying the income phase-out: its 2021 calculator computes # ROUND(FMR * 12 * 10%, 0), and its published tables are whole dollars. @@ -79,7 +89,15 @@ def formula(tax_unit, period, parameters): # 6066(b)(1)); 2026 Vt. Act 169 raises this for claim year 2027 only. capped_credit = min_(credit_value, p.max_credit) unrounded = capped_credit * (1 - shared_residence_reduction) + # 6066(c)(2): the claimant "may not be a person claimed as a dependent + # by any taxpayer", an actual claim. On a joint return either spouse + # may be the claimant, so only a return on which every filer is + # claimed loses it. + person = tax_unit.members + filer = person("is_tax_unit_head_or_spouse", period) + claimed = person("claimed_as_dependent_on_another_return", period) + claimant_eligible = tax_unit.any(filer & ~claimed) # The department calculators use ROUND(..., 0): Calculator!G16 in # 2021-2022 and Calculator!G17 in 2023-2025. Credits are nonnegative, # so floor(x + 0.5) matches their half-up rounding at exact ties. - return np.floor(unrounded + 0.5) + return claimant_eligible * np.floor(unrounded + 0.5) diff --git a/policyengine_us/variables/gov/states/vt/tax/income/exemptions/vt_personal_exemptions.py b/policyengine_us/variables/gov/states/vt/tax/income/exemptions/vt_personal_exemptions.py index c93c3526bca..484a862d1a5 100644 --- a/policyengine_us/variables/gov/states/vt/tax/income/exemptions/vt_personal_exemptions.py +++ b/policyengine_us/variables/gov/states/vt/tax/income/exemptions/vt_personal_exemptions.py @@ -18,7 +18,17 @@ def formula(tax_unit, period, parameters): eligible_head = (~elsewhere_head).astype(int) eligible_spouse = (~elsewhere_spouse).astype(int) eligible_count = eligible_head + (eligible_spouse * is_joint) - # add number of other dependents claimed on federal Form 1040 (line 5c) - dependents = tax_unit("tax_unit_count_dependents", period) + # add number of other dependents claimed on federal Form 1040 (line 5c). + # 32 V.S.A. 5811(21)(C): "no exemption may be claimed" for a dependent + # individual, and under IRC 152(b)(1) a return on which the filer (or, + # if joint, either spouse) can be claimed as a dependent has no + # dependents, unless the would-be claimant meets the filing exception + # (Publication 501). + filer_is_dependent = tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + dependents = where( + filer_is_dependent, 0, tax_unit("tax_unit_count_dependents", period) + ) total_exemption_count = eligible_count + dependents return total_exemption_count * p.personal diff --git a/policyengine_us/variables/gov/states/wi/tax/income/credits/childcare_expense/wi_childcare_expense_credit_potential.py b/policyengine_us/variables/gov/states/wi/tax/income/credits/childcare_expense/wi_childcare_expense_credit_potential.py index 3df0c6e0477..a296d445201 100644 --- a/policyengine_us/variables/gov/states/wi/tax/income/credits/childcare_expense/wi_childcare_expense_credit_potential.py +++ b/policyengine_us/variables/gov/states/wi/tax/income/credits/childcare_expense/wi_childcare_expense_credit_potential.py @@ -31,7 +31,11 @@ def formula(tax_unit, period, parameters): # limits, so the §21 employment-related expense definition # applies: childcare plus care for a disabled adult qualifying # individual (care_expenses). - childcare = tax_unit("tax_unit_childcare_expenses", period) + # Only childcare for a qualifying individual counts (IRC + # 21(b)(2)(A)(ii)): outside the claimant filing exception, a + # return whose filer can be claimed has no qualifying child + # under 13 (152(b)(1)), unless incapable of self-care. + childcare = tax_unit("cdcc_qualifying_childcare_expenses", period) adult_care = add(tax_unit, period, ["care_expenses"]) raw_expenses = childcare + adult_care # Cap to WI limit, then also cap to min head/spouse earned (§21(d)) diff --git a/policyengine_us/variables/gov/states/wi/tax/income/credits/homestead/wi_homestead_income.py b/policyengine_us/variables/gov/states/wi/tax/income/credits/homestead/wi_homestead_income.py index 7ab07ce19be..01e5cc637f9 100644 --- a/policyengine_us/variables/gov/states/wi/tax/income/credits/homestead/wi_homestead_income.py +++ b/policyengine_us/variables/gov/states/wi/tax/income/credits/homestead/wi_homestead_income.py @@ -18,5 +18,14 @@ def formula(tax_unit, period, parameters): p = parameters(period).gov.states.wi.tax.income.credits income = add(tax_unit, period, p.homestead.income.sources) disqualified_losses = tax_unit("wi_homestead_disqualified_losses", period) - dependents = tax_unit("tax_unit_dependents", period) + # The $500 deduction is for each dependent under IRC 152; a return on + # which the claimant (or, if joint, either spouse) can be claimed as a + # dependent has none (IRC 152(b)(1)), unless the would-be claimant + # meets the filing exception (Publication 501). + filer_is_dependent = tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + dependents = where( + filer_is_dependent, 0, tax_unit("tax_unit_dependents", period) + ) return income + disqualified_losses - dependents * p.homestead.income.exemption diff --git a/policyengine_us/variables/gov/states/wi/tax/income/exemptions/wi_additional_exemption.py b/policyengine_us/variables/gov/states/wi/tax/income/exemptions/wi_additional_exemption.py index c270c849cba..312251d4477 100644 --- a/policyengine_us/variables/gov/states/wi/tax/income/exemptions/wi_additional_exemption.py +++ b/policyengine_us/variables/gov/states/wi/tax/income/exemptions/wi_additional_exemption.py @@ -13,14 +13,23 @@ class wi_additional_exemption(Variable): "https://www.revenue.wi.gov/TaxForms2022/2022-Form1f.pdf", "https://www.revenue.wi.gov/TaxForms2022/2022-Form1-Inst.pdf", "https://docs.legis.wisconsin.gov/misc/lfb/informational_papers/january_2023/0002_individual_income_tax_informational_paper_2.pdf", + # Lines 10a and 10b + # PDF pages 15-16 + "https://www.revenue.wi.gov/TaxForms2025/2025-Form1-Inst.pdf#page=15", ) defined_for = StateCode.WI def formula(tax_unit, period, parameters): # compute extra exemption amount p = parameters(period).gov.states.wi.tax.income - elderly_head = (tax_unit("age_head", period) >= p.exemption.old_age).astype(int) - elderly_spouse = (tax_unit("age_spouse", period) >= p.exemption.old_age).astype( - int - ) - return (elderly_head + elderly_spouse) * p.exemption.extra + person = tax_unit.members + filer = person("is_tax_unit_head_or_spouse", period) + elderly = person("age", period) >= p.exemption.old_age + # Form 1 instructions, line 10b: the $250 exemption is for "you and/or + # your spouse only if you and/or your spouse are 65 years of age or + # older and are allowed the $700 exemption on line 10a", which a + # filer who can be claimed as a dependent is not, whether or not + # anyone claims that filer. Each spouse is tested separately. + claimable = person("claimable_as_dependent_on_another_return", period) + eligible_filers = tax_unit.sum(filer & elderly & ~claimable) + return eligible_filers * p.exemption.extra diff --git a/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_childcare_expense_subtraction.py b/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_childcare_expense_subtraction.py index 739f18d564c..47feef772ce 100644 --- a/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_childcare_expense_subtraction.py +++ b/policyengine_us/variables/gov/states/wi/tax/income/subtractions/wi_childcare_expense_subtraction.py @@ -19,7 +19,11 @@ def formula(tax_unit, period, parameters): # §71.05(6)(b)43. adopts the IRC §21 employment-related expense # definition, which covers childcare plus care for a disabled adult # qualifying individual (care_expenses). - childcare = tax_unit("tax_unit_childcare_expenses", period) + # Only childcare for a qualifying individual counts (IRC + # 21(b)(2)(A)(ii)): outside the claimant filing exception, a return + # whose filer can be claimed has no qualifying child under 13 + # (152(b)(1)), unless the child is incapable of self-care. + childcare = tax_unit("cdcc_qualifying_childcare_expenses", period) adult_care = add(tax_unit, period, ["care_expenses"]) uncapped_expenses = childcare + adult_care eligible_dependents = tax_unit("count_cdcc_eligible", period) diff --git a/policyengine_us/variables/gov/states/wi/tax/income/wi_retirement_income_exclusion_tax.py b/policyengine_us/variables/gov/states/wi/tax/income/wi_retirement_income_exclusion_tax.py index 031448a3262..6e2f61491cd 100644 --- a/policyengine_us/variables/gov/states/wi/tax/income/wi_retirement_income_exclusion_tax.py +++ b/policyengine_us/variables/gov/states/wi/tax/income/wi_retirement_income_exclusion_tax.py @@ -1,5 +1,6 @@ from policyengine_us.model_api import * from policyengine_us.variables.gov.states.wi.tax.income.wi_standard_deduction import ( + wi_dependent_standard_deduction_limit, wi_standard_deduction_for_income, ) @@ -37,8 +38,13 @@ def formula(tax_unit, period, parameters): fstatus = tax_unit("filing_status", period) wi_agi = tax_unit("wi_agi", period) standard_deduction_full = tax_unit("wi_standard_deduction", period) - standard_deduction_reduced = wi_standard_deduction_for_income( - max_(0, wi_agi - line16 + line17_offset), fstatus, parameters, period + # The dependent limit (71.05(22)(f)) caps the deduction on this path + # too; it depends on earned income, which line 16 does not change. + standard_deduction_reduced = min_( + wi_standard_deduction_for_income( + max_(0, wi_agi - line16 + line17_offset), fstatus, parameters, period + ), + wi_dependent_standard_deduction_limit(tax_unit, period, parameters), ) extra_standard_deduction = standard_deduction_reduced - standard_deduction_full exclusion_taxinc = max_( diff --git a/policyengine_us/variables/gov/states/wi/tax/income/wi_standard_deduction.py b/policyengine_us/variables/gov/states/wi/tax/income/wi_standard_deduction.py index 362bdf7f14b..0a4d1dc6f88 100644 --- a/policyengine_us/variables/gov/states/wi/tax/income/wi_standard_deduction.py +++ b/policyengine_us/variables/gov/states/wi/tax/income/wi_standard_deduction.py @@ -29,6 +29,36 @@ def wi_standard_deduction_for_income(income, filing_status, parameters, period): return max_(0, max_amount - phase_out_amount) +def wi_dependent_standard_deduction_limit(tax_unit, period, parameters): + # Wis. Stat. 71.05(22)(f): for a taxpayer whom another person can claim + # as a dependent, the standard deduction is the lesser of the ordinary + # deduction and the greater of $500 or earned income (IRC 911(d)(2)) plus + # $250, both indexed "in the manner prescribed by sections 1 (f) (3) to + # (6) and 63 (c) (4)" of the IRC, so they equal the federal amounts (Form + # 1 instructions: $1,100 + $350 in 2021 through $1,350 + $450 in 2025). + # The Form 1 worksheet applies when "you (or your spouse if filing a + # joint return) can be claimed", using the return's earned income. + # Returns infinity when no filer can be claimed. + p = parameters(period).gov.irs.deductions.standard.dependent + # Worksheet line 1 uses earnings included in Wisconsin income: wages + # after pretax payroll deductions, plus net self-employment income. + # Non-W-2 scholarship/grant income is excluded from these sources. + earned_income = add( + tax_unit.members, + period, + [ + "irs_employment_income", + "self_employment_income", + "sstb_self_employment_income", + ], + ) + is_filer = ~tax_unit.members("is_tax_unit_dependent", period) + earned_income = max_(tax_unit.sum(earned_income * is_filer), 0) + limit = max_(p.amount, earned_income + p.additional_earned_income) + filer_is_dependent = tax_unit("head_or_spouse_is_dependent_elsewhere", period) + return where(filer_is_dependent, limit, np.inf) + + class wi_standard_deduction(Variable): value_type = float entity = TaxUnit @@ -41,13 +71,19 @@ class wi_standard_deduction(Variable): "https://www.revenue.wi.gov/TaxForms2022/2022-Form1f.pdf", "https://www.revenue.wi.gov/TaxForms2022/2022-Form1-Inst.pdf", "https://docs.legis.wisconsin.gov/misc/lfb/informational_papers/january_2023/0002_individual_income_tax_informational_paper_2.pdf", - # Standard Deduction Table (keyed to WI income, line 7) and the statute, corroborating the phaseout: - "https://www.revenue.wi.gov/TaxForms2025/2025-Form1-inst.pdf#page=35", "https://docs.legis.wisconsin.gov/statutes/statutes/71/i/05/22", + # Dependent worksheet and standard deduction table, PDF pages 15, 35-37 + "https://www.revenue.wi.gov/TaxForms2025/2025-Form1-Inst.pdf#page=15", ) defined_for = StateCode.WI def formula(tax_unit, period, parameters): fstatus = tax_unit("filing_status", period) agi = tax_unit("wi_agi", period) - return wi_standard_deduction_for_income(agi, fstatus, parameters, period) + standard_deduction = wi_standard_deduction_for_income( + agi, fstatus, parameters, period + ) + return min_( + standard_deduction, + wi_dependent_standard_deduction_limit(tax_unit, period, parameters), + ) diff --git a/policyengine_us/variables/gov/states/wv/tax/income/credits/liftc/wv_low_income_family_tax_credit_eligible.py b/policyengine_us/variables/gov/states/wv/tax/income/credits/liftc/wv_low_income_family_tax_credit_eligible.py index 28551572e43..0b45e1eb847 100644 --- a/policyengine_us/variables/gov/states/wv/tax/income/credits/liftc/wv_low_income_family_tax_credit_eligible.py +++ b/policyengine_us/variables/gov/states/wv/tax/income/credits/liftc/wv_low_income_family_tax_credit_eligible.py @@ -6,10 +6,19 @@ class wv_low_income_family_tax_credit_eligible(Variable): entity = TaxUnit label = "Eligible for the West Virginia low-income family tax credit" unit = USD - reference = "https://code.wvlegislature.gov/11-21-22/" + reference = ( + "https://code.wvlegislature.gov/11-21-22/", + "https://code.wvlegislature.gov/11-21-22A/", + "https://tax.wv.gov/Documents/PIT/2025/it140.PersonalIncomeTaxFormsAndInstructions.2025.pdf#page=13", + ) definition_period = YEAR defined_for = StateCode.WV def formula(tax_unit, period, parameters): alternative_minimum_tax = tax_unit("alternative_minimum_tax", period) - return alternative_minimum_tax == 0 + # Family size is the number of exemptions that may be legally claimed + # (W. Va. Code 11-21-22A), so a return with zero exemptions, such as a + # filer who can be claimed as a dependent, cannot claim the credit + # (IT-140 instructions). + has_exemption = tax_unit("exemptions_count", period) > 0 + return (alternative_minimum_tax == 0) & has_exemption diff --git a/policyengine_us/variables/gov/states/wv/tax/income/credits/liftc/wv_low_income_family_tax_credit_fpg.py b/policyengine_us/variables/gov/states/wv/tax/income/credits/liftc/wv_low_income_family_tax_credit_fpg.py index d61d8af8840..3e4e341b9d0 100644 --- a/policyengine_us/variables/gov/states/wv/tax/income/credits/liftc/wv_low_income_family_tax_credit_fpg.py +++ b/policyengine_us/variables/gov/states/wv/tax/income/credits/liftc/wv_low_income_family_tax_credit_fpg.py @@ -9,6 +9,7 @@ class wv_low_income_family_tax_credit_fpg(Variable): ) unit = USD definition_period = YEAR + reference = "https://code.wvlegislature.gov/11-21-22A/" defined_for = "wv_low_income_family_tax_credit_eligible" def formula(tax_unit, period, parameters): @@ -16,8 +17,11 @@ def formula(tax_unit, period, parameters): period ).gov.states.wv.tax.income.credits.liftc # low_income_family_tax_credit - # max family size limit - n = tax_unit("tax_unit_size", period) + # W. Va. Code 11-21-22A: family size is "the total number of exemptions + # that may be legally claimed", not the number of people in the unit. + # A filer who can be claimed as a dependent has no exemption, and a + # return where either filer can be has no dependent exemptions. + n = tax_unit("exemptions_count", period) state_group = tax_unit.household("state_group_str", period) p_fpg = parameters(period).gov.hhs.fpg diff --git a/policyengine_us/variables/gov/states/wv/tax/income/exemptions/wv_personal_exemption.py b/policyengine_us/variables/gov/states/wv/tax/income/exemptions/wv_personal_exemption.py index 4e685595093..b9ea51c6fb2 100644 --- a/policyengine_us/variables/gov/states/wv/tax/income/exemptions/wv_personal_exemption.py +++ b/policyengine_us/variables/gov/states/wv/tax/income/exemptions/wv_personal_exemption.py @@ -8,9 +8,33 @@ class wv_personal_exemption(Variable): defined_for = StateCode.WV unit = USD definition_period = YEAR - reference = "https://code.wvlegislature.gov/11-21/" + reference = ( + "https://code.wvlegislature.gov/11-21-16/", + # Form IT-140 exemptions box (e) and line 6 instructions + # PDF pages 3, 26 + "https://tax.wv.gov/Documents/PIT/2025/it140.PersonalIncomeTaxFormsAndInstructions.2025.pdf#page=3", + ) def formula(tax_unit, period, parameters): p = parameters(period).gov.states.wv.tax.income.exemptions - tax_unit_size = tax_unit("tax_unit_size", period) - return where(tax_unit_size == 0, p.base_personal, p.personal * tax_unit_size) + # Section 11-21-16(d) grants each claimable individual $500. + # Limit this correction to units without dependent members: applying + # the single-exemption limit with dependents requires attribution. + person = tax_unit.members + claimable_filers = tax_unit.sum( + person("is_tax_unit_head_or_spouse", period) + & person("claimable_as_dependent_on_another_return", period) + ) + own_exemptions = tax_unit("head_spouse_count_not_dependent_elsewhere", period) + filer_allowances = ( + p.personal * own_exemptions + p.base_personal * claimable_filers + ) + childless_claimable = (tax_unit("tax_unit_dependents", period) == 0) & ( + claimable_filers > 0 + ) + # Preserve the existing dependent allocation pending resolution. + exemptions = tax_unit("exemptions_count", period) + ordinary_amount = where( + exemptions == 0, p.base_personal, p.personal * exemptions + ) + return where(childless_claimable, filer_allowances, ordinary_amount)