diff --git a/changelog.d/claimable-filer-federal.fixed.md b/changelog.d/claimable-filer-federal.fixed.md new file mode 100644 index 00000000000..82a77ce8992 --- /dev/null +++ b/changelog.d/claimable-filer-federal.fixed.md @@ -0,0 +1 @@ +Apply the federal rules for a filer who can be claimed as a dependent on another return: no child tax credit, credit for other dependents or under-13 care qualifying child (or that child's care expenses) on such a return (IRC 24, 21, 152(b)(1)), no personal exemption for that filer (IRC 151(d)(2)) in the exemption count Rhode Island, Delaware, Ohio, Wisconsin, Oregon, Hawaii and New Mexico read, no recovery rebate for that filer, including under the Armed Forces exception, no tuition and fees deduction (IRC 222(c)(3)), and no education credits or student loan interest deduction on a return with a claimed filer (IRC 25A(g)(3), 221(c)). diff --git a/changelog.d/claimable-filer-nm.fixed.md b/changelog.d/claimable-filer-nm.fixed.md new file mode 100644 index 00000000000..228f3f97b68 --- /dev/null +++ b/changelog.d/claimable-filer-nm.fixed.md @@ -0,0 +1 @@ +Apply New Mexico's rules for a filer who can be claimed as a dependent: no child income tax credit when every filer can be claimed (NMSA 7-2-18.34), no childless EITC, child care credit child or certain-dependents deduction on a return with a claimable filer, and the medical care credit, property tax rebate and centenarian exemption only for a filer who meets the age test and cannot be claimed; the medical expense credit and exemption and the childless EITC now test filers' ages, not a dependent's, and the EITC's child route also counts older qualifying children under IRC 32(c)(3) (a dependent aged 18, a student under 24 or a permanently disabled child). diff --git a/changelog.d/head-dependent-elsewhere-swap.fixed.md b/changelog.d/head-dependent-elsewhere-swap.fixed.md new file mode 100644 index 00000000000..5222c01b901 --- /dev/null +++ b/changelog.d/head-dependent-elsewhere-swap.fixed.md @@ -0,0 +1 @@ +The federal standard deduction and the New York, Michigan, Oregon, Virginia, Missouri, New Mexico, Maine and Hawaii rules for a filer claimed as a dependent elsewhere no longer depend on which spouse is labelled head; each follows its jurisdiction's rule for a joint return where one spouse can be claimed. New York's $3,100 dependent standard deduction now applies only to single filers; Hawaii now limits the standard deduction of a filer who can be claimed as a dependent; the federal EITC without a qualifying child now requires that no filer can be claimed as a dependent; and New Mexico's medical care credit requires a filer who is both 65 or older and not a dependent when a filer is a dependent elsewhere. Separate actual dependency claims from claimability and the nonrequired claimant filing exception, preserving dependent deduction limits while restoring EITC and lawful own-dependent counts. Exclude externally claimable children from Hawaii food/excise ordinary exemptions. diff --git a/policyengine_us/parameters/gov/states/hi/tax/income/deductions/itemized/threshold/dependent.yaml b/policyengine_us/parameters/gov/states/hi/tax/income/deductions/itemized/threshold/dependent.yaml index 0a894e4a148..36300fde6de 100644 --- a/policyengine_us/parameters/gov/states/hi/tax/income/deductions/itemized/threshold/dependent.yaml +++ b/policyengine_us/parameters/gov/states/hi/tax/income/deductions/itemized/threshold/dependent.yaml @@ -1,4 +1,4 @@ -description: Hawaii allows for itemized deductions for dependent filers with deductions above this amount. +description: Hawaii limits the standard deduction of a filer who can be claimed as a dependent to the greater of this amount or earned income, and lets such a filer itemize deductions above that limit. values: 2018-01-01: 500 metadata: @@ -16,6 +16,6 @@ metadata: - title: 2018 Hawaii Resident Income Tax Instructions Itemized Deductions Worksheet href: https://files.hawaii.gov/tax/forms/2018/n11ins.pdf#page=38 - title: Hawaii Income Tax Law, Chapter 235, Section 235-2.4, (a)(3) - href: https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=10 + href: https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=11 - title: 2025 Hawaii N-11 Instructions Itemized Deductions href: https://files.hawaii.gov/tax/forms/current/n11ins.pdf#page=32 diff --git a/policyengine_us/parameters/gov/states/mi/tax/income/exemptions/dependent_on_other_return.yaml b/policyengine_us/parameters/gov/states/mi/tax/income/exemptions/dependent_on_other_return.yaml index 44fbabc57c8..46ca0dabbff 100644 --- a/policyengine_us/parameters/gov/states/mi/tax/income/exemptions/dependent_on_other_return.yaml +++ b/policyengine_us/parameters/gov/states/mi/tax/income/exemptions/dependent_on_other_return.yaml @@ -1,21 +1,10 @@ -description: Michigan provides this exemption amount for a taxpayer who can be claimed as a dependent on someone else’s return. -SINGLE: - 2021-01-01: 1_500 -JOINT: - 2021-01-01: 3_000 -HEAD_OF_HOUSEHOLD: - 2021-01-01: 1_500 -SURVIVING_SPOUSE: - 2021-01-01: 1_500 -SEPARATE: +description: Michigan provides this exemption amount to each individual who can be claimed as a dependent on another taxpayer's return, in place of that individual's personal exemption. +values: 2021-01-01: 1_500 metadata: - propagate_metadata_to_children: true unit: currency-USD period: year - breakdown: - - filing_status - label: Michigan dependent on other return exemption amount + label: Michigan exemption amount per individual claimable as a dependent elsewhere reference: - title: Michigan Legal Code Section 206.30 - (4) href: https://www.legislature.mi.gov/Laws/MCL?objectName=mcl-206-30 diff --git a/policyengine_us/parameters/gov/states/ny/tax/income/deductions/standard/dependent_elsewhere.yaml b/policyengine_us/parameters/gov/states/ny/tax/income/deductions/standard/dependent_elsewhere.yaml index 4744cadf89b..efe6e74704b 100644 --- a/policyengine_us/parameters/gov/states/ny/tax/income/deductions/standard/dependent_elsewhere.yaml +++ b/policyengine_us/parameters/gov/states/ny/tax/income/deductions/standard/dependent_elsewhere.yaml @@ -1,10 +1,10 @@ -description: New York standard deduction for filers who can be claimed as a dependent elsewhere. +description: New York provides this standard deduction to single filers who can be claimed as a dependent on another taxpayer's federal return. values: 2020-01-01: 3_100 metadata: unit: currency-USD period: year - label: New York standard deduction for dependent filers + label: New York standard deduction for single dependent filers reference: - title: 2021 NY Form IT-201 Instructions Line 34 href: https://www.tax.ny.gov/pdf/2021/inc/it201i_2021.pdf#page=19 diff --git a/policyengine_us/reforms/cdcc/cdcc_single_parent_work_requirement.py b/policyengine_us/reforms/cdcc/cdcc_single_parent_work_requirement.py index b83cb1ab43d..a84182005de 100644 --- a/policyengine_us/reforms/cdcc/cdcc_single_parent_work_requirement.py +++ b/policyengine_us/reforms/cdcc/cdcc_single_parent_work_requirement.py @@ -30,7 +30,7 @@ class cdcc_relevant_expenses(Variable): ) def formula(tax_unit, period, parameters): - expenses = tax_unit("tax_unit_childcare_expenses", period) + expenses = tax_unit("cdcc_qualifying_childcare_expenses", period) cdcc_limit = tax_unit("cdcc_limit", period) eligible_capped_expenses = min_(expenses, cdcc_limit) diff --git a/policyengine_us/reforms/congress/watca/working_americans_tax_cut_act.py b/policyengine_us/reforms/congress/watca/working_americans_tax_cut_act.py index 860462a6ed5..27becb3a73f 100644 --- a/policyengine_us/reforms/congress/watca/working_americans_tax_cut_act.py +++ b/policyengine_us/reforms/congress/watca/working_americans_tax_cut_act.py @@ -52,7 +52,11 @@ class watca_alternative_tax_eligible(Variable): label = "Eligible for WATCA alternative maximum tax" definition_period = YEAR reference = WATCA_REFERENCES - documentation = "Section 1A(b): MAGI < 175% of exemption, and not claimed as dependent on another return." + documentation = ( + "Section 1A(b): MAGI < 175% of exemption. Retains the reform's " + "modeled actual-dependent-claim restriction, which is not stated " + "in the cited bill's section 1A(b)(2)." + ) def formula(tax_unit, period, parameters): magi = tax_unit("watca_alternative_tax_magi", period) @@ -61,9 +65,10 @@ def formula(tax_unit, period, parameters): exemption_amount = p.amount[filing_status] income_limit = exemption_amount * p.income_limit_multiple income_eligible = magi < income_limit - head_dependent = tax_unit("head_is_dependent_elsewhere", period) - spouse_dependent = tax_unit("spouse_is_dependent_elsewhere", period) - not_dependent = ~head_dependent & ~spouse_dependent + person = tax_unit.members + claimed = person("claimed_as_dependent_on_another_return", period) + filer = person("is_tax_unit_head_or_spouse", period) + not_dependent = ~tax_unit.any(claimed & filer) return income_eligible & not_dependent class watca_alternative_max_tax(Variable): diff --git a/policyengine_us/reforms/reconciliation/reconciled_ssn_for_llc_and_aoc.py b/policyengine_us/reforms/reconciliation/reconciled_ssn_for_llc_and_aoc.py index 86740f80b31..b145dbd15f7 100644 --- a/policyengine_us/reforms/reconciliation/reconciled_ssn_for_llc_and_aoc.py +++ b/policyengine_us/reforms/reconciliation/reconciled_ssn_for_llc_and_aoc.py @@ -25,8 +25,15 @@ def formula(tax_unit, period, parameters): is_aoc_eligible = person( "is_eligible_for_american_opportunity_credit", period ) + # This reform leaves the dependency rules of IRC 25A(g)(3) and + # 25A(f)(1)(A)(iii) in place. + barred_by_dependency = person( + "is_barred_from_education_credits_by_dependency", period + ) eligible_expenses = tax_unit.sum( - person("qualified_tuition_expenses", period) * ~is_aoc_eligible + person("qualified_tuition_expenses", period) + * ~is_aoc_eligible + * ~barred_by_dependency ) capped_expenses = min_(llc.expense_limit, eligible_expenses) maximum_amount = llc.rate * capped_expenses 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 55765f89e4b..d05820bfb6b 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 @@ -93,7 +93,7 @@ def formula(person, period, parameters): # if they are not claimed as a dependent elsewhere head_or_spouse = person("is_tax_unit_head_or_spouse", period) dependent_on_another_return = person( - "claimed_as_dependent_on_another_return", period + "claimable_as_dependent_on_another_return", period ) # The personal exemption is also provided to dependents return ~dependent_on_another_return & head_or_spouse diff --git a/policyengine_us/reforms/states/ct/hb5114/ct_hb5114.py b/policyengine_us/reforms/states/ct/hb5114/ct_hb5114.py index 91d44eb6f65..c95f0f8a032 100644 --- a/policyengine_us/reforms/states/ct/hb5114/ct_hb5114.py +++ b/policyengine_us/reforms/states/ct/hb5114/ct_hb5114.py @@ -19,11 +19,12 @@ def formula(tax_unit, period, parameters): rent = add(tax_unit, period, ["rent"]) pays_rent = rent > 0 - # Must not be claimed as a dependent on another return - head_is_dependent_elsewhere = tax_unit( - "head_is_dependent_elsewhere", period - ) - not_dependent = ~head_is_dependent_elsewhere + # Preserve the modeled actual-claim gate; the cited bill does + # not state this restriction. + person = tax_unit.members + claimed = person("claimed_as_dependent_on_another_return", period) + head = person("is_tax_unit_head", period) + not_dependent = ~tax_unit.any(claimed & head) # Income eligibility filing_status = tax_unit("filing_status", period) diff --git a/policyengine_us/reforms/states/ga/ctc/ga_ctc_reform.py b/policyengine_us/reforms/states/ga/ctc/ga_ctc_reform.py index 6ff5bf1eb8a..8b8f54bc4c6 100644 --- a/policyengine_us/reforms/states/ga/ctc/ga_ctc_reform.py +++ b/policyengine_us/reforms/states/ga/ctc/ga_ctc_reform.py @@ -33,12 +33,7 @@ def formula(tax_unit, period, parameters): unused_credit = max_(potential - non_refundable, 0) # Cap the refund at amount per eligible child (same child count as # ga_ctc_potential: qualifying children under the age threshold). - baseline = parameters(period).gov.states.ga.tax.income.credits.ctc - person = tax_unit.members - age = person("age", period) - ctc_eligible_child = person("ctc_qualifying_child", period) - ga_child_age_eligible = age < baseline.age_threshold - eligible_children = tax_unit.sum(ctc_eligible_child & ga_child_age_eligible) + eligible_children = add(tax_unit, period, ["ga_ctc_eligible_child"]) refund_limit = p.refundable.amount * eligible_children refundable_credit = min_(unused_credit, refund_limit) # Only pay the refund in periods where the reform is in effect. The diff --git a/policyengine_us/reforms/states/ga/sb520/ga_sb520_reform.py b/policyengine_us/reforms/states/ga/sb520/ga_sb520_reform.py index c6b4cfb0fc5..cabfb410d6c 100644 --- a/policyengine_us/reforms/states/ga/sb520/ga_sb520_reform.py +++ b/policyengine_us/reforms/states/ga/sb520/ga_sb520_reform.py @@ -89,12 +89,8 @@ def formula(tax_unit, period, parameters): sb520_active = p_sb520.in_effect - person = tax_unit.members - age = person("age", period) - ctc_eligible_child = person("ctc_qualifying_child", period) - # SB 520 preserves baseline GA CTC age threshold (under 6) - ga_child_age_eligible = age < p.age_threshold - eligible_children = tax_unit.sum(ctc_eligible_child & ga_child_age_eligible) + # SB 520 preserves the baseline GA CTC child test (under 6) + eligible_children = add(tax_unit, period, ["ga_ctc_eligible_child"]) sb520_amount = p_sb520.credits.ctc.amount baseline_amount = p.amount diff --git a/policyengine_us/reforms/states/hi/dependent_exemption/hi_dependent_exemption_reform.py b/policyengine_us/reforms/states/hi/dependent_exemption/hi_dependent_exemption_reform.py index c2ec738773b..d1b0283f0b2 100644 --- a/policyengine_us/reforms/states/hi/dependent_exemption/hi_dependent_exemption_reform.py +++ b/policyengine_us/reforms/states/hi/dependent_exemption/hi_dependent_exemption_reform.py @@ -15,7 +15,11 @@ def formula(tax_unit, period, parameters): person = tax_unit.members age = person("age", period) - is_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)). + 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 +53,11 @@ class hi_older_dependents_count(Variable): def formula(tax_unit, period, parameters): person = tax_unit.members - is_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)). + 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( "hi_eligible_dependents_count", period @@ -66,14 +74,16 @@ class hi_regular_exemptions(Variable): defined_for = StateCode.HI def formula(tax_unit, period, parameters): - exemptions_count = tax_unit("exemptions_count", period) p = parameters(period).gov.states.hi.tax.income.exemptions - # Personal exemptions exclude the dependent portion. Over-age - # dependents fall back to the personal count. - dependents = tax_unit("tax_unit_dependents", period) + # Personal exemptions exclude the dependent portion: the filers' + # own exemptions (none for a filer who can be claimed as a + # dependent). Over-age dependents fall back to the personal count. + own_exemptions = tax_unit( + "head_spouse_count_not_dependent_elsewhere", period + ) older_dependents = tax_unit("hi_older_dependents_count", period) - personal_count = exemptions_count - dependents + older_dependents + personal_count = own_exemptions + older_dependents # Aged heads and spouses get an extra base exemption (preserved # exactly as the baseline computes it). diff --git a/policyengine_us/reforms/states/wi/dependent_exemption/wi_dependent_exemption_reform.py b/policyengine_us/reforms/states/wi/dependent_exemption/wi_dependent_exemption_reform.py index cf44d6a86f2..0471bac9c9a 100644 --- a/policyengine_us/reforms/states/wi/dependent_exemption/wi_dependent_exemption_reform.py +++ b/policyengine_us/reforms/states/wi/dependent_exemption/wi_dependent_exemption_reform.py @@ -15,7 +15,11 @@ def formula(tax_unit, period, parameters): person = tax_unit.members age = person("age", period) - is_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)). + 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 +53,11 @@ class wi_older_dependents_count(Variable): def formula(tax_unit, period, parameters): person = tax_unit.members - is_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)). + 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( "wi_eligible_dependents_count", period @@ -68,12 +76,13 @@ def formula(tax_unit, period, parameters): p_base = parameters(period).gov.states.wi.tax.income # Personal exemptions exclude the dependent portion. - total_exemptions_count = tax_unit("exemptions_count", period) - dependents = tax_unit("tax_unit_dependents", period) - older_dependents = tax_unit("wi_older_dependents_count", period) - personal_exemptions_count = ( - total_exemptions_count - dependents + older_dependents + # These are the filers' own exemptions (none for a filer who can + # be claimed as a dependent) plus over-age dependents. + own_exemptions = tax_unit( + "head_spouse_count_not_dependent_elsewhere", period ) + older_dependents = tax_unit("wi_older_dependents_count", period) + personal_exemptions_count = own_exemptions + older_dependents personal_exemption_amount = ( personal_exemptions_count * p_base.exemption.base ) diff --git a/policyengine_us/reforms/treasury/repeal_dependent_exemptions.py b/policyengine_us/reforms/treasury/repeal_dependent_exemptions.py index ab54afe5e89..fbfd6b94c1e 100644 --- a/policyengine_us/reforms/treasury/repeal_dependent_exemptions.py +++ b/policyengine_us/reforms/treasury/repeal_dependent_exemptions.py @@ -13,7 +13,15 @@ class exemptions_count(Variable): def formula(tax_unit, period, parameters): total_unit_size = tax_unit("tax_unit_size", period) dependents = tax_unit("tax_unit_dependents", period) - return total_unit_size - dependents + # Only the filers' own exemptions remain; a filer who can be + # claimed as a dependent has none (IRC 151(d)(2)). + dependent_filer = tax_unit("head_or_spouse_is_dependent_elsewhere", period) + independent_filers = tax_unit( + "head_spouse_count_not_dependent_elsewhere", period + ) + return where( + dependent_filer, independent_filers, total_unit_size - dependents + ) class reform(Reform): def apply(self): diff --git a/policyengine_us/tests/core/test_claimable_filer_federal_invariants.py b/policyengine_us/tests/core/test_claimable_filer_federal_invariants.py new file mode 100644 index 00000000000..aab5f3a0156 --- /dev/null +++ b/policyengine_us/tests/core/test_claimable_filer_federal_invariants.py @@ -0,0 +1,167 @@ +"""Federal rules for a filer who can be claimed as a dependent elsewhere. + +A filer who can be claimed as a dependent on another return is treated as +having no dependents (IRC 152(b)(1); on a joint return, if either spouse can be +claimed, "you and your spouse can't claim any dependents", Publication 501) and +has no personal exemption (IRC 151(d)(2)). So: + +- `exemptions_count` counts only the filers who cannot be claimed, plus the + dependents when no filer can be claimed; +- `ctc_qualifying_child` and the credit for other dependents are zero on a + return with a claimable filer; +- a child under 13 is not a child and dependent care qualifying person on such + a return (a disabled person still is, IRC 21(b)(1)(B)); +- recovery rebates leave out a claimable filer and, on such a return, the + dependents; +- the state amounts that read the exemption count follow it (Georgia's two + credits keep their own count). + +For couples with either, both or neither spouse claimed, in 2021-2026: + +1. Swap invariance: each output is the same under either head/spouse + labelling (Hypothesis batches and the seeded population). +2. Monotonicity: marking another filer as claimed never raises any of the + amounts or counts below (seeded population only). +3. Identities: `exemptions_count` equals the filers who cannot be claimed plus + the dependents when no filer can be claimed, and a return with a claimable + filer has no CTC-qualifying child and no credit for other dependents + (both populations). + +The generated adults have no tuition or student loan interest, so the education +credit, tuition deduction and student loan interest gates are covered by YAML +cases only, as are the contributed reforms. +""" + +import numpy as np +import pytest +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +from policyengine_us import Simulation +from policyengine_us.tests.core.test_dependent_elsewhere_head_spouse_swap_invariance import ( + CLAIM_PATTERNS, + TOLERANCE, + YEARS, + _calc, + _crafted_cases, + _monotone_variants, + _seeded_couples, + _situation, + _swap_variants, + adults, + dependents, +) + +# Texas has no income tax; the others read the federal exemption count. +STATES = ["TX", "OR", "HI", "NM", "GA", "RI", "DE", "OH", "WI"] +# State amounts that read the federal exemption count; each is zero outside +# its state. +STATE_OUTPUTS = [ + "ri_exemptions", + "de_personal_credit_potential", + "oh_personal_exemptions", + "wi_base_exemption", + "or_regular_exemptions", + "hi_regular_exemptions", + "nm_low_and_middle_income_exemption", + "nm_low_income_comprehensive_tax_rebate", + "ga_ctc_potential", + "ga_low_income_credit_potential", +] +# Amounts that marking another filer as claimed must never raise. +MONOTONE = [ + "ctc_maximum", + "ctc_qualifying_children", + "capped_count_cdcc_eligible", + "cdcc_relevant_expenses", + "exemptions_count", + "rrc_arpa", +] + STATE_OUTPUTS +OUTPUTS = ["income_tax"] + MONOTONE + + +@st.composite +def couples(draw): + return { + "state": draw(st.sampled_from(STATES)), + "adults": [draw(adults()), draw(adults())], + "dependents": draw(st.lists(dependents(), max_size=2)), + "claimed": draw(st.sampled_from(CLAIM_PATTERNS)), + } + + +def check_swap(units, year, outputs, identities=None): + """Each output is the same under either head/spouse labelling.""" + sim = Simulation(situation=_situation(units, year, _swap_variants)) + for name in outputs: + values = _calc(sim, name, year) + assert np.isfinite(values).all(), f"{name} in {year} is not finite" + drawn, swapped = values[0::2], values[1::2] + differs = ~(np.abs(swapped - drawn) <= TOLERANCE) + assert not differs.any(), ( + f"{name} in {year} changes when the head and spouse labels are " + "exchanged: " + + ", ".join( + f"{units[i]['state']} claimed={units[i]['claimed']} " + f"{drawn[i]:.2f} -> {swapped[i]:.2f}" + for i in np.flatnonzero(differs)[:10] + ) + ) + if identities is not None: + identities(sim, year) + + +def check_monotone(units, year, outputs, identities=None): + """Marking another filer as claimed never raises an output.""" + sim = Simulation(situation=_situation(units, year, _monotone_variants)) + for name in outputs: + values = _calc(sim, name, year).reshape(-1, 4) + nobody, first, second, both = values.T + for more, fewer, label in ( + (first, nobody, "first adult"), + (second, nobody, "second adult"), + (both, first, "both after first"), + (both, second, "both after second"), + ): + rises = more > fewer + TOLERANCE + assert not rises.any(), ( + f"{name} in {year} rises when the {label} is claimed " + "elsewhere: " + + ", ".join( + f"{units[i]['state']} {fewer[i]:.2f} -> {more[i]:.2f}" + for i in np.flatnonzero(rises)[:10] + ) + ) + if identities is not None: + identities(sim, year) + + +def _federal_identities(sim, year): + claimed_filer = _calc(sim, "head_or_spouse_is_dependent_elsewhere", year) > 0 + independent = _calc(sim, "head_spouse_count_not_dependent_elsewhere", year) + dependents_count = _calc(sim, "tax_unit_count_dependents", year) + expected = independent + np.where(claimed_filer, 0, dependents_count) + np.testing.assert_array_equal(_calc(sim, "exemptions_count", year), expected) + assert not _calc(sim, "ctc_qualifying_children", year)[claimed_filer].any() + odc = np.asarray( + sim.calculate("ctc_adult_individual_maximum", year, map_to="tax_unit") + ) + assert not odc[claimed_filer].any() + + +@settings( + max_examples=4, + 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=15)) +def test_claimable_filer_federal_rules_are_label_free(year, units): + check_swap(units, year, OUTPUTS, _federal_identities) + + +@pytest.mark.parametrize("year", YEARS) +def test_claimable_filer_federal_rules_seeded_population(year): + units = _seeded_couples(STATES, per_state=2) + _crafted_cases(STATES) + check_swap(units, year, OUTPUTS, _federal_identities) + check_monotone(units, year, MONOTONE, _federal_identities) diff --git a/policyengine_us/tests/core/test_claimable_filer_nm_invariants.py b/policyengine_us/tests/core/test_claimable_filer_nm_invariants.py new file mode 100644 index 00000000000..e34647f5b2f --- /dev/null +++ b/policyengine_us/tests/core/test_claimable_filer_nm_invariants.py @@ -0,0 +1,95 @@ +"""New Mexico rules for a filer who can be claimed as a dependent. + +Several credits and exemptions bar "a dependent of another individual", and +dependent-based amounts need dependents that a return with a claimable filer +cannot have (IRC 152(b)(1)). + +For couples with either, both or neither spouse claimed: + +1. Swap invariance: each output is the same under either head/spouse + labelling (Hypothesis batches, the seeded population and the crafted + centenarian cases). +2. Monotonicity: marking another filer as claimed never raises an output + (seeded population and crafted cases only). + +The crafted cases add spouses aged 100 or older, whom the generated population +(ages 18 to 90) never has. +""" + +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, + _crafted_cases, + _seeded_couples, + adults, + dependents, +) + +STATES = ["NM"] +YEARS = [2023, 2025, 2026] +OUTPUTS = [ + "nm_ctc", + "nm_medical_expense_credit", + "nm_medical_expense_exemption", + "nm_eitc", + "nm_deduction_for_certain_dependents", + "nm_property_tax_rebate", + "nm_cdcc_max_amount", + "nm_hundred_year_exemption", +] + + +def _centenarian_cases(): + # One or both spouses aged 100 or older, with income to exempt. + centenarian = {"age": 101, "taxable_pension_income": 20_000.0} + older = {"age": 103, "taxable_interest_income": 5_000.0} + younger = {"age": 70, "social_security_retirement": 12_000.0} + return [ + { + "state": "NM", + "adults": couple, + "dependents": [], + "claimed": claimed, + } + for couple in ([centenarian, younger], [centenarian, older]) + for claimed in [(True, False), (False, True), (True, True)] + ] + + +@st.composite +def couples(draw): + return { + "state": draw(st.sampled_from(STATES)), + "adults": [draw(adults()), draw(adults())], + "dependents": draw(st.lists(dependents(), max_size=2)), + "claimed": draw(st.sampled_from(CLAIM_PATTERNS)), + } + + +@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_nm_claimable_filer_rules_are_label_free(year, units): + check_swap(units, year, OUTPUTS) + + +@pytest.mark.parametrize("year", YEARS) +def test_nm_claimable_filer_rules_seeded_population(year): + units = ( + _seeded_couples(STATES, per_state=3) + + _crafted_cases(STATES) + + _centenarian_cases() + ) + check_swap(units, year, OUTPUTS) + check_monotone(units, year, OUTPUTS) diff --git a/policyengine_us/tests/core/test_dependent_elsewhere_head_spouse_swap_invariance.py b/policyengine_us/tests/core/test_dependent_elsewhere_head_spouse_swap_invariance.py new file mode 100644 index 00000000000..4d5f97ae469 --- /dev/null +++ b/policyengine_us/tests/core/test_dependent_elsewhere_head_spouse_swap_invariance.py @@ -0,0 +1,555 @@ +"""Rules for a filer claimed as a dependent elsewhere do not depend on which +spouse is labelled head. + +A married couple may list either spouse first, so exchanging the two adults' +`is_tax_unit_head` and `is_tax_unit_spouse` labels, with every other input +kept, must not change their taxes. On main, the federal standard deduction and +16 state formulas read only `head_is_dependent_elsewhere`, so a joint return +where one spouse can be claimed on another return (a joint return filed only +to recover withholding can meet the federal exception, IRS Publication 501) +was taxed differently depending on which spouse was labelled head. Each +formula now applies its jurisdiction's rule for that case: + +- Either spouse limits the return (the IRC 63(c)(5) worksheet): the federal + standard deduction, Oregon's and Hawaii's standard deductions, and + Virginia's credit for low-income individuals. The federal EITC without a + qualifying child also requires that neither spouse is claimable outside the + nonrequired-claimant filing exception. +- Only single filers: New York's dependent standard deduction. +- Each spouse separately: Michigan's exemptions and Hawaii's food/excise, + renters and Act 115 credits count only the filers who cannot be claimed. +- Only when every filer is a dependent: New Mexico's rebates, credits and + dependents deduction, and Maine's sales tax fairness credit. When a filer + is a dependent elsewhere, New Mexico's medical care credit also needs a + filer who is both 65 or older and not a dependent. +- Never on a joint return: Missouri's own stop in its working family credit, + since such a couple files as married filing combined. + +Hypothesis draws batches of married couples, with and without dependents, in +the eight states with such a rule and one without, for 2021-2026, with either, +both or neither spouse claimed or claimable elsewhere, independently of the +nonrequired-claimant filing exception, and checks 1 and 3. A seeded +population and crafted cases check 1, 2 and 3 in every year, and two seeded +couples plus the review case in every state check 1 for federal and state +income tax in 2026. Each batch is one vectorized simulation. For each couple: + +1. Swap invariance: federal income tax, state income tax before and after + refundable credits, and each formula in CONSUMERS are the same to the cent + (or the same boolean) under either labelling. +2. Monotonicity: marking another filer as claimed elsewhere never raises any + amount in CONSUMERS or turns an eligibility on. This holds for current + parameters and inputs the model derives; for example, a Hawaii standard + deduction input below the itemization threshold could break it. +3. The helper identities: `head_or_spouse_is_dependent_elsewhere` equals + `head_is_dependent_elsewhere | spouse_is_dependent_elsewhere`, + `every_filer_is_dependent_elsewhere` equals their conjunction for a + couple, and `head_spouse_count_not_dependent_elsewhere` plus the claimable + filers equals the number of filers. + +The 2025 seeded population also compares legacy input only with explicit +claimability equal to that input, protecting the new input's fallback. A +separate vectorized population holds actual claims and claimability fixed +while toggling the exception: general claimability rules and Medicaid stay +unchanged, childless EITC eligibility is restored, and Michigan/Hawaii may +count the filer's own dependents. Benefits derived from the restored federal +EITC may also change: Missouri's working family credit eligibility must track +positive federal EITC for this population's joint returns with no investment +income. Its separate claimability gate stays fixed. YAML examples establish +the corresponding legal amounts, including the limited $2,450 federal +standard deduction. +""" + +import numpy as np +import pytest +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +from policyengine_us import Simulation +from policyengine_us.model_api import STATES + +TOLERANCE = 0.01 # dollars: the same to the cent +YEARS = [2021, 2022, 2023, 2024, 2025, 2026] +AFFECTED = ["HI", "ME", "MI", "MO", "NM", "NY", "OR", "VA", "CA"] +ALL_STATES = [s for s in STATES if s not in ("PR", "VI")] +TAX_UNIT_OUTPUTS = [ + "income_tax", + "state_income_tax", + "state_income_tax_before_refundable_credits", +] +# The formulas that read a filer's claimability or dependent-taxpayer status. +CONSUMERS = [ + "basic_standard_deduction", + "eitc", + "eitc_demographic_eligible", + "ny_standard_deduction", + "mi_exemptions", + "or_standard_deduction", + "va_low_income_tax_credit_eligible", + "mo_wftc_eligible", + "nm_2021_income_rebate", + "nm_additional_2021_income_rebate", + "nm_supplemental_2021_income_rebate", + "nm_deduction_for_certain_dependents_eligible", + "nm_medical_expense_credit", + "nm_cdcc_eligible", + "me_sales_tax_fairness_credit_eligible", + "hi_deductions", + "hi_act_115_rebate", + "hi_food_excise_exemption_amount", + "hi_food_excise_credit_minor_child_count", + "hi_food_excise_credit", + "hi_tax_credit_for_low_income_household_renters_eligible", + "hi_tax_credit_for_low_income_household_renters", +] +CLAIM_PATTERNS = [(True, False), (False, True), (True, True), (False, False)] +DEPENDENT_TAXPAYER_TEST_OUTPUTS = { + "mi_exemptions", + "hi_act_115_rebate", + "hi_food_excise_exemption_amount", + "hi_food_excise_credit", + "hi_tax_credit_for_low_income_household_renters", +} +# Federal EITC eligibility is restored directly. The federal amount and +# Missouri eligibility can change as a consequence, without changing their +# general claimability gates. +EITC_RELATED_OUTPUTS = { + "eitc_demographic_eligible", + "eitc", + "mo_wftc_eligible", +} +EXCEPTION_SENSITIVE = DEPENDENT_TAXPAYER_TEST_OUTPUTS | EITC_RELATED_OUTPUTS +ACTUAL_CLAIM_OUTPUTS = [ + "medicaid_is_tax_dependent", + "medicaid_uses_missing_claimant_fallback", +] + + +def money(high): + return st.one_of(st.just(0.0), st.integers(1, high).map(float)) + + +@st.composite +def adults(draw): + # Low incomes reach the credits' limits; ages reach the 65+ rules. + return { + "age": draw(st.integers(18, 90)), + "is_blind": draw(st.booleans()), + "is_disabled": draw(st.booleans()), + "employment_income": draw(money(60_000)), + "self_employment_income": draw(money(20_000)), + "taxable_interest_income": draw(money(3_000)), + "social_security_retirement": draw(money(25_000)), + "real_estate_taxes": draw(money(6_000)), + "rent": draw(money(18_000)), + "charitable_cash_donations": draw(money(6_000)), + "other_medical_expenses": draw(money(40_000)), + } + + +@st.composite +def dependents(draw): + age = draw(st.integers(0, 23)) + return { + "age": age, + "is_full_time_student": age >= 18, + "employment_income": draw(money(10_000)), + "pre_subsidy_childcare_expenses": draw(money(8_000)), + } + + +@st.composite +def couples(draw): + claimable = draw(st.sampled_from(CLAIM_PATTERNS)) + claimed = tuple(can_claim and draw(st.booleans()) for can_claim in claimable) + return { + "state": draw(st.sampled_from(AFFECTED)), + "adults": [draw(adults()), draw(adults())], + "dependents": draw(st.lists(dependents(), max_size=2)), + "claimed": claimed, + "claimable": claimable, + "exception": tuple( + not is_claimed and draw(st.booleans()) for is_claimed in claimed + ), + } + + +SEED = 20261008 + + +def _seeded_adult(rng): + def some(high, p): + return float(round(rng.uniform(1, high))) if rng.random() < p else 0.0 + + age = int(rng.integers(18, 91)) + return { + "age": age, + "is_blind": bool(rng.random() < 0.1), + "is_disabled": bool(rng.random() < 0.1), + "employment_income": some(60_000, 0.7), + "self_employment_income": some(20_000, 0.15), + "taxable_interest_income": some(3_000, 0.3), + "social_security_retirement": some(25_000, 0.5 if age >= 62 else 0.03), + "real_estate_taxes": some(6_000, 0.3), + "rent": some(18_000, 0.5), + "charitable_cash_donations": some(6_000, 0.3), + "other_medical_expenses": some(40_000, 0.15), + } + + +def _seeded_couples(states, per_state): + rng = np.random.default_rng(SEED) + return [ + { + "state": state, + "adults": [_seeded_adult(rng), _seeded_adult(rng)], + "dependents": [ + {"age": int(rng.integers(0, 18))} + for _ in range(int(rng.choice([0, 0, 1, 2]))) + ], + "claimed": CLAIM_PATTERNS[int(rng.integers(0, 3))], + } + for state in states + for _ in range(per_state) + ] + + +def _crafted_cases(states, review_case_only=False): + # The review case (married adults aged 20 earning $8,000 each, one + # claimed by a parent), with and without a child, and older couples who + # reach the 65+ and renter rules. + young = {"age": 20, "employment_income": 8_000.0, "rent": 6_000.0} + old = { + "age": 70, + "social_security_retirement": 12_000.0, + "rent": 9_000.0, + "other_medical_expenses": 30_000.0, + } + # One claimed adult covers both labellings of a claimed spouse, since each + # case runs with the labels exchanged. + cases = [] + for state in states: + for claimed in [(True, False), (True, True)]: + cases += [ + { + "state": state, + "adults": [young, young], + "dependents": [], + "claimed": claimed, + }, + ] + if review_case_only: + continue + cases += [ + { + "state": state, + "adults": [young, {"age": 22, "employment_income": 3_000.0}], + "dependents": [{"age": 2}], + "claimed": claimed, + }, + { + "state": state, + "adults": [old, {**old, "age": 66}], + "dependents": [], + "claimed": claimed, + }, + ] + return cases + + +def _situation(units, year, variants, explicit_claimability=False): + # Each unit appears once per variant: (head is the first adult, first + # adult claimed, second adult claimed). People keep their order and every + # other input in every copy. + people = {} + groups = { + "tax_units": {}, + "spm_units": {}, + "families": {}, + "marital_units": {}, + "households": {}, + } + for i, unit in enumerate(units): + for copy, variant in enumerate(variants(unit)): + first_is_head, claim_a, claim_b = variant[:3] + claimable = unit.get("claimable") + exception = unit.get("exception") + if len(variant) == 5: + claimable, exception = variant[3:] + if explicit_claimability: + claimable = (claim_a, claim_b) + a, b = f"a_{i}_{copy}", f"b_{i}_{copy}" + for adult_index, (name, amounts, is_head, claimed) in enumerate( + ( + (a, unit["adults"][0], first_is_head, claim_a), + (b, unit["adults"][1], not first_is_head, claim_b), + ) + ): + people[name] = { + **amounts, + "is_tax_unit_head": is_head, + "is_tax_unit_spouse": not is_head, + "is_tax_unit_dependent": False, + "claimed_as_dependent_on_another_return": claimed, + } + if claimable is not None: + people[name]["claimable_as_dependent_on_another_return"] = ( + claimable[adult_index] + ) + if exception is not None: + people[name]["dependent_claimant_filing_exception"] = exception[ + adult_index + ] + members = [a, b] + groups["marital_units"][f"couple_{i}_{copy}"] = {"members": [a, b]} + for j, amounts in enumerate(unit["dependents"]): + child = f"dependent_{i}_{copy}_{j}" + people[child] = { + **amounts, + "is_tax_unit_head": False, + "is_tax_unit_spouse": False, + "is_tax_unit_dependent": True, + } + if explicit_claimability: + people[child]["claimable_as_dependent_on_another_return"] = ( + amounts.get("claimed_as_dependent_on_another_return", False) + ) + members.append(child) + groups["marital_units"][f"single_{i}_{copy}_{j}"] = {"members": [child]} + for group, prefix in ( + ("tax_units", "tax_unit"), + ("spm_units", "spm_unit"), + ("families", "family"), + ): + groups[group][f"{prefix}_{i}_{copy}"] = {"members": members} + groups["households"][f"household_{i}_{copy}"] = { + "members": members, + "state_code": {year: unit["state"]}, + } + people = { + name: {k: {year: v} for k, v in values.items()} + for name, values in people.items() + } + return {"people": people, **groups} + + +def _swap_variants(unit): + claim_a, claim_b = unit["claimed"] + return [(True, claim_a, claim_b), (False, claim_a, claim_b)] + + +def _calc(sim, name, year): + return np.asarray(sim.calculate(name, year), dtype=float) + + +def _check_swap(units, year, outputs, capture_fallback=False): + sim = Simulation(situation=_situation(units, year, _swap_variants)) + states = np.array([u["state"] for u in units]) + for name in outputs: + values = _calc(sim, name, year) + assert np.isfinite(values).all(), f"{name} in {year} is not finite" + drawn, swapped = values[0::2], values[1::2] + differs = ~(np.abs(swapped - drawn) <= TOLERANCE) + assert not differs.any(), ( + f"{name} in {year} changes when the head and spouse labels are " + f"exchanged: " + + ", ".join( + f"{states[i]} claimed={units[i]['claimed']} " + f"{drawn[i]:.2f} -> {swapped[i]:.2f}" + for i in np.flatnonzero(differs)[:10] + ) + ) + # 3. The helper identities. + either = _calc(sim, "head_or_spouse_is_dependent_elsewhere", year) + head = _calc(sim, "head_is_dependent_elsewhere", year) + spouse = _calc(sim, "spouse_is_dependent_elsewhere", year) + np.testing.assert_array_equal(either, np.maximum(head, spouse)) + independent = _calc(sim, "head_spouse_count_not_dependent_elsewhere", year) + np.testing.assert_array_equal(independent + head + spouse, 2) + every = _calc(sim, "every_filer_is_dependent_elsewhere", year) + np.testing.assert_array_equal(every, np.minimum(head, spouse)) + blocked = _calc(sim, "is_dependent_elsewhere_without_filing_exception", year) + filers = _calc(sim, "is_tax_unit_head", year) + _calc( + sim, "is_tax_unit_spouse", year + ) + np.testing.assert_array_equal( + _calc( + sim, "head_or_spouse_is_dependent_elsewhere_without_filing_exception", year + ), + sim.populations["tax_unit"].any(blocked.astype(bool) & filers.astype(bool)), + ) + if capture_fallback: + # Keep only arrays so the compatibility comparison can release this + # simulation before constructing the next full model. + return { + name: _calc(sim, name, year) + for name in TAX_UNIT_OUTPUTS + CONSUMERS + ACTUAL_CLAIM_OUTPUTS + } + + +def _check_fallback(units, year, legacy_outputs): + # The absence of a new input is simulation-wide: compare separate + # simulations so Core does not fill omitted people with input defaults. + explicit_sim = Simulation( + situation=_situation(units, year, _swap_variants, explicit_claimability=True) + ) + for name in TAX_UNIT_OUTPUTS + CONSUMERS + ACTUAL_CLAIM_OUTPUTS: + np.testing.assert_allclose( + legacy_outputs[name], + _calc(explicit_sim, name, year), + atol=TOLERANCE, + rtol=0, + err_msg=f"{name} changes when fallback claimability is made explicit", + ) + + +def _exception_variants(unit): + claimable = unit["claimed"] + return [ + (True, False, False, claimable, (False, False)), + (False, False, False, claimable, (False, False)), + (True, False, False, claimable, (True, True)), + (False, False, False, claimable, (True, True)), + ] + + +def _check_exception_scope(): + year = 2025 + units = [ + { + "state": state, + "adults": [{"age": 26, "employment_income": 2_000}, {"age": 30}], + "dependents": children, + "claimed": claimed, + } + for state in AFFECTED + # Isolate ordinary dependents: publicly supported minors have a + # separate Hawaii qualification that does not use this exception. + for children in ( + [], + [{"age": 5, "hi_food_excise_credit_child_receiving_public_support": False}], + ) + for claimed in CLAIM_PATTERNS + ] + sim = Simulation(situation=_situation(units, year, _exception_variants)) + for name in CONSUMERS + ACTUAL_CLAIM_OUTPUTS: + values = _calc(sim, name, year) + if name in ACTUAL_CLAIM_OUTPUTS: + # Person outputs have two filers and optionally one child per unit. + start = 0 + for unit in units: + size = 2 + len(unit["dependents"]) + copies = values[start : start + 4 * size].reshape(4, size) + np.testing.assert_array_equal(copies[0:2], copies[2:4]) + start += 4 * size + continue + copies = values.reshape(-1, 4) + np.testing.assert_allclose( + copies[:, 0::2], copies[:, 1::2], atol=TOLERANCE, rtol=0 + ) + if name not in EXCEPTION_SENSITIVE: + np.testing.assert_allclose( + copies[:, :2], + copies[:, 2:], + atol=TOLERANCE, + rtol=0, + err_msg=f"The filing exception changes general claimability rule {name}", + ) + eligibility = _calc(sim, "eitc_demographic_eligible", year).reshape(-1, 4) + childless = np.array([not unit["dependents"] for unit in units]) + claimable = np.array([any(unit["claimed"]) for unit in units]) + assert not eligibility[childless & claimable, :2].any() + assert eligibility[childless, 2:].all() + # RSMo 143.177.2 requires federal EITC. These units file jointly, so the + # separate dependent-filer stop does not apply, and their zero investment + # income meets Missouri's limit. The exception's Missouri effect must + # therefore follow positive federal EITC, rather than alter claimability. + missouri = np.array([unit["state"] == "MO" for unit in units]) + federal_eitc = _calc(sim, "eitc", year).reshape(-1, 4) + missouri_eligible = _calc(sim, "mo_wftc_eligible", year).reshape(-1, 4) + np.testing.assert_array_equal( + missouri_eligible[missouri].astype(bool), federal_eitc[missouri] > 0 + ) + direct_claimability = _calc( + sim, "head_or_spouse_is_dependent_elsewhere", year + ).reshape(-1, 4) + np.testing.assert_array_equal( + direct_claimability, np.repeat(claimable[:, None], 4, axis=1) + ) + for name, state in (("mi_exemptions", "MI"), ("hi_food_excise_credit", "HI")): + values = _calc(sim, name, year).reshape(-1, 4) + restores_child = np.array( + [ + unit["state"] == state + and bool(unit["dependents"]) + and sum(unit["claimed"]) == 1 + for unit in units + ] + ) + assert (values[restores_child, 2:] > values[restores_child, :2]).all() + + +def _monotone_variants(unit): + # Nobody, either adult, then both adults claimed; labels fixed. + return [ + (True, False, False), + (True, True, False), + (True, False, True), + (True, True, True), + ] + + +def _check_monotone(units, year): + sim = Simulation(situation=_situation(units, year, _monotone_variants)) + states = np.array([u["state"] for u in units]) + for name in CONSUMERS: + values = _calc(sim, name, year).reshape(-1, 4) + nobody, first, second, both = values.T + for more, fewer, label in ( + (first, nobody, "first adult"), + (second, nobody, "second adult"), + (both, first, "both after first"), + (both, second, "both after second"), + ): + rises = more > fewer + TOLERANCE + assert not rises.any(), ( + f"{name} in {year} rises when the {label} is claimed " + f"elsewhere: " + + ", ".join( + f"{states[i]} {fewer[i]:.2f} -> {more[i]:.2f}" + for i in np.flatnonzero(rises)[:10] + ) + ) + + +# A batch's cost is mostly per-variable overhead, so each example is a large +# batch and there are few examples. +@settings( + max_examples=4, + 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=15)) +def test_claimed_spouse_does_not_depend_on_head_label(year, units): + _check_swap(units, year, TAX_UNIT_OUTPUTS + CONSUMERS) + + +@pytest.mark.parametrize("year", YEARS) +def test_seeded_population(year): + units = _seeded_couples(AFFECTED, per_state=2) + _crafted_cases(AFFECTED) + legacy_outputs = _check_swap( + units, year, TAX_UNIT_OUTPUTS + CONSUMERS, capture_fallback=year == 2025 + ) + if year == 2025: + _check_fallback(units, year, legacy_outputs) + _check_exception_scope() + _check_monotone(units, year) + + +def test_every_state_with_a_claimed_spouse(): + # Other states' rules for a claimed filer read both spouses already; + # this guards their state income tax in one year. + units = _seeded_couples(ALL_STATES, per_state=2) + _crafted_cases( + ALL_STATES, review_case_only=True + ) + _check_swap(units, 2026, TAX_UNIT_OUTPUTS) diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/income/medicaid_is_tax_dependent.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/income/medicaid_is_tax_dependent.yaml new file mode 100644 index 00000000000..c04ad8732f3 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/income/medicaid_is_tax_dependent.yaml @@ -0,0 +1,49 @@ +- name: Claimability alone does not create an expected Medicaid tax-dependent claim + period: 2025 + input: + age: 18 + is_tax_unit_head: true + is_tax_unit_spouse: false + is_tax_unit_dependent: false + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + medicaid_has_known_claiming_tax_unit: false + tax_unit_is_filer: true + output: + # 42 CFR 435.603(f)(1)-(2) uses expected actual claims, not claimability. + medicaid_is_tax_dependent: false + medicaid_uses_missing_claimant_fallback: false + medicaid_uses_non_filer_rules: false + +- name: An expected actual claim invokes Medicaid's dependent and missing-claimant rules + period: 2025 + input: + age: 18 + is_tax_unit_head: true + is_tax_unit_spouse: false + is_tax_unit_dependent: false + claimed_as_dependent_on_another_return: true + claimable_as_dependent_on_another_return: true + medicaid_has_known_claiming_tax_unit: false + tax_unit_is_filer: true + output: + medicaid_is_tax_dependent: true + medicaid_uses_missing_claimant_fallback: true + medicaid_uses_non_filer_rules: true + +- name: The tax filing exception leaves Medicaid's expected actual claim unchanged + period: 2025 + input: + age: 18 + is_tax_unit_head: true + is_tax_unit_spouse: false + is_tax_unit_dependent: false + claimed_as_dependent_on_another_return: true + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + medicaid_has_known_claiming_tax_unit: false + tax_unit_is_filer: true + output: + medicaid_is_tax_dependent: true + medicaid_uses_missing_claimant_fallback: true + medicaid_uses_non_filer_rules: true diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/cdcc/cdcc_relevant_expenses.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/cdcc/cdcc_relevant_expenses.yaml index 8ed8c1ecdd6..d772de304e6 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/cdcc/cdcc_relevant_expenses.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/cdcc/cdcc_relevant_expenses.yaml @@ -40,3 +40,231 @@ min_head_spouse_earned: 10_000 output: cdcc_relevant_expenses: 3_000 # 1_000 childcare + 2_000 adult care + +# IRC 21(b)(2)(A)(ii): only expenses for the care of a qualifying individual count. +# The child of a return on which a filer can be claimed is not one (IRC 152(b)(1)), +# while the incapacitated relative still is (IRC 21(b)(1)(B)). +- name: 2025 childcare for the child of a claimable single filer does not count + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 5000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + relative: + age: 40 + is_incapable_of_self_care: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, child, relative] + tax_unit_childcare_expenses: 3000 + households: + household: + members: [person_a, child, relative] + state_code: TX + output: + count_cdcc_eligible: 1 + cdcc_relevant_expenses: 0 + +- name: 2025 childcare for the child of a joint return with one claimable spouse does not count (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 5000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 5000 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + relative: + age: 40 + is_incapable_of_self_care: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child, relative] + filing_status: JOINT + tax_unit_childcare_expenses: 3000 + households: + household: + members: [person_a, person_b, child, relative] + state_code: TX + output: + count_cdcc_eligible: 1 + cdcc_relevant_expenses: 0 + +- name: 2025 childcare for the child of a joint return with one claimable spouse does not count (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + employment_income: 5000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + employment_income: 5000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + relative: + age: 40 + is_incapable_of_self_care: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child, relative] + filing_status: JOINT + tax_unit_childcare_expenses: 3000 + households: + household: + members: [person_b, person_a, child, relative] + state_code: TX + output: + count_cdcc_eligible: 1 + cdcc_relevant_expenses: 0 + +- name: 2025 care expenses for the incapacitated relative of a claimable filer still count + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 5000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + relative: + age: 40 + is_incapable_of_self_care: true + pre_subsidy_care_expenses: 2000 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, child, relative] + tax_unit_childcare_expenses: 3000 + households: + household: + members: [person_a, child, relative] + state_code: TX + output: + cdcc_relevant_expenses: 2000 + +- name: 2025 the same household with nobody claimable counts the childcare + period: 2025 + input: + people: + person_a: + age: 30 + employment_income: 5000 + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + relative: + age: 40 + is_incapable_of_self_care: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, child, relative] + tax_unit_childcare_expenses: 3000 + households: + household: + members: [person_a, child, relative] + state_code: TX + output: + count_cdcc_eligible: 2 + cdcc_relevant_expenses: 3000 + +# Publication 501, Dependent Taxpayer Test: a filer whose would-be claimant is not +# required to file and files no return or only for a refund can claim dependents. +- name: 2025 childcare for the child of a claimable filer within the filing exception counts + period: 2025 + input: + people: + parent: + age: 30 + employment_income: 5000 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child] + tax_unit_childcare_expenses: 3000 + households: + household: + members: [parent, child] + state_code: TX + output: + count_cdcc_eligible: 1 + cdcc_relevant_expenses: 3000 + +# IRC 21(b)(1)(B): a dependent incapable of self-care is a qualifying individual at +# any age, determined without regard to IRC 152(b)(1), so the childcare of an +# incapacitated 14-year-old counts on a return with a claimable filer. +- name: 2025 childcare for the incapacitated teenager of a claimable filer counts + period: 2025 + input: + people: + parent: + age: 40 + employment_income: 5000 + claimable_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 14 + is_incapable_of_self_care: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child] + tax_unit_childcare_expenses: 1000 + households: + household: + members: [parent, child] + state_code: TX + output: + count_cdcc_eligible: 1 + cdcc_relevant_expenses: 1000 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/cdcc/is_cdcc_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/cdcc/is_cdcc_eligible.yaml index 9a4d8616b69..1c590c6f3cf 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/cdcc/is_cdcc_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/cdcc/is_cdcc_eligible.yaml @@ -54,3 +54,99 @@ is_tax_unit_spouse: false output: is_cdcc_eligible: true + +- name: 2025 child under 13 is not a qualifying person when the single filer can be claimed as a dependent + period: 2025 + input: + people: + parent: + age: 20 + claimed_as_dependent_on_another_return: true + child: + age: 5 + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: TX + output: + # Publication 503: "Your qualifying child who is your dependent and who + # was under age 13"; IRC 152(b)(1). + is_cdcc_eligible: [false, false] + +- name: 2025 joint return with one claimable spouse has no under-13 qualifying person (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: TX + output: + is_cdcc_eligible: [false, false, false] + +- name: 2025 joint return with one claimable spouse has no under-13 qualifying person (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: TX + output: + is_cdcc_eligible: [false, false, false] + +- name: 2025 disabled person still qualifies when the filer can be claimed as a dependent + period: 2025 + input: + people: + filer: + age: 30 + claimed_as_dependent_on_another_return: true + relative: + age: 60 + is_incapable_of_self_care: true + tax_units: + tax_unit: + members: [filer, relative] + households: + household: + members: [filer, relative] + state_code: TX + output: + # IRC 21(b)(1)(B) determines dependency "without regard to subsections + # (b)(1), (b)(2), and (d)(1)(B)" of section 152; Publication 503 item + # 3(b)(iii). + is_cdcc_eligible: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/ctc/maximum/ctc_qualifying_child.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/ctc/maximum/ctc_qualifying_child.yaml index 3f4a66e3619..fc96d52a969 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/ctc/maximum/ctc_qualifying_child.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/ctc/maximum/ctc_qualifying_child.yaml @@ -56,3 +56,190 @@ members: [adult, child, child2] output: ctc_qualifying_child: [False, True, False] + +- name: 2025 single filer who can be claimed as a dependent has no CTC-qualifying child + period: 2025 + input: + people: + parent: + age: 20 + employment_income: 5_000 + claimed_as_dependent_on_another_return: true + child: + age: 5 + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: TX + output: + # IRC 24(a), 152(b)(1); Publication 501, Dependent Taxpayer Test. + ctc_qualifying_child: [false, false] + ctc_maximum: 0 + +- name: 2025 joint return with one claimable spouse has no CTC-qualifying child (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: TX + output: + # "If you are filing a joint return and your spouse can be claimed as a + # dependent by another taxpayer, you and your spouse can't claim any + # dependents on your joint return" (Publication 501). + ctc_qualifying_child: [false, false, false] + ctc_maximum: 0 + +- name: 2025 joint return with one claimable spouse has no CTC-qualifying child (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: TX + output: + ctc_qualifying_child: [false, false, false] + ctc_maximum: 0 + +- name: 2025 joint return with neither spouse claimable keeps the CTC-qualifying child + period: 2025 + input: + people: + person_a: + age: 20 + person_b: + age: 20 + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: TX + output: + ctc_qualifying_child: [false, false, true] + ctc_maximum: 2_200 + +# Publication 501, Dependent Taxpayer Test: a filer whose would-be claimant is not +# required to file and files no return or only for a refund can claim dependents. +- name: 2025 claimable single filer within the filing exception keeps the CTC-qualifying child + period: 2025 + input: + people: + parent: + age: 30 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: TX + output: + ctc_qualifying_child: [false, true] + +- name: 2025 joint return whose claimable spouse is within the filing exception keeps the CTC-qualifying child (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: TX + output: + ctc_qualifying_child: [false, false, true] + +- name: 2025 joint return whose claimable spouse is within the filing exception keeps the CTC-qualifying child (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: TX + output: + ctc_qualifying_child: [false, false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/ctc/maximum/individual/ctc_adult_individual_maximum.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/ctc/maximum/individual/ctc_adult_individual_maximum.yaml index fec059bb2d7..79cfb1685d3 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/ctc/maximum/individual/ctc_adult_individual_maximum.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/ctc/maximum/individual/ctc_adult_individual_maximum.yaml @@ -43,3 +43,96 @@ ctc_child_individual_maximum: 0 output: ctc_adult_individual_maximum: 500 + +- name: 2025 single filer who can be claimed as a dependent gets no credit for other dependents + period: 2025 + input: + people: + filer: + age: 22 + claimed_as_dependent_on_another_return: true + sibling: + age: 18 + tax_units: + tax_unit: + members: [filer, sibling] + households: + household: + members: [filer, sibling] + state_code: TX + output: + # IRC 24(h)(4)(A) "each dependent of the taxpayer"; IRC 152(b)(1). + ctc_adult_individual_maximum: [0, 0] + +- name: 2025 joint return with one claimable spouse gets no credit for other dependents (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 22 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + is_tax_unit_head: false + is_tax_unit_spouse: true + sibling: + age: 18 + tax_units: + tax_unit: + members: [person_a, person_b, sibling] + filing_status: JOINT + households: + household: + members: [person_a, person_b, sibling] + state_code: TX + output: + ctc_adult_individual_maximum: [0, 0, 0] + +- name: 2025 joint return with one claimable spouse gets no credit for other dependents (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 22 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 22 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + sibling: + age: 18 + tax_units: + tax_unit: + members: [person_b, person_a, sibling] + filing_status: JOINT + households: + household: + members: [person_b, person_a, sibling] + state_code: TX + output: + ctc_adult_individual_maximum: [0, 0, 0] + +- name: 2025 joint return with neither spouse claimable gets the credit for other dependents + period: 2025 + input: + people: + person_a: + age: 22 + person_b: + age: 22 + sibling: + age: 18 + tax_units: + tax_unit: + members: [person_a, person_b, sibling] + filing_status: JOINT + households: + household: + members: [person_a, person_b, sibling] + state_code: TX + output: + ctc_adult_individual_maximum: [0, 0, 500] diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_demographic_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_demographic_eligible.yaml index ae065070ccc..584e066b887 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_demographic_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/earned_income/eitc_demographic_eligible.yaml @@ -127,3 +127,224 @@ is_full_time_student: true output: eitc_demographic_eligible: false + +- name: 2025 childless single filer who can be claimed as a dependent is ineligible + period: 2025 + input: + people: + head: + age: 30 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head] + output: + # IRC 32(c)(1)(A)(ii)(III). + eitc_demographic_eligible: false + +- name: 2025 childless joint return where one spouse can be claimed is ineligible (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + 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: CA + output: + # Publication 596 (2025, p.18): "neither you nor your spouse can be claimed as a + # dependent by another person if you claim the EIC on your joint return." + eitc_demographic_eligible: false + +- name: 2025 childless joint return where one spouse can be claimed is ineligible (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + 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: CA + output: + # Publication 596 (2025, p.18): "neither you nor your spouse can be claimed as a + # dependent by another person if you claim the EIC on your joint return." + eitc_demographic_eligible: false + +- name: 2025 joint return with a child where one spouse can be claimed (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child_1] + state_code: CA + output: + # The dependent condition in IRC 32(c)(1)(A)(ii)(III) applies only without a + # qualifying child. + eitc_demographic_eligible: true + +- name: 2025 joint return with a child where one spouse can be claimed (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child_1] + state_code: CA + output: + # The dependent condition in IRC 32(c)(1)(A)(ii)(III) applies only without a + # qualifying child. + eitc_demographic_eligible: true + +- name: 2025 claimable childless filer qualifies when nonrequired parent files only for a withholding refund + period: 2025 + input: + people: + head: + age: 26 + employment_income: 2_000 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: CA + output: + # Pub. 596 PDF p.18: nonrequired parent files only for a refund of income tax + # withheld. Pub. 501 PDF p.24: claimability still limits the standard deduction. + eitc_demographic_eligible: true + basic_standard_deduction: 2_450 + +- name: 2025 claimable childless filer qualifies when nonrequired parent files no return + period: 2025 + input: + people: + head: + age: 26 + employment_income: 2_000 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: CA + output: + # Pub. 596 PDF p.18 also covers a nonrequired claimant who files no return. + # The exception changes EITC, while Pub. 501 PDF p.24 still limits deductions. + eitc_demographic_eligible: true + basic_standard_deduction: 2_450 + +- name: 2025 unclaimed childless filer remains ineligible when claimable by a parent required to file + period: 2025 + input: + people: + head: + age: 26 + employment_income: 2_000 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: false + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: CA + output: + # Pub. 596 PDF p.18 Example 2: choosing not to claim the filer is insufficient. + eitc_demographic_eligible: false + basic_standard_deduction: 2_450 + +- name: 2025 unclaimed childless filer remains ineligible when parent files for refundable credits + period: 2025 + input: + people: + head: + age: 26 + employment_income: 2_000 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: false + tax_units: + tax_unit: + members: [head] + households: + household: + members: [head] + state_code: CA + output: + # Pub. 596 PDF pp.18-19: filing for a credit is not filing solely for a refund + # of withholding or estimated payments, even if no return was required. + eitc_demographic_eligible: false + basic_standard_deduction: 2_450 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/education/american_opportunity_credit/is_eligible_for_american_opportunity_credit.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/education/american_opportunity_credit/is_eligible_for_american_opportunity_credit.yaml index 0d102e18b78..5544205c3d5 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/education/american_opportunity_credit/is_eligible_for_american_opportunity_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/education/american_opportunity_credit/is_eligible_for_american_opportunity_credit.yaml @@ -177,3 +177,323 @@ has_tin: true output: is_eligible_for_american_opportunity_credit: false + +- name: 2024 student claimed as a dependent elsewhere cannot claim the credit + period: 2024 + input: + people: + student: + age: 20 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [student] + households: + household: + members: [student] + state_code: TX + output: + # IRC 25A(g)(3); Form 8863: "You're claimed as a dependent on another + # person's tax return". + is_eligible_for_american_opportunity_credit: false + +- name: 2024 joint return with one spouse claimed elsewhere cannot claim the credit for either spouse (the claimable spouse is the head) + period: 2024 + input: + people: + person_a: + age: 20 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: true + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: 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: TX + output: + # Form 1040 instructions: "or your spouse if filing jointly". + is_eligible_for_american_opportunity_credit: [false, false] + +- name: 2024 joint return with one spouse claimed elsewhere cannot claim the credit for either spouse (the claimable spouse is the spouse) + period: 2024 + input: + people: + person_b: + age: 20 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: true + 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: TX + output: + is_eligible_for_american_opportunity_credit: [false, false] + +- name: 2024 joint return with neither spouse claimed keeps both students' eligibility + period: 2024 + input: + people: + person_a: + age: 20 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: true + person_b: + age: 20 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: TX + output: + is_eligible_for_american_opportunity_credit: [true, true] + +# IRC 25A(g)(3) and 26 CFR 1.25A-1(f): the bar applies to a student who is +# claimed; a student who can be claimed but is not keeps the credit. +- name: 2024 student who can be claimed but is not claimed keeps the credit + period: 2024 + input: + people: + person_a: + age: 20 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_a] + households: + household: + members: [person_a] + state_code: TX + output: + is_eligible_for_american_opportunity_credit: true + +# IRC 25A(f)(1)(A)(iii): a dependent's tuition counts only if the taxpayer is +# allowed a section 151 deduction for the dependent, and a return on which a filer +# can be claimed has no dependents (IRC 152(b)(1)), unless the would-be claimant +# meets the filing exception (Publication 501). +- name: 2024 dependent student of a filer who can be claimed is not eligible + period: 2024 + input: + people: + parent: + age: 45 + has_tin: true + claimable_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + student: + age: 19 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, student] + households: + household: + members: [parent, student] + state_code: TX + output: + is_eligible_for_american_opportunity_credit: [false, false] + +- name: 2024 dependent student of a claimable filer within the filing exception is eligible + period: 2024 + input: + people: + parent: + age: 45 + has_tin: true + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + student: + age: 19 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, student] + households: + household: + members: [parent, student] + state_code: TX + output: + is_eligible_for_american_opportunity_credit: [false, true] + +- name: 2024 dependent student of a filer who cannot be claimed is eligible + period: 2024 + input: + people: + parent: + age: 45 + has_tin: true + is_tax_unit_head: true + is_tax_unit_spouse: false + student: + age: 19 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, student] + households: + household: + members: [parent, student] + state_code: TX + output: + is_eligible_for_american_opportunity_credit: [false, true] + +- name: 2024 dependent student of a joint return with one claimable spouse is not eligible (the claimable spouse is the head) + period: 2024 + input: + people: + person_a: + age: 45 + has_tin: true + claimable_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 45 + has_tin: true + is_tax_unit_head: false + is_tax_unit_spouse: true + student: + age: 19 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, student] + filing_status: JOINT + households: + household: + members: [person_a, person_b, student] + state_code: TX + output: + is_eligible_for_american_opportunity_credit: [false, false, false] + +- name: 2024 dependent student of a joint return with one claimable spouse is not eligible (the claimable spouse is the spouse) + period: 2024 + input: + people: + person_b: + age: 45 + has_tin: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 45 + has_tin: true + claimable_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + student: + age: 19 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + has_tin: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, student] + filing_status: JOINT + households: + household: + members: [person_b, person_a, student] + state_code: TX + output: + is_eligible_for_american_opportunity_credit: [false, false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/education/lifetime_learning_credit/is_eligible_for_lifetime_learning_credit.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/education/lifetime_learning_credit/is_eligible_for_lifetime_learning_credit.yaml index 72ca159a702..4bff0f55a7d 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/education/lifetime_learning_credit/is_eligible_for_lifetime_learning_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/education/lifetime_learning_credit/is_eligible_for_lifetime_learning_credit.yaml @@ -70,3 +70,110 @@ has_tin: true output: is_eligible_for_lifetime_learning_credit: false + + +- name: 2024 student claimed as a dependent elsewhere cannot claim the credit + period: 2024 + input: + people: + student: + age: 30 + attends_eligible_educational_institution_for_lifetime_learning_credit: true + has_lifetime_learning_credit_1098_t_or_exception: true + has_tin: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [student] + households: + household: + members: [student] + state_code: TX + output: + # IRC 25A(g)(3). + is_eligible_for_lifetime_learning_credit: false + +- name: 2024 joint return with one spouse claimed elsewhere cannot claim the credit for either spouse (the claimable spouse is the head) + period: 2024 + input: + people: + person_a: + age: 30 + attends_eligible_educational_institution_for_lifetime_learning_credit: true + has_lifetime_learning_credit_1098_t_or_exception: true + has_tin: true + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + attends_eligible_educational_institution_for_lifetime_learning_credit: true + has_lifetime_learning_credit_1098_t_or_exception: true + has_tin: 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: TX + output: + is_eligible_for_lifetime_learning_credit: [false, false] + +- name: 2024 joint return with one spouse claimed elsewhere cannot claim the credit for either spouse (the claimable spouse is the spouse) + period: 2024 + input: + people: + person_b: + age: 30 + attends_eligible_educational_institution_for_lifetime_learning_credit: true + has_lifetime_learning_credit_1098_t_or_exception: true + has_tin: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + attends_eligible_educational_institution_for_lifetime_learning_credit: true + has_lifetime_learning_credit_1098_t_or_exception: true + has_tin: true + 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: TX + output: + is_eligible_for_lifetime_learning_credit: [false, false] + +- name: 2024 joint return with neither spouse claimed keeps both students' eligibility + period: 2024 + input: + people: + person_a: + age: 30 + attends_eligible_educational_institution_for_lifetime_learning_credit: true + has_lifetime_learning_credit_1098_t_or_exception: true + has_tin: true + person_b: + age: 30 + attends_eligible_educational_institution_for_lifetime_learning_credit: true + has_lifetime_learning_credit_1098_t_or_exception: true + has_tin: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: TX + output: + is_eligible_for_lifetime_learning_credit: [true, true] diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/recovery_rebate_credit/recovery_rebate_credit.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/recovery_rebate_credit/recovery_rebate_credit.yaml index e84c1db994a..01ed4209665 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/recovery_rebate_credit/recovery_rebate_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/recovery_rebate_credit/recovery_rebate_credit.yaml @@ -47,3 +47,382 @@ members: [parent, child_1, child_2] output: recovery_rebate_credit: 3_920 # https://www.efile.com/stimulus-check-three/ + +- name: 2021 single filer who can be claimed as a dependent gets no ARPA rebate + period: 2021 + input: + people: + filer: + age: 20 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: TX + output: + # IRC 6428B(c)(2): an eligible individual excludes "any individual who is a + # dependent of another taxpayer". + rrc_arpa: 0 + +- name: 2021 claimable single filer's child adds no ARPA rebate + period: 2021 + input: + people: + parent: + age: 20 + claimed_as_dependent_on_another_return: true + child: + age: 2 + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: TX + output: + # IRC 152(b)(1): such a filer has no dependents. + rrc_arpa: 0 + +- name: 2021 joint return with one claimable spouse gets the other spouse's ARPA rebate (the claimable spouse is the head) + period: 2021 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + 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: TX + output: + # Each spouse is an eligible individual or not on their own; $1,400 for + # the spouse who cannot be claimed. + rrc_arpa: 1_400 + +- name: 2021 joint return with one claimable spouse gets the other spouse's ARPA rebate (the claimable spouse is the spouse) + period: 2021 + input: + people: + person_b: + age: 22 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + 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: TX + output: + rrc_arpa: 1_400 + +- name: 2021 joint return with neither spouse claimable gets both rebates and the child's + period: 2021 + input: + people: + person_a: + age: 20 + person_b: + age: 22 + 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: TX + output: + # 3 x $1,400. + rrc_arpa: 4_200 + +# The Armed Forces exception (IRC 6428B(e)(2)(E)) waives the identification rule +# for the other spouse; it does not make a dependent of another taxpayer an +# eligible individual (IRC 6428B(c)(2)). +- name: 2021 military joint return with one claimable spouse gets one ARPA rebate (the claimable spouse is the head) + period: 2021 + input: + people: + person_a: + age: 30 + is_military: true + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + 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: TX + output: + rrc_arpa: 1400 + +- name: 2021 military joint return with one claimable spouse gets one ARPA rebate (the claimable spouse is the spouse) + period: 2021 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + is_military: true + 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: TX + output: + rrc_arpa: 1400 + +- name: 2021 military joint return whose other spouse is claimable gets one ARPA rebate (the claimable spouse is the head) + period: 2021 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_military: 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: TX + output: + rrc_arpa: 1400 + +- name: 2021 military joint return whose other spouse is claimable gets one ARPA rebate (the claimable spouse is the spouse) + period: 2021 + input: + people: + person_b: + age: 30 + is_military: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + 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: TX + output: + rrc_arpa: 1400 + +- name: 2021 military joint return with both spouses claimable gets no ARPA rebate + period: 2021 + input: + people: + person_a: + age: 30 + is_military: true + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + 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: TX + output: + rrc_arpa: 0 + +- name: 2021 military joint return with neither spouse claimable gets both ARPA rebates + period: 2021 + input: + people: + person_a: + age: 30 + is_military: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + 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: TX + output: + rrc_arpa: 2800 + +# IRC 6428B(c)(2): an individual "who is a dependent of another taxpayer" is not +# eligible, whether or not that taxpayer claims them. +- name: 2021 single filer who can be claimed but is not claimed gets no ARPA rebate + period: 2021 + input: + people: + person_a: + age: 20 + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_a] + households: + household: + members: [person_a] + state_code: TX + output: + rrc_arpa: 0 + +# IRC 6428B(a) allows the credit to an eligible individual, so a return whose only +# filer is a dependent of another taxpayer gets none, even when the filing +# exception lets that filer claim the child. +- name: 2021 claimable single filer within the filing exception gets no ARPA rebate for the child + period: 2021 + input: + people: + parent: + age: 30 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: TX + output: + rrc_arpa: 0 + +# IRC 6428(g)(1)(C) and 6428A(g)(3): children count when a spouse has a valid SSN, +# whether or not that spouse is an eligible individual. Here the spouse with the +# SSN can be claimed (within the filing exception) and serves in the Armed +# Forces; the other spouse has no SSN. +- name: 2020 child payments need a spouse with an SSN, not an eligible spouse with one (the claimable spouse is the head) + period: 2020 + input: + people: + person_a: + age: 30 + is_military: true + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + ssn_card_type: NONE + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: TX + output: + # One adult payment under the Armed Forces exception plus the child's. + rrc_cares: 1700 + rrc_caa: 1200 + +- name: 2020 child payments need a spouse with an SSN, not an eligible spouse with one (the claimable spouse is the spouse) + period: 2020 + input: + people: + person_b: + age: 30 + ssn_card_type: NONE + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + is_military: true + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: TX + output: + rrc_cares: 1700 + rrc_caa: 1200 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/credits/retirement_saving/savers_credit_eligible_person.yaml b/policyengine_us/tests/policy/baseline/gov/irs/credits/retirement_saving/savers_credit_eligible_person.yaml index 7309a5c6dc6..c070b58f18f 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/credits/retirement_saving/savers_credit_eligible_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/credits/retirement_saving/savers_credit_eligible_person.yaml @@ -17,3 +17,25 @@ is_full_time_student: false output: savers_credit_eligible_person: false + +- name: Savers credit admits a claimable filer who is not actually claimed + period: 2025 + input: + age: 26 + is_full_time_student: false + is_tax_unit_head_or_spouse: true + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + output: + savers_credit_eligible_person: true + +- name: Savers credit excludes an actually claimed filer + period: 2025 + input: + age: 26 + is_full_time_student: false + is_tax_unit_head_or_spouse: true + claimed_as_dependent_on_another_return: true + claimable_as_dependent_on_another_return: true + output: + savers_credit_eligible_person: false diff --git a/policyengine_us/tests/policy/baseline/gov/irs/deductions/standard/basic_standard_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/irs/deductions/standard/basic_standard_deduction.yaml index 483f073599a..4099214070c 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/deductions/standard/basic_standard_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/deductions/standard/basic_standard_deduction.yaml @@ -207,3 +207,81 @@ members: [head] output: basic_standard_deduction: 3_650 + +- name: 2025 joint return uses the dependent worksheet when either spouse can be claimed (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + employment_income: 8_000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + employment_income: 8_000 + claimed_as_dependent_on_another_return: false + 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: CA + output: + # Joint earned income $16,000 + $450 = $16,450, below the $31,500 joint amount. + basic_standard_deduction: 16_450 + +- name: 2025 joint return uses the dependent worksheet when either spouse can be claimed (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + employment_income: 8_000 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + employment_income: 8_000 + 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: CA + output: + # Joint earned income $16,000 + $450 = $16,450, below the $31,500 joint amount. + basic_standard_deduction: 16_450 + +- name: 2025 dependent filer with self-employment income uses earned income net of the self-employment tax deduction + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 20 + self_employment_income: 3_000 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head] + filing_status: SINGLE + households: + household: + members: [head] + state_code: CA + output: + # Worksheet earned income subtracts Schedule 1 line 15: + # $3,000 - $3,000 x 0.9235 x 15.3% / 2 = $2,788.06; plus $450 = $3,238.06. + basic_standard_deduction: 3238.06 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/student_loan_interest/student_loan_interest_ald_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/student_loan_interest/student_loan_interest_ald_eligible.yaml index ca6f654768e..e161077097f 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/student_loan_interest/student_loan_interest_ald_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/student_loan_interest/student_loan_interest_ald_eligible.yaml @@ -37,3 +37,89 @@ filing_status: SEPARATE output: student_loan_interest_ald_eligible: false + +- name: 2024 single filer claimed as a dependent elsewhere cannot deduct student loan interest + period: 2024 + input: + people: + filer: + age: 24 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: TX + output: + # IRC 221(c). + student_loan_interest_ald_eligible: false + +- name: 2024 joint return with one spouse claimed elsewhere cannot deduct student loan interest (the claimable spouse is the head) + period: 2024 + input: + people: + person_a: + age: 24 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 24 + 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: TX + output: + # Form 1040 instructions: "you, or your spouse if filing jointly, aren't + # claimed as a dependent". + student_loan_interest_ald_eligible: [false, false] + +- name: 2024 joint return with one spouse claimed elsewhere cannot deduct student loan interest (the claimable spouse is the spouse) + period: 2024 + input: + people: + person_b: + age: 24 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 24 + 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: TX + output: + student_loan_interest_ald_eligible: [false, false] + +# IRC 221(c): the bar applies to an individual who is claimed. +- name: 2024 single filer who can be claimed but is not claimed can deduct student loan interest + period: 2024 + input: + people: + person_a: + age: 22 + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_a] + households: + household: + members: [person_a] + state_code: TX + output: + student_loan_interest_ald_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/tuition_and_fees_deduction_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/tuition_and_fees_deduction_eligible.yaml index 4912f0155de..c55f696055c 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/tuition_and_fees_deduction_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/deductions/tuition_and_fees_deduction_eligible.yaml @@ -26,3 +26,111 @@ output: tuition_and_fees_deduction_eligible: false # Can't claim this deduction if the household has taken the American Oppportunity or Lifetime Learning Credit. + +# IRC 222(c)(3): no deduction to an individual for whom a section 151 deduction +# may be allowed to another taxpayer. +- name: 2020 single filer who can be claimed as a dependent is not eligible + period: 2020 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_a] + households: + household: + members: [person_a] + state_code: TX + output: + tuition_and_fees_deduction_eligible: false + +- name: 2020 joint return with one claimable spouse is not eligible (the claimable spouse is the head) + period: 2020 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + 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: TX + output: + tuition_and_fees_deduction_eligible: false + +- name: 2020 joint return with one claimable spouse is not eligible (the claimable spouse is the spouse) + period: 2020 + input: + people: + person_b: + age: 22 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + 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: TX + output: + tuition_and_fees_deduction_eligible: false + +- name: 2020 joint return with neither spouse claimable is eligible + period: 2020 + input: + people: + person_a: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 22 + 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: TX + output: + tuition_and_fees_deduction_eligible: true + +- name: 2020 single filer who can be claimed but is not claimed is not eligible + period: 2020 + input: + people: + person_a: + age: 20 + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_a] + households: + household: + members: [person_a] + state_code: TX + output: + # IRC 222(c)(3): a section 151 deduction "may be allowed to another taxpayer". + tuition_and_fees_deduction_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/exemptions/exemptions_count.yaml b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/exemptions/exemptions_count.yaml new file mode 100644 index 00000000000..40ce1bf5142 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/exemptions/exemptions_count.yaml @@ -0,0 +1,242 @@ +- name: 2025 single filer with a child counts both + period: 2025 + input: + people: + parent: + age: 30 + child: + age: 5 + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: TX + output: + exemptions_count: 2 + +- name: 2025 single filer who can be claimed as a dependent has no exemptions + period: 2025 + input: + people: + parent: + age: 20 + claimed_as_dependent_on_another_return: true + child: + age: 5 + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: TX + output: + # IRC 151(d)(2) for the filer; IRC 152(b)(1) for the child. + exemptions_count: 0 + +- name: 2025 joint return with one claimable spouse counts only the other spouse (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: TX + output: + exemptions_count: 1 + +- name: 2025 joint return with one claimable spouse counts only the other spouse (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: TX + output: + exemptions_count: 1 + +- name: 2025 joint return with both spouses claimable has no exemptions + period: 2025 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + person_b: + age: 20 + claimed_as_dependent_on_another_return: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: TX + output: + exemptions_count: 0 + +- name: 2025 joint return with neither spouse claimable counts everyone + period: 2025 + input: + people: + person_a: + age: 20 + person_b: + age: 20 + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: TX + output: + exemptions_count: 3 + +# Publication 501, Dependent Taxpayer Test: a filer whose would-be claimant is not +# required to file and files no return or only for a refund can claim dependents. +# The filer's own exemption is still zero (IRC 151(d)(2)). +- name: 2025 claimable single filer within the filing exception counts the child but not themselves + period: 2025 + input: + people: + parent: + age: 30 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: TX + output: + exemptions_count: 1 + +- name: 2025 joint return whose claimable spouse is within the filing exception counts the other spouse and the child (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: TX + output: + exemptions_count: 2 + +- name: 2025 joint return whose claimable spouse is within the filing exception counts the other spouse and the child (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: TX + output: + exemptions_count: 2 + +- name: 2025 filer who can be claimed but is not claimed has no own exemption and no dependents + period: 2025 + input: + people: + parent: + age: 30 + claimable_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: TX + output: + # Exemptions turn on whether the filer can be claimed, not on an actual claim. + exemptions_count: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/az/tax/income/exemptions/az_aged_exemption_eligible_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/az/tax/income/exemptions/az_aged_exemption_eligible_person.yaml index a4d945380ab..1bb415b0fed 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/az/tax/income/exemptions/az_aged_exemption_eligible_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/az/tax/income/exemptions/az_aged_exemption_eligible_person.yaml @@ -4,13 +4,13 @@ people: person1: is_tax_unit_head: true + claimed_as_dependent_on_another_return: false person2: is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true tax_units: tax_unit: az_filing_status: JOINT - head_is_dependent_elsewhere: false - spouse_is_dependent_elsewhere: true members: [person1, person2] household: members: [person1, person2] @@ -24,13 +24,13 @@ people: person1: is_tax_unit_head: true + claimed_as_dependent_on_another_return: true person2: is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true tax_units: tax_unit: az_filing_status: JOINT - head_is_dependent_elsewhere: true - spouse_is_dependent_elsewhere: true members: [person1, person2] household: members: [person1, person2] @@ -44,13 +44,13 @@ people: person1: is_tax_unit_head: true + claimed_as_dependent_on_another_return: false person2: is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: false tax_units: tax_unit: az_filing_status: SEPARATE - head_is_dependent_elsewhere: false - spouse_is_dependent_elsewhere: false members: [person1, person2] household: members: [person1, person2] @@ -64,19 +64,41 @@ people: person1: is_tax_unit_head: true + claimed_as_dependent_on_another_return: false person2: is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: false person3: is_tax_unit_head: false is_tax_unit_spouse: false tax_units: tax_unit: az_filing_status: SEPARATE - head_is_dependent_elsewhere: false - spouse_is_dependent_elsewhere: false members: [person1, person2, person3] household: members: [person1, person2, person3] state_code: AZ output: az_aged_exemption_eligible_person: [true, false, false] + +- name: Arizona aged exemption retains an unclaimed claimable filer + period: 2025 + input: + state_code: AZ + age: 70 + is_tax_unit_head: true + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + output: + az_aged_exemption_eligible_person: true + +- name: Arizona aged exemption excludes an actually claimed filer + period: 2025 + input: + state_code: AZ + age: 70 + is_tax_unit_head: true + claimed_as_dependent_on_another_return: true + claimable_as_dependent_on_another_return: true + output: + az_aged_exemption_eligible_person: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/credits/child_dependent_care/ca_cdcc_relevant_expenses.yaml b/policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/credits/child_dependent_care/ca_cdcc_relevant_expenses.yaml index 41bb2e8353e..e415e951776 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/credits/child_dependent_care/ca_cdcc_relevant_expenses.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/credits/child_dependent_care/ca_cdcc_relevant_expenses.yaml @@ -117,3 +117,64 @@ dependent_care_assistance_exclusion: 4_000 # min(10_000 expenses, $6,000 two-child cap - $4,000 exclusion, 38_000) = 2_000. ca_cdcc_relevant_expenses: 2_000 + +# FTB 3506 counts expenses for qualifying persons. The child of a filer who can be +# claimed as a dependent is not one (IRC 152(b)(1)); the incapacitated relative is. +- name: 2025 childcare for the child of a claimable filer does not count + period: 2025 + input: + people: + parent: + age: 30 + employment_income: 5000 + claimable_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + relative: + age: 40 + is_incapable_of_self_care: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child, relative] + tax_unit_childcare_expenses: 3000 + households: + household: + members: [parent, child, relative] + state_code: CA + output: + ca_cdcc_relevant_expenses: 0 + +- name: 2025 the same household with a filer who cannot be claimed counts the childcare + period: 2025 + input: + people: + parent: + age: 30 + employment_income: 5000 + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + relative: + age: 40 + is_incapable_of_self_care: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child, relative] + tax_unit_childcare_expenses: 3000 + households: + household: + members: [parent, child, relative] + state_code: CA + output: + ca_cdcc_relevant_expenses: 3000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/de/tax/income/credits/personal/de_personal_credit_indv.yaml b/policyengine_us/tests/policy/baseline/gov/states/de/tax/income/credits/personal/de_personal_credit_indv.yaml index 406b0d0f8f9..5964fe8cf76 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/de/tax/income/credits/personal/de_personal_credit_indv.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/de/tax/income/credits/personal/de_personal_credit_indv.yaml @@ -71,3 +71,54 @@ output: # Equal capacity: split evenly (both columns can absorb their share) de_personal_credit_indv: [110, 110] + + +- name: 2025 spouse who can be claimed as a dependent has no personal credit (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + de_income_tax_before_non_refundable_credits_indv: 1000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + de_income_tax_before_non_refundable_credits_indv: 1000 + 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: DE + output: + # 30 Del. C. 1110(b)(1): $110 for each personal exemption to which the + # individual is entitled for federal purposes; IRC 151(d)(2). + de_personal_credit_indv: [0, 110] + +- name: 2025 spouse who can be claimed as a dependent has no personal credit (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + de_income_tax_before_non_refundable_credits_indv: 1000 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + de_income_tax_before_non_refundable_credits_indv: 1000 + 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: DE + output: + de_personal_credit_indv: [110, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/de/tax/income/credits/personal/de_personal_credits.yaml b/policyengine_us/tests/policy/baseline/gov/states/de/tax/income/credits/personal/de_personal_credits.yaml index fd12e7c01ce..b13f8f2f86d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/de/tax/income/credits/personal/de_personal_credits.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/de/tax/income/credits/personal/de_personal_credits.yaml @@ -30,3 +30,58 @@ de_income_tax_before_non_refundable_credits_unit: 1000000 output: de_personal_credit: 0 + + +- name: 2025 joint return with one claimable spouse gets one personal credit (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: DE + output: + # Federal exemptions: the other spouse only; IRC 152(b)(1) leaves no + # dependents. + de_personal_credit_potential: 110 + +- name: 2025 joint return with one claimable spouse gets one personal credit (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: DE + output: + de_personal_credit_potential: 110 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/tax/income/credits/ga_ctc.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/tax/income/credits/ga_ctc.yaml index 658c2647ad9..0690ba455ca 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/tax/income/credits/ga_ctc.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/tax/income/credits/ga_ctc.yaml @@ -6,7 +6,6 @@ age: 30 child: age: 2 - ctc_qualifying_child: true tax_units: tax_unit: members: @@ -30,7 +29,6 @@ age: 30 child: age: 6 - ctc_qualifying_child: true tax_units: tax_unit: members: @@ -54,10 +52,8 @@ age: 32 child1: age: 1 - ctc_qualifying_child: true child2: age: 5 - ctc_qualifying_child: true tax_units: tax_unit: members: @@ -83,7 +79,6 @@ age: 30 child: age: 2 - ctc_qualifying_child: true tax_units: tax_unit: members: @@ -107,7 +102,6 @@ age: 30 child: age: 2 - ctc_qualifying_child: true tax_units: tax_unit: members: @@ -123,3 +117,27 @@ state_code: GA output: ga_non_refundable_credits: 0 + + +- name: 2026 GA CTC still counts the child of a filer who can be claimed as a dependent + period: 2026 + input: + people: + parent: + age: 20 + claimed_as_dependent_on_another_return: true + child: + age: 2 + tax_units: + tax_unit: + members: [parent, child] + filing_status: SINGLE + ga_income_tax_before_non_refundable_credits: 10000 + households: + household: + members: [parent, child] + state_code: GA + output: + # Georgia uses the IRC 24(c) qualifying-child definition only; whether IRC + # 152(b)(1) reaches it is not settled, so the child test is kept. + ga_ctc: 250 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/tax/income/credits/ga_low_income_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/tax/income/credits/ga_low_income_credit.yaml index 5a059239e46..2a410aa94df 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/tax/income/credits/ga_low_income_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/tax/income/credits/ga_low_income_credit.yaml @@ -5,7 +5,7 @@ adjusted_gross_income: 14000 age_head: 67 age_spouse: 70 - exemptions_count: 2 + tax_unit_size: 2 ga_income_tax_before_non_refundable_credits: 1000000 output: ga_low_income_credit: 32 @@ -16,7 +16,7 @@ adjusted_gross_income: 4000 age_head: 67 age_spouse: 56 - exemptions_count: 2 + tax_unit_size: 2 ga_income_tax_before_non_refundable_credits: 1000000 output: ga_low_income_credit: 78 @@ -27,7 +27,7 @@ adjusted_gross_income: 15500 age_head: 80 age_spouse: 75 - exemptions_count: 3 + tax_unit_size: 3 ga_income_tax_before_non_refundable_credits: 1000000 output: ga_low_income_credit: 25 @@ -38,7 +38,7 @@ adjusted_gross_income: 4000 age_head: 67 age_spouse: 56 - exemptions_count: 0 + tax_unit_size: 0 ga_income_tax_before_non_refundable_credits: 1000000 output: ga_low_income_credit: 26 @@ -49,7 +49,7 @@ adjusted_gross_income: 10500 age_head: 67 age_spouse: 56 - exemptions_count: 0 + tax_unit_size: 0 ga_income_tax_before_non_refundable_credits: 1000000 output: ga_low_income_credit: 8 @@ -60,7 +60,7 @@ adjusted_gross_income: 10500 age_head: 56 age_spouse: 56 - exemptions_count: 0 + tax_unit_size: 0 ga_income_tax_before_non_refundable_credits: 1000000 output: ga_low_income_credit: 0 @@ -71,7 +71,7 @@ adjusted_gross_income: 10500 age_head: 65 age_spouse: 64 - exemptions_count: 1 + tax_unit_size: 1 ga_income_tax_before_non_refundable_credits: 1000000 output: ga_low_income_credit: 16 @@ -82,7 +82,7 @@ adjusted_gross_income: 10000 age_head: 64 age_spouse: 64 - exemptions_count: 2 + tax_unit_size: 2 ga_income_tax_before_non_refundable_credits: 1000000 output: ga_low_income_credit: 16 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/act_163_sunset.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/act_163_sunset.yaml index 4116a0a6dac..778252cac05 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/act_163_sunset.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/act_163_sunset.yaml @@ -34,7 +34,6 @@ adjusted_gross_income: 10_000 filing_status: JOINT exemptions_count: 2 - head_is_dependent_elsewhere: false households: household: members: [person1, person2] @@ -58,7 +57,6 @@ adjusted_gross_income: 4_000 filing_status: JOINT exemptions_count: 2 - head_is_dependent_elsewhere: false households: household: members: [person1, person2] @@ -80,7 +78,6 @@ adjusted_gross_income: 10_000 filing_status: SINGLE exemptions_count: 1 - head_is_dependent_elsewhere: false households: household: members: [person1] @@ -102,7 +99,6 @@ adjusted_gross_income: 4_000 filing_status: SINGLE exemptions_count: 1 - head_is_dependent_elsewhere: false households: household: members: [person1] diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_credit.yaml index 9ad568e7fee..c4daec08bc0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_credit.yaml @@ -20,7 +20,6 @@ adjusted_gross_income: 4_000 filing_status: SINGLE exemptions_count: 3 - head_is_dependent_elsewhere: false households: household: members: [person1, person2, person3] @@ -50,7 +49,6 @@ adjusted_gross_income: 4_000 filing_status: SINGLE exemptions_count: 3 - head_is_dependent_elsewhere: false households: household: members: [person1, person2, person3] @@ -71,6 +69,7 @@ person2: age: 39 is_child: false + claimed_as_dependent_on_another_return: true spm_units: spm_unit: members: [person1, person2] @@ -81,7 +80,6 @@ adjusted_gross_income: 4_000 filing_status: SINGLE exemptions_count: 2 - head_is_dependent_elsewhere: true households: household: members: [person1, person2] @@ -111,7 +109,6 @@ adjusted_gross_income: 35_000 filing_status: SINGLE exemptions_count: 3 - head_is_dependent_elsewhere: false households: household: members: [person1, person2, person3] @@ -141,7 +138,6 @@ adjusted_gross_income: 35_000 filing_status: JOINT exemptions_count: 3 - head_is_dependent_elsewhere: false households: household: members: [person1, person2, person3] @@ -171,7 +167,6 @@ adjusted_gross_income: 55_000 filing_status: JOINT exemptions_count: 3 - head_is_dependent_elsewhere: false households: household: members: [person1, person2, person3] @@ -197,7 +192,6 @@ members: [person1, person2] adjusted_gross_income: 6_000 filing_status: SINGLE - head_is_dependent_elsewhere: false households: household: members: [person1, person2] @@ -223,7 +217,6 @@ members: [person1, person2] adjusted_gross_income: 6_000 filing_status: SINGLE - head_is_dependent_elsewhere: false households: household: members: [person1, person2] @@ -258,3 +251,686 @@ exemptions_count: 2 hi_food_excise_credit: 440 hi_income_tax: -440 + +- name: 2027 joint return where only one spouse can be claimed (the claimable spouse is the head) + period: 2027 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + adjusted_gross_income: 10_000 + households: + household: + members: [person_a, person_b] + state_code: HI + output: + # Form N-311 counts only the spouse who cannot be claimed: 1 x $220. + hi_food_excise_credit: 220 + +- name: 2027 joint return where only one spouse can be claimed (the claimable spouse is the spouse) + period: 2027 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + 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 + adjusted_gross_income: 10_000 + households: + household: + members: [person_b, person_a] + state_code: HI + output: + # Form N-311 counts only the spouse who cannot be claimed: 1 x $220. + hi_food_excise_credit: 220 + +- name: 2027 joint return where both spouses can be claimed + period: 2027 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + 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 + adjusted_gross_income: 10_000 + households: + household: + members: [person_a, person_b] + state_code: HI + output: + hi_food_excise_credit: 0 + +- name: 2022 joint return with a publicly supported minor where only one spouse can be claimed (the claimable spouse is the head) + period: 2022 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4_000 + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + # The spouse who cannot be claimed: $110; HRS 235-55.85(c) lets the minor + # receiving public support count for this credit: $110. + hi_food_excise_credit: 220 + +- name: 2022 joint return with a publicly supported minor where only one spouse can be claimed (the claimable spouse is the spouse) + period: 2022 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 4_000 + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + # The spouse who cannot be claimed: $110; HRS 235-55.85(c) lets the minor + # receiving public support count for this credit: $110. + hi_food_excise_credit: 220 + +- name: 2025 joint return with a publicly supported minor where only one spouse can be claimed (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4_000 + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + # From 2023 the minor counts as a qualified exemption: 2 x $220. + hi_food_excise_credit: 440 + +- name: 2025 joint return with a publicly supported minor where only one spouse can be claimed (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 4_000 + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + # From 2023 the minor counts as a qualified exemption: 2 x $220. + hi_food_excise_credit: 440 + +- name: 2022 joint return where one spouse and the publicly supported minor can be claimed elsewhere (the claimable spouse is the head) + period: 2022 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4_000 + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + # Form N-311 line 3 lists only minors who cannot be claimed by another taxpayer, + # so only the spouse who cannot be claimed counts: $110. + hi_food_excise_credit: 110 + +- name: 2022 joint return where one spouse and the publicly supported minor can be claimed elsewhere (the claimable spouse is the spouse) + period: 2022 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 4_000 + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + # Form N-311 line 3 lists only minors who cannot be claimed by another taxpayer, + # so only the spouse who cannot be claimed counts: $110. + hi_food_excise_credit: 110 + +- name: 2025 joint return where one spouse and the publicly supported minor can be claimed elsewhere (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4_000 + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + # Only the spouse who cannot be claimed counts: 1 x $220. + hi_food_excise_credit: 220 + +- name: 2025 joint return where one spouse and the publicly supported minor can be claimed elsewhere (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 4_000 + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + # Only the spouse who cannot be claimed counts: 1 x $220. + hi_food_excise_credit: 220 + +# N-311 (2022 and 2025), PDF p.1 lines 2-3, excludes externally claimable +# persons from both ordinary qualified persons and publicly supported minors. +# At $4,000 AGI, 2022 lines 7-10 give 2 x $110; 2025 lines 7-9 give 2 x $220. +- name: 2022 independent joint filers exclude externally claimable publicly supported child when person_a is head + period: 2022 + input: + people: + person_a: + age: 40 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: false + dependent_claimant_filing_exception: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 45 + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + hi_food_excise_credit: 220 + hi_food_excise_exemption_amount: 220 + hi_food_excise_credit_minor_child_count: 0 + +- name: 2022 independent joint filers exclude externally claimable publicly supported child when person_b is head + period: 2022 + input: + people: + person_b: + age: 45 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 40 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: false + dependent_claimant_filing_exception: false + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + hi_food_excise_credit: 220 + hi_food_excise_exemption_amount: 220 + hi_food_excise_credit_minor_child_count: 0 + +- name: 2025 independent joint filers exclude externally claimable publicly supported child when person_a is head + period: 2025 + input: + people: + person_a: + age: 40 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: false + dependent_claimant_filing_exception: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 45 + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + hi_food_excise_credit: 440 + hi_food_excise_exemption_amount: 440 + hi_food_excise_credit_minor_child_count: 0 + +- name: 2025 independent joint filers exclude externally claimable publicly supported child when person_b is head + period: 2025 + input: + people: + person_b: + age: 45 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 40 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: false + dependent_claimant_filing_exception: false + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + hi_food_excise_credit: 440 + hi_food_excise_exemption_amount: 440 + hi_food_excise_credit_minor_child_count: 0 + +- name: 2022 joint return filing exception restores own ordinary dependent but excludes claimable head + period: 2022 + input: + people: + person_a: + age: 26 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: false + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + hi_food_excise_credit_minor_child_count: 0 + hi_food_excise_credit: 220 + hi_food_excise_exemption_amount: 220 + +- name: 2022 joint return filing exception restores own ordinary dependent but excludes claimable spouse + period: 2022 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 26 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: false + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + hi_food_excise_credit_minor_child_count: 0 + hi_food_excise_credit: 220 + hi_food_excise_exemption_amount: 220 + +- name: 2025 joint return filing exception restores own ordinary dependent but excludes claimable head + period: 2025 + input: + people: + person_a: + age: 26 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: false + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + hi_food_excise_credit_minor_child_count: 0 + hi_food_excise_credit: 440 + hi_food_excise_exemption_amount: 440 + +- name: 2025 joint return filing exception restores own ordinary dependent but excludes claimable spouse + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 26 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: false + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + hi_food_excise_credit_minor_child_count: 0 + hi_food_excise_credit: 440 + hi_food_excise_exemption_amount: 440 + +# A publicly supported minor filer belongs to N-311 line 2, not line 3. +# At $16,000 AGI in 2022, 2 ordinary persons x $70 = $140. +- name: 2022 publicly supported minor filer is only an ordinary qualified person when labelled head + period: 2022 + input: + people: + person_a: + age: 17 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: false + dependent_claimant_filing_exception: false + is_tax_unit_head: true + is_tax_unit_spouse: false + hi_food_excise_credit_child_receiving_public_support: true + person_b: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + adjusted_gross_income: 16000 + households: + household: + members: [person_a, person_b] + state_code: HI + output: + hi_food_excise_credit: 140 + hi_food_excise_credit_minor_child_count: 0 + +- name: 2022 publicly supported minor filer is only an ordinary qualified person when labelled spouse + period: 2022 + input: + people: + person_b: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 17 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: false + dependent_claimant_filing_exception: false + is_tax_unit_head: false + is_tax_unit_spouse: true + hi_food_excise_credit_child_receiving_public_support: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + adjusted_gross_income: 16000 + households: + household: + members: [person_b, person_a] + state_code: HI + output: + hi_food_excise_credit: 140 + hi_food_excise_credit_minor_child_count: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/hi_act_115_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/hi_act_115_rebate.yaml index 13ebfd8d94a..124ffe32e48 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/hi_act_115_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/hi_act_115_rebate.yaml @@ -162,3 +162,156 @@ state_code: HI output: hi_act_115_rebate: 0 + +- name: Joint return with a child where only one spouse can be claimed (the claimable spouse is the head) + period: 2021 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 5_000 + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + # Only the spouse who cannot be claimed has a qualified exemption; a joint + # return on which a spouse can be claimed claims no dependents. 1 x $300. + hi_act_115_rebate: 300 + +- name: Joint return with a child where only one spouse can be claimed (the claimable spouse is the spouse) + period: 2021 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 5_000 + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + # Only the spouse who cannot be claimed has a qualified exemption; a joint + # return on which a spouse can be claimed claims no dependents. 1 x $300. + hi_act_115_rebate: 300 + +- name: Joint return where both spouses can be claimed + period: 2021 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + 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 + adjusted_gross_income: 5_000 + households: + household: + members: [person_a, person_b] + state_code: HI + output: + hi_act_115_rebate: 0 + +# Act 115 sec.3(a)-(b), HRS 235-54(a), and Pub. 501 PDF p.11. +- name: Joint return filing exception restores own dependent but excludes claimable head from Act 115 + period: 2021 + input: + people: + person_a: + age: 26 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + hi_act_115_rebate: 600 + +- name: Joint return filing exception restores own dependent but excludes claimable spouse from Act 115 + period: 2021 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 26 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + hi_act_115_rebate: 600 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_low_income_household_renters_tax_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_low_income_household_renters_tax_credit.yaml index cddb436375d..cc6de0fb9ea 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_low_income_household_renters_tax_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_low_income_household_renters_tax_credit.yaml @@ -37,3 +37,258 @@ hi_tax_credit_for_low_income_household_renters_eligible: false output: hi_tax_credit_for_low_income_household_renters: 0 + +- name: Joint return with a child where only one spouse can be claimed (the claimable spouse is the head) + period: 2021 + input: + people: + person_a: + age: 66 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 66 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + hi_tax_credit_for_low_income_household_renters_eligible: true + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + # Schedule X lines 8-10: the spouse who cannot be claimed, plus their age + # 65 exemption. 2 x $50. + hi_tax_credit_for_low_income_household_renters: 100 + +- name: Joint return with a child where only one spouse can be claimed (the claimable spouse is the spouse) + period: 2021 + input: + people: + person_b: + age: 66 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 66 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + hi_tax_credit_for_low_income_household_renters_eligible: true + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + # Schedule X lines 8-10: the spouse who cannot be claimed, plus their age + # 65 exemption. 2 x $50. + hi_tax_credit_for_low_income_household_renters: 100 + +# Schedule X lines 8-10; Pub. 501 filing exception restores only dependents. +- name: Joint return filing exception restores own dependent without claimable head personal or aged exemption + period: 2021 + input: + people: + person_a: + age: 66 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 66 + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + hi_tax_credit_for_low_income_household_renters_eligible: true + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + hi_tax_credit_for_low_income_household_renters: 150 + +- name: Joint return filing exception restores own dependent without claimable spouse personal or aged exemption + period: 2021 + input: + people: + person_b: + age: 66 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 66 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + hi_tax_credit_for_low_income_household_renters_eligible: true + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + hi_tax_credit_for_low_income_household_renters: 150 + +# Schedule X counts only people who cannot be claimed as a dependent by another +# taxpayer, so a child in the household who can be claimed elsewhere adds no +# exemption. +- name: Joint return with a child who can be claimed elsewhere counts the two filers + period: 2021 + input: + people: + person_a: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + claimable_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + hi_tax_credit_for_low_income_household_renters_eligible: true + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + hi_tax_credit_for_low_income_household_renters: 100 + +- name: Joint return with a child who cannot be claimed elsewhere counts the child + period: 2021 + input: + people: + person_a: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + hi_tax_credit_for_low_income_household_renters_eligible: true + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + hi_tax_credit_for_low_income_household_renters: 150 + +- name: Joint return within the filing exception with a child who can be claimed elsewhere counts only the other spouse (the claimable spouse is the head) + period: 2021 + input: + people: + person_a: + age: 30 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + claimable_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + hi_tax_credit_for_low_income_household_renters_eligible: true + households: + household: + members: [person_a, person_b, child_1] + state_code: HI + output: + hi_tax_credit_for_low_income_household_renters: 50 + +- name: Joint return within the filing exception with a child who can be claimed elsewhere counts only the other spouse (the claimable spouse is the spouse) + period: 2021 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + claimable_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + hi_tax_credit_for_low_income_household_renters_eligible: true + households: + household: + members: [person_b, person_a, child_1] + state_code: HI + output: + hi_tax_credit_for_low_income_household_renters: 50 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_tax_credit_for_low_income_household_renters_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_tax_credit_for_low_income_household_renters_eligible.yaml index 4916c7667b8..629efc27e05 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_tax_credit_for_low_income_household_renters_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_tax_credit_for_low_income_household_renters_eligible.yaml @@ -2,7 +2,7 @@ period: 2021 input: state_code: HI - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false hi_agi: 29_000 rent: 1_100 output: @@ -12,7 +12,7 @@ period: 2021 input: state_code: HI - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false hi_agi: 31_000 rent: 1_100 output: @@ -22,7 +22,7 @@ period: 2021 input: state_code: HI - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false hi_agi: 29_000 rent: 900 output: @@ -32,8 +32,91 @@ period: 2021 input: state_code: HI - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false hi_agi: 32_000 rent: 900 output: hi_tax_credit_for_low_income_household_renters_eligible: false + +- name: Joint return where only one spouse can be claimed (the claimable spouse is the head) + period: 2021 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + rent: 1_100 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + hi_agi: 29_000 + households: + household: + members: [person_a, person_b] + state_code: HI + output: + # HRS 235-55.7(b): the spouse who cannot be claimed may claim the credit. + hi_tax_credit_for_low_income_household_renters_eligible: true + +- name: Joint return where only one spouse can be claimed (the claimable spouse is the spouse) + period: 2021 + input: + people: + person_b: + age: 20 + rent: 1_100 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + 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 + hi_agi: 29_000 + households: + household: + members: [person_b, person_a] + state_code: HI + output: + # HRS 235-55.7(b): the spouse who cannot be claimed may claim the credit. + hi_tax_credit_for_low_income_household_renters_eligible: true + +- name: Joint return where both spouses can be claimed + period: 2021 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + rent: 1_100 + 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 + hi_agi: 29_000 + households: + household: + members: [person_a, person_b] + state_code: HI + output: + hi_tax_credit_for_low_income_household_renters_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/deductions/hi_deductions.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/deductions/hi_deductions.yaml index fee63c3b063..56eb95f2a84 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/deductions/hi_deductions.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/deductions/hi_deductions.yaml @@ -7,7 +7,7 @@ hi_agi: 1_000 hi_total_itemized_deductions: 5_000 hi_reduced_itemized_deductions: 1_000 - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: hi_deductions: 5_000 @@ -20,7 +20,7 @@ hi_agi: 1_000_000 hi_total_itemized_deductions: 5_000 hi_reduced_itemized_deductions: 1_000 - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: hi_deductions: 4_400 @@ -33,7 +33,7 @@ hi_agi: 1_000 hi_total_itemized_deductions: 1_000 hi_reduced_itemized_deductions: 1_000 - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: hi_deductions: 4_400 @@ -46,7 +46,7 @@ hi_agi: 1_000_000 hi_total_itemized_deductions: 5_000 hi_reduced_itemized_deductions: 1_000 - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: hi_deductions: 2_200 @@ -59,7 +59,7 @@ hi_agi: 1_000_000 hi_total_itemized_deductions: 5_000 hi_reduced_itemized_deductions: 4_500 - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: hi_deductions: 4_500 @@ -71,3 +71,208 @@ employment_income: 62_000 output: hi_deductions: 8_800 + +- name: 2025 joint standard deduction limited when either spouse can be claimed (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + tax_unit_earned_income: 3_000 + hi_itemized_deductions: 0 + households: + household: + members: [person_a, person_b] + state_code: HI + output: + # HRS 235-2.4(a)(3): greater of $500 or earned income ($3,000), up to $8,800. + hi_deductions: 3_000 + +- name: 2025 joint standard deduction limited when either spouse can be claimed (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + 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 + tax_unit_earned_income: 3_000 + hi_itemized_deductions: 0 + households: + household: + members: [person_b, person_a] + state_code: HI + output: + # HRS 235-2.4(a)(3): greater of $500 or earned income ($3,000), up to $8,800. + hi_deductions: 3_000 + +- name: 2025 joint filers with a claimable spouse itemize above the limited standard deduction (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + tax_unit_earned_income: 3_000 + hi_itemized_deductions: 4_000 + households: + household: + members: [person_a, person_b] + state_code: HI + output: + # Itemized deductions of $4,000 exceed the limited $3,000 standard deduction. + hi_deductions: 4_000 + +- name: 2025 joint filers with a claimable spouse itemize above the limited standard deduction (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + 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 + tax_unit_earned_income: 3_000 + hi_itemized_deductions: 4_000 + households: + household: + members: [person_b, person_a] + state_code: HI + output: + # Itemized deductions of $4,000 exceed the limited $3,000 standard deduction. + hi_deductions: 4_000 + +- name: 2025 single dependent filer with little earned income gets the $500 minimum + period: 2025 + input: + state_code: HI + filing_status: SINGLE + claimed_as_dependent_on_another_return: true + tax_unit_earned_income: 300 + hi_itemized_deductions: 0 + output: + # HRS 235-2.4(a)(3): greater of $500 or earned income ($300). + hi_deductions: 500 + +- name: 2025 single dependent filer with self-employment income uses earned income net of the self-employment tax deduction + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 20 + self_employment_income: 3_000 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head] + filing_status: SINGLE + hi_itemized_deductions: 0 + households: + household: + members: [head] + state_code: HI + output: + # N-11 worksheet earned income subtracts Schedule 1 line 15: + # $3,000 x 0.9235 x 15.3% / 2 = $211.94, so $3,000 - $211.94 = $2,788.06. + hi_deductions: 2_788.06 + +- name: 2025 joint return with a claimable self-employed spouse uses earned income net of the self-employment tax deduction (the claimable spouse is the head) + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person_a: + age: 20 + self_employment_income: 3_000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + hi_itemized_deductions: 0 + households: + household: + members: [person_a, person_b] + state_code: HI + output: + # $3,000 - $3,000 x 0.9235 x 15.3% / 2 = $2,788.06, below the $8,800 joint amount. + hi_deductions: 2788.06 + +- name: 2025 joint return with a claimable self-employed spouse uses earned income net of the self-employment tax deduction (the claimable spouse is the spouse) + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + self_employment_income: 3_000 + 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 + hi_itemized_deductions: 0 + households: + household: + members: [person_b, person_a] + state_code: HI + output: + # $3,000 - $3,000 x 0.9235 x 15.3% / 2 = $2,788.06, below the $8,800 joint amount. + hi_deductions: 2788.06 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/deductions/itemized/hi_salt_deduction_integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/deductions/itemized/hi_salt_deduction_integration.yaml index 74db648797c..7efb22ba1f0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/deductions/itemized/hi_salt_deduction_integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/tax/income/deductions/itemized/hi_salt_deduction_integration.yaml @@ -4,7 +4,7 @@ state_code: HI filing_status: SINGLE age: 40 - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false adjusted_gross_income: 99_999 hi_agi: 99_999 state_withheld_income_tax: 6_000 @@ -32,7 +32,7 @@ state_code: HI filing_status: SINGLE age: 40 - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false adjusted_gross_income: 100_000 hi_agi: 100_000 state_withheld_income_tax: 6_000 @@ -60,7 +60,7 @@ state_code: HI filing_status: SINGLE age: 40 - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false adjusted_gross_income: 99_999 hi_agi: 99_999 state_withheld_income_tax: 2_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/me/tax/income/credits/sales_tax_fairness_credit/me_sales_tax_fairness_credit_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/me/tax/income/credits/sales_tax_fairness_credit/me_sales_tax_fairness_credit_eligible.yaml index b3afa273542..b81ac606775 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/me/tax/income/credits/sales_tax_fairness_credit/me_sales_tax_fairness_credit_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/me/tax/income/credits/sales_tax_fairness_credit/me_sales_tax_fairness_credit_eligible.yaml @@ -2,7 +2,7 @@ period: 2022 input: state_code: ME - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true filing_status: JOINT output: me_sales_tax_fairness_credit_eligible: false @@ -11,7 +11,7 @@ period: 2022 input: state_code: ME - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false filing_status: SINGLE output: me_sales_tax_fairness_credit_eligible: true @@ -20,7 +20,86 @@ period: 2022 input: state_code: ME - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true filing_status: SEPARATE output: me_sales_tax_fairness_credit_eligible: false + +- name: Joint return where only one spouse can be claimed as a dependent (the claimable spouse is the head) + period: 2022 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + 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: ME + output: + # 36 MRSA 5213-A(6)(C) excludes the claimable individual; the other spouse + # still qualifies for the joint credit. + me_sales_tax_fairness_credit_eligible: true + +- name: Joint return where only one spouse can be claimed as a dependent (the claimable spouse is the spouse) + period: 2022 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + 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: ME + output: + # 36 MRSA 5213-A(6)(C) excludes the claimable individual; the other spouse + # still qualifies for the joint credit. + me_sales_tax_fairness_credit_eligible: true + +- name: Joint return where both spouses can be claimed as dependents + period: 2022 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + 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: ME + output: + me_sales_tax_fairness_credit_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/exemptions/mi_exemptions.yaml b/policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/exemptions/mi_exemptions.yaml index f916a47b51d..e67f331c532 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/exemptions/mi_exemptions.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/exemptions/mi_exemptions.yaml @@ -55,20 +55,36 @@ period: 2021 input: mi_personal_exemptions: 5_000 - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true filing_status: SINGLE state_code: MI output: mi_exemptions: 1_500 -- name: not disabled, is a dependent, married +- name: not disabled, both spouses can be claimed as dependents, married period: 2021 input: - mi_personal_exemptions: 10_000 - head_is_dependent_elsewhere: true - filing_status: JOINT - state_code: MI + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + 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: MI output: + # $1,500 for each spouse. mi_exemptions: 3_000 # 2025 test cases - personal exemption $5,800, disabled exemption $3,400 @@ -301,15 +317,220 @@ person1: mi_disabled_exemption_eligible_person: true is_fully_disabled_service_connected_veteran: false + claimed_as_dependent_on_another_return: true tax_units: tax_unit: mi_personal_exemptions: 5_800 - head_is_dependent_elsewhere: true filing_status: SINGLE members: [person1] household: members: [person1] state_code: MI output: - # Dependent exemption: $1,500 (for single) + $3,400 disabled = $4,900 + # Dependent exemption: $1,500 + $3,400 disabled = $4,900 mi_exemptions: 4_900 + +- name: 2025 joint return where only one spouse can be claimed (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + 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: MI + output: + # MCL 206.30(4): $1,500 for the claimable spouse, plus the other + # spouse's own $5,800 personal exemption. + mi_exemptions: 7_300 + +- name: 2025 joint return where only one spouse can be claimed (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + 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: MI + output: + # MCL 206.30(4): $1,500 for the claimable spouse, plus the other + # spouse's own $5,800 personal exemption. + mi_exemptions: 7_300 + +- name: 2025 joint return with a child where only one spouse can be claimed (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child_1] + state_code: MI + output: + # A joint return on which a spouse can be claimed claims no dependents + # (IRS Publication 501), so the child adds no exemption. + mi_exemptions: 7_300 + +- name: 2025 joint return with a child where only one spouse can be claimed (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child_1] + state_code: MI + output: + # A joint return on which a spouse can be claimed claims no dependents + # (IRS Publication 501), so the child adds no exemption. + mi_exemptions: 7_300 + +# Pub. 501 (2025), Dependent Taxpayer Test, PDF p.11; MCL 206.30(4). +- name: 2025 joint return filing exception restores own dependent while claimable head keeps the dependent allowance + period: 2025 + input: + people: + person_a: + age: 26 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + households: + household: + members: [person_a, person_b, child_1] + state_code: MI + output: + mi_exemptions: 13100 + +- name: 2025 joint return filing exception restores own dependent while claimable spouse keeps the dependent allowance + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 26 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child_1] + filing_status: JOINT + adjusted_gross_income: 4000 + households: + household: + members: [person_b, person_a, child_1] + state_code: MI + output: + mi_exemptions: 13100 + +- name: 2025 single filer with a nonrequired claimant who files no return may claim their own dependent + period: 2025 + input: + people: + filer: + age: 26 + is_tax_unit_head: true + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [filer, child] + filing_status: SINGLE + households: + household: + members: [filer, child] + state_code: MI + output: + # $1,500 claimable-filer allowance + $5,800 for their child. + mi_exemptions: 7_300 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/tax/income/credits/wftc/mo_wftc_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/tax/income/credits/wftc/mo_wftc_eligible.yaml index dba14ed3fb0..0cea1d97f45 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/tax/income/credits/wftc/mo_wftc_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/tax/income/credits/wftc/mo_wftc_eligible.yaml @@ -133,3 +133,121 @@ # $4,401 is below the federal EITC investment income limit ($11,950 in # 2025) but above Missouri's $4,400 limit. mo_wftc_eligible: false + +- name: 2025 married couple filing combined is not stopped by a claimable spouse (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + eitc: 500 + households: + household: + members: [person_a, person_b] + state_code: MO + output: + # A joint federal filer whose spouse can be claimed still files Form MO-1040 + # as married filing combined, not as claimed as a dependent. + mo_wftc_eligible: true + +- name: 2025 married couple filing combined is not stopped by a claimable spouse (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + 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 + eitc: 500 + households: + household: + members: [person_b, person_a] + state_code: MO + output: + # A joint federal filer whose spouse can be claimed still files Form MO-1040 + # as married filing combined, not as claimed as a dependent. + mo_wftc_eligible: true + +- name: 2025 childless couple with a claimable student spouse gets no federal EITC and so no WFTC (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + is_full_time_student: true + employment_income: 8_000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + employment_income: 8_000 + claimed_as_dependent_on_another_return: false + 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: MO + output: + # Without a qualifying child, neither spouse may be claimable for the federal + # EITC (Publication 596), which RSMo 143.177 requires. + eitc: 0 + mo_wftc_eligible: false + +- name: 2025 childless couple with a claimable student spouse gets no federal EITC and so no WFTC (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + employment_income: 8_000 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + is_full_time_student: true + employment_income: 8_000 + 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: MO + output: + # Without a qualifying child, neither spouse may be claimable for the federal + # EITC (Publication 596), which RSMo 143.177 requires. + eitc: 0 + mo_wftc_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible.yaml index df774c30456..de3db5f2233 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible.yaml @@ -1,7 +1,7 @@ - name: Is dependent on another return period: 2022 input: - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true state_code: NM earned_income: 1 is_disabled: false @@ -15,7 +15,7 @@ - name: No earned income period: 2022 input: - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false state_code: NM earned_income: 0 is_disabled: false @@ -29,7 +29,7 @@ - name: No earned income but disabled - eligible period: 2022 input: - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false state_code: NM earned_income: 0 is_disabled: true @@ -43,7 +43,7 @@ - name: Over income threshold period: 2022 input: - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false state_code: NM earned_income: 0 is_disabled: false @@ -57,7 +57,7 @@ - name: Receives tanf period: 2022 input: - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false state_code: NM earned_income: 0 is_disabled: false @@ -71,7 +71,7 @@ - name: Eligible period: 2022 input: - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false state_code: NM earned_income: 1 is_disabled: false @@ -101,7 +101,6 @@ tax_units: tax_unit: members: [head, spouse] - head_is_dependent_elsewhere: false filing_status: JOINT nm_modified_gross_income: 30_159 households: @@ -130,7 +129,6 @@ tax_units: tax_unit: members: [head, spouse] - head_is_dependent_elsewhere: false filing_status: JOINT nm_modified_gross_income: 30_159 households: @@ -159,7 +157,6 @@ tax_units: tax_unit: members: [head, spouse] - head_is_dependent_elsewhere: false filing_status: JOINT nm_modified_gross_income: 30_159 households: @@ -188,7 +185,6 @@ tax_units: tax_unit: members: [head, spouse] - head_is_dependent_elsewhere: false filing_status: JOINT nm_modified_gross_income: 30_159 households: @@ -217,7 +213,6 @@ tax_units: tax_unit: members: [head, spouse] - head_is_dependent_elsewhere: false filing_status: JOINT nm_modified_gross_income: 30_159 households: @@ -230,7 +225,7 @@ - name: Reported TANF receipt disqualifies despite zero computed TANF period: 2022 input: - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false state_code: NM earned_income: 0 is_disabled: true @@ -241,3 +236,89 @@ nm_modified_gross_income: 30_159 output: nm_cdcc_eligible: false + +- name: Joint return where only one spouse is a dependent of another taxpayer (the claimable spouse is the head) + period: 2022 + input: + people: + person_a: + age: 30 + earned_income: 1 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + earned_income: 1 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + nm_modified_gross_income: 30_159 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + # A spouse who is not a dependent may still qualify (PIT-RC instructions). + nm_cdcc_eligible: true + +- name: Joint return where only one spouse is a dependent of another taxpayer (the claimable spouse is the spouse) + period: 2022 + input: + people: + person_b: + age: 30 + earned_income: 1 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + earned_income: 1 + 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 + nm_modified_gross_income: 30_159 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + # A spouse who is not a dependent may still qualify (PIT-RC instructions). + nm_cdcc_eligible: true + +- name: Joint return where both spouses are a dependent of another taxpayer + period: 2022 + input: + people: + person_a: + age: 30 + earned_income: 1 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + earned_income: 1 + 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 + nm_modified_gross_income: 30_159 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + nm_cdcc_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible_child.yaml index 107b50cc08d..c2967302962 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible_child.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible_child.yaml @@ -24,3 +24,140 @@ is_tax_unit_dependent: true output: nm_cdcc_eligible_child: true + +- name: 2025 joint return with one claimable spouse has no eligible child (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: NM + output: + # NMSA 7-2-18.1 counts IRC 152 dependents; IRC 152(b)(1) leaves such a + # return none. + nm_cdcc_eligible_child: [false, false, false] + +- name: 2025 joint return with one claimable spouse has no eligible child (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: NM + output: + # NMSA 7-2-18.1 counts IRC 152 dependents; IRC 152(b)(1) leaves such a + # return none. + nm_cdcc_eligible_child: [false, false, false] + +- name: 2025 joint return with neither spouse claimable has an eligible child + period: 2025 + input: + people: + person_a: + age: 30 + person_b: + age: 30 + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: NM + output: + nm_cdcc_eligible_child: [false, false, true] + +# Publication 501, Dependent Taxpayer Test: a filer whose would-be claimant is not +# required to file and files no return or only for a refund can claim dependents. +- name: 2025 joint return whose claimable spouse is within the filing exception has an eligible child (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: NM + output: + nm_cdcc_eligible_child: [false, false, true] + +- name: 2025 joint return whose claimable spouse is within the filing exception has an eligible child (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: NM + output: + nm_cdcc_eligible_child: [false, false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/eitc/nm_eitc_demographic_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/eitc/nm_eitc_demographic_eligible.yaml index 4b6d82715d8..6e6a7ce13f5 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/eitc/nm_eitc_demographic_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/eitc/nm_eitc_demographic_eligible.yaml @@ -48,3 +48,488 @@ state_code: NM output: nm_eitc_demographic_eligible: true + +- name: 2025 childless single filer who can be claimed as a dependent is ineligible + period: 2025 + input: + people: + filer: + age: 21 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + households: + household: + members: [filer] + state_code: NM + output: + # NMSA 7-2-18.15 imports IRC 32(c)(1)(A)(ii)(III). + nm_eitc_demographic_eligible: false + +- name: 2025 childless joint return with one claimable spouse is ineligible (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 21 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 25 + 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: NM + output: + # Publication 596, Rule 12: neither spouse may be claimable. + nm_eitc_demographic_eligible: false + +- name: 2025 childless joint return with one claimable spouse is ineligible (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 25 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 21 + 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: NM + output: + # Publication 596, Rule 12: neither spouse may be claimable. + nm_eitc_demographic_eligible: false + +- name: 2025 childless joint return with neither spouse claimable is eligible + period: 2025 + input: + people: + person_a: + age: 21 + person_b: + age: 25 + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + households: + household: + members: [person_a, person_b] + state_code: NM + output: + nm_eitc_demographic_eligible: true + +- name: 2025 claimable single filer with a child is not barred by the dependent test + period: 2025 + input: + people: + filer: + age: 35 + claimed_as_dependent_on_another_return: true + child: + age: 3 + tax_units: + tax_unit: + members: [filer, child] + households: + household: + members: [filer, child] + state_code: NM + output: + # The dependent test applies only without a qualifying child. + nm_eitc_demographic_eligible: true + +- name: 2025 a dependent's age does not make a childless return eligible + period: 2025 + input: + people: + person_a: + age: 70 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 70 + is_tax_unit_head: false + is_tax_unit_spouse: true + relative: + age: 40 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, relative] + filing_status: JOINT + households: + household: + members: [person_a, person_b, relative] + state_code: NM + output: + # The age test applies to the filers (IRC 32(c)(1)(A)(ii)(II)), both + # above the federal maximum age of 64; the dependent aged 40 is within + # the age range but is not a filer, and is not a child. + nm_eitc_demographic_eligible: false + +# The dependent test applies only without a qualifying child (IRC +# 32(c)(1)(A)(ii)), and a qualifying child is a dependent under 19, a student +# under 24, or permanently and totally disabled (IRC 32(c)(3), 152(c)(3)). +- name: 2025 claimable single filer with a child aged 18 is not barred by the dependent test + period: 2025 + input: + people: + parent: + age: 35 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 18 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: NM + output: + nm_eitc_demographic_eligible: true + +- name: 2025 claimable single filer with a student aged 22 is not barred by the dependent test + period: 2025 + input: + people: + parent: + age: 45 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 22 + is_full_time_student: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: NM + output: + nm_eitc_demographic_eligible: true + +- name: 2025 claimable single filer with a permanently disabled adult child is not barred by the dependent test + period: 2025 + input: + people: + parent: + age: 60 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 30 + is_permanently_and_totally_disabled: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: NM + output: + nm_eitc_demographic_eligible: true + +- name: 2025 filer above the maximum age with a student aged 20 is eligible + period: 2025 + input: + people: + parent: + age: 70 + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 20 + is_full_time_student: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: NM + output: + nm_eitc_demographic_eligible: true + +- name: 2025 claimable single filer with a dependent aged 22 who is not a student is barred + period: 2025 + input: + people: + parent: + age: 45 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 22 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: NM + output: + # The dependent aged 22 is not a qualifying child, so the return is childless. + nm_eitc_demographic_eligible: false + +- name: 2025 childless joint return with neither spouse claimable is eligible (the younger spouse is the head) + period: 2025 + input: + people: + person_a: + age: 21 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 25 + 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: NM + output: + nm_eitc_demographic_eligible: true + +# Publication 596, Rule 12: a filer whose would-be claimant is not required to +# file and files no return or only for a refund is not treated as a dependent. +- name: 2025 childless single filer within the claimant filing exception is eligible + period: 2025 + input: + people: + person: + age: 21 + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + is_tax_unit_head: true + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person] + households: + household: + members: [person] + state_code: NM + output: + nm_eitc_demographic_eligible: true + +# A spouse under 18 is not the return's qualifying child, so a childless joint +# return with a spouse who can be claimed stays barred (Publication 596, Rule 12). +- name: 2025 childless joint return with a claimable spouse and a spouse under 18 is ineligible (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 21 + is_full_time_student: true + claimable_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 17 + 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: NM + output: + nm_eitc_demographic_eligible: false + +- name: 2025 childless joint return with a claimable spouse and a spouse under 18 is ineligible (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 17 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 21 + is_full_time_student: true + claimable_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: NM + output: + nm_eitc_demographic_eligible: false + +- name: 2025 childless joint return with a spouse under 18 and nobody claimable is eligible by the other spouse's age + period: 2025 + input: + people: + person_a: + age: 21 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 17 + 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: NM + output: + nm_eitc_demographic_eligible: true + +# A child who is not a qualifying child (for example one who fails the residency +# test) does not open the child route, so the dependent test still applies. +- name: 2025 claimable single filer with a child who is not a qualifying child is barred + period: 2025 + input: + people: + parent: + age: 35 + claimable_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + child: + age: 10 + is_eitc_qualifying_child: false + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: NM + output: + nm_eitc_demographic_eligible: false + +- name: 2025 joint return with a claimable spouse and a child who is not a qualifying child is barred (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 35 + claimable_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 33 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 10 + is_eitc_qualifying_child: false + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: NM + output: + nm_eitc_demographic_eligible: false + +- name: 2025 joint return with a claimable spouse and a child who is not a qualifying child is barred (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 33 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 35 + claimable_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 10 + is_eitc_qualifying_child: false + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: NM + output: + nm_eitc_demographic_eligible: false + +- name: 2025 childless joint return with a spouse under 18 and nobody claimable is eligible by the other spouse's age (the younger spouse is the head) + period: 2025 + input: + people: + person_b: + age: 17 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 21 + 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: NM + output: + nm_eitc_demographic_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/nm_ctc.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/nm_ctc.yaml index afe322b813f..e0145ad405e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/nm_ctc.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/nm_ctc.yaml @@ -37,3 +37,107 @@ filing_status: SINGLE output: nm_ctc: 75 + +- name: 2025 single filer who can be claimed as a dependent gets no child income tax credit + period: 2025 + input: + people: + parent: + age: 20 + employment_income: 10_000 + claimed_as_dependent_on_another_return: true + child: + age: 2 + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: NM + output: + # NMSA 7-2-18.34(A): "a taxpayer who is a resident and is not a dependent + # of another individual". + nm_ctc: 0 + +- name: 2025 joint return with one claimable spouse keeps the child income tax credit (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + employment_income: 10_000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + 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: NM + output: + # "your spouse may still qualify to claim rebates or credits" (PIT-RC); + # AGI $10,000 is in the first bracket: $637 per qualifying child. + nm_ctc: 637 + +- name: 2025 joint return with one claimable spouse keeps the child income tax credit (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + employment_income: 10_000 + 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: NM + output: + nm_ctc: 637 + +- name: 2025 joint return with both spouses claimable gets no child income tax credit + period: 2025 + input: + people: + person_a: + age: 20 + employment_income: 10_000 + claimed_as_dependent_on_another_return: true + person_b: + age: 20 + claimed_as_dependent_on_another_return: 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: NM + output: + nm_ctc: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/nm_medical_expense_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/nm_medical_expense_credit.yaml index df55277d73a..2e71f96ffec 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/nm_medical_expense_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/credits/nm_medical_expense_credit.yaml @@ -4,7 +4,7 @@ state_code: NM age: 64 other_medical_expenses: 30_000 - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_medical_expense_credit: 0 @@ -16,7 +16,7 @@ medicare_enrolled: false other_medical_expenses: 27_999 filing_status: JOINT - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_medical_expense_credit: 0 @@ -27,7 +27,7 @@ age: 65 other_medical_expenses: 28_000 filing_status: JOINT - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_medical_expense_credit: 2_800 @@ -38,7 +38,7 @@ age: 65 other_medical_expenses: 28_000 filing_status: SEPARATE - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_medical_expense_credit: 1_400 @@ -49,7 +49,7 @@ age: 65 other_medical_expenses: 40_000 filing_status: SINGLE - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_medical_expense_credit: 2_800 @@ -60,6 +60,271 @@ age: 65 other_medical_expenses: 40_000 filing_status: SINGLE - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true output: nm_medical_expense_credit: 0 + +- name: Joint return where only one spouse is a dependent of another taxpayer (the claimable spouse is the head) + period: 2023 + input: + people: + person_a: + age: 66 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 66 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + itemized_medical_expenses: 28_000 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + # A spouse who is not a dependent may still qualify (PIT-RC instructions). + nm_medical_expense_credit: 2_800 + +- name: Joint return where only one spouse is a dependent of another taxpayer (the claimable spouse is the spouse) + period: 2023 + input: + people: + person_b: + age: 66 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 66 + 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 + itemized_medical_expenses: 28_000 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + # A spouse who is not a dependent may still qualify (PIT-RC instructions). + nm_medical_expense_credit: 2_800 + +- name: Joint return where both spouses are a dependent of another taxpayer + period: 2023 + input: + people: + person_a: + age: 66 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 66 + 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 + itemized_medical_expenses: 28_000 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + nm_medical_expense_credit: 0 + +- name: Joint return where only the claimable spouse is 65 or older (the claimable spouse is the head) + period: 2023 + input: + people: + person_a: + age: 70 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 60 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + itemized_medical_expenses: 28_000 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + # NMSA 7-2-18.13(A): the taxpayer who is 65 or older must also not be a dependent. + nm_medical_expense_credit: 0 + +- name: Joint return where only the claimable spouse is 65 or older (the claimable spouse is the spouse) + period: 2023 + input: + people: + person_b: + age: 60 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 70 + 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 + itemized_medical_expenses: 28_000 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + # NMSA 7-2-18.13(A): the taxpayer who is 65 or older must also not be a dependent. + nm_medical_expense_credit: 0 + +- name: Joint return where the spouse who is not claimable is 65 or older (the claimable spouse is the head) + period: 2023 + input: + people: + person_a: + age: 60 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 70 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + itemized_medical_expenses: 28_000 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + nm_medical_expense_credit: 2_800 + +- name: Joint return where the spouse who is not claimable is 65 or older (the claimable spouse is the spouse) + period: 2023 + input: + people: + person_b: + age: 70 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 60 + 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 + itemized_medical_expenses: 28_000 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + nm_medical_expense_credit: 2_800 + +- name: 2025 a dependent aged 65 or older does not qualify the return + period: 2025 + input: + people: + person_a: + age: 40 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 40 + is_tax_unit_head: false + is_tax_unit_spouse: true + parent: + age: 70 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, parent] + filing_status: JOINT + itemized_medical_expenses: 30_000 + households: + household: + members: [person_a, person_b, parent] + state_code: NM + output: + # NMSA 7-2-18.13(A): "a taxpayer ... who is sixty-five years of age or + # older"; PIT-RC line 23: "If you or your spouse are 65 years of age or + # older". + nm_medical_expense_credit: 0 + +- name: 2025 joint return with a spouse aged 65 or older qualifies whichever spouse is the head + period: 2025 + input: + people: + person_b: + age: 40 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 70 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + itemized_medical_expenses: 30_000 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + nm_medical_expense_credit: 2_800 + +- name: 2025 joint return with a spouse aged 65 or older qualifies when that spouse is the head + period: 2025 + input: + people: + person_a: + age: 70 + 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 + itemized_medical_expenses: 30000 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + nm_medical_expense_credit: 2800 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents.yaml index c819101fe40..9c40e8ef783 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents.yaml @@ -51,3 +51,88 @@ nm_deduction_for_certain_dependents_eligible: true output: nm_deduction_for_certain_dependents: 16_000 + + +- name: 2025 joint return with one claimable spouse has no dependents to deduct (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + child_2: + age: 8 + tax_units: + tax_unit: + members: [person_a, person_b, child_1, child_2] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child_1, child_2] + state_code: NM + output: + # IRC 152(b)(1): such a return has no dependents (NMSA 7-2-39 defines + # dependent by IRC 152). + nm_deduction_for_certain_dependents: 0 + +- name: 2025 joint return with one claimable spouse has no dependents to deduct (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child_1: + age: 5 + child_2: + age: 8 + tax_units: + tax_unit: + members: [person_b, person_a, child_1, child_2] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child_1, child_2] + state_code: NM + output: + # IRC 152(b)(1): such a return has no dependents (NMSA 7-2-39 defines + # dependent by IRC 152). + nm_deduction_for_certain_dependents: 0 + +- name: 2025 joint return with neither spouse claimable deducts all but one dependent + period: 2025 + input: + people: + person_a: + age: 30 + person_b: + age: 30 + child_1: + age: 5 + child_2: + age: 8 + tax_units: + tax_unit: + members: [person_a, person_b, child_1, child_2] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child_1, child_2] + state_code: NM + output: + # $4,000 x (2 - 1). + nm_deduction_for_certain_dependents: 4_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents_eligible.yaml index 6f65f043918..bcb29cf3062 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents_eligible.yaml @@ -3,7 +3,7 @@ input: exemptions: 0 state_code: NM - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_deduction_for_certain_dependents_eligible: true @@ -12,7 +12,7 @@ input: exemptions: 1 state_code: NM - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_deduction_for_certain_dependents_eligible: false @@ -22,6 +22,86 @@ input: exemptions: 0 state_code: NM - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true + output: + nm_deduction_for_certain_dependents_eligible: false + +- name: Joint return where only one spouse is a dependent of another taxpayer (the claimable spouse is the head) + period: 2021 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + exemptions: 0 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + # A spouse who is not a dependent may still qualify (PIT-RC instructions). + nm_deduction_for_certain_dependents_eligible: true + +- name: Joint return where only one spouse is a dependent of another taxpayer (the claimable spouse is the spouse) + period: 2021 + input: + people: + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + 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 + exemptions: 0 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + # A spouse who is not a dependent may still qualify (PIT-RC instructions). + nm_deduction_for_certain_dependents_eligible: true + +- name: Joint return where both spouses are a dependent of another taxpayer + period: 2021 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + 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 + exemptions: 0 + households: + household: + members: [person_a, person_b] + state_code: NM output: nm_deduction_for_certain_dependents_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_hundred_year_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_hundred_year_exemption.yaml index 9ed4d307148..8160a003512 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_hundred_year_exemption.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_hundred_year_exemption.yaml @@ -51,3 +51,110 @@ filing_status: SINGLE output: nm_hundred_year_exemption: 10_000 + + +- name: 2025 claimable spouse aged 100 or older gets no exemption (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 100 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + adjusted_gross_income: 10_000 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + # NMSA 7-2-5.7: an individual 100 or older "who is not a dependent of + # another individual". + nm_hundred_year_exemption: 0 + +- name: 2025 claimable spouse aged 100 or older gets no exemption (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 100 + 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 + adjusted_gross_income: 10_000 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + # NMSA 7-2-5.7: an individual 100 or older "who is not a dependent of + # another individual". + nm_hundred_year_exemption: 0 + +- name: 2025 spouse aged 100 or older keeps the exemption when the other spouse can be claimed (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 100 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + adjusted_gross_income: 10_000 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + # Half of the joint income, as for any one eligible spouse. + nm_hundred_year_exemption: 5_000 + +- name: 2025 spouse aged 100 or older keeps the exemption when the other spouse can be claimed (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 100 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + 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 + adjusted_gross_income: 10_000 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + # Half of the joint income, as for any one eligible spouse. + nm_hundred_year_exemption: 5_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_low_and_middle_income_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_low_and_middle_income_exemption.yaml index f4acfca8392..5f236216e86 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_low_and_middle_income_exemption.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_low_and_middle_income_exemption.yaml @@ -27,3 +27,102 @@ exemptions_count: 3 output: nm_low_and_middle_income_exemption: 4_500 + + +- name: 2025 single filer who can be claimed as a dependent has no exemptions + period: 2025 + input: + people: + filer: + age: 30 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + adjusted_gross_income: 10_000 + households: + household: + members: [filer] + state_code: NM + output: + # NMSA 7-2-5.8 counts federal exemptions; IRC 151(d)(2). + nm_low_and_middle_income_exemption: 0 + +- name: 2025 joint return with one claimable spouse counts only the other spouse (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + adjusted_gross_income: 10_000 + households: + household: + members: [person_a, person_b, child] + state_code: NM + output: + # One exemption (the child is not a dependent, IRC 152(b)(1)) x $2,500. + nm_low_and_middle_income_exemption: 2_500 + +- name: 2025 joint return with one claimable spouse counts only the other spouse (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + adjusted_gross_income: 10_000 + households: + household: + members: [person_b, person_a, child] + state_code: NM + output: + # One exemption (the child is not a dependent, IRC 152(b)(1)) x $2,500. + nm_low_and_middle_income_exemption: 2_500 + +- name: 2025 joint return with neither spouse claimable counts everyone + period: 2025 + input: + people: + person_a: + age: 30 + person_b: + age: 30 + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + adjusted_gross_income: 10_000 + households: + household: + members: [person_a, person_b, child] + state_code: NM + output: + # 3 exemptions x $2,500. + nm_low_and_middle_income_exemption: 7_500 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_medical_expense_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_medical_expense_exemption.yaml index 65264be9353..d1c6c67950a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_medical_expense_exemption.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/exemptions/nm_medical_expense_exemption.yaml @@ -48,3 +48,81 @@ filing_status: SURVIVING_SPOUSE output: nm_medical_expense_exemption: 3_000 + +- name: 2025 a dependent aged 65 or older does not qualify the return for the exemption + period: 2025 + input: + people: + person_a: + age: 40 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 40 + is_tax_unit_head: false + is_tax_unit_spouse: true + parent: + age: 70 + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, parent] + filing_status: JOINT + itemized_medical_expenses: 30_000 + households: + household: + members: [person_a, person_b, parent] + state_code: NM + output: + # NMSA 7-2-5.9(A): "any individual sixty-five years of age or older"; + # PIT-ADJ line 18: "If you or your spouse are 65 years of age or older". + nm_medical_expense_exemption: 0 + +- name: 2025 joint return with a spouse aged 65 or older gets the exemption (the older spouse is the head) + period: 2025 + input: + people: + person_a: + age: 70 + 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 + itemized_medical_expenses: 30_000 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + nm_medical_expense_exemption: 3_000 + +- name: 2025 joint return with a spouse aged 65 or older gets the exemption (the older 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: 70 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_b, person_a] + filing_status: JOINT + itemized_medical_expenses: 30_000 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + nm_medical_expense_exemption: 3_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/2021_income/nm_2021_income_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/2021_income/nm_2021_income_rebate.yaml index 72c2bb91a67..3a1c22772bc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/2021_income/nm_2021_income_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/2021_income/nm_2021_income_rebate.yaml @@ -4,7 +4,7 @@ state_code: NM adjusted_gross_income: 74_999 filing_status: SINGLE - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_2021_income_rebate: 250 @@ -14,7 +14,7 @@ state_code: NM adjusted_gross_income: 75_000 filing_status: SEPARATE - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_2021_income_rebate: 0 @@ -24,7 +24,7 @@ state_code: NM adjusted_gross_income: 149_999 filing_status: JOINT - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_2021_income_rebate: 500 @@ -34,7 +34,7 @@ state_code: NM adjusted_gross_income: 150_000 filing_status: SURVIVING_SPOUSE - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_2021_income_rebate: 0 @@ -44,6 +44,86 @@ state_code: NM adjusted_gross_income: 149_999 filing_status: JOINT - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true + output: + nm_2021_income_rebate: 0 + +- name: Joint return where only one spouse is a dependent of another taxpayer (the claimable spouse is the head) + period: 2021 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + adjusted_gross_income: 50_000 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + # A spouse who is not a dependent may still qualify (PIT-RC instructions). + nm_2021_income_rebate: 500 + +- name: Joint return where only one spouse is a dependent of another taxpayer (the claimable spouse is the spouse) + period: 2021 + input: + people: + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + 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 + adjusted_gross_income: 50_000 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + # A spouse who is not a dependent may still qualify (PIT-RC instructions). + nm_2021_income_rebate: 500 + +- name: Joint return where both spouses are a dependent of another taxpayer + period: 2021 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + 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 + adjusted_gross_income: 50_000 + households: + household: + members: [person_a, person_b] + state_code: NM output: nm_2021_income_rebate: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/2021_income/nm_additional_2021_income_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/2021_income/nm_additional_2021_income_rebate.yaml index ddf2f6150d1..91a64599414 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/2021_income/nm_additional_2021_income_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/2021_income/nm_additional_2021_income_rebate.yaml @@ -3,7 +3,7 @@ input: state_code: NM filing_status: JOINT - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_additional_2021_income_rebate: 1_000 @@ -12,7 +12,7 @@ input: state_code: NM filing_status: SINGLE - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_additional_2021_income_rebate: 500 @@ -21,7 +21,7 @@ input: state_code: NM filing_status: SEPARATE - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_additional_2021_income_rebate: 500 @@ -30,7 +30,7 @@ input: state_code: NM filing_status: SURVIVING_SPOUSE - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_additional_2021_income_rebate: 1_000 @@ -39,7 +39,7 @@ input: state_code: NM filing_status: HEAD_OF_HOUSEHOLD - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_additional_2021_income_rebate: 1_000 @@ -48,6 +48,83 @@ input: state_code: NM filing_status: SEPARATE - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true + output: + nm_additional_2021_income_rebate: 0 + +- name: Joint return where only one spouse is a dependent of another taxpayer (the claimable spouse is the head) + period: 2021 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + 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: NM + output: + # A spouse who is not a dependent may still qualify (PIT-RC instructions). + nm_additional_2021_income_rebate: 1_000 + +- name: Joint return where only one spouse is a dependent of another taxpayer (the claimable spouse is the spouse) + period: 2021 + input: + people: + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + 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: NM + output: + # A spouse who is not a dependent may still qualify (PIT-RC instructions). + nm_additional_2021_income_rebate: 1_000 + +- name: Joint return where both spouses are a dependent of another taxpayer + period: 2021 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + 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: NM output: nm_additional_2021_income_rebate: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/2021_income/nm_supplemental_2021_income_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/2021_income/nm_supplemental_2021_income_rebate.yaml index ac64cc9f434..0b1b8565f7a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/2021_income/nm_supplemental_2021_income_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/2021_income/nm_supplemental_2021_income_rebate.yaml @@ -3,7 +3,7 @@ input: state_code: NM filing_status: JOINT - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_supplemental_2021_income_rebate: 1_000 @@ -12,7 +12,7 @@ input: state_code: NM filing_status: SINGLE - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_supplemental_2021_income_rebate: 500 @@ -21,7 +21,7 @@ input: state_code: NM filing_status: SEPARATE - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_supplemental_2021_income_rebate: 500 @@ -30,7 +30,7 @@ input: state_code: NM filing_status: SURVIVING_SPOUSE - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_supplemental_2021_income_rebate: 1_000 @@ -39,7 +39,7 @@ input: state_code: NM filing_status: HEAD_OF_HOUSEHOLD - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false output: nm_supplemental_2021_income_rebate: 1_000 @@ -48,6 +48,83 @@ input: state_code: NM filing_status: HEAD_OF_HOUSEHOLD - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true + output: + nm_supplemental_2021_income_rebate: 0 + +- name: Joint return where only one spouse is a dependent of another taxpayer (the claimable spouse is the head) + period: 2021 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + 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: NM + output: + # A spouse who is not a dependent may still qualify (PIT-RC instructions). + nm_supplemental_2021_income_rebate: 1_000 + +- name: Joint return where only one spouse is a dependent of another taxpayer (the claimable spouse is the spouse) + period: 2021 + input: + people: + person_b: + age: 30 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + 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: NM + output: + # A spouse who is not a dependent may still qualify (PIT-RC instructions). + nm_supplemental_2021_income_rebate: 1_000 + +- name: Joint return where both spouses are a dependent of another taxpayer + period: 2021 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + 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: NM output: nm_supplemental_2021_income_rebate: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate.yaml index 7bcd28c10fa..84ae85e14bf 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate.yaml @@ -246,3 +246,112 @@ state_code: NM output: nm_low_income_comprehensive_tax_rebate: 583 + +- name: 2025 single filer who can be claimed as a dependent gets no rebate + period: 2025 + input: + people: + person: + age: 20 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person] + nm_modified_gross_income: 5_000 + households: + household: + members: [person] + state_code: NM + output: + # NMSA 7-2-14(A): only a resident "who is not a dependent of another + # individual" may claim the rebate. + nm_low_income_comprehensive_tax_rebate: 0 + +- name: 2025 single filer who cannot be claimed gets the one-exemption rebate + period: 2025 + input: + people: + person: + age: 20 + tax_units: + tax_unit: + members: [person] + nm_modified_gross_income: 5_000 + households: + household: + members: [person] + state_code: NM + output: + # $1,000-$7,500 row, one exemption. + nm_low_income_comprehensive_tax_rebate: 252 + +- name: 2025 single filer aged 65 or older who can be claimed as a dependent gets no rebate + period: 2025 + input: + people: + person: + age: 70 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person] + nm_modified_gross_income: 5_000 + households: + household: + members: [person] + state_code: NM + output: + # The age-65 exemptions do not make a dependent of another individual a + # claimant (NMSA 7-2-14(A)). + nm_low_income_comprehensive_tax_rebate: 0 + +- name: 2025 joint return with one claimable spouse keeps the rebate with the couple's combined income (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + nm_modified_gross_income: 8500 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + # One exemption; the $8,000-$9,000 row of the one-exemption table. + nm_low_income_comprehensive_tax_rebate: 212 + +- name: 2025 joint return with one claimable spouse keeps the rebate with the couple's combined income (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + 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 + nm_modified_gross_income: 8500 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + nm_low_income_comprehensive_tax_rebate: 212 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate_exemptions.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate_exemptions.yaml index 5b10b5cf2d8..6fa092fcffe 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate_exemptions.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate_exemptions.yaml @@ -24,3 +24,104 @@ blind_head: true output: nm_low_income_comprehensive_tax_rebate_exemptions: 2 + +- name: 2025 single filer who can be claimed as a dependent has no rebate exemptions + period: 2025 + input: + people: + parent: + age: 20 + claimed_as_dependent_on_another_return: true + child: + age: 2 + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: NM + output: + # NMSA 7-2-14(A),(C); PIT-RC line 2a. + nm_low_income_comprehensive_tax_rebate_exemptions: 0 + +- name: 2025 joint return with one claimable spouse drops its ordinary exemption and the dependents (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 70 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 40 + claimed_as_dependent_on_another_return: false + 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: NM + output: + # "the non-qualifying spouse is not eligible" (PIT-RC line 2a) and a + # return on which a filer can be claimed has no dependents (IRC + # 152(b)(1)), leaving 1 ordinary exemption; NMSA 7-2-14(C) still adds 2 + # for "each individual ... included in the return who is sixty-five years + # of age or older". + nm_low_income_comprehensive_tax_rebate_exemptions: 3 + +- name: 2025 joint return with one claimable spouse drops its ordinary exemption and the dependents (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 40 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 70 + 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: NM + output: + nm_low_income_comprehensive_tax_rebate_exemptions: 3 + +- name: 2025 joint return with neither spouse claimable counts everyone plus the age-65 exemptions + period: 2025 + input: + people: + person_a: + age: 70 + person_b: + age: 40 + 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: NM + output: + # 3 federal exemptions + 2 for the spouse aged 65 or older. + nm_low_income_comprehensive_tax_rebate_exemptions: 5 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/nm_property_tax_rebate_eligibility.yaml b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/nm_property_tax_rebate_eligibility.yaml index d673a251d8f..f886a19850b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/nm_property_tax_rebate_eligibility.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/nm/tax/income/rebates/nm_property_tax_rebate_eligibility.yaml @@ -47,3 +47,124 @@ nm_modified_gross_income: 16_000 output: nm_property_tax_rebate_eligible: true + + +- name: 2025 single filer aged 65 or older who can be claimed as a dependent is ineligible + period: 2025 + input: + people: + filer: + age: 70 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [filer] + nm_modified_gross_income: 5_000 + households: + household: + members: [filer] + state_code: NM + output: + # NMSA 7-2-18: a resident 65 or over "who is not a dependent of another + # individual". + nm_property_tax_rebate_eligible: false + +- name: 2025 joint return whose only spouse aged 65 or older can be claimed is ineligible (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 70 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + nm_modified_gross_income: 5_000 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + nm_property_tax_rebate_eligible: false + +- name: 2025 joint return whose only spouse aged 65 or older can be claimed is ineligible (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 70 + 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 + nm_modified_gross_income: 5_000 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + nm_property_tax_rebate_eligible: false + +- name: 2025 joint return whose spouse aged 65 or older cannot be claimed is eligible (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 70 + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + nm_modified_gross_income: 5_000 + households: + household: + members: [person_a, person_b] + state_code: NM + output: + nm_property_tax_rebate_eligible: true + +- name: 2025 joint return whose spouse aged 65 or older cannot be claimed is eligible (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 70 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + 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 + nm_modified_gross_income: 5_000 + households: + household: + members: [person_b, person_a] + state_code: NM + output: + nm_property_tax_rebate_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/taxable_income/deductions/ny_standard_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/taxable_income/deductions/ny_standard_deduction.yaml new file mode 100644 index 00000000000..cd98af8b0dc --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/tax/income/taxable_income/deductions/ny_standard_deduction.yaml @@ -0,0 +1,94 @@ +- name: 2025 single filer who can be claimed as a dependent + period: 2025 + input: + state_code: NY + filing_status: SINGLE + claimed_as_dependent_on_another_return: true + output: + ny_standard_deduction: 3_100 + +- name: 2025 single filer who cannot be claimed as a dependent + period: 2025 + input: + state_code: NY + filing_status: SINGLE + claimed_as_dependent_on_another_return: false + output: + ny_standard_deduction: 8_000 + +- name: 2025 head of household who can be claimed as a dependent keeps the regular amount + period: 2025 + input: + state_code: NY + filing_status: HEAD_OF_HOUSEHOLD + claimed_as_dependent_on_another_return: true + output: + # The IT-201 table gives the dependent amount only to filing status 1. + ny_standard_deduction: 11_200 + +- name: 2025 separate filer who can be claimed as a dependent keeps the regular amount + period: 2025 + input: + state_code: NY + filing_status: SEPARATE + claimed_as_dependent_on_another_return: true + output: + ny_standard_deduction: 8_000 + +- name: 2025 joint return where only one spouse can be claimed (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 20 + employment_income: 8_000 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + employment_income: 8_000 + claimed_as_dependent_on_another_return: false + 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: NY + output: + # The IT-201 table gives married filing jointly $16,050 whether or not + # item C is marked. + ny_standard_deduction: 16_050 + +- name: 2025 joint return where only one spouse can be claimed (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 20 + employment_income: 8_000 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + employment_income: 8_000 + 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: NY + output: + # The IT-201 table gives married filing jointly $16,050 whether or not + # item C is marked. + ny_standard_deduction: 16_050 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/income/exemptions/personal/oh_personal_exemptions_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/income/exemptions/personal/oh_personal_exemptions_eligible.yaml index 97f70fe2376..676c54bab9c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/income/exemptions/personal/oh_personal_exemptions_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/income/exemptions/personal/oh_personal_exemptions_eligible.yaml @@ -27,3 +27,67 @@ is_tax_unit_dependent: true output: oh_personal_exemptions_eligible_person: true + +- name: Ohio personal exemption excludes a claimable but unclaimed filer + period: 2025 + input: + state_code: OH + is_tax_unit_head_or_spouse: true + is_tax_unit_dependent: false + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + output: + oh_personal_exemptions_eligible_person: false + +- name: 2025 joint return with one claimable spouse makes neither that spouse nor the child eligible (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + households: + household: + members: [person_a, person_b, child] + state_code: OH + output: + # Ohio R.C. 5747.025; IRC 152(b)(1) leaves the return no dependents. + oh_personal_exemptions_eligible_person: [false, true, false] + +- name: 2025 joint return with one claimable spouse makes neither that spouse nor the child eligible (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + households: + household: + members: [person_b, person_a, child] + state_code: OH + output: + oh_personal_exemptions_eligible_person: [true, false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/or/tax/income/deductions/standard/or_standard_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/or/tax/income/deductions/standard/or_standard_deduction.yaml index 6c2182a4783..c040dee6619 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/or/tax/income/deductions/standard/or_standard_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/or/tax/income/deductions/standard/or_standard_deduction.yaml @@ -68,7 +68,7 @@ state_code: OR filing_status: JOINT age_head: 35 - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true tax_unit_earned_income: 600 output: # $1100 base @@ -80,7 +80,7 @@ state_code: OR filing_status: SINGLE age_head: 35 - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true tax_unit_earned_income: 1_000 output: # $1000 income + $350 addition, below the $2,350 normal standard deduction cap. @@ -92,7 +92,7 @@ state_code: OR filing_status: SINGLE age: 35 - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true tax_unit_earned_income: 1_000 blind_head: true output: @@ -137,3 +137,79 @@ output: # $2,835 base + $1,200 aged or_standard_deduction: 4_035 + +- name: 2025 joint return limited to the dependent amount when either spouse can be claimed (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 35 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 35 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: false + is_tax_unit_spouse: true + tax_units: + tax_unit: + members: [person_a, person_b] + filing_status: JOINT + tax_unit_earned_income: 3_000 + households: + household: + members: [person_a, person_b] + state_code: OR + output: + # max($1,350, $3,000 + $450) = $3,450, below the $5,670 joint amount. + or_standard_deduction: 3_450 + +- name: 2025 joint return limited to the dependent amount when either spouse can be claimed (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 35 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 35 + 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 + tax_unit_earned_income: 3_000 + households: + household: + members: [person_b, person_a] + state_code: OR + output: + # max($1,350, $3,000 + $450) = $3,450, below the $5,670 joint amount. + or_standard_deduction: 3_450 + +- name: 2025 dependent filer with self-employment income uses earned income net of the self-employment tax deduction + period: 2025 + absolute_error_margin: 0.01 + input: + people: + head: + age: 20 + self_employment_income: 1_500 + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head] + filing_status: SINGLE + households: + household: + members: [head] + state_code: OR + output: + # $1,500 - $1,500 x 0.9235 x 15.3% / 2 = $1,394.03; plus $450 = $1,844.03, + # above the $1,350 minimum and below the $2,835 single amount. + or_standard_deduction: 1844.03 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/exemption/ri_exemptions.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/exemption/ri_exemptions.yaml index 874ee89a624..539a40f00a6 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/exemption/ri_exemptions.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/tax/income/exemption/ri_exemptions.yaml @@ -135,3 +135,82 @@ exemptions_count: 2 output: ri_exemptions: 0 + + +- name: 2025 joint return with one claimable spouse counts only the other spouse (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + ri_agi: 10000 + households: + household: + members: [person_a, person_b, child] + state_code: RI + output: + # R.I. Gen. Laws 44-30-2.6: "If someone else can claim you on their return, + # your exemption amount is zero"; IRC 152(b)(1). + ri_exemptions: 5_100 + +- name: 2025 joint return with one claimable spouse counts only the other spouse (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + tax_units: + tax_unit: + members: [person_b, person_a, child] + filing_status: JOINT + ri_agi: 10000 + households: + household: + members: [person_b, person_a, child] + state_code: RI + output: + ri_exemptions: 5_100 + +- name: 2025 joint return with neither spouse claimable counts everyone + period: 2025 + input: + people: + person_a: + age: 30 + person_b: + age: 30 + child: + age: 5 + tax_units: + tax_unit: + members: [person_a, person_b, child] + filing_status: JOINT + ri_agi: 10000 + households: + household: + members: [person_a, person_b, child] + state_code: RI + output: + ri_exemptions: 15_300 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ut/tax/property/homeowner_renter_relief/ut_homeowner_renter_relief_pre_one_claimant_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ut/tax/property/homeowner_renter_relief/ut_homeowner_renter_relief_pre_one_claimant_eligible.yaml new file mode 100644 index 00000000000..64ee21b5111 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ut/tax/property/homeowner_renter_relief/ut_homeowner_renter_relief_pre_one_claimant_eligible.yaml @@ -0,0 +1,21 @@ +- name: Utah property relief retains an unclaimed claimable filer + period: 2025 + input: + state_code: UT + age: 66 + rent: 12_000 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + output: + ut_homeowner_renter_relief_pre_one_claimant_eligible: true + +- name: Utah property relief excludes an actually claimed filer + period: 2025 + input: + state_code: UT + age: 66 + rent: 12_000 + claimed_as_dependent_on_another_return: true + claimable_as_dependent_on_another_return: true + output: + ut_homeowner_renter_relief_pre_one_claimant_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/credits/low_income_credit/va_low_income_tax_credit_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/credits/low_income_credit/va_low_income_tax_credit_eligible.yaml index 5584f3c0288..b5cf4a21af1 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/credits/low_income_credit/va_low_income_tax_credit_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/va/tax/income/credits/low_income_credit/va_low_income_tax_credit_eligible.yaml @@ -2,7 +2,7 @@ period: 2021 input: state_code: VA - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true va_aged_blind_exemption: 0 va_age_deduction: 0 va_military_benefit_subtraction: 0 @@ -14,7 +14,7 @@ period: 2021 input: state_code: VA - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false va_aged_blind_exemption: 1_600 va_age_deduction: 12_000 va_military_benefit_subtraction: 0 @@ -26,10 +26,60 @@ period: 2021 input: state_code: VA - head_is_dependent_elsewhere: false + claimed_as_dependent_on_another_return: false va_aged_blind_exemption: 0 va_age_deduction: 0 va_military_benefit_subtraction: 0 va_federal_state_employees_subtraction: 0 output: va_low_income_tax_credit_eligible: true + +- name: Joint return is ineligible when either spouse is claimed as a dependent (the claimable spouse is the head) + period: 2021 + input: + people: + person_a: + age: 20 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + 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: VA + output: + va_low_income_tax_credit_eligible: false + +- name: Joint return is ineligible when either spouse is claimed as a dependent (the claimable spouse is the spouse) + period: 2021 + input: + people: + person_b: + age: 20 + claimed_as_dependent_on_another_return: false + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 20 + 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: VA + output: + va_low_income_tax_credit_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_base_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_base_exemption.yaml index 9e54d8bd87f..f1f8087f317 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_base_exemption.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/tax/income/wi_base_exemption.yaml @@ -5,3 +5,79 @@ state_code: WI output: wi_base_exemption: 5 * 700 + + +- name: 2025 joint return with one claimable spouse counts only the other spouse (the claimable spouse is the head) + period: 2025 + input: + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + 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: + # Form 1 instructions: "either you or your spouse (not both) can be claimed"; + # IRC 152(b)(1). + wi_base_exemption: 700 + +- name: 2025 joint return with one claimable spouse counts only the other spouse (the claimable spouse is the spouse) + period: 2025 + input: + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + child: + age: 5 + 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_base_exemption: 700 + +- name: 2025 joint return with neither spouse claimable counts everyone + period: 2025 + input: + people: + person_a: + age: 30 + person_b: + age: 30 + child: + age: 5 + 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_base_exemption: 2_100 diff --git a/policyengine_us/tests/policy/baseline/household/demographic/person/claimable_as_dependent_on_another_return.yaml b/policyengine_us/tests/policy/baseline/household/demographic/person/claimable_as_dependent_on_another_return.yaml new file mode 100644 index 00000000000..2530e578832 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/household/demographic/person/claimable_as_dependent_on_another_return.yaml @@ -0,0 +1,34 @@ +- name: An existing actual claim supplies the default claimability + period: 2025 + input: + claimed_as_dependent_on_another_return: true + output: + claimable_as_dependent_on_another_return: true + +- name: An existing false claim input preserves default independence + period: 2025 + input: + claimed_as_dependent_on_another_return: false + output: + claimable_as_dependent_on_another_return: false + +- name: No claim inputs preserves default independence + period: 2025 + input: + age: 26 + output: + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: false + +- name: A parent can claim the filer without making or expecting a claim + period: 2025 + input: + age: 26 + employment_income: 2_000 + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + output: + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + basic_standard_deduction: 2_450 + eitc_demographic_eligible: false diff --git a/policyengine_us/tests/policy/baseline/household/demographic/person/is_dependent_elsewhere_without_filing_exception.yaml b/policyengine_us/tests/policy/baseline/household/demographic/person/is_dependent_elsewhere_without_filing_exception.yaml new file mode 100644 index 00000000000..4164a45064a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/household/demographic/person/is_dependent_elsewhere_without_filing_exception.yaml @@ -0,0 +1,36 @@ +- name: Unclaimed but claimable filer fails the dependent taxpayer test + period: 2025 + input: + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + output: + dependent_claimant_filing_exception: false + is_dependent_elsewhere_without_filing_exception: true + +- name: Nonrequired refund-only claimant restores dependent taxpayer eligibility + period: 2025 + input: + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + output: + # Publication 501 PDF p.11, Dependent Taxpayer Test exception. + is_dependent_elsewhere_without_filing_exception: false + claimable_as_dependent_on_another_return: true + +- name: Nonrequired claimant filing no return restores dependent taxpayer eligibility + period: 2025 + input: + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + output: + # Publication 596 PDF p.18 includes the nonrequired claimant who files no return. + is_dependent_elsewhere_without_filing_exception: false + claimable_as_dependent_on_another_return: true + +- name: The filing exception does not create claimability + period: 2025 + input: + claimable_as_dependent_on_another_return: false + dependent_claimant_filing_exception: true + output: + is_dependent_elsewhere_without_filing_exception: false diff --git a/policyengine_us/tests/policy/baseline/household/demographic/tax_unit/every_filer_is_dependent_elsewhere.yaml b/policyengine_us/tests/policy/baseline/household/demographic/tax_unit/every_filer_is_dependent_elsewhere.yaml new file mode 100644 index 00000000000..2b934fda74a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/household/demographic/tax_unit/every_filer_is_dependent_elsewhere.yaml @@ -0,0 +1,89 @@ +- name: Only the head is claimed elsewhere + period: 2025 + input: + people: + head: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: true + spouse: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: [head, spouse] + output: + every_filer_is_dependent_elsewhere: false + +- name: Only the spouse is claimed elsewhere + period: 2025 + input: + people: + head: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: false + spouse: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head, spouse] + output: + every_filer_is_dependent_elsewhere: false + +- name: Both spouses are claimed elsewhere + period: 2025 + input: + people: + head: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: true + spouse: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head, spouse] + output: + every_filer_is_dependent_elsewhere: true + +- name: Single filer claimed elsewhere + period: 2025 + input: + people: + head: + age: 19 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head] + output: + every_filer_is_dependent_elsewhere: true + +- name: A tax unit with neither a head nor a spouse has no filer claimed elsewhere + period: 2025 + input: + people: + child: + age: 10 + is_tax_unit_head: false + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: [child] + output: + every_filer_is_dependent_elsewhere: false diff --git a/policyengine_us/tests/policy/baseline/household/demographic/tax_unit/head_or_spouse_is_dependent_elsewhere.yaml b/policyengine_us/tests/policy/baseline/household/demographic/tax_unit/head_or_spouse_is_dependent_elsewhere.yaml new file mode 100644 index 00000000000..80029885451 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/household/demographic/tax_unit/head_or_spouse_is_dependent_elsewhere.yaml @@ -0,0 +1,114 @@ +- name: Head is claimed elsewhere + period: 2025 + input: + people: + head: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: true + spouse: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: [head, spouse] + output: + head_or_spouse_is_dependent_elsewhere: true + +- name: Spouse is claimed elsewhere + period: 2025 + input: + people: + head: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: false + spouse: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head, spouse] + output: + head_or_spouse_is_dependent_elsewhere: true + +- name: Both spouses are claimed elsewhere + period: 2025 + input: + people: + head: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: true + spouse: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head, spouse] + output: + head_or_spouse_is_dependent_elsewhere: true + +- name: Neither spouse is claimed elsewhere + period: 2025 + input: + people: + head: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: false + spouse: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: [head, spouse] + output: + head_or_spouse_is_dependent_elsewhere: false + +- name: A dependent claimed elsewhere is not a filer + period: 2025 + input: + people: + head: + age: 40 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: false + child: + age: 10 + is_tax_unit_head: false + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head, child] + output: + head_or_spouse_is_dependent_elsewhere: false + +- name: Single filer claimed elsewhere + period: 2025 + input: + people: + head: + age: 19 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head] + output: + head_or_spouse_is_dependent_elsewhere: true diff --git a/policyengine_us/tests/policy/baseline/household/demographic/tax_unit/head_or_spouse_is_dependent_elsewhere_without_filing_exception.yaml b/policyengine_us/tests/policy/baseline/household/demographic/tax_unit/head_or_spouse_is_dependent_elsewhere_without_filing_exception.yaml new file mode 100644 index 00000000000..8b9e439d173 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/household/demographic/tax_unit/head_or_spouse_is_dependent_elsewhere_without_filing_exception.yaml @@ -0,0 +1,119 @@ +- name: Claimable unclaimed head prevents claiming the return's own dependents + period: 2025 + input: + people: + person_a: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + person_b: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: [person_a, person_b] + output: + head_or_spouse_is_dependent_elsewhere: true + head_or_spouse_is_dependent_elsewhere_without_filing_exception: true + +- name: Claimable unclaimed spouse prevents claiming the return's own dependents + period: 2025 + input: + people: + person_b: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: false + person_a: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: false + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [person_b, person_a] + output: + head_or_spouse_is_dependent_elsewhere: true + head_or_spouse_is_dependent_elsewhere_without_filing_exception: true + +- name: The head's nonrequired claimant filing exception restores own-dependent eligibility + period: 2025 + input: + people: + person_a: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + person_b: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: [person_a, person_b] + output: + head_or_spouse_is_dependent_elsewhere: true + head_or_spouse_is_dependent_elsewhere_without_filing_exception: false + +- name: The spouse's nonrequired claimant filing exception restores own-dependent eligibility + period: 2025 + input: + people: + person_b: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: false + person_a: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + tax_units: + tax_unit: + members: [person_b, person_a] + output: + head_or_spouse_is_dependent_elsewhere: true + head_or_spouse_is_dependent_elsewhere_without_filing_exception: false + +- name: One exception is insufficient when the other spouse has an ordinary claimant + period: 2025 + input: + people: + head: + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + spouse: + is_tax_unit_head: false + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: false + tax_units: + tax_unit: + members: [head, spouse] + output: + head_or_spouse_is_dependent_elsewhere_without_filing_exception: true + +- name: A claimable child does not apply the dependent taxpayer test to independent filers + period: 2025 + input: + people: + head: + age: 40 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: false + child: + age: 10 + is_tax_unit_head: false + is_tax_unit_spouse: false + claimable_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head, child] + output: + head_or_spouse_is_dependent_elsewhere_without_filing_exception: false diff --git a/policyengine_us/tests/policy/baseline/household/demographic/tax_unit/head_spouse_count_not_dependent_elsewhere.yaml b/policyengine_us/tests/policy/baseline/household/demographic/tax_unit/head_spouse_count_not_dependent_elsewhere.yaml new file mode 100644 index 00000000000..ac5381a1b4b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/household/demographic/tax_unit/head_spouse_count_not_dependent_elsewhere.yaml @@ -0,0 +1,114 @@ +- name: Head is claimed elsewhere + period: 2025 + input: + people: + head: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: true + spouse: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: [head, spouse] + output: + head_spouse_count_not_dependent_elsewhere: 1 + +- name: Spouse is claimed elsewhere + period: 2025 + input: + people: + head: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: false + spouse: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head, spouse] + output: + head_spouse_count_not_dependent_elsewhere: 1 + +- name: Both spouses are claimed elsewhere + period: 2025 + input: + people: + head: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: true + spouse: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head, spouse] + output: + head_spouse_count_not_dependent_elsewhere: 0 + +- name: Neither spouse is claimed elsewhere + period: 2025 + input: + people: + head: + age: 20 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: false + spouse: + age: 20 + is_tax_unit_head: false + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: false + tax_units: + tax_unit: + members: [head, spouse] + output: + head_spouse_count_not_dependent_elsewhere: 2 + +- name: A dependent claimed elsewhere is not a filer + period: 2025 + input: + people: + head: + age: 40 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: false + child: + age: 10 + is_tax_unit_head: false + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head, child] + output: + head_spouse_count_not_dependent_elsewhere: 1 + +- name: Single filer claimed elsewhere + period: 2025 + input: + people: + head: + age: 19 + is_tax_unit_head: true + is_tax_unit_spouse: false + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head] + output: + head_spouse_count_not_dependent_elsewhere: 0 diff --git a/policyengine_us/tests/policy/contrib/congress/watca.yaml b/policyengine_us/tests/policy/contrib/congress/watca.yaml index 500ed7e863b..2b40103ff7f 100644 --- a/policyengine_us/tests/policy/contrib/congress/watca.yaml +++ b/policyengine_us/tests/policy/contrib/congress/watca.yaml @@ -440,7 +440,7 @@ gov.contrib.congress.watca.in_effect: true adjusted_gross_income: 30_000 filing_status: SINGLE - head_is_dependent_elsewhere: true + claimed_as_dependent_on_another_return: true output: # Even though income is below limit, not eligible because claimed as dependent watca_alternative_tax_eligible: false @@ -450,9 +450,18 @@ reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 30_000 - filing_status: JOINT - spouse_is_dependent_elsewhere: true + people: + head: + is_tax_unit_head: true + claimed_as_dependent_on_another_return: false + spouse: + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head, spouse] + adjusted_gross_income: 30_000 + filing_status: JOINT output: watca_alternative_tax_eligible: false @@ -529,10 +538,18 @@ reforms: policyengine_us.reforms.congress.watca.working_americans_tax_cut_act.watca_reform_object input: gov.contrib.congress.watca.in_effect: true - adjusted_gross_income: 30_000 - filing_status: JOINT - head_is_dependent_elsewhere: true - spouse_is_dependent_elsewhere: true + people: + head: + is_tax_unit_head: true + claimed_as_dependent_on_another_return: true + spouse: + is_tax_unit_spouse: true + claimed_as_dependent_on_another_return: true + tax_units: + tax_unit: + members: [head, spouse] + adjusted_gross_income: 30_000 + filing_status: JOINT output: watca_alternative_tax_eligible: false diff --git a/policyengine_us/tests/policy/contrib/reconciliation/reconciled_ssn_for_llc_and_aoc.yaml b/policyengine_us/tests/policy/contrib/reconciliation/reconciled_ssn_for_llc_and_aoc.yaml index 8a61f5667d5..4740dfe0d8e 100644 --- a/policyengine_us/tests/policy/contrib/reconciliation/reconciled_ssn_for_llc_and_aoc.yaml +++ b/policyengine_us/tests/policy/contrib/reconciliation/reconciled_ssn_for_llc_and_aoc.yaml @@ -73,3 +73,165 @@ output: american_opportunity_credit: 1_000 lifetime_learning_credit: 0 + +# The reform keeps the dependency rules: a dependent student's tuition does not +# count on a return whose filer can be claimed as a dependent (IRC +# 25A(f)(1)(A)(iii), 152(b)(1)), under either credit. +- name: Dependent student of a filer who can be claimed gets neither credit + period: 2026 + reforms: policyengine_us.reforms.reconciliation.reconciled_ssn_for_llc_and_aoc.reconciled_ssn_for_llc_and_aoc + input: + gov.contrib.reconciliation.ssn_for_llc_and_aoc.in_effect: true + people: + parent: + age: 45 + ssn_card_type: CITIZEN + has_tin: true + claimable_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + student: + age: 19 + ssn_card_type: CITIZEN + has_tin: true + qualified_tuition_expenses: 4_000 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, student] + filing_status: HEAD_OF_HOUSEHOLD + households: + household: + members: [parent, student] + state_code: TX + output: + american_opportunity_credit: 0 + lifetime_learning_credit: 0 + +- name: Dependent student of a joint return with one claimable spouse gets neither credit (the claimable spouse is the head) + period: 2026 + reforms: policyengine_us.reforms.reconciliation.reconciled_ssn_for_llc_and_aoc.reconciled_ssn_for_llc_and_aoc + input: + gov.contrib.reconciliation.ssn_for_llc_and_aoc.in_effect: true + people: + person_a: + age: 45 + ssn_card_type: CITIZEN + has_tin: true + claimable_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 45 + ssn_card_type: CITIZEN + has_tin: true + is_tax_unit_head: false + is_tax_unit_spouse: true + student: + age: 19 + ssn_card_type: CITIZEN + has_tin: true + qualified_tuition_expenses: 4_000 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_a, person_b, student] + filing_status: JOINT + households: + household: + members: [person_a, person_b, student] + state_code: TX + output: + american_opportunity_credit: 0 + lifetime_learning_credit: 0 + +- name: Dependent student of a joint return with one claimable spouse gets neither credit (the claimable spouse is the spouse) + period: 2026 + reforms: policyengine_us.reforms.reconciliation.reconciled_ssn_for_llc_and_aoc.reconciled_ssn_for_llc_and_aoc + input: + gov.contrib.reconciliation.ssn_for_llc_and_aoc.in_effect: true + people: + person_b: + age: 45 + ssn_card_type: CITIZEN + has_tin: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 45 + ssn_card_type: CITIZEN + has_tin: true + claimable_as_dependent_on_another_return: true + is_tax_unit_head: false + is_tax_unit_spouse: true + student: + age: 19 + ssn_card_type: CITIZEN + has_tin: true + qualified_tuition_expenses: 4_000 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [person_b, person_a, student] + filing_status: JOINT + households: + household: + members: [person_b, person_a, student] + state_code: TX + output: + american_opportunity_credit: 0 + lifetime_learning_credit: 0 + +- name: Dependent student of a filer who cannot be claimed is eligible for the American Opportunity Credit, not the Lifetime Learning Credit + period: 2026 + reforms: policyengine_us.reforms.reconciliation.reconciled_ssn_for_llc_and_aoc.reconciled_ssn_for_llc_and_aoc + input: + gov.contrib.reconciliation.ssn_for_llc_and_aoc.in_effect: true + people: + parent: + age: 45 + ssn_card_type: CITIZEN + has_tin: true + is_tax_unit_head: true + is_tax_unit_spouse: false + student: + age: 19 + ssn_card_type: CITIZEN + has_tin: true + qualified_tuition_expenses: 4_000 + is_pursuing_credential_for_american_opportunity_credit: true + attends_eligible_educational_institution_for_american_opportunity_credit: true + is_enrolled_at_least_half_time_for_american_opportunity_credit: true + has_american_opportunity_credit_1098_t_or_exception: true + has_american_opportunity_credit_institution_ein: true + is_tax_unit_head: false + is_tax_unit_spouse: false + tax_units: + tax_unit: + members: [parent, student] + filing_status: HEAD_OF_HOUSEHOLD + households: + household: + members: [parent, student] + state_code: TX + output: + is_eligible_for_american_opportunity_credit: [false, true] + lifetime_learning_credit: 0 diff --git a/policyengine_us/tests/policy/contrib/states/ct/hb5114/ct_hb5114.yaml b/policyengine_us/tests/policy/contrib/states/ct/hb5114/ct_hb5114.yaml index 9557ae1102e..bc07699ca08 100644 --- a/policyengine_us/tests/policy/contrib/states/ct/hb5114/ct_hb5114.yaml +++ b/policyengine_us/tests/policy/contrib/states/ct/hb5114/ct_hb5114.yaml @@ -427,11 +427,11 @@ age: 20 employment_income: 30_000 rent: 12_000 + claimed_as_dependent_on_another_return: true tax_units: tax_unit: members: [person1] filing_status: SINGLE - head_is_dependent_elsewhere: true households: household: members: [person1] diff --git a/policyengine_us/tests/policy/contrib/states/ga/ctc/ga_ctc_reform.yaml b/policyengine_us/tests/policy/contrib/states/ga/ctc/ga_ctc_reform.yaml index 77fcd5db26d..c236fb692d2 100644 --- a/policyengine_us/tests/policy/contrib/states/ga/ctc/ga_ctc_reform.yaml +++ b/policyengine_us/tests/policy/contrib/states/ga/ctc/ga_ctc_reform.yaml @@ -127,3 +127,93 @@ # $10k liability fully absorbs the $250 nonrefundable credit, leaving # nothing unused to refund. ga_refundable_ctc: 0 + +# The refund cap counts the same children as ga_ctc_potential (Georgia's own +# IRC 24(c) child test), not children allowed the federal credit. +- name: Refund cap keeps the child of a filer who can be claimed as a dependent + period: 2026 + absolute_error_margin: 0.01 + reforms: policyengine_us.reforms.states.ga.ctc.ga_ctc_reform.ga_ctc_reform + input: + gov.contrib.states.ga.ctc.refundable.in_effect: true + people: + parent: + age: 30 + claimed_as_dependent_on_another_return: true + child: + age: 2 + tax_units: + tax_unit: + members: [parent, child] + filing_status: SINGLE + ga_income_tax_before_non_refundable_credits: 0 + households: + household: + members: [parent, child] + state_code: GA + output: + ctc_qualifying_child: [false, false] + ga_ctc_potential: 250 + ga_refundable_ctc: 250 + +- name: Refund cap keeps the child of a joint return with one claimable spouse (the claimable spouse is the head) + period: 2026 + absolute_error_margin: 0.01 + reforms: policyengine_us.reforms.states.ga.ctc.ga_ctc_reform.ga_ctc_reform + input: + gov.contrib.states.ga.ctc.refundable.in_effect: true + people: + person_a: + age: 30 + claimed_as_dependent_on_another_return: true + is_tax_unit_head: true + is_tax_unit_spouse: false + person_b: + age: 30 + 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 + ga_income_tax_before_non_refundable_credits: 0 + households: + household: + members: [person_a, person_b, child] + state_code: GA + output: + ga_ctc_potential: 250 + ga_refundable_ctc: 250 + +- name: Refund cap keeps the child of a joint return with one claimable spouse (the claimable spouse is the spouse) + period: 2026 + absolute_error_margin: 0.01 + reforms: policyengine_us.reforms.states.ga.ctc.ga_ctc_reform.ga_ctc_reform + input: + gov.contrib.states.ga.ctc.refundable.in_effect: true + people: + person_b: + age: 30 + is_tax_unit_head: true + is_tax_unit_spouse: false + person_a: + age: 30 + 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 + ga_income_tax_before_non_refundable_credits: 0 + households: + household: + members: [person_b, person_a, child] + state_code: GA + output: + ga_ctc_potential: 250 + ga_refundable_ctc: 250 diff --git a/policyengine_us/tests/policy/contrib/states/hi/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/hi/dependent_exemption_reform_test.yaml index 8a11f290155..398865a7a4d 100644 --- a/policyengine_us/tests/policy/contrib/states/hi/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/hi/dependent_exemption_reform_test.yaml @@ -150,3 +150,57 @@ # exemptions from 3,432 to 1,144, widening taxable income and raising HI # income tax from 2,855.97 to 3,029.86 (about +173.89). output: {hi_income_tax: 3029.86} + +# As in the baseline, a filer who can be claimed as a dependent has no exemption of +# their own and, outside the claimant filing exception, no dependents. +- name: HI dependent exemption reform - claimable single filer has no exemptions + period: 2025 + reforms: policyengine_us.reforms.states.hi.dependent_exemption.hi_dependent_exemption_reform.hi_dependent_exemption_reform + input: + gov.contrib.states.hi.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 60_000, claimable_as_dependent_on_another_return: true} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: HI}} + output: {hi_regular_exemptions: 0} + +- name: HI dependent exemption reform - the filing exception keeps the dependents only + period: 2025 + reforms: policyengine_us.reforms.states.hi.dependent_exemption.hi_dependent_exemption_reform.hi_dependent_exemption_reform + input: + gov.contrib.states.hi.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 60_000, claimable_as_dependent_on_another_return: true, dependent_claimant_filing_exception: true} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: HI}} + output: {hi_regular_exemptions: 2_288} + +- name: HI dependent exemption reform - joint return with one claimable spouse keeps the other spouse only (the claimable spouse is the head) + period: 2025 + reforms: policyengine_us.reforms.states.hi.dependent_exemption.hi_dependent_exemption_reform.hi_dependent_exemption_reform + input: + gov.contrib.states.hi.dependent_exemption.in_effect: true + people: + person_a: {age: 40, claimable_as_dependent_on_another_return: true, is_tax_unit_head: true, is_tax_unit_spouse: false} + person_b: {age: 40, employment_income: 60_000, is_tax_unit_head: false, is_tax_unit_spouse: true} + child1: {age: 10, 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_name: HI}} + output: {hi_regular_exemptions: 1_144} + +- name: HI dependent exemption reform - joint return with one claimable spouse keeps the other spouse only (the claimable spouse is the spouse) + period: 2025 + reforms: policyengine_us.reforms.states.hi.dependent_exemption.hi_dependent_exemption_reform.hi_dependent_exemption_reform + input: + gov.contrib.states.hi.dependent_exemption.in_effect: true + people: + person_b: {age: 40, employment_income: 60_000, is_tax_unit_head: true, is_tax_unit_spouse: false} + person_a: {age: 40, claimable_as_dependent_on_another_return: true, is_tax_unit_head: false, is_tax_unit_spouse: true} + child1: {age: 10, 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_name: HI}} + output: {hi_regular_exemptions: 1_144} diff --git a/policyengine_us/tests/policy/contrib/states/wi/dependent_exemption_reform_test.yaml b/policyengine_us/tests/policy/contrib/states/wi/dependent_exemption_reform_test.yaml index 05709219f00..c6cfa3a680a 100644 --- a/policyengine_us/tests/policy/contrib/states/wi/dependent_exemption_reform_test.yaml +++ b/policyengine_us/tests/policy/contrib/states/wi/dependent_exemption_reform_test.yaml @@ -137,3 +137,57 @@ # 50,594. Wis. Stat. 71.06(1r): 3.5% x 14,680 + 4.4% x (50,480 - 14,680) # + 5.3% x (50,594 - 50,480) = 2,095.04 (baseline 2,032.42). output: {wi_income_tax: 2095.04} + +# As in the baseline, a filer who can be claimed as a dependent has no exemption of +# their own and, outside the claimant filing exception, no dependents. +- name: WI dependent exemption reform - claimable single filer has no exemptions + period: 2025 + reforms: policyengine_us.reforms.states.wi.dependent_exemption.wi_dependent_exemption_reform.wi_dependent_exemption_reform + input: + gov.contrib.states.wi.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 60_000, claimable_as_dependent_on_another_return: true} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: WI}} + output: {wi_base_exemption: 0} + +- name: WI dependent exemption reform - the filing exception keeps the dependents only + period: 2025 + reforms: policyengine_us.reforms.states.wi.dependent_exemption.wi_dependent_exemption_reform.wi_dependent_exemption_reform + input: + gov.contrib.states.wi.dependent_exemption.in_effect: true + people: + parent: {age: 40, employment_income: 60_000, claimable_as_dependent_on_another_return: true, dependent_claimant_filing_exception: true} + child1: {age: 10, is_tax_unit_dependent: true} + child2: {age: 12, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child1, child2], filing_status: SINGLE}} + households: {household: {members: [parent, child1, child2], state_name: WI}} + output: {wi_base_exemption: 1_400} + +- name: WI dependent exemption reform - joint return with one claimable spouse keeps the other spouse only (the claimable spouse is the head) + period: 2025 + reforms: policyengine_us.reforms.states.wi.dependent_exemption.wi_dependent_exemption_reform.wi_dependent_exemption_reform + input: + gov.contrib.states.wi.dependent_exemption.in_effect: true + people: + person_a: {age: 40, claimable_as_dependent_on_another_return: true, is_tax_unit_head: true, is_tax_unit_spouse: false} + person_b: {age: 40, employment_income: 60_000, is_tax_unit_head: false, is_tax_unit_spouse: true} + child1: {age: 10, 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_name: WI}} + output: {wi_base_exemption: 700} + +- name: WI dependent exemption reform - joint return with one claimable spouse keeps the other spouse only (the claimable spouse is the spouse) + period: 2025 + reforms: policyengine_us.reforms.states.wi.dependent_exemption.wi_dependent_exemption_reform.wi_dependent_exemption_reform + input: + gov.contrib.states.wi.dependent_exemption.in_effect: true + people: + person_b: {age: 40, employment_income: 60_000, is_tax_unit_head: true, is_tax_unit_spouse: false} + person_a: {age: 40, claimable_as_dependent_on_another_return: true, is_tax_unit_head: false, is_tax_unit_spouse: true} + child1: {age: 10, 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_name: WI}} + output: {wi_base_exemption: 700} diff --git a/policyengine_us/tests/policy/contrib/treasury/repeal_dependent_exemptions.yaml b/policyengine_us/tests/policy/contrib/treasury/repeal_dependent_exemptions.yaml index ec4d5fb575f..42c59a9621b 100644 --- a/policyengine_us/tests/policy/contrib/treasury/repeal_dependent_exemptions.yaml +++ b/policyengine_us/tests/policy/contrib/treasury/repeal_dependent_exemptions.yaml @@ -63,3 +63,46 @@ output: exemptions_count: 2 exemptions: 0 + +# The personal exemptions that remain are the filers' own, and a filer who can be +# claimed as a dependent has none (IRC 151(d)(2)). +- name: Claimable single filer with a child has no personal exemption + period: 2022 + reforms: policyengine_us.reforms.treasury.repeal_dependent_exemptions.repeal_dependent_exemptions + input: + gov.contrib.treasury.repeal_dependent_exemptions: true + people: + parent: {age: 30, claimable_as_dependent_on_another_return: true} + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [parent, child]}} + households: {household: {members: [parent, child], state_code: TX}} + output: + exemptions_count: 0 + +- name: Joint return with one claimable spouse keeps the other spouse's exemption (the claimable spouse is the head) + period: 2022 + reforms: policyengine_us.reforms.treasury.repeal_dependent_exemptions.repeal_dependent_exemptions + input: + gov.contrib.treasury.repeal_dependent_exemptions: true + people: + person_a: {age: 30, claimable_as_dependent_on_another_return: true, is_tax_unit_head: true, is_tax_unit_spouse: false} + person_b: {age: 30, is_tax_unit_head: false, is_tax_unit_spouse: true} + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [person_a, person_b, child], filing_status: JOINT}} + households: {household: {members: [person_a, person_b, child], state_code: TX}} + output: + exemptions_count: 1 + +- name: Joint return with one claimable spouse keeps the other spouse's exemption (the claimable spouse is the spouse) + period: 2022 + reforms: policyengine_us.reforms.treasury.repeal_dependent_exemptions.repeal_dependent_exemptions + input: + gov.contrib.treasury.repeal_dependent_exemptions: true + people: + person_b: {age: 30, is_tax_unit_head: true, is_tax_unit_spouse: false} + person_a: {age: 30, claimable_as_dependent_on_another_return: true, is_tax_unit_head: false, is_tax_unit_spouse: true} + child: {age: 5, is_tax_unit_dependent: true} + tax_units: {tax_unit: {members: [person_b, person_a, child], filing_status: JOINT}} + households: {household: {members: [person_b, person_a, child], state_code: TX}} + output: + exemptions_count: 1 diff --git a/policyengine_us/tests/policy/reform/cdcc_single_parent_work_requirement.yaml b/policyengine_us/tests/policy/reform/cdcc_single_parent_work_requirement.yaml index b19d62d4314..5de44b287cf 100644 --- a/policyengine_us/tests/policy/reform/cdcc_single_parent_work_requirement.yaml +++ b/policyengine_us/tests/policy/reform/cdcc_single_parent_work_requirement.yaml @@ -152,3 +152,60 @@ min_head_spouse_earned: 0 # Reform: min($8,000, $3,000, max($0, $60,000)) = min($8,000, $3,000, $60,000) = $3,000 cdcc_relevant_expenses: 3_000 + +# The reform changes the earnings test only. Childcare for the child of a filer +# who can be claimed as a dependent still does not count (IRC 21(b)(2)(A)(ii)). +- name: Reform keeps out childcare for the child of a filer who can be claimed + period: 2024 + reforms: policyengine_us.reforms.cdcc.cdcc_single_parent_work_requirement.cdcc_single_parent_work_requirement + input: + people: + adult1: + age: 35 + is_tax_unit_head: true + employment_income: 50_000 + claimable_as_dependent_on_another_return: true + child: + age: 5 + is_tax_unit_dependent: true + relative: + age: 40 + is_tax_unit_dependent: true + is_incapable_of_self_care: true + tax_units: + tax_unit: + members: [adult1, child, relative] + tax_unit_childcare_expenses: 3_000 + households: + household: + members: [adult1, child, relative] + state_code: TX + output: + cdcc_relevant_expenses: 0 + +- name: Reform counts the childcare when the filer cannot be claimed + period: 2024 + reforms: policyengine_us.reforms.cdcc.cdcc_single_parent_work_requirement.cdcc_single_parent_work_requirement + input: + people: + adult1: + age: 35 + is_tax_unit_head: true + employment_income: 50_000 + child: + age: 5 + is_tax_unit_dependent: true + relative: + age: 40 + is_tax_unit_dependent: true + is_incapable_of_self_care: true + tax_units: + tax_unit: + members: [adult1, child, relative] + tax_unit_childcare_expenses: 3_000 + households: + household: + members: [adult1, child, relative] + state_code: TX + output: + cdcc_relevant_expenses: 3_000 diff --git a/policyengine_us/variables/gov/irs/credits/cdcc/cdcc_eligible.py b/policyengine_us/variables/gov/irs/credits/cdcc/cdcc_eligible.py index 82861496784..c7dbc104092 100644 --- a/policyengine_us/variables/gov/irs/credits/cdcc/cdcc_eligible.py +++ b/policyengine_us/variables/gov/irs/credits/cdcc/cdcc_eligible.py @@ -9,6 +9,9 @@ class is_cdcc_eligible(Variable): reference = ( "https://www.law.cornell.edu/uscode/text/26/21#b_1", "https://www.law.cornell.edu/uscode/text/26/21#e_5", + "https://www.law.cornell.edu/uscode/text/26/152#b_1", + # Publication 503, Who Is a Qualifying Person? + "https://www.irs.gov/pub/irs-prior/p503--2025.pdf#page=3", ) def formula(person, period, parameters): @@ -21,8 +24,20 @@ def formula(person, period, parameters): # qualifying individual even when the noncustodial parent claims the # dependent, so any under-age member other than the head or spouse # qualifies. - qualifies_by_age = ~head_or_spouse & (age < p.child_age) - # Subsections (b)(1)(B) (dependent) and (b)(1)(C) (spouse). + # A child qualifies only as the filer's dependent ("Your qualifying + # child who is your dependent", Publication 503), 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. The model has no + # input for an IRC 152(e) release, so the 21(e)(5) child of a + # custodial parent who can be claimed is not kept. + filer_is_dependent = person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + qualifies_by_age = ~head_or_spouse & (age < p.child_age) & ~filer_is_dependent + # Subsections (b)(1)(B) (dependent) and (b)(1)(C) (spouse). Subsection + # (b)(1)(B) determines dependency "without regard to subsections + # (b)(1), (b)(2), and (d)(1)(B)" of section 152, so a disabled person + # still qualifies when the filer can be claimed as a dependent. disabled = person("is_incapable_of_self_care", period) married = person.tax_unit("tax_unit_married", period) qualifies_by_disability = disabled & (is_dependent | (head_or_spouse & married)) diff --git a/policyengine_us/variables/gov/irs/credits/cdcc/cdcc_qualifying_childcare_expenses.py b/policyengine_us/variables/gov/irs/credits/cdcc/cdcc_qualifying_childcare_expenses.py new file mode 100644 index 00000000000..f7885005bbf --- /dev/null +++ b/policyengine_us/variables/gov/irs/credits/cdcc/cdcc_qualifying_childcare_expenses.py @@ -0,0 +1,32 @@ +from policyengine_us.model_api import * + + +class cdcc_qualifying_childcare_expenses(Variable): + value_type = float + entity = TaxUnit + label = "Childcare expenses that count for the child and dependent care credit" + unit = USD + definition_period = YEAR + reference = ( + "https://www.law.cornell.edu/uscode/text/26/21#b_2_A", + "https://www.law.cornell.edu/uscode/text/26/152#b_1", + ) + + def formula(tax_unit, period, parameters): + childcare = tax_unit("tax_unit_childcare_expenses", period) + # IRC 21(b)(2)(A)(ii) counts only expenses "for the care of a + # qualifying individual". A return on which a filer can be claimed as + # a dependent (outside the claimant filing exception) has no + # qualifying child unless the child is incapable of self-care, so its + # childcare expenses do not count otherwise. Childcare expenses are + # those of the tax unit's children under 18, recorded as a tax-unit + # total, so one child's share cannot be left out when another child + # qualifies. + person = tax_unit.members + qualifying_child = person("is_cdcc_eligible", period) & person( + "is_child", period + ) + dependent_filer = tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + return where(dependent_filer & ~tax_unit.any(qualifying_child), 0, childcare) diff --git a/policyengine_us/variables/gov/irs/credits/cdcc/cdcc_relevant_expenses.py b/policyengine_us/variables/gov/irs/credits/cdcc/cdcc_relevant_expenses.py index 797f2bbcf39..aa020f78a20 100644 --- a/policyengine_us/variables/gov/irs/credits/cdcc/cdcc_relevant_expenses.py +++ b/policyengine_us/variables/gov/irs/credits/cdcc/cdcc_relevant_expenses.py @@ -18,7 +18,10 @@ def formula(tax_unit, period, parameters): # (tax_unit_childcare_expenses) plus care for a disabled qualifying # individual of any age — a disabled adult dependent or spouse # (care_expenses, a person-level yearly input). - childcare = tax_unit("tax_unit_childcare_expenses", period) + # cdcc_qualifying_childcare_expenses leaves out childcare for a child + # who is not a qualifying individual because a filer can be claimed + # as a dependent. + childcare = tax_unit("cdcc_qualifying_childcare_expenses", period) adult_care = add(tax_unit, period, ["care_expenses"]) expenses = childcare + adult_care cdcc_limit = tax_unit("cdcc_limit", period) diff --git a/policyengine_us/variables/gov/irs/credits/ctc/maximum/ctc_qualifying_child.py b/policyengine_us/variables/gov/irs/credits/ctc/maximum/ctc_qualifying_child.py index ae2c1bfab24..f8906588f5d 100644 --- a/policyengine_us/variables/gov/irs/credits/ctc/maximum/ctc_qualifying_child.py +++ b/policyengine_us/variables/gov/irs/credits/ctc/maximum/ctc_qualifying_child.py @@ -8,7 +8,13 @@ class ctc_qualifying_child(Variable): documentation = "Child qualifies for the Child Tax Credit" definition_period = YEAR defined_for = "is_tax_unit_dependent" - reference = "https://www.law.cornell.edu/uscode/text/26/24#c" + reference = ( + # Subsections (a) and (c). + "https://www.law.cornell.edu/uscode/text/26/24#c", + "https://www.law.cornell.edu/uscode/text/26/152#b_1", + # Publication 501, Dependent Taxpayer Test. + "https://www.irs.gov/pub/irs-prior/p501--2025.pdf#page=11", + ) def formula(person, period, parameters): age = person("age", period) @@ -18,4 +24,12 @@ def formula(person, period, parameters): meets_identification_requirements = person( "meets_ctc_child_identification_requirements", period ) - return age_eligible & meets_identification_requirements + # IRC 24(a) allows the credit only for a qualifying child for whom the + # taxpayer is allowed a deduction under section 151. Under IRC + # 152(b)(1) a taxpayer who can be claimed as a dependent is treated as + # having no dependents, and on a joint return neither spouse may be + # claimable (Publication 501, Dependent Taxpayer Test). + filer_is_dependent = person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + return age_eligible & meets_identification_requirements & ~filer_is_dependent diff --git a/policyengine_us/variables/gov/irs/credits/ctc/maximum/individual/ctc_adult_individual_maximum.py b/policyengine_us/variables/gov/irs/credits/ctc/maximum/individual/ctc_adult_individual_maximum.py index 4caaab2f978..13c2ffd4c52 100644 --- a/policyengine_us/variables/gov/irs/credits/ctc/maximum/individual/ctc_adult_individual_maximum.py +++ b/policyengine_us/variables/gov/irs/credits/ctc/maximum/individual/ctc_adult_individual_maximum.py @@ -15,6 +15,7 @@ class ctc_adult_individual_maximum(Variable): "https://www.law.cornell.edu/uscode/text/26/24#a", "https://www.law.cornell.edu/uscode/text/26/24#h", "https://www.law.cornell.edu/uscode/text/26/24#i", + "https://www.law.cornell.edu/uscode/text/26/152#b_1", ) def formula(person, period, parameters): @@ -24,9 +25,16 @@ def formula(person, period, parameters): filer_meets_tin_requirement = person.tax_unit( "filer_meets_ctc_identification_requirements", period ) + # IRC 24(h)(4)(A) gives the credit for "each dependent of the taxpayer"; + # 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. + filer_is_dependent = person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) return ( is_adult * dependent_has_tin * filer_meets_tin_requirement + * ~filer_is_dependent * p.amount.adult_dependent ) diff --git a/policyengine_us/variables/gov/irs/credits/earned_income/eligibility/eitc_demographic_eligible.py b/policyengine_us/variables/gov/irs/credits/earned_income/eligibility/eitc_demographic_eligible.py index 2338356763e..9cb742b764f 100644 --- a/policyengine_us/variables/gov/irs/credits/earned_income/eligibility/eitc_demographic_eligible.py +++ b/policyengine_us/variables/gov/irs/credits/earned_income/eligibility/eitc_demographic_eligible.py @@ -6,7 +6,10 @@ class eitc_demographic_eligible(Variable): entity = TaxUnit label = "Meets demographic eligibility for EITC" definition_period = YEAR - reference = "https://www.law.cornell.edu/uscode/text/26/32#c_1_A_ii_II" + reference = ( + "https://www.law.cornell.edu/uscode/text/26/32#c_1_A_ii", + "https://www.irs.gov/pub/irs-prior/p596--2025.pdf#page=18", + ) def formula(tax_unit, period, parameters): person = tax_unit.members @@ -27,4 +30,17 @@ def formula(tax_unit, period, parameters): # IRC § 32(c)(1)(A)(ii)(II) applies the age test to the filer or, # on a joint return, either spouse — never to dependents. is_filer_or_spouse = ~person("is_tax_unit_dependent", period) - return has_child | tax_unit.any(meets_age_requirements & is_filer_or_spouse) + # IRC § 32(c)(1)(A)(ii)(III): without a qualifying child, the filer + # must not be a dependent of another taxpayer; on a joint return, + # "neither you nor your spouse can be claimed as a dependent by another + # person" (IRS Publication 596). A nonrequired claimant who files + # no return or only for a withholding/estimated-payment refund is + # excepted, without changing the standard-deduction limitation. + dependent_elsewhere = tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + childless_eligible = ( + tax_unit.any(meets_age_requirements & is_filer_or_spouse) + & ~dependent_elsewhere + ) + return has_child | childless_eligible diff --git a/policyengine_us/variables/gov/irs/credits/education/american_opportunity_credit/is_eligible_for_american_opportunity_credit.py b/policyengine_us/variables/gov/irs/credits/education/american_opportunity_credit/is_eligible_for_american_opportunity_credit.py index 6509aa1f045..b3d5406e196 100644 --- a/policyengine_us/variables/gov/irs/credits/education/american_opportunity_credit/is_eligible_for_american_opportunity_credit.py +++ b/policyengine_us/variables/gov/irs/credits/education/american_opportunity_credit/is_eligible_for_american_opportunity_credit.py @@ -18,6 +18,12 @@ def formula(person, period, parameters): filing_status = tax_unit("filing_status", period) filing_status_values = filing_status.possible_values filing_status_eligible = filing_status != filing_status_values.SEPARATE + # The dependency rules of IRC 25A(g)(3) and 25A(f)(1)(A)(iii): a + # claimed filer bars the return, and a dependent student needs the + # return to have dependents. + barred_by_dependency = person( + "is_barred_from_education_credits_by_dependency", period + ) requires_1098_t = aoc.eligibility.requires_1098_t_or_exception has_1098_t_or_exception = ( person("has_american_opportunity_credit_1098_t_or_exception", period) @@ -66,4 +72,5 @@ def formula(person, period, parameters): period, ) & filing_status_eligible + & ~barred_by_dependency ) diff --git a/policyengine_us/variables/gov/irs/credits/education/is_barred_from_education_credits_by_dependency.py b/policyengine_us/variables/gov/irs/credits/education/is_barred_from_education_credits_by_dependency.py new file mode 100644 index 00000000000..6a08d71c198 --- /dev/null +++ b/policyengine_us/variables/gov/irs/credits/education/is_barred_from_education_credits_by_dependency.py @@ -0,0 +1,34 @@ +from policyengine_us.model_api import * + + +class is_barred_from_education_credits_by_dependency(Variable): + value_type = bool + entity = Person + label = "Barred from the education credits by the dependency rules" + definition_period = YEAR + reference = ( + # Subsections (f)(1)(A)(iii) and (g)(3). + "https://www.law.cornell.edu/uscode/text/26/25A#g_3", + "https://www.law.cornell.edu/uscode/text/26/152#b_1", + "https://www.ecfr.gov/current/title-26/section-1.25A-1", + ) + + def formula(person, period, parameters): + tax_unit = person.tax_unit + # IRC 25A(g)(3): no credit to an individual for whom a section 151 + # deduction "is allowed to another taxpayer", and the Form 1040 + # instructions extend this to "your spouse if filing jointly", so + # either filer being claimed bars the return's credit. This turns on + # an actual claim (26 CFR 1.25A-1(f)), so it reads the claimed input + # rather than a claimability helper. + filer = person("is_tax_unit_head_or_spouse", period) + claimed = person("claimed_as_dependent_on_another_return", period) + filer_claimed = tax_unit.any(filer & claimed) + # IRC 25A(f)(1)(A)(iii) counts the tuition of a dependent only if the + # taxpayer "is allowed a deduction under section 151" for them, and a + # return on which a filer can be claimed as a dependent (outside the + # claimant filing exception) has no dependents (IRC 152(b)(1)). + dependent_student_barred = person("is_tax_unit_dependent", period) & tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + return filer_claimed | dependent_student_barred diff --git a/policyengine_us/variables/gov/irs/credits/education/is_eligible_for_lifetime_learning_credit.py b/policyengine_us/variables/gov/irs/credits/education/is_eligible_for_lifetime_learning_credit.py index 3d80f23da5f..1a7bbf0a847 100644 --- a/policyengine_us/variables/gov/irs/credits/education/is_eligible_for_lifetime_learning_credit.py +++ b/policyengine_us/variables/gov/irs/credits/education/is_eligible_for_lifetime_learning_credit.py @@ -19,6 +19,12 @@ def formula(person, period, parameters): filing_status = tax_unit("filing_status", period) filing_status_values = filing_status.possible_values filing_status_eligible = filing_status != filing_status_values.SEPARATE + # The dependency rules of IRC 25A(g)(3) and 25A(f)(1)(A)(iii): a + # claimed filer bars the return, and a dependent student needs the + # return to have dependents. + barred_by_dependency = person( + "is_barred_from_education_credits_by_dependency", period + ) requires_1098_t = llc.eligibility.requires_1098_t_or_exception has_1098_t_or_exception = ( person("has_lifetime_learning_credit_1098_t_or_exception", period) @@ -45,4 +51,5 @@ def formula(person, period, parameters): period, ) & filing_status_eligible + & ~barred_by_dependency ) diff --git a/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_adult_count_with_valid_ssn.py b/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_adult_count_with_valid_ssn.py index 2250e5d6698..81b908901fd 100644 --- a/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_adult_count_with_valid_ssn.py +++ b/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_adult_count_with_valid_ssn.py @@ -7,12 +7,12 @@ class rrc_adult_count_with_valid_ssn(Variable): definition_period = YEAR label = "Count of tax unit head/spouse with valid SSN for RRC" reference = ( - "https://www.law.cornell.edu/uscode/text/26/6428#g_1_A", - "https://www.law.cornell.edu/uscode/text/26/6428#g_1_B", + # Subsections (d)(2) and (g)(1)(A)-(B). + "https://www.law.cornell.edu/uscode/text/26/6428#g_1", + # Subsections (d)(2) and (g)(1)-(2). "https://www.law.cornell.edu/uscode/text/26/6428A#g_1", - "https://www.law.cornell.edu/uscode/text/26/6428A#g_2", - "https://www.law.cornell.edu/uscode/text/26/6428B#e_2_A", - "https://www.law.cornell.edu/uscode/text/26/6428B#e_2_B", + # Subsections (c)(2) and (e)(2)(A)-(B). + "https://www.law.cornell.edu/uscode/text/26/6428B#e_2", ) def formula(tax_unit, period, parameters): @@ -20,4 +20,9 @@ def formula(tax_unit, period, parameters): head_or_spouse = person("is_tax_unit_head_or_spouse", period) # Reuse existing EITC SSN check - identical definition (SSN required) has_valid_ssn = person("meets_eitc_identification_requirements", period) - return tax_unit.sum(head_or_spouse & has_valid_ssn) + # An "eligible individual" excludes "any individual with respect to + # whom a deduction under section 151 is allowable to another + # taxpayer" (IRC 6428(d)(2), 6428A(d)(2)) or "who is a dependent of + # another taxpayer" (IRC 6428B(c)(2)): a claimability test. + claimable = person("claimable_as_dependent_on_another_return", period) + return tax_unit.sum(head_or_spouse & has_valid_ssn & ~claimable) diff --git a/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_arpa.py b/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_arpa.py index 252017448f7..e5f35eb2829 100644 --- a/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_arpa.py +++ b/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_arpa.py @@ -26,9 +26,17 @@ def formula(tax_unit, period, parameters): ) is_joint = tax_unit("tax_unit_is_joint", period) adults_with_ssn = tax_unit("rrc_adult_count_with_valid_ssn", period) + # The exception waives the identification rule, not the exclusion of + # a spouse who is another taxpayer's dependent. + person = tax_unit.members + dependent_filers = tax_unit.sum( + person("is_tax_unit_head_or_spouse", period) + & person("claimable_as_dependent_on_another_return", period) + ) count_adults = where( armed_forces_exception, - 2, # Joint filers always have 2 adults (structural constant) + # Joint filers always have 2 adults (structural constant) + max_(2 - dependent_filers, 0), where(is_joint, adults_with_ssn, min_(adults_with_ssn, 1)), ) max_payment = ( @@ -39,4 +47,8 @@ def formula(tax_unit, period, parameters): excess = max_(0, agi - rrc.arpa.phase_out.threshold[filing_status]) payment_reduction_percent = excess / phase_out_length payment_reduction = max_payment * payment_reduction_percent - return max_(0, max_payment - payment_reduction) + # IRC 6428B(a) allows the credit to "an eligible individual", so a + # return whose every filer is a dependent of another taxpayer gets + # none, even for its own dependents. + no_eligible_filer = tax_unit("every_filer_is_dependent_elsewhere", period) + return where(no_eligible_filer, 0, max_(0, max_payment - payment_reduction)) diff --git a/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_arpa_dependents_with_valid_ssn.py b/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_arpa_dependents_with_valid_ssn.py index 00b05333a86..45245ce16a2 100644 --- a/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_arpa_dependents_with_valid_ssn.py +++ b/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_arpa_dependents_with_valid_ssn.py @@ -13,6 +13,12 @@ class rrc_arpa_dependents_with_valid_ssn(Variable): def formula(tax_unit, period, parameters): person = tax_unit.members - is_dependent = person("is_tax_unit_dependent", period) + # IRC 6428B(b)(2) counts "the number of dependents of the taxpayer", and + # under 152(b)(1) a return on which the filer (or, if joint, either + # spouse) can be claimed as a dependent has none. + dependent_filer = person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + is_dependent = person("is_tax_unit_dependent", period) & ~dependent_filer has_valid_ssn = person("meets_eitc_identification_requirements", period) return tax_unit.sum(is_dependent & has_valid_ssn) diff --git a/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_caa.py b/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_caa.py index 577228072bb..7bd14989385 100644 --- a/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_caa.py +++ b/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_caa.py @@ -23,9 +23,17 @@ def formula(tax_unit, period, parameters): "rrc_qualifies_for_armed_forces_exception", period ) is_joint = tax_unit("tax_unit_is_joint", period) + # The exception waives the identification rule, not the exclusion of + # a spouse who is another taxpayer's dependent. + person = tax_unit.members + dependent_filers = tax_unit.sum( + person("is_tax_unit_head_or_spouse", period) + & person("claimable_as_dependent_on_another_return", period) + ) count_adults = where( armed_forces_exception, - 2, # Joint filers always have 2 adults (structural constant) + # Joint filers always have 2 adults (structural constant) + max_(2 - dependent_filers, 0), where(is_joint, adults_with_ssn, min_(adults_with_ssn, 1)), ) # Per 26 USC 6428A(g)(3), children count only if: @@ -34,7 +42,15 @@ def formula(tax_unit, period, parameters): children_with_ssn = tax_unit( "rrc_cares_qualifying_children_with_valid_ssn", period ) - count_children = where(adults_with_ssn > 0, children_with_ssn, 0) + # This prerequisite is a spouse with a valid SSN, whether or not that + # spouse is an eligible individual; the credit itself needs a filer + # who is not a dependent of another taxpayer. + filer_has_ssn = tax_unit.any( + person("is_tax_unit_head_or_spouse", period) + & person("meets_eitc_identification_requirements", period) + ) + no_eligible_filer = tax_unit("every_filer_is_dependent_elsewhere", period) + count_children = where(filer_has_ssn & ~no_eligible_filer, children_with_ssn, 0) max_payment = ( rrc.caa.max.adult * count_adults + rrc.caa.max.child * count_children ) diff --git a/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_cares.py b/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_cares.py index bbbf38b4a21..20868403722 100644 --- a/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_cares.py +++ b/policyengine_us/variables/gov/irs/credits/recovery_rebate_credit/rrc_cares.py @@ -23,9 +23,17 @@ def formula(tax_unit, period, parameters): "rrc_qualifies_for_armed_forces_exception", period ) is_joint = tax_unit("tax_unit_is_joint", period) + # The exception waives the identification rule, not the exclusion of + # a spouse who is another taxpayer's dependent. + person = tax_unit.members + dependent_filers = tax_unit.sum( + person("is_tax_unit_head_or_spouse", period) + & person("claimable_as_dependent_on_another_return", period) + ) count_adults = where( armed_forces_exception, - 2, # Joint filers always have 2 adults (structural constant) + # Joint filers always have 2 adults (structural constant) + max_(2 - dependent_filers, 0), where(is_joint, adults_with_ssn, min_(adults_with_ssn, 1)), ) # Per 26 USC 6428(g)(1)(C), children count only if: @@ -34,7 +42,15 @@ def formula(tax_unit, period, parameters): children_with_ssn = tax_unit( "rrc_cares_qualifying_children_with_valid_ssn", period ) - count_children = where(adults_with_ssn > 0, children_with_ssn, 0) + # This prerequisite is a spouse with a valid SSN, whether or not that + # spouse is an eligible individual; the credit itself needs a filer + # who is not a dependent of another taxpayer. + filer_has_ssn = tax_unit.any( + person("is_tax_unit_head_or_spouse", period) + & person("meets_eitc_identification_requirements", period) + ) + no_eligible_filer = tax_unit("every_filer_is_dependent_elsewhere", period) + count_children = where(filer_has_ssn & ~no_eligible_filer, children_with_ssn, 0) max_payment = ( rrc.cares.max.adult * count_adults + rrc.cares.max.child * count_children ) diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/student_loan_interest/student_loan_interest_ald_eligible.py b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/student_loan_interest/student_loan_interest_ald_eligible.py index 9bf6a41feb0..fd1bcc2bab0 100644 --- a/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/student_loan_interest/student_loan_interest_ald_eligible.py +++ b/policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/student_loan_interest/student_loan_interest_ald_eligible.py @@ -19,9 +19,16 @@ class student_loan_interest_ald_eligible(Variable): ) def formula(person, period, parameters): - # Per IRC § 221(c), taxpayer cannot be claimed as a dependent head_or_spouse = person("is_tax_unit_head_or_spouse", period) + # Per IRC § 221(c), no deduction for an individual for whom a section + # 151 deduction "is allowed to another taxpayer"; the Form 1040 + # instructions require that "you, or your spouse if filing jointly, + # aren't claimed as a dependent", so either filer being claimed bars + # the return. This turns on an actual claim, so it reads the claimed + # input rather than a claimability helper. + claimed = person("claimed_as_dependent_on_another_return", period) + filer_claimed = person.tax_unit.any(head_or_spouse & claimed) # Per IRC § 221(e)(2), taxpayer cannot file as Married Filing Separately filing_status = person.tax_unit("filing_status", period) separate = filing_status == filing_status.possible_values.SEPARATE - return head_or_spouse & ~separate + return head_or_spouse & ~separate & ~filer_claimed diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/deductions/standard_deduction/basic_standard_deduction.py b/policyengine_us/variables/gov/irs/income/taxable_income/deductions/standard_deduction/basic_standard_deduction.py index e3d3745bdc5..952da61a05f 100644 --- a/policyengine_us/variables/gov/irs/income/taxable_income/deductions/standard_deduction/basic_standard_deduction.py +++ b/policyengine_us/variables/gov/irs/income/taxable_income/deductions/standard_deduction/basic_standard_deduction.py @@ -7,19 +7,35 @@ class basic_standard_deduction(Variable): label = "Basic standard deduction" definition_period = YEAR unit = USD - reference = "https://www.law.cornell.edu/uscode/text/26/63#c_2" + reference = ( + "https://www.law.cornell.edu/uscode/text/26/63#c_2", + "https://www.law.cornell.edu/uscode/text/26/63#c_5", + # Standard Deduction Worksheet for Dependents: "Use this worksheet + # only if someone can claim you, or your spouse if filing jointly, + # as a dependent." + "https://www.irs.gov/pub/irs-prior/i1040gi--2025.pdf#page=35", + ) def formula(tax_unit, period, parameters): p = parameters(period).gov.irs.deductions.standard filing_status = tax_unit("filing_status", period) separate_filer_itemizes = tax_unit("separate_filer_itemizes", period) - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) + # A joint return uses the dependent worksheet, with the couple's + # earned income and the joint amount as the cap, when either spouse + # can be claimed. + dependent_elsewhere = tax_unit("head_or_spouse_is_dependent_elsewhere", period) standard_deduction = p.amount[filing_status] + # Worksheet earned income: wages and self-employment income minus the + # deductible part of self-employment tax (Schedule 1, line 15). + worksheet_earned_income = max_( + tax_unit("tax_unit_earned_income", period) + - tax_unit("self_employment_tax_ald", period), + 0, + ) standard_deduction_if_dependent = min_( standard_deduction, max_( - p.dependent.additional_earned_income - + tax_unit("tax_unit_earned_income", period), + p.dependent.additional_earned_income + worksheet_earned_income, p.dependent.amount, ), ) diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/deductions/tuition_and_fees_deduction_eligible.py b/policyengine_us/variables/gov/irs/income/taxable_income/deductions/tuition_and_fees_deduction_eligible.py index ac202b88a48..0b169af9c13 100644 --- a/policyengine_us/variables/gov/irs/income/taxable_income/deductions/tuition_and_fees_deduction_eligible.py +++ b/policyengine_us/variables/gov/irs/income/taxable_income/deductions/tuition_and_fees_deduction_eligible.py @@ -27,4 +27,9 @@ def formula(tax_unit, period, parameters): "lifetime_learning_credit_potential", ], ) - return ~separate & (aoc_llc == 0) + # IRC 222(c)(3): no deduction to an individual for whom a section 151 + # deduction "may be allowed to another taxpayer". Without this, a + # filer barred from the education credits for that reason would + # become eligible here. + dependent_filer = tax_unit("head_or_spouse_is_dependent_elsewhere", period) + return ~separate & (aoc_llc == 0) & ~dependent_filer diff --git a/policyengine_us/variables/gov/irs/income/taxable_income/exemptions/exemptions_count.py b/policyengine_us/variables/gov/irs/income/taxable_income/exemptions/exemptions_count.py index b8e19acbdab..57eaacb22f8 100644 --- a/policyengine_us/variables/gov/irs/income/taxable_income/exemptions/exemptions_count.py +++ b/policyengine_us/variables/gov/irs/income/taxable_income/exemptions/exemptions_count.py @@ -7,5 +7,35 @@ class exemptions_count(Variable): label = "Number of tax exemptions" unit = USD definition_period = YEAR + documentation = ( + "Number of personal exemptions on the federal return: one for each " + "filer who cannot be claimed as a dependent by another taxpayer, plus " + "one for each dependent unless a filer can be claimed and the " + "would-be claimant does not meet the filing exception." + ) + reference = ( + "https://www.law.cornell.edu/uscode/text/26/151#d_2", + "https://www.law.cornell.edu/uscode/text/26/152#b_1", + # Publication 501, Dependent Taxpayer Test. + "https://www.irs.gov/pub/irs-prior/p501--2025.pdf#page=11", + # 2017 Form 1040, line 6a: "If someone can claim you as a dependent, + # do not check box 6a"; instructions, line 6b: the spouse box only + # if the "spouse can't be claimed as a dependent". + "https://www.irs.gov/pub/irs-prior/f1040--2017.pdf#page=1", + "https://www.irs.gov/pub/irs-prior/i1040gi--2017.pdf#page=15", + ) - adds = ["tax_unit_size"] + def formula(tax_unit, period, parameters): + tax_unit_size = tax_unit("tax_unit_size", period) + # IRC 151(d)(2): no exemption for a filer whom another taxpayer can + # claim as a dependent. + claimable_filer = tax_unit("head_or_spouse_is_dependent_elsewhere", period) + own = tax_unit("head_spouse_count_not_dependent_elsewhere", period) + # IRC 152(b)(1): such a filer has no dependents, unless the would-be + # claimant is not required to file and files no return or only for a + # refund (Publication 501, Dependent Taxpayer Test). + no_dependents = tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + dependents = where(no_dependents, 0, tax_unit("tax_unit_dependents", period)) + return where(claimable_filer, own + dependents, tax_unit_size) diff --git a/policyengine_us/variables/gov/states/az/tax/income/exemptions/az_aged_exemption_eligible_person.py b/policyengine_us/variables/gov/states/az/tax/income/exemptions/az_aged_exemption_eligible_person.py index 6169e38bb5e..af27ae56bd4 100644 --- a/policyengine_us/variables/gov/states/az/tax/income/exemptions/az_aged_exemption_eligible_person.py +++ b/policyengine_us/variables/gov/states/az/tax/income/exemptions/az_aged_exemption_eligible_person.py @@ -8,6 +8,7 @@ class az_aged_exemption_eligible_person(Variable): unit = USD definition_period = YEAR defined_for = StateCode.AZ + reference = "https://azdor.gov/sites/default/files/document/FORMS_INDIVIDUAL_2025_140i.pdf#page=6" def formula(person, period, parameters): head = person("is_tax_unit_head", period) @@ -17,9 +18,6 @@ def formula(person, period, parameters): filing_status = tax_unit("az_filing_status", period) separate = filing_status == filing_status.possible_values.SEPARATE - dependent_head = tax_unit("head_is_dependent_elsewhere", period) - - dependent_spouse = tax_unit("spouse_is_dependent_elsewhere", period) - spouse_eligible_condition = ~dependent_spouse * ~separate - - return (head & ~dependent_head) | (spouse & spouse_eligible_condition) + # Form 140, Box 8, excludes each spouse only when actually claimed. + claimed_elsewhere = person("claimed_as_dependent_on_another_return", period) + return ~claimed_elsewhere & (head | (spouse & ~separate)) diff --git a/policyengine_us/variables/gov/states/ca/tax/income/credits/ca_cdcc_relevant_expenses.py b/policyengine_us/variables/gov/states/ca/tax/income/credits/ca_cdcc_relevant_expenses.py index 25fe3bf1736..06462eec8cc 100644 --- a/policyengine_us/variables/gov/states/ca/tax/income/credits/ca_cdcc_relevant_expenses.py +++ b/policyengine_us/variables/gov/states/ca/tax/income/credits/ca_cdcc_relevant_expenses.py @@ -20,7 +20,7 @@ def formula(tax_unit, period, parameters): # Qualifying expenses cover childcare plus care for a disabled # qualifying individual of any age (FTB 3506 instructions, # Section D). - childcare = tax_unit("tax_unit_childcare_expenses", period) + childcare = tax_unit("cdcc_qualifying_childcare_expenses", period) adult_care = add(tax_unit, period, ["care_expenses"]) expenses = childcare + adult_care # First, cap based on the number of eligible care receivers diff --git a/policyengine_us/variables/gov/states/de/tax/income/credits/personal/de_personal_credit_indv.py b/policyengine_us/variables/gov/states/de/tax/income/credits/personal/de_personal_credit_indv.py index 6722f22b3c2..9701ad23833 100644 --- a/policyengine_us/variables/gov/states/de/tax/income/credits/personal/de_personal_credit_indv.py +++ b/policyengine_us/variables/gov/states/de/tax/income/credits/personal/de_personal_credit_indv.py @@ -32,16 +32,27 @@ def formula(person, period, parameters): fixed = person("de_aged_personal_credit_indv", period) + person( "de_cdcc_indv", period ) - # Each column's own $110 personal credit is fixed to that column. - head_fixed = person.tax_unit.sum(is_head * fixed) + credit_per - spouse_fixed = person.tax_unit.sum(is_spouse * fixed) + credit_per + # Each column's own $110 personal credit is fixed to that column. 30 + # Del. C. 1110(b)(1) gives it "for each personal exemption to which + # such individual is entitled ... for federal income tax purposes", + # and a spouse who can be claimed as a dependent has none (IRC + # 151(d)(2)). + head_own = where( + person.tax_unit("head_is_dependent_elsewhere", period), 0, credit_per + ) + spouse_own = where( + person.tax_unit("spouse_is_dependent_elsewhere", period), 0, credit_per + ) + head_fixed = person.tax_unit.sum(is_head * fixed) + head_own + spouse_fixed = person.tax_unit.sum(is_spouse * fixed) + spouse_own head_capacity = max_(head_tax - head_fixed, 0) spouse_capacity = max_(spouse_tax - spouse_fixed, 0) total_units = person.tax_unit("exemptions_count", period) - # Dependent increments: exemptions beyond the two spouses. - dep_units = max_(total_units - 2, 0) + # Dependent increments: exemptions beyond the spouses' own. + own_units = person.tax_unit("head_spouse_count_not_dependent_elsewhere", period) + dep_units = max_(total_units - own_units, 0) # Optimal dependent split: try proportional floor and ceil, pick # whichever maximises effective credits (min of alloc vs @@ -62,7 +73,7 @@ def formula(person, period, parameters): ) n_head_dep = where(eff_high > eff_low, n_high, n_low) - head_alloc = credit_per + n_head_dep * credit_per - spouse_alloc = credit_per + (dep_units - n_head_dep) * credit_per + head_alloc = head_own + n_head_dep * credit_per + spouse_alloc = spouse_own + (dep_units - n_head_dep) * credit_per return is_head_or_spouse * where(is_head, head_alloc, spouse_alloc) diff --git a/policyengine_us/variables/gov/states/ga/tax/income/credits/ctc/ga_ctc_eligible_child.py b/policyengine_us/variables/gov/states/ga/tax/income/credits/ctc/ga_ctc_eligible_child.py new file mode 100644 index 00000000000..2017b09d4b3 --- /dev/null +++ b/policyengine_us/variables/gov/states/ga/tax/income/credits/ctc/ga_ctc_eligible_child.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class ga_ctc_eligible_child(Variable): + value_type = bool + entity = Person + label = "Eligible child for the Georgia Child Tax Credit" + definition_period = YEAR + defined_for = StateCode.GA + reference = ( + "https://legiscan.com/GA/text/HB136/id/3204611/Georgia-2025-HB136-Enrolled.pdf#page=3", + "https://www.law.cornell.edu/uscode/text/26/24#c", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ga.tax.income.credits.ctc + age = person("age", period) + # Georgia gives "qualifying child" the meaning of IRC 24(c) only, so + # it is not limited to children for whom the federal credit is + # allowed (IRC 24(a), 152(b)(1)). Whether a filer who can be claimed + # as a dependent can claim it is not settled; this keeps the IRC + # 24(c) child test. + p_federal = parameters(period).gov.irs.credits.ctc + ctc_eligible_child = ( + person("is_tax_unit_dependent", period) + & (age < p_federal.amount.base.thresholds[-1]) + & person("meets_ctc_child_identification_requirements", period) + ) + return ctc_eligible_child & (age < p.age_threshold) diff --git a/policyengine_us/variables/gov/states/ga/tax/income/credits/ctc/ga_ctc_potential.py b/policyengine_us/variables/gov/states/ga/tax/income/credits/ctc/ga_ctc_potential.py index 46ceaac454b..52e40cca462 100644 --- a/policyengine_us/variables/gov/states/ga/tax/income/credits/ctc/ga_ctc_potential.py +++ b/policyengine_us/variables/gov/states/ga/tax/income/credits/ctc/ga_ctc_potential.py @@ -14,10 +14,6 @@ class ga_ctc_potential(Variable): def formula(tax_unit, period, parameters): p = parameters(period).gov.states.ga.tax.income.credits.ctc - person = tax_unit.members - age = person("age", period) - ctc_eligible_child = person("ctc_qualifying_child", period) - ga_child_age_eligible = age < p.age_threshold - eligible_children = tax_unit.sum(ctc_eligible_child & ga_child_age_eligible) + eligible_children = add(tax_unit, period, ["ga_ctc_eligible_child"]) return eligible_children * p.amount diff --git a/policyengine_us/variables/gov/states/ga/tax/income/credits/ga_low_income_credit_potential.py b/policyengine_us/variables/gov/states/ga/tax/income/credits/ga_low_income_credit_potential.py index 4487e9e448a..07708fa354f 100644 --- a/policyengine_us/variables/gov/states/ga/tax/income/credits/ga_low_income_credit_potential.py +++ b/policyengine_us/variables/gov/states/ga/tax/income/credits/ga_low_income_credit_potential.py @@ -15,7 +15,10 @@ def formula(tax_unit, period, parameters): # "multiplied by the number of dependents which the taxpayer is entitled to claim." # The tax form excludes adult dependents: # "Exemptions are self, spouse and natural or legally adopted children" - exemptions = tax_unit("exemptions_count", period) + # Georgia counts its own exemptions (O.C.G.A. 48-7A-3 deems each joint + # spouse a dependent), not the federal count, which leaves out a + # filer who can be claimed as a dependent. + exemptions = tax_unit("tax_unit_size", period) p = parameters(period).gov.states.ga.tax.income.credits.low_income # age threshold age_threshold = p.supplement_age_eligibility diff --git a/policyengine_us/variables/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_credit.py b/policyengine_us/variables/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_credit.py index c4f098d02f1..a1c5b5ff4aa 100644 --- a/policyengine_us/variables/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_credit.py +++ b/policyengine_us/variables/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_credit.py @@ -8,17 +8,22 @@ class hi_food_excise_credit(Variable): defined_for = StateCode.HI unit = USD definition_period = YEAR - reference = "https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=44" + reference = ( + "https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=50", + "https://files.hawaii.gov/tax/forms/2025/n311_i.pdf#page=1", + ) def formula(tax_unit, period, parameters): - # filer can not be a dependent on another return - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) - total_amount = add( - tax_unit, - period, - [ - "hi_food_excise_credit_minor_child_amount", - "hi_food_excise_exemption_amount", - ], + # HRS 235-55.85(a): only a taxpayer who cannot be claimed as a + # dependent may claim the credit, for each qualified exemption; the + # exemption amount excludes own ordinary dependents when either + # filer can be claimed without the Dependent Taxpayer Test exception. + # Minor children receiving public support count for this + # credit under 235-55.85(c), so they keep their amount unless every + # filer can be claimed. + every_filer_dependent = tax_unit("every_filer_is_dependent_elsewhere", period) + exemption_amount = tax_unit("hi_food_excise_exemption_amount", period) + minor_child_amount = tax_unit( + "hi_food_excise_credit_minor_child_amount", period ) - return ~dependent_elsewhere * total_amount + return exemption_amount + where(every_filer_dependent, 0, minor_child_amount) diff --git a/policyengine_us/variables/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_credit_minor_child_count.py b/policyengine_us/variables/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_credit_minor_child_count.py index ba06f9635a3..15cb4a0c8de 100644 --- a/policyengine_us/variables/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_credit_minor_child_count.py +++ b/policyengine_us/variables/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_credit_minor_child_count.py @@ -7,6 +7,10 @@ class hi_food_excise_credit_minor_child_count(Variable): label = "Minor child's number for the Hawaii Food/Excise Tax Credit" definition_period = YEAR defined_for = StateCode.HI + reference = ( + "https://files.hawaii.gov/tax/forms/2022/n311_i.pdf#page=1", + "https://files.hawaii.gov/tax/forms/2025/n311_i.pdf#page=1", + ) def formula(tax_unit, period, parameters): p = parameters(period).gov.states.hi.tax.income.credits.food_excise_tax @@ -16,6 +20,13 @@ def formula(tax_unit, period, parameters): ) is_child = person("is_child", period) minor = person("age", period) < p.minor_child.age_threshold - eligible_minor_child = is_child & minor & public_support_over_half + # Form N-311 line 3 lists minor children who, among other tests, + # "Cannot be claimed as a dependent by another taxpayer"; the filers + # are listed on line 2. + claimable_elsewhere = person("claimable_as_dependent_on_another_return", period) + filer = person("is_tax_unit_head_or_spouse", period) + eligible_minor_child = ( + is_child & minor & public_support_over_half & ~claimable_elsewhere & ~filer + ) return tax_unit.sum(eligible_minor_child) diff --git a/policyengine_us/variables/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_exemption_amount.py b/policyengine_us/variables/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_exemption_amount.py index 1b4e22e61bc..39bbb252a55 100644 --- a/policyengine_us/variables/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_exemption_amount.py +++ b/policyengine_us/variables/gov/states/hi/tax/income/credits/food_excise/hi_food_excise_exemption_amount.py @@ -7,13 +7,18 @@ class hi_food_excise_exemption_amount(Variable): label = "Exemption amount for Hawaii Food/Excise Tax Credit" definition_period = YEAR defined_for = StateCode.HI + reference = ( + "https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=50", + "https://files.hawaii.gov/tax/forms/2022/n311_i.pdf#page=1", + "https://files.hawaii.gov/tax/forms/2025/n311_i.pdf#page=1", + "https://www.irs.gov/pub/irs-prior/p501--2025.pdf#page=11", + ) def formula(tax_unit, period, parameters): p = parameters(period).gov.states.hi.tax.income.credits.food_excise_tax income = tax_unit("adjusted_gross_income", period) - minor_child_include = p.minor_child.in_effect # Count exemptions as number of people # The legal code defines exemptions as Hawaii exemptions, # which normally include additional exemptions for aged and @@ -38,11 +43,47 @@ def formula(tax_unit, period, parameters): p.amount.surviving_spouse.calc(income), ], ) - exemptions = tax_unit("exemptions_count", period) + # Both 2022 and 2025 N-311 lines 2-3 exclude every person who can + # be claimed by another taxpayer, including children. In 2022, + # lines 8-10 price ordinary persons and publicly supported minors + # separately; 2025 lines 8-9 combine the two qualified counts. + # exemptions_count already leaves out a filer who can be claimed, so + # only the dependents who can be claimed elsewhere come off here. + person = tax_unit.members + externally_claimable_dependents = tax_unit.sum( + person("is_tax_unit_dependent", period) + & person("claimable_as_dependent_on_another_return", period) + ) + exemptions = max_( + tax_unit("exemptions_count", period) - externally_claimable_dependents, 0 + ) + minor_children = tax_unit("hi_food_excise_credit_minor_child_count", period) if p.minor_child.in_effect: - # Reduce number of exemptions by the number of minor children - minor_children = tax_unit("hi_food_excise_credit_minor_child_count", period) - claimable_exemptions = exemptions - minor_children + # Reduce number of exemptions by the number of minor children, + # who get a fixed amount instead. + claimable_exemptions = max_(exemptions - minor_children, 0) + minor_child_exemptions = 0 else: claimable_exemptions = exemptions - return claimable_exemptions * amount_per_exemption + minor_child_exemptions = minor_children + # Form N-311 counts only people who cannot be claimed as a dependent + # by another taxpayer. A return on which a filer can be claimed + # generally claims no dependents (IRS Publication 501, Dependent + # Taxpayer Test). Its filing exception restores ordinary dependent + # entries, but never a claimable person's own exemption. Publicly + # supported minors count independently under HRS 235-55.85(c). + dependent_taxpayer = tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + independent_filers = tax_unit( + "head_spouse_count_not_dependent_elsewhere", period + ) + mixed_return_exemptions = independent_filers + where( + independent_filers > 0, minor_child_exemptions, 0 + ) + qualified_exemptions = where( + dependent_taxpayer, mixed_return_exemptions, claimable_exemptions + ) + every_filer_dependent = tax_unit("every_filer_is_dependent_elsewhere", period) + qualified_exemptions = where(every_filer_dependent, 0, qualified_exemptions) + return qualified_exemptions * amount_per_exemption diff --git a/policyengine_us/variables/gov/states/hi/tax/income/credits/hi_act_115_rebate.py b/policyengine_us/variables/gov/states/hi/tax/income/credits/hi_act_115_rebate.py index 8fd79179391..f0c3d84ac13 100644 --- a/policyengine_us/variables/gov/states/hi/tax/income/credits/hi_act_115_rebate.py +++ b/policyengine_us/variables/gov/states/hi/tax/income/credits/hi_act_115_rebate.py @@ -12,6 +12,8 @@ class hi_act_115_rebate(Variable): "https://tax.hawaii.gov/act-115-ref/", "https://data.capitol.hawaii.gov/sessions/session2022/bills/SB514_CD2_.HTM", "https://files.hawaii.gov/tax/news/announce/ann22-03.pdf#page=2", + "https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=45", + "https://www.irs.gov/pub/irs-prior/p501--2025.pdf#page=11", ) def formula(tax_unit, period, parameters): @@ -39,6 +41,21 @@ def formula(tax_unit, period, parameters): # person in the tax unit is one exemption. exemptions = tax_unit("exemptions_count", period) # A person who can be claimed as a dependent by another taxpayer is - # not a qualifying resident taxpayer. - head_is_dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) - return where(head_is_dependent_elsewhere, 0, amount_per_exemption * exemptions) + # not a qualifying resident taxpayer, and each qualifying resident + # taxpayer claims the refund for the exemptions they are entitled to. + # A filer who can be claimed has no exemption (HRS 235-54(a)), and a + # return on which a filer can be claimed generally claims no dependents + # (IRS Publication 501, Dependent Taxpayer Test). Its filing exception + # restores those dependents, but does not restore the claimable + # filer's personal exemption or qualification as a claimant. + dependent_filer = tax_unit("head_or_spouse_is_dependent_elsewhere", period) + independent_filers = tax_unit( + "head_spouse_count_not_dependent_elsewhere", period + ) + # exemptions_count applies these rules: it leaves out a claimable + # filer's own exemption and, unless the filing exception applies, the + # return's dependents. + qualified_exemptions = where( + dependent_filer & (independent_filers == 0), 0, exemptions + ) + return amount_per_exemption * qualified_exemptions diff --git a/policyengine_us/variables/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_low_income_household_renters_tax_credit.py b/policyengine_us/variables/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_low_income_household_renters_tax_credit.py index e0a69bef748..d55ac2607ca 100644 --- a/policyengine_us/variables/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_low_income_household_renters_tax_credit.py +++ b/policyengine_us/variables/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_low_income_household_renters_tax_credit.py @@ -8,18 +8,48 @@ class hi_tax_credit_for_low_income_household_renters(Variable): unit = USD definition_period = YEAR defined_for = "hi_tax_credit_for_low_income_household_renters_eligible" + reference = ( + "https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=48", + "https://files.hawaii.gov/tax/forms/2025/schx_i.pdf#page=1", + "https://www.irs.gov/pub/irs-prior/p501--2025.pdf#page=11", + ) def formula(tax_unit, period, parameters): p = parameters(period).gov.states.hi.tax.income.credits.lihrtc - # Aged extra exemptions - aged_head = (tax_unit("age_head", period) >= p.aged_age_threshold).astype(int) - aged_spouse = (tax_unit("age_spouse", period) >= p.aged_age_threshold).astype( - int + # Schedule X lines 8-10 count only people who cannot be claimed as a + # dependent by another taxpayer, with an extra exemption for each + # such filer aged 65 or over. A return on which a filer can be + # claimed generally claims no dependents (IRS Publication 501, + # Dependent Taxpayer Test). Its filing exception restores the + # return's own dependents, while claimable filers and their age + # additions remain excluded. + aged_head = (tax_unit("age_head", period) >= p.aged_age_threshold) & ~tax_unit( + "head_is_dependent_elsewhere", period ) + aged_spouse = ( + tax_unit("age_spouse", period) >= p.aged_age_threshold + ) & ~tax_unit("spouse_is_dependent_elsewhere", period) + aged_exemptions = aged_head.astype(int) + aged_spouse.astype(int) - aged_exemptions = aged_head + aged_spouse - exemptions = tax_unit("exemptions_count", period) + # exemptions_count applies these rules to the filers and to the + # return's dependents. A dependent who can be claimed by another + # taxpayer is also left out; a return without dependents has none to + # take off. + dependent_taxpayer = tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + person = tax_unit.members + externally_claimable_dependents = tax_unit.sum( + person("is_tax_unit_dependent", period) + & person("claimable_as_dependent_on_another_return", period) + ) + exemptions_count = tax_unit("exemptions_count", period) + exemptions = where( + dependent_taxpayer, + exemptions_count, + max_(exemptions_count - externally_claimable_dependents, 0), + ) total_exemptions = exemptions + aged_exemptions return p.amount * total_exemptions diff --git a/policyengine_us/variables/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_tax_credit_for_low_income_household_renters_eligible.py b/policyengine_us/variables/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_tax_credit_for_low_income_household_renters_eligible.py index 3c99b935916..e25924271ee 100644 --- a/policyengine_us/variables/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_tax_credit_for_low_income_household_renters_eligible.py +++ b/policyengine_us/variables/gov/states/hi/tax/income/credits/hi_low_income_household_renters/hi_tax_credit_for_low_income_household_renters_eligible.py @@ -6,16 +6,26 @@ class hi_tax_credit_for_low_income_household_renters_eligible(Variable): entity = TaxUnit label = "Eligible for the Hawaii low income household renters tax credit" definition_period = YEAR - reference = "https://files.hawaii.gov/tax/legal/har/har_235.pdf#page=105" # §18-235-55.7 (b) + reference = ( + "https://files.hawaii.gov/tax/legal/har/har_235.pdf#page=105", # §18-235-55.7 (b) + "https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=48", + "https://files.hawaii.gov/tax/forms/2025/schx_i.pdf#page=1", + ) defined_for = StateCode.HI def formula(tax_unit, period, parameters): - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) + # HRS 235-55.7(b) allows the credit to each resident taxpayer who + # cannot be claimed as a dependent, and Schedule X stops at line 3 if + # "you" can be claimed. Neither settles a joint return where only one + # spouse can be claimed; since the credit and its exemption count are + # per person, we read them as letting the other spouse claim it, so a + # joint return qualifies unless both spouses can be claimed. + every_filer_dependent = tax_unit("every_filer_is_dependent_elsewhere", period) p = parameters(period).gov.states.hi.tax.income.credits.lihrtc agi = tax_unit("hi_agi", period) rent = add(tax_unit, period, ["rent"]) return ( (rent > p.eligibility.rent_threshold) & (agi < p.eligibility.agi_limit) - & ~dependent_elsewhere + & ~every_filer_dependent ) diff --git a/policyengine_us/variables/gov/states/hi/tax/income/deductions/hi_deductions.py b/policyengine_us/variables/gov/states/hi/tax/income/deductions/hi_deductions.py index a92860b971e..fe50a345a3c 100644 --- a/policyengine_us/variables/gov/states/hi/tax/income/deductions/hi_deductions.py +++ b/policyengine_us/variables/gov/states/hi/tax/income/deductions/hi_deductions.py @@ -7,8 +7,11 @@ class hi_deductions(Variable): label = "Hawaii deductions" unit = USD reference = ( - "https://files.hawaii.gov/tax/forms/2022/n11ins.pdf#page=15", # Itemized Deduction - "https://files.hawaii.gov/tax/forms/2022/n11ins.pdf#page=20", # Standard Deduction + "https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=11", + # PDF pages 15 (itemized deduction), 20 (standard deduction) + "https://files.hawaii.gov/tax/forms/2022/n11ins.pdf#page=15", + # PDF pages 15, 20 + "https://files.hawaii.gov/tax/forms/2025/n11ins.pdf#page=15", ) definition_period = YEAR defined_for = StateCode.HI @@ -25,14 +28,31 @@ def formula(tax_unit, period, parameters): filing_status_eligible = ( total_itemized_deduction > p.threshold.deductions[filing_status] ) - is_dependent_on_another_return = tax_unit("head_is_dependent_elsewhere", period) - standard_cap = min_(tax_unit_earned_income, standard_deduction) - dependent_floor = max_(p.threshold.dependent, standard_cap) + # HRS 235-2.4(a)(3) applies IRC 63(c)(5): the standard deduction of a + # filer who can be claimed as a dependent is the greater of $500 or + # earned income, up to the regular amount. As federally, a joint + # return is limited when either spouse can be claimed. + is_dependent_on_another_return = tax_unit( + "head_or_spouse_is_dependent_elsewhere", period + ) + # Worksheet earned income: wages and self-employment income minus the + # deductible part of self-employment tax (Schedule 1, line 15). + worksheet_earned_income = max_( + tax_unit_earned_income - tax_unit("self_employment_tax_ald", period), 0 + ) + dependent_standard_deduction = min_( + max_(p.threshold.dependent, worksheet_earned_income), standard_deduction + ) + applicable_standard_deduction = where( + is_dependent_on_another_return, + dependent_standard_deduction, + standard_deduction, + ) dependent_eligible = is_dependent_on_another_return & ( - total_itemized_deduction > dependent_floor + total_itemized_deduction > dependent_standard_deduction ) itemized_deductions_eligible = filing_status_eligible | dependent_eligible itemized_deduction = where( itemized_deductions_eligible, total_itemized_deduction, 0 ) - return max_(itemized_deduction, standard_deduction) + return max_(itemized_deduction, applicable_standard_deduction) diff --git a/policyengine_us/variables/gov/states/me/tax/income/credits/fairness/sales_tax_fairness_credit/me_sales_tax_fairness_credit_eligible.py b/policyengine_us/variables/gov/states/me/tax/income/credits/fairness/sales_tax_fairness_credit/me_sales_tax_fairness_credit_eligible.py index c0ea36df12a..cf13c6de8ea 100644 --- a/policyengine_us/variables/gov/states/me/tax/income/credits/fairness/sales_tax_fairness_credit/me_sales_tax_fairness_credit_eligible.py +++ b/policyengine_us/variables/gov/states/me/tax/income/credits/fairness/sales_tax_fairness_credit/me_sales_tax_fairness_credit_eligible.py @@ -6,11 +6,19 @@ class me_sales_tax_fairness_credit_eligible(Variable): entity = TaxUnit label = "Eligible for the Maine sales tax fairness credit" definition_period = YEAR - reference = "https://legislature.maine.gov/statutes/36/title36sec5213-A.html" + reference = ( + "https://legislature.maine.gov/statutes/36/title36sec5213-A.html", + "https://www.maine.gov/revenue/sites/maine.gov.revenue/files/inline-files/25_1040me_sch_ptfc_fillable.pdf#page=3", + ) defined_for = StateCode.ME def formula(tax_unit, period, parameters): - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) + # 36 MRSA 5213-A(6)(C) excludes individuals who may be claimed as a + # dependent on another return, and subsection 2 allows each resident + # individual the base credit for the return's filing status. Neither + # settles a joint return where only one spouse can be claimed; we read + # them as letting the other spouse qualify for the joint credit. + every_filer_dependent = tax_unit("every_filer_is_dependent_elsewhere", period) filing_status = tax_unit("filing_status", period) separate = filing_status == filing_status.possible_values.SEPARATE - return ~dependent_elsewhere & ~separate + return ~every_filer_dependent & ~separate diff --git a/policyengine_us/variables/gov/states/me/tax/income/credits/me_affordability_payment.py b/policyengine_us/variables/gov/states/me/tax/income/credits/me_affordability_payment.py index b488cf00424..7f1a547ff0e 100644 --- a/policyengine_us/variables/gov/states/me/tax/income/credits/me_affordability_payment.py +++ b/policyengine_us/variables/gov/states/me/tax/income/credits/me_affordability_payment.py @@ -14,7 +14,7 @@ class me_affordability_payment(Variable): "payment from a Special Revenue Fund rather than a refundable tax " "credit. PolicyEngine folds the payment into Maine's refundable " "credit aggregation to surface it in tax-unit-level outputs. " - "Sec. T-1, sub-§1(C)(3) excludes individuals claimed as a " + "Sec. T-1, sub-§1(C)(3) excludes individuals who may be claimed as a " "dependent on another taxpayer's return, evaluated per recipient." ) @@ -24,6 +24,6 @@ def formula(tax_unit, period, parameters): is_recipient = person("is_tax_unit_head", period) | person( "is_tax_unit_spouse", period ) - dependent_elsewhere = person("claimed_as_dependent_on_another_return", period) + dependent_elsewhere = person("claimable_as_dependent_on_another_return", period) eligible_recipients = tax_unit.sum(is_recipient & ~dependent_elsewhere) return eligible_recipients * p.amount diff --git a/policyengine_us/variables/gov/states/mi/tax/income/exemptions/mi_exemptions.py b/policyengine_us/variables/gov/states/mi/tax/income/exemptions/mi_exemptions.py index 5974fd46303..7c9874052ea 100644 --- a/policyengine_us/variables/gov/states/mi/tax/income/exemptions/mi_exemptions.py +++ b/policyengine_us/variables/gov/states/mi/tax/income/exemptions/mi_exemptions.py @@ -11,6 +11,8 @@ class mi_exemptions(Variable): reference = ( "https://www.legislature.mi.gov/Laws/MCL?objectName=mcl-206-30", "https://www.legislature.mi.gov/Publications/TaxpayerGuide.pdf", + "https://www.michigan.gov/taxes/-/media/Project/Websites/taxes/Forms/IIT/TY2025/MI-1040-Book.pdf#page=10", + "https://www.irs.gov/pub/irs-prior/p501--2025.pdf#page=11", ) def formula(tax_unit, period, parameters): @@ -31,16 +33,42 @@ def formula(tax_unit, period, parameters): ) disabled_veteran_exemption = disabled_veterans * p.disabled.amount.veteran - # Dependent-on-other-return exemptions - filing_status = tax_unit("filing_status", period) - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) - dependent_exemption = ( - dependent_elsewhere * p.dependent_on_other_return[filing_status] + # MCL 206.30(4): an individual who can be claimed as a dependent on + # another return gets no personal exemption but subtracts $1,500. + # Treasury's instructions do not address a joint return where only + # one spouse can be claimed; since subsection (4) speaks of an + # individual, we apply it to each spouse, so the other keeps their own + # personal exemption (and any stillbirth exemption). A joint return on + # which either spouse can be claimed generally claims no dependents + # (IRS Publication 501, "Dependent Taxpayer Test"). The filing + # exception restores the return's own dependents, while each + # claimable filer keeps the $1,500 allowance. + filers = add(tax_unit, period, ["is_tax_unit_head_or_spouse"]) + independent_filers = tax_unit( + "head_spouse_count_not_dependent_elsewhere", period ) + dependent_filers = filers - independent_filers + stillborn = tax_unit("tax_unit_stillborn_children", period) + independent_filer_exemptions = ( + independent_filers + where(independent_filers > 0, stillborn, 0) + ) * p.personal + dependent_filer_exemptions = dependent_filers * p.dependent_on_other_return + + dependent_taxpayer = tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + own_dependents = max_(tax_unit("tax_unit_size", period) - filers, 0) + dependent_exemptions = where(dependent_taxpayer, 0, own_dependents) * p.personal # Total exemptions return ( - where(dependent_elsewhere, dependent_exemption, personal_exemption) + where( + dependent_filers > 0, + independent_filer_exemptions + + dependent_filer_exemptions + + dependent_exemptions, + personal_exemption, + ) + disabled_exemption + disabled_veteran_exemption ) diff --git a/policyengine_us/variables/gov/states/mn/tax/property/homestead_credit_refund/mn_homestead_credit_refund_household_income.py b/policyengine_us/variables/gov/states/mn/tax/property/homestead_credit_refund/mn_homestead_credit_refund_household_income.py index ef104baa938..416d57eeb7a 100644 --- a/policyengine_us/variables/gov/states/mn/tax/property/homestead_credit_refund/mn_homestead_credit_refund_household_income.py +++ b/policyengine_us/variables/gov/states/mn/tax/property/homestead_credit_refund/mn_homestead_credit_refund_household_income.py @@ -33,7 +33,7 @@ def formula(tax_unit, period, parameters): people = tax_unit.members is_dependent = people("is_tax_unit_dependent", period) | people( - "claimed_as_dependent_on_another_return", period + "claimable_as_dependent_on_another_return", period ) social_security = people("social_security", period) taxable_social_security = people("taxable_social_security", period) diff --git a/policyengine_us/variables/gov/states/mo/tax/income/credits/mo_wftc_eligible.py b/policyengine_us/variables/gov/states/mo/tax/income/credits/mo_wftc_eligible.py index d1b71e8d93e..582fdb3ed2a 100644 --- a/policyengine_us/variables/gov/states/mo/tax/income/credits/mo_wftc_eligible.py +++ b/policyengine_us/variables/gov/states/mo/tax/income/credits/mo_wftc_eligible.py @@ -8,7 +8,8 @@ class mo_wftc_eligible(Variable): definition_period = YEAR reference = ( "https://revisor.mo.gov/main/OneSection.aspx?section=143.177&bid=49978&hl=", - "https://dor.mo.gov/forms/MO-1040%20Instructions_2025.pdf#page=43", + # PDF pages 6, 43 + "https://dor.mo.gov/forms/MO-1040%20Instructions_2025.pdf#page=6", ) defined_for = StateCode.MO @@ -23,10 +24,17 @@ def formula(tax_unit, period, parameters): # married filing separately. filing_status = tax_unit("filing_status", period) separate = filing_status == filing_status.possible_values.SEPARATE - # The 2024 and 2025 Form MO-WFTC checklists also stop filers - # claimed as a dependent on another return; the 2023 form does not. - excluded_dependent = p.dependent_filers_excluded & tax_unit( - "head_is_dependent_elsewhere", period + # The 2024 and 2025 Form MO-WFTC checklists also stop filers with a + # filing status of "claimed as a dependent"; the 2023 form does not. + # A couple filing a joint federal return files Form MO-1040 as + # married filing combined even when a spouse can be claimed (2025 + # MO-1040 instructions, "Filing status"), so the stop never applies + # to a joint return. + joint = filing_status == filing_status.possible_values.JOINT + excluded_dependent = ( + p.dependent_filers_excluded + & ~joint + & tax_unit("head_or_spouse_is_dependent_elsewhere", period) ) # Form MO-WFTC applies Missouri's own investment income limit, # reflecting IRC Section 32(i) as of January 1, 2021 per RSMo diff --git a/policyengine_us/variables/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible.py b/policyengine_us/variables/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible.py index ea1c0e9fd46..3bdf5fa4fed 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible.py @@ -6,13 +6,20 @@ class nm_cdcc_eligible(Variable): entity = TaxUnit label = "Eligible household for the New Mexico dependent child day care credit" definition_period = YEAR - reference = "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503752/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgDsfAEwBKADTJspQhACKiQrgCe0AOSapEQmFwJlqjdt37DIAMp5SAIQ0AlAKIAZZwDUAggDkAws5SpGAARtCk7BISQA" + reference = ( + "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503752/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgDsfAEwBKADTJspQhACKiQrgCe0AOSapEQmFwJlqjdt37DIAMp5SAIQ0AlAKIAZZwDUAggDkAws5SpGAARtCk7BISQA", + "https://realfile.tax.newmexico.gov/2025pit-rc-ins.pdf#page=2", + ) defined_for = StateCode.NM def formula(tax_unit, period, parameters): person = tax_unit.members - # Filer can not be a dependent on another tax return - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) + # Filer can not be a dependent on another tax return, but "If you are + # a dependent with a spouse who was not a dependent of another + # taxpayer, your spouse may still qualify to claim rebates or + # credits" (PIT-RC instructions). So only a return on which every + # filer is a dependent elsewhere is barred. + every_filer_dependent = tax_unit("every_filer_is_dependent_elsewhere", period) p = parameters(period).gov.states.nm.tax.income.credits.cdcc # Filer has to be be gainfully employed to receive credit has_earnings = person("earned_income", period) > 0 @@ -43,7 +50,7 @@ def formula(tax_unit, period, parameters): ) income_eligible = nm_modified_gross_income <= income_limit return ( - ~dependent_elsewhere + ~every_filer_dependent & employment_eligible & ~receives_tanf & income_eligible diff --git a/policyengine_us/variables/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible_child.py b/policyengine_us/variables/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible_child.py index 14d728cf50b..3f34bb8fd28 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible_child.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/credits/cdcc/nm_cdcc_eligible_child.py @@ -14,4 +14,10 @@ def formula(person, period, parameters): age = person("age", period) age_eligible = age < p.age_eligible dependent = person("is_tax_unit_dependent", period) - return age_eligible & dependent + # NMSA 7-2-18.1 counts a dependent as defined in IRC 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. + dependent_filer = person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + return age_eligible & dependent & ~dependent_filer diff --git a/policyengine_us/variables/gov/states/nm/tax/income/credits/eitc/nm_eitc_demographic_eligible.py b/policyengine_us/variables/gov/states/nm/tax/income/credits/eitc/nm_eitc_demographic_eligible.py index 743b732d797..903ac290010 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/credits/eitc/nm_eitc_demographic_eligible.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/credits/eitc/nm_eitc_demographic_eligible.py @@ -12,7 +12,19 @@ def formula(tax_unit, period, parameters): # New Mexico applies the same criteria as the federal EITC, but # changes the minimum age. person = tax_unit.members - has_child = tax_unit("tax_unit_children", period) > 0 + # A qualifying child under IRC 32(c)(3), before the identification + # requirement that New Mexico does not apply: a dependent under 19, a + # student under 24, or permanently and totally disabled. A filer is + # not their own or their spouse's qualifying child. For a child under + # 18 the count of children must also be positive, so a supplied count + # of zero still means no children. + filer = person("is_tax_unit_head_or_spouse", period) + qualifying_child = person("is_eitc_qualifying_child", period) + minor = person("is_child", period) + minor_child = (tax_unit("tax_unit_children", period) > 0) & tax_unit.any( + qualifying_child & minor + ) + has_child = minor_child | tax_unit.any(qualifying_child & ~minor) age = person("age", period) # Relative parameter reference break branching in some states that # modify EITC age limits. @@ -21,4 +33,17 @@ def formula(tax_unit, period, parameters): ) max_age = parameters.gov.irs.credits.eitc.eligibility.age.max(period) meets_age_requirements = (age >= min_age) & (age <= max_age) - return has_child | tax_unit.any(meets_age_requirements) + # NMSA 7-2-18.15 takes the federal credit's eligibility rules apart + # from the age and identification exceptions. As federally (IRC + # 32(c)(1)(A)(ii)(II)), the age test applies to the filers, not to + # dependents. A filer without a qualifying child must not be a + # dependent of another taxpayer (IRC 32(c)(1)(A)(ii)(III)), and on a + # joint return neither spouse may be claimable (Publication 596, + # Rule 12). + dependent_filer = tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + childless_eligible = ( + tax_unit.any(meets_age_requirements & filer) & ~dependent_filer + ) + return has_child | childless_eligible diff --git a/policyengine_us/variables/gov/states/nm/tax/income/credits/nm_ctc.py b/policyengine_us/variables/gov/states/nm/tax/income/credits/nm_ctc.py index 7295a240d3b..df105c86537 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/credits/nm_ctc.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/credits/nm_ctc.py @@ -7,7 +7,10 @@ class nm_ctc(Variable): label = "New Mexico child income tax credit" definition_period = YEAR unit = USD - reference = "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503818/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgAcHYQEoANMmylCEAIqJCuAJ7QA5BskRCYXAiUr1WnXoMgAynlIAhdQCUAogBknANQCCAOQDCTyVIwACNoUnZxcSA" + reference = ( + "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503818/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgAcHYQEoANMmylCEAIqJCuAJ7QA5BskRCYXAiUr1WnXoMgAynlIAhdQCUAogBknANQCCAOQDCTyVIwACNoUnZxcSA", + "https://realfile.tax.newmexico.gov/2025pit-rc-ins.pdf#page=10", + ) defined_for = StateCode.NM def formula(tax_unit, period, parameters): @@ -25,4 +28,9 @@ def formula(tax_unit, period, parameters): filing_status = tax_unit("filing_status", period) separate = filing_status == filing_status.possible_values.SEPARATE denominator = where(separate, 2, 1) - return amount / denominator + # NMSA 7-2-18.34(A) allows the credit to "a taxpayer who is a resident + # and is not a dependent of another individual". On a joint return a + # spouse who is not a dependent may still claim it (PIT-RC: "your + # spouse may still qualify to claim rebates or credits"). + every_filer_dependent = tax_unit("every_filer_is_dependent_elsewhere", period) + return where(every_filer_dependent, 0, amount / denominator) diff --git a/policyengine_us/variables/gov/states/nm/tax/income/credits/nm_medical_expense_credit.py b/policyengine_us/variables/gov/states/nm/tax/income/credits/nm_medical_expense_credit.py index e516884f45e..5857fc5edea 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/credits/nm_medical_expense_credit.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/credits/nm_medical_expense_credit.py @@ -6,7 +6,11 @@ class nm_medical_expense_credit(Variable): entity = TaxUnit label = "New Mexico unreimbursed medical expense care credit" definition_period = YEAR - reference = "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503776/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgDswgGwBKADTJspQhACKiQrgCe0AOSapEQmFwJlqjdt37DIAMp5SAIQ0AlAKIAZZwDUAggDkAws5SpGAARtCk7BISQA" + reference = ( + "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503776/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgDswgGwBKADTJspQhACKiQrgCe0AOSapEQmFwJlqjdt37DIAMp5SAIQ0AlAKIAZZwDUAggDkAws5SpGAARtCk7BISQA", + # PDF pages 2, 9 + "https://realfile.tax.newmexico.gov/2025pit-rc-ins.pdf#page=2", + ) defined_for = StateCode.NM def formula(tax_unit, period, parameters): @@ -15,10 +19,19 @@ def formula(tax_unit, period, parameters): p = pcredits.unreimbursed_medical_care_expense age = person("age", period) medical_expense = tax_unit("itemized_medical_expenses", period) - age_eligible = tax_unit.any(age >= p.age_eligibility) expense_eligible = medical_expense >= p.min_expenses - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) - eligible = age_eligible & expense_eligible & ~dependent_elsewhere + # NMSA 7-2-18.13(A) allows the credit to "a taxpayer ... who is + # sixty-five years of age or older and who is not a dependent of + # another taxpayer", so both tests apply to the same filer: a + # dependent aged 65 or older does not qualify the return (PIT-RC line + # 23: "If you or your spouse are 65 years of age or older"), and on a + # joint return a spouse who is not a dependent may still qualify + # ("If you are a dependent with a spouse who was not a dependent of + # another taxpayer, your spouse may still qualify"). + filer = person("is_tax_unit_head_or_spouse", period) + claimable = person("claimable_as_dependent_on_another_return", period) + qualifying_filer = filer & (age >= p.age_eligibility) & ~claimable + eligible = tax_unit.any(qualifying_filer) & expense_eligible # exemption is halved for married filing separately filing_status = tax_unit("filing_status", period) separate = filing_status == filing_status.possible_values.SEPARATE diff --git a/policyengine_us/variables/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents.py b/policyengine_us/variables/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents.py index 886cc8d6029..6dd59817b74 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents.py @@ -16,7 +16,12 @@ def formula(tax_unit, period, parameters): # The law 7-2-39(D) defines dependents as those from IRC 152. # IRC 152 refers to all dependents. # https://www.law.cornell.edu/uscode/text/26/152 - dependents = tax_unit("tax_unit_dependents", period) + # IRC 152(b)(1): a return on which the filer (or, if joint, either + # spouse) can be claimed as a dependent has no dependents. + dependent_filer = tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + dependents = where(dependent_filer, 0, tax_unit("tax_unit_dependents", period)) # New Mexico reduces the number of claimable dependents by one. countable_dependents = max_(dependents - 1, 0) amount_per_dependent = p.amount[filing_status] diff --git a/policyengine_us/variables/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents_eligible.py b/policyengine_us/variables/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents_eligible.py index d0415b60595..c083077aebd 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents_eligible.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/deductions/certain_dependents/nm_deduction_for_certain_dependents_eligible.py @@ -6,12 +6,21 @@ class nm_deduction_for_certain_dependents_eligible(Variable): entity = TaxUnit label = "Eligibility for New Mexico deduction for certain dependents" definition_period = YEAR - reference = "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503892/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgAcATgBMASgA0ybKUIQAiokK4AntADkW6REJhcCFWs069BoyADKeUgCFNAJQCiAGRcA1AIIA5AMIu0qRgAEbQpOySkkA" + reference = ( + "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503892/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgAcATgBMASgA0ybKUIQAiokK4AntADkW6REJhcCFWs069BoyADKeUgCFNAJQCiAGRcA1AIIA5AMIu0qRgAEbQpOySkkA", + "https://realfile.tax.newmexico.gov/2025pit-rc-ins.pdf#page=2", + ) defined_for = StateCode.NM def formula(tax_unit, period, parameters): - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) + # The deduction uses the same "not a dependent of another individual" + # test as the rebates and credits on Schedule PIT-RC, and the law does + # not settle a joint return where only one spouse is a dependent. We + # apply the PIT-RC instructions' reading, which lets a spouse who is + # not a dependent still qualify, so only a return on which every + # filer is a dependent elsewhere is barred. + every_filer_dependent = tax_unit("every_filer_is_dependent_elsewhere", period) # deduction does not apply if an exemption under IRS 151 is claimed; # IRC 151 refers to the federal personal exemption federal_exemption_amount = tax_unit("exemptions", period) - return ~dependent_elsewhere & (federal_exemption_amount == 0) + return ~every_filer_dependent & (federal_exemption_amount == 0) diff --git a/policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_hundred_year_exemption.py b/policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_hundred_year_exemption.py index 68d8253cc04..a6bc609baf3 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_hundred_year_exemption.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_hundred_year_exemption.py @@ -14,8 +14,15 @@ def formula(tax_unit, period, parameters): age_head = tax_unit("age_head", period) age_spouse = tax_unit("age_spouse", period) p = parameters(period).gov.states.nm.tax.income.exemptions.hundred_year - head_eligible = age_head >= p.age_eligibility - spouse_eligible = age_spouse >= p.age_eligibility + # NMSA 7-2-5.7 exempts an individual 100 or older "who is not a + # dependent of another individual", so each spouse qualifies on their + # own. + head_eligible = (age_head >= p.age_eligibility) & ~tax_unit( + "head_is_dependent_elsewhere", period + ) + spouse_eligible = (age_spouse >= p.age_eligibility) & ~tax_unit( + "spouse_is_dependent_elsewhere", period + ) filing_status = tax_unit("filing_status", period) joint = filing_status == filing_status.possible_values.JOINT # Halve the exemption if only one of head and spouse is eligible of a joint filer. diff --git a/policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_low_and_middle_income_exemption.py b/policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_low_and_middle_income_exemption.py index 98a265dc9e8..c1540e1b65f 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_low_and_middle_income_exemption.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_low_and_middle_income_exemption.py @@ -25,5 +25,8 @@ def formula(tax_unit, period, parameters): exemption_amount = p.max_amount - reduction_amount # Multiply the exemption amount by the number of exemptions + # NMSA 7-2-5.8 multiplies by the number of federal exemptions, which + # leaves out a filer who can be claimed as a dependent and, on such a + # return, the dependents. exemptions_count = tax_unit("exemptions_count", period) return eligible * exemption_amount * exemptions_count diff --git a/policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_medical_expense_exemption.py b/policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_medical_expense_exemption.py index 3b5bed34f4a..dd02d6d3eb8 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_medical_expense_exemption.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/exemptions/nm_medical_expense_exemption.py @@ -6,7 +6,10 @@ class nm_medical_expense_exemption(Variable): entity = TaxUnit label = "New Mexico unreimbursed medical expense care exemption" definition_period = YEAR - reference = "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503680/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgBsADh4BKADTJspQhACKiQrgCe0AOSapEQmFwJlqjdt37DIAMp5SAIQ0AlAKIAZZwDUAggDkAws5SpGAARtCk7BISQA" + reference = ( + "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503680/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgBsADh4BKADTJspQhACKiQrgCe0AOSapEQmFwJlqjdt37DIAMp5SAIQ0AlAKIAZZwDUAggDkAws5SpGAARtCk7BISQA", + "https://klvg4oyd4j.execute-api.us-west-2.amazonaws.com/prod/PublicFiles/34821a9573ca43e7b06dfad20f5183fd/0558a902-6362-47ca-8e3b-7cca3bc69b9d/2025%20PIT%20Packet_Final.pdf#page=50", + ) defined_for = StateCode.NM def formula(tax_unit, period, parameters): @@ -16,7 +19,13 @@ def formula(tax_unit, period, parameters): ).gov.states.nm.tax.income.exemptions.unreimbursed_medical_care_expense age = person("age", period) medical_expense = tax_unit("itemized_medical_expenses", period) - age_eligible = tax_unit.any(age >= p.age_eligibility) + # NMSA 7-2-5.9(A) allows the exemption to "any individual sixty-five + # years of age or older" for expenses paid "for that individual or + # for the individual's spouse or dependent", and PIT-ADJ line 18 asks + # whether "you or your spouse are 65 years of age or older". A + # dependent aged 65 or older does not qualify the return. + filer = person("is_tax_unit_head_or_spouse", period) + age_eligible = tax_unit.any(filer & (age >= p.age_eligibility)) expense_eligible = medical_expense >= p.min_expenses eligible = age_eligible & expense_eligible # Exemption is halved for married filing separately diff --git a/policyengine_us/variables/gov/states/nm/tax/income/rebates/2021_rebate/nm_2021_income_rebate.py b/policyengine_us/variables/gov/states/nm/tax/income/rebates/2021_rebate/nm_2021_income_rebate.py index 1f37e1c7c21..0dab3d96509 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/rebates/2021_rebate/nm_2021_income_rebate.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/rebates/2021_rebate/nm_2021_income_rebate.py @@ -6,15 +6,27 @@ class nm_2021_income_rebate(Variable): entity = TaxUnit label = "New Mexico 2021 income tax rebate" definition_period = YEAR - reference = "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503708/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgDsPABwBKADTJspQhACKiQrgCe0AOSapEQmFwJlqjdt37DIAMp5SAIQ0AlAKIAZZwDUAggDkAws5SpGAARtCk7BISQA" + reference = ( + "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503708/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgDsPABwBKADTJspQhACKiQrgCe0AOSapEQmFwJlqjdt37DIAMp5SAIQ0AlAKIAZZwDUAggDkAws5SpGAARtCk7BISQA", + # PDF pages 2-3 + "https://realfile.tax.newmexico.gov/2021pit-rc-ins.pdf#page=2", + ) defined_for = StateCode.NM def formula(tax_unit, period, parameters): - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) + # The rebate goes to "a resident ... who is not a dependent of another + # individual", and the law does not settle a joint return where only + # one spouse is. For the same phrase on its rebate and credit schedule, + # TRD says "If you are a dependent with a spouse who was not a + # dependent of another taxpayer, your spouse may still qualify to + # claim rebates or credits" (PIT-RC instructions); we apply that + # reading, so only a return on which every filer is a dependent + # elsewhere is barred. + every_filer_dependent = tax_unit("every_filer_is_dependent_elsewhere", period) agi = tax_unit("adjusted_gross_income", period) filing_status = tax_unit("filing_status", period) p = parameters(period).gov.states.nm.tax.income.rebates["2021_income"] income_eligible = agi < p.main.income_limit[filing_status] - eligible = income_eligible & ~dependent_elsewhere + eligible = income_eligible & ~every_filer_dependent amount_if_eligible = p.main.amount[filing_status] return eligible * amount_if_eligible diff --git a/policyengine_us/variables/gov/states/nm/tax/income/rebates/2021_rebate/nm_additional_2021_income_rebate.py b/policyengine_us/variables/gov/states/nm/tax/income/rebates/2021_rebate/nm_additional_2021_income_rebate.py index 891ce07d54e..78493990ef0 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/rebates/2021_rebate/nm_additional_2021_income_rebate.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/rebates/2021_rebate/nm_additional_2021_income_rebate.py @@ -6,11 +6,23 @@ class nm_additional_2021_income_rebate(Variable): entity = TaxUnit label = "New Mexico additional 2021 income tax rebate" definition_period = YEAR - reference = "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503710/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgDsHHgEoANMmylCEAIqJCuAJ7QA5BskRCYXAiUr1WnXoMgAynlIAhdQCUAogBknANQCCAOQDCTyVIwACNoUnZxcSA" + reference = ( + "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503710/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgDsHHgEoANMmylCEAIqJCuAJ7QA5BskRCYXAiUr1WnXoMgAynlIAhdQCUAogBknANQCCAOQDCTyVIwACNoUnZxcSA", + # PDF pages 2-3 + "https://realfile.tax.newmexico.gov/2021pit-rc-ins.pdf#page=2", + ) defined_for = StateCode.NM def formula(tax_unit, period, parameters): - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) + # The rebate goes to "a resident ... who is not a dependent of another + # individual", and the law does not settle a joint return where only + # one spouse is. For the same phrase on its rebate and credit schedule, + # TRD says "If you are a dependent with a spouse who was not a + # dependent of another taxpayer, your spouse may still qualify to + # claim rebates or credits" (PIT-RC instructions); we apply that + # reading, so only a return on which every filer is a dependent + # elsewhere is barred. + every_filer_dependent = tax_unit("every_filer_is_dependent_elsewhere", period) p = parameters(period).gov.states.nm.tax.income.rebates["2021_income"] filing_status = tax_unit("filing_status", period) - return ~dependent_elsewhere * p.additional.amount[filing_status] + return ~every_filer_dependent * p.additional.amount[filing_status] diff --git a/policyengine_us/variables/gov/states/nm/tax/income/rebates/2021_rebate/nm_supplemental_2021_income_rebate.py b/policyengine_us/variables/gov/states/nm/tax/income/rebates/2021_rebate/nm_supplemental_2021_income_rebate.py index 7839b75873d..cd82e30a49b 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/rebates/2021_rebate/nm_supplemental_2021_income_rebate.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/rebates/2021_rebate/nm_supplemental_2021_income_rebate.py @@ -6,11 +6,23 @@ class nm_supplemental_2021_income_rebate(Variable): entity = TaxUnit label = "New Mexico supplemental 2021 income tax rebate" definition_period = YEAR - reference = "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503706/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgDsPAGwBKADTJspQhACKiQrgCe0AOSapEQmFwJlqjdt37DIAMp5SAIQ0AlAKIAZZwDUAggDkAws5SpGAARtCk7BISQA" + reference = ( + "https://nmonesource.com/nmos/nmsa/en/item/4340/index.do#!fragment/zoupio-_Toc140503706/BQCwhgziBcwMYgK4DsDWszIQewE4BUBTADwBdoAvbRABwEtsBaAfX2zgEYAWABgFYeAZgDsPAGwBKADTJspQhACKiQrgCe0AOSapEQmFwJlqjdt37DIAMp5SAIQ0AlAKIAZZwDUAggDkAws5SpGAARtCk7BISQA", + # PDF pages 2-3 + "https://realfile.tax.newmexico.gov/2021pit-rc-ins.pdf#page=2", + ) defined_for = StateCode.NM def formula(tax_unit, period, parameters): - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) + # The rebate goes to "a resident ... who is not a dependent of another + # individual", and the law does not settle a joint return where only + # one spouse is. For the same phrase on its rebate and credit schedule, + # TRD says "If you are a dependent with a spouse who was not a + # dependent of another taxpayer, your spouse may still qualify to + # claim rebates or credits" (PIT-RC instructions); we apply that + # reading, so only a return on which every filer is a dependent + # elsewhere is barred. + every_filer_dependent = tax_unit("every_filer_is_dependent_elsewhere", period) p = parameters(period).gov.states.nm.tax.income.rebates["2021_income"] filing_status = tax_unit("filing_status", period) - return ~dependent_elsewhere * p.supplemental.amount[filing_status] + return ~every_filer_dependent * p.supplemental.amount[filing_status] diff --git a/policyengine_us/variables/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate.py b/policyengine_us/variables/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate.py index 1fbb3a4d6b7..33bf6d2e2a3 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate.py @@ -49,4 +49,10 @@ def formula(tax_unit, period, parameters): p.divisor, 1, ) - return rebate / divisor + # NMSA 7-2-14(A) allows the rebate only to a resident "who is not a + # dependent of another individual"; on a joint return the spouse who + # is not may still claim it (PIT-RC). The table starts at one + # exemption. + every_filer_dependent = tax_unit("every_filer_is_dependent_elsewhere", period) + eligible = ~every_filer_dependent & (exemptions > 0) + return where(eligible, rebate / divisor, 0) diff --git a/policyengine_us/variables/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate_exemptions.py b/policyengine_us/variables/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate_exemptions.py index cd8f89ad180..05621600269 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate_exemptions.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/rebates/low_income_comprehensive/nm_low_income_comprehensive_tax_rebate_exemptions.py @@ -9,6 +9,7 @@ class nm_low_income_comprehensive_tax_rebate_exemptions(Variable): definition_period = YEAR reference = ( "https://law.justia.com/codes/new-mexico/chapter-7/article-2/section-7-2-14/", + "https://realfile.tax.newmexico.gov/2025pit-rc-ins.pdf#page=3", ) defined_for = StateCode.NM @@ -21,6 +22,11 @@ def formula(tax_unit, period, parameters): tax purposes for each individual included in the return who is domiciled in New Mexico... """ + # The federal count leaves out a filer who can be claimed as a + # dependent and, on such a return, the dependents, as PIT-RC line 2a + # does: "If either you or your spouse meet the general + # qualifications, but not both, then the non-qualifying spouse is not + # eligible". federal_exemptions = tax_unit("exemptions_count", period) """ ...plus two additional exemptions for each individual domiciled diff --git a/policyengine_us/variables/gov/states/nm/tax/income/rebates/property_tax_rebate/nm_property_tax_rebate_eligible.py b/policyengine_us/variables/gov/states/nm/tax/income/rebates/property_tax_rebate/nm_property_tax_rebate_eligible.py index 5a84b11372c..973bfcec8fc 100644 --- a/policyengine_us/variables/gov/states/nm/tax/income/rebates/property_tax_rebate/nm_property_tax_rebate_eligible.py +++ b/policyengine_us/variables/gov/states/nm/tax/income/rebates/property_tax_rebate/nm_property_tax_rebate_eligible.py @@ -6,17 +6,23 @@ class nm_property_tax_rebate_eligible(Variable): entity = TaxUnit label = "Eligible for the New Mexico property tax rebate" definition_period = YEAR - reference = "https://klvg4oyd4j.execute-api.us-west-2.amazonaws.com/prod/PublicFiles/34821a9573ca43e7b06dfad20f5183fd/1afc56af-ea90-4d48-82e5-1f9aeb43255a/PITbook2022.pdf" + reference = "https://klvg4oyd4j.execute-api.us-west-2.amazonaws.com/prod/PublicFiles/34821a9573ca43e7b06dfad20f5183fd/1afc56af-ea90-4d48-82e5-1f9aeb43255a/PITbook2022.pdf#page=70" defined_for = StateCode.NM def formula(tax_unit, period, parameters): p = parameters(period).gov.states.nm.tax.income.rebates.property_tax - # Head or spouse eligible if 65 or over. + # NMSA 7-2-18 allows the rebate to a resident 65 or over "who is not + # a dependent of another individual", so the same filer must meet + # both tests; on a joint return either spouse may. age_head = tax_unit("age_head", period) age_spouse = tax_unit("age_spouse", period) - head_age_eligible = age_head >= p.age_eligibility - spouse_age_eligible = age_spouse >= p.age_eligibility - age_eligible = head_age_eligible | spouse_age_eligible + head_eligible = (age_head >= p.age_eligibility) & ~tax_unit( + "head_is_dependent_elsewhere", period + ) + spouse_eligible = (age_spouse >= p.age_eligibility) & ~tax_unit( + "spouse_is_dependent_elsewhere", period + ) + age_eligible = head_eligible | spouse_eligible # Person eligible if income at or below $16,000 agi = tax_unit("nm_modified_gross_income", period) agi_eligible = agi <= p.income_threshold diff --git a/policyengine_us/variables/gov/states/ny/tax/income/taxable_income/deductions/ny_standard_deduction.py b/policyengine_us/variables/gov/states/ny/tax/income/taxable_income/deductions/ny_standard_deduction.py index d98250ebddb..1720bb49cd2 100644 --- a/policyengine_us/variables/gov/states/ny/tax/income/taxable_income/deductions/ny_standard_deduction.py +++ b/policyengine_us/variables/gov/states/ny/tax/income/taxable_income/deductions/ny_standard_deduction.py @@ -7,17 +7,21 @@ class ny_standard_deduction(Variable): label = "NY standard deduction" unit = USD definition_period = YEAR - reference = "https://www.nysenate.gov/legislation/laws/TAX/613" + reference = ( + "https://www.nysenate.gov/legislation/laws/TAX/614", + # Standard deduction table: the dependent amount applies only to + # filing status 1, "Single and you marked item C Yes". + "https://www.tax.ny.gov/pdf/2025/inc/it201i_2025.pdf#page=11", + ) defined_for = StateCode.NY def formula(tax_unit, period, parameters): - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) - standard_deduction = parameters( - period - ).gov.states.ny.tax.income.deductions.standard + p = parameters(period).gov.states.ny.tax.income.deductions.standard filing_status = tax_unit("filing_status", period) + single = filing_status == filing_status.possible_values.SINGLE + dependent_elsewhere = tax_unit("head_or_spouse_is_dependent_elsewhere", period) return where( - dependent_elsewhere, - standard_deduction.dependent_elsewhere, - standard_deduction.amount[filing_status], + single & dependent_elsewhere, + p.dependent_elsewhere, + p.amount[filing_status], ) diff --git a/policyengine_us/variables/gov/states/oh/tax/income/exemptions/oh_personal_exemptions_eligible_person.py b/policyengine_us/variables/gov/states/oh/tax/income/exemptions/oh_personal_exemptions_eligible_person.py index e222b7bf362..813a61fd698 100644 --- a/policyengine_us/variables/gov/states/oh/tax/income/exemptions/oh_personal_exemptions_eligible_person.py +++ b/policyengine_us/variables/gov/states/oh/tax/income/exemptions/oh_personal_exemptions_eligible_person.py @@ -16,8 +16,13 @@ def formula(person, period, parameters): # if they are not claimed as a dependent elsewhere head_or_spouse = person("is_tax_unit_head_or_spouse", period) dependent_on_another_return = person( - "claimed_as_dependent_on_another_return", period + "claimable_as_dependent_on_another_return", period ) - # The personal exemption is also provided to dependents - dependent = person("is_tax_unit_dependent", period) + # The personal exemption is also provided to dependents, but a return + # on which the filer (or, if joint, either spouse) can be claimed as a + # dependent has none (IRC 152(b)(1)). + dependent_filer = person.tax_unit( + "head_or_spouse_is_dependent_elsewhere_without_filing_exception", period + ) + dependent = person("is_tax_unit_dependent", period) & ~dependent_filer return (~dependent_on_another_return & head_or_spouse) | dependent diff --git a/policyengine_us/variables/gov/states/or/tax/income/deductions/or_standard_deduction.py b/policyengine_us/variables/gov/states/or/tax/income/deductions/or_standard_deduction.py index 6d8dde3554d..54d2dc18fbc 100644 --- a/policyengine_us/variables/gov/states/or/tax/income/deductions/or_standard_deduction.py +++ b/policyengine_us/variables/gov/states/or/tax/income/deductions/or_standard_deduction.py @@ -8,9 +8,10 @@ class or_standard_deduction(Variable): unit = USD definition_period = YEAR documentation = "Oregon standard deduction, including bonus for aged or blind and special rules for filers who are claimable as dependents." - reference = ( # TODO: update + reference = ( "https://www.oregon.gov/dor/forms/FormsPubs/form-or-40-inst_101-040-1_2021.pdf#page=18", - "https://www.oregonlegislature.gov/bills_laws/ors/ors316.html", # Subsection 316.695 (7) + "https://www.oregonlegislature.gov/bills_laws/ors/ors316.html", # ORS 316.695(7)-(8) + "https://www.oregon.gov/dor/forms/FormsPubs/publication-or-17_101-431_2025.pdf#page=96", ) defined_for = StateCode.OR @@ -19,13 +20,23 @@ def formula(tax_unit, period, parameters): # Core deduction based on filing status. filing_status = tax_unit("filing_status", period) initial_core_deduction = p.amount[filing_status] - # Replace if claimable as a dependent. - earned_income = tax_unit("tax_unit_earned_income", period) + # Replace if claimable as a dependent. Earned income is figured as in + # the federal worksheet, net of the deductible part of self-employment + # tax (Schedule 1, line 15). + earned_income = max_( + tax_unit("tax_unit_earned_income", period) + - tax_unit("self_employment_tax_ald", period), + 0, + ) claimable_dep_floor = p.claimable_as_dependent.min claimable_dep_earned_amount = ( earned_income + p.claimable_as_dependent.earned_income_addition ) - dependent_elsewhere = tax_unit("head_is_dependent_elsewhere", period) + # ORS 316.695(8) limits the deduction as IRC 63(c)(5) does, so a joint + # return uses the couple's earned income and the joint amount when + # either spouse can be claimed (Publication OR-17, "Standard deduction + # worksheet for married filing jointly (MFJ) dependents"). + dependent_elsewhere = tax_unit("head_or_spouse_is_dependent_elsewhere", period) # Set floor and ceiling around earned income plus additional amount. floored_claimable_dep_amount = max_( claimable_dep_earned_amount, claimable_dep_floor diff --git a/policyengine_us/variables/gov/states/ut/tax/property/homeowner_renter_relief/ut_homeowner_renter_relief_pre_one_claimant_eligible.py b/policyengine_us/variables/gov/states/ut/tax/property/homeowner_renter_relief/ut_homeowner_renter_relief_pre_one_claimant_eligible.py index 28c3dbbdf03..146db78e423 100644 --- a/policyengine_us/variables/gov/states/ut/tax/property/homeowner_renter_relief/ut_homeowner_renter_relief_pre_one_claimant_eligible.py +++ b/policyengine_us/variables/gov/states/ut/tax/property/homeowner_renter_relief/ut_homeowner_renter_relief_pre_one_claimant_eligible.py @@ -36,9 +36,12 @@ def formula(tax_unit, period, parameters): claimant_is_tax_unit_dependent = tax_unit.any( claimants & tax_unit.members("is_tax_unit_dependent", period) ) - claimant_is_dependent_elsewhere = tax_unit( - "head_is_dependent_elsewhere", period - ) | tax_unit("spouse_is_dependent_elsewhere", period) + # Utah Code 59-2a-205(4) and 59-2a-305(2)(a) turn on another + # taxpayer actually claiming the exemption or dependent credit. + claimant_is_dependent_elsewhere = tax_unit.any( + claimants + & tax_unit.members("claimed_as_dependent_on_another_return", period) + ) claimant_is_dependent = ( claimant_is_tax_unit_dependent | claimant_is_dependent_elsewhere ) diff --git a/policyengine_us/variables/gov/states/va/tax/income/credits/low_income_credit/va_low_income_tax_credit_eligible.py b/policyengine_us/variables/gov/states/va/tax/income/credits/low_income_credit/va_low_income_tax_credit_eligible.py index 82b96fe10d0..58934026c25 100644 --- a/policyengine_us/variables/gov/states/va/tax/income/credits/low_income_credit/va_low_income_tax_credit_eligible.py +++ b/policyengine_us/variables/gov/states/va/tax/income/credits/low_income_credit/va_low_income_tax_credit_eligible.py @@ -7,16 +7,24 @@ class va_low_income_tax_credit_eligible(Variable): label = "Eligible for the Virginia Low Income Tax Credit" definition_period = YEAR defined_for = StateCode.VA + reference = ( + "https://law.lis.virginia.gov/vacode/title58.1/chapter3/section58.1-339.8/", + "https://www.tax.virginia.gov/sites/default/files/vatax-pdf/2025-760-instructions.pdf#page=30", + ) def formula(tax_unit, period, parameters): # Criteria 1: Not qualified to claim EITC if anyone in the tax unit claimed any of the following: p = parameters(period).gov.states.va.tax.income.credits.eitc.low_income_tax program_eligible = add(tax_unit, period, p.ineligible_programs) == 0 - # Criteria 2: Not qualified to claim EITC if the filier is claimed as a dependent on another taxpayer's return - - head_is_not_dependent_elsewhere = ~tax_unit( - "head_is_dependent_elsewhere", period + # Criteria 2: Not qualified if a filer is claimed as a dependent on + # another taxpayer's return. Neither Va. Code 58.1-339.8 nor the + # instructions settle a joint return where only one spouse is + # claimed. We read the statute's bar on the credit "against such tax + # of a dependent" as reaching a joint return, which carries both + # spouses' tax, so either spouse being claimed bars it. + filer_is_dependent_elsewhere = tax_unit( + "head_or_spouse_is_dependent_elsewhere", period ) - return program_eligible & head_is_not_dependent_elsewhere + return program_eligible & ~filer_is_dependent_elsewhere diff --git a/policyengine_us/variables/household/demographic/person/claimable_as_dependent_on_another_return.py b/policyengine_us/variables/household/demographic/person/claimable_as_dependent_on_another_return.py new file mode 100644 index 00000000000..5643c2eb30d --- /dev/null +++ b/policyengine_us/variables/household/demographic/person/claimable_as_dependent_on_another_return.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class claimable_as_dependent_on_another_return(Variable): + value_type = bool + entity = Person + definition_period = YEAR + label = "Can be claimed as a dependent elsewhere" + documentation = ( + "Whether another taxpayer, in another tax unit, can claim the person " + "as a dependent: a " + "deduction under IRC section 151 for the person is allowable to " + "another taxpayer, whether or not claimed. Defaults to the actual " + "or expected claim input for compatibility with existing callers. " + "The dependent_claimant_filing_exception does not change this fact " + "or the dependent standard-deduction limit." + ) + reference = ( + "https://www.law.cornell.edu/uscode/text/26/151#c", + "https://www.irs.gov/pub/irs-prior/p501--2025.pdf#page=24", + ) + + def formula(person, period, parameters): + return person("claimed_as_dependent_on_another_return", period) diff --git a/policyengine_us/variables/household/demographic/person/claimed_as_dependent_on_another_return.py b/policyengine_us/variables/household/demographic/person/claimed_as_dependent_on_another_return.py index a62ae0c4703..cfaa9d32825 100644 --- a/policyengine_us/variables/household/demographic/person/claimed_as_dependent_on_another_return.py +++ b/policyengine_us/variables/household/demographic/person/claimed_as_dependent_on_another_return.py @@ -6,4 +6,9 @@ class claimed_as_dependent_on_another_return(Variable): entity = Person definition_period = YEAR label = "Is claimed as a dependent elsewhere" - documentation = "Whether the person is claimed as a dependent in another tax unit." + documentation = ( + "Whether the person is actually claimed, or expected to be claimed, " + "as a dependent in another tax unit. Claimability, whether or not " + "another taxpayer claims the person, is represented separately by " + "claimable_as_dependent_on_another_return." + ) diff --git a/policyengine_us/variables/household/demographic/person/dependent_claimant_filing_exception.py b/policyengine_us/variables/household/demographic/person/dependent_claimant_filing_exception.py new file mode 100644 index 00000000000..d4acf034fba --- /dev/null +++ b/policyengine_us/variables/household/demographic/person/dependent_claimant_filing_exception.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class dependent_claimant_filing_exception(Variable): + value_type = bool + entity = Person + definition_period = YEAR + label = "Dependent's would-be claimant meets the filing exception" + documentation = ( + "Whether the person who could claim this person (all such claimants " + "if more than one) is not required to file an income tax return and " + "either files no return or files solely to obtain a refund of income " + "tax withheld or estimated tax paid. A return filed to claim refundable " + "tax credits, including EITC, does not qualify. This fact permits EITC and claiming " + "one's own dependents under the Dependent Taxpayer Test; it does not " + "remove general claimability or its standard-deduction limitation." + ) + reference = ( + "https://www.irs.gov/pub/irs-prior/p596--2025.pdf#page=18", + "https://www.irs.gov/pub/irs-prior/p501--2025.pdf#page=11", + ) diff --git a/policyengine_us/variables/household/demographic/person/is_dependent_elsewhere_without_filing_exception.py b/policyengine_us/variables/household/demographic/person/is_dependent_elsewhere_without_filing_exception.py new file mode 100644 index 00000000000..79384c81b5e --- /dev/null +++ b/policyengine_us/variables/household/demographic/person/is_dependent_elsewhere_without_filing_exception.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class is_dependent_elsewhere_without_filing_exception(Variable): + value_type = bool + entity = Person + definition_period = YEAR + label = "Claimable elsewhere without the claimant filing exception" + documentation = ( + "Whether the person is claimable as a dependent on another return " + "and the would-be claimant does not meet the nonrequired-filing " + "exception. Used for childless EITC and the Dependent Taxpayer Test." + ) + reference = ( + "https://www.irs.gov/pub/irs-prior/p596--2025.pdf#page=18", + "https://www.irs.gov/pub/irs-prior/p501--2025.pdf#page=11", + ) + + def formula(person, period, parameters): + return person("claimable_as_dependent_on_another_return", period) & ~person( + "dependent_claimant_filing_exception", period + ) diff --git a/policyengine_us/variables/household/demographic/tax_unit/every_filer_is_dependent_elsewhere.py b/policyengine_us/variables/household/demographic/tax_unit/every_filer_is_dependent_elsewhere.py new file mode 100644 index 00000000000..e2135a89019 --- /dev/null +++ b/policyengine_us/variables/household/demographic/tax_unit/every_filer_is_dependent_elsewhere.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class every_filer_is_dependent_elsewhere(Variable): + value_type = bool + entity = TaxUnit + definition_period = YEAR + label = "Every head and spouse is claimable elsewhere" + documentation = ( + "Whether the tax unit has a head or spouse claimable as a dependent in " + "another tax unit and none who is not. False for a tax unit with " + "neither a head nor a spouse." + ) + + def formula(tax_unit, period, parameters): + return tax_unit("head_or_spouse_is_dependent_elsewhere", period) & ( + tax_unit("head_spouse_count_not_dependent_elsewhere", period) == 0 + ) diff --git a/policyengine_us/variables/household/demographic/tax_unit/head_is_dependent_elsewhere.py b/policyengine_us/variables/household/demographic/tax_unit/head_is_dependent_elsewhere.py index 04064b39948..b8d43c53e5e 100644 --- a/policyengine_us/variables/household/demographic/tax_unit/head_is_dependent_elsewhere.py +++ b/policyengine_us/variables/household/demographic/tax_unit/head_is_dependent_elsewhere.py @@ -6,12 +6,12 @@ class head_is_dependent_elsewhere(Variable): entity = TaxUnit definition_period = YEAR label = "Is tax-unit head a dependent elsewhere" - documentation = "Whether the filer for this tax unit is claimed as a dependent in another tax unit." + documentation = "Whether the filer for this tax unit is claimable as a dependent in another tax unit." def formula(tax_unit, period, parameters): person = tax_unit.members - claimed_on_another_return = person( - "claimed_as_dependent_on_another_return", period + claimable_on_another_return = person( + "claimable_as_dependent_on_another_return", period ) is_head = person("is_tax_unit_head", period) - return tax_unit.any(claimed_on_another_return & is_head) + return tax_unit.any(claimable_on_another_return & is_head) diff --git a/policyengine_us/variables/household/demographic/tax_unit/head_or_spouse_is_dependent_elsewhere.py b/policyengine_us/variables/household/demographic/tax_unit/head_or_spouse_is_dependent_elsewhere.py new file mode 100644 index 00000000000..34f5593350b --- /dev/null +++ b/policyengine_us/variables/household/demographic/tax_unit/head_or_spouse_is_dependent_elsewhere.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class head_or_spouse_is_dependent_elsewhere(Variable): + value_type = bool + entity = TaxUnit + definition_period = YEAR + label = "Head or spouse is claimable elsewhere" + documentation = ( + "Whether the head or the spouse of this tax unit is claimable as a " + "dependent in another tax unit. Unlike head_is_dependent_elsewhere, " + "this does not depend on which spouse is labelled head." + ) + + def formula(tax_unit, period, parameters): + person = tax_unit.members + claimable_on_another_return = person( + "claimable_as_dependent_on_another_return", period + ) + filer = person("is_tax_unit_head_or_spouse", period) + return tax_unit.any(claimable_on_another_return & filer) diff --git a/policyengine_us/variables/household/demographic/tax_unit/head_or_spouse_is_dependent_elsewhere_without_filing_exception.py b/policyengine_us/variables/household/demographic/tax_unit/head_or_spouse_is_dependent_elsewhere_without_filing_exception.py new file mode 100644 index 00000000000..26a1d3d3eb4 --- /dev/null +++ b/policyengine_us/variables/household/demographic/tax_unit/head_or_spouse_is_dependent_elsewhere_without_filing_exception.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class head_or_spouse_is_dependent_elsewhere_without_filing_exception(Variable): + value_type = bool + entity = TaxUnit + definition_period = YEAR + label = "Either filer claimable elsewhere without the claimant filing exception" + documentation = ( + "Whether a tax-unit head or spouse is claimable on another return " + "without the claimant filing exception. Symmetric Dependent Taxpayer " + "Test gate; other claimability rules use the ordinary helper." + ) + reference = ( + "https://www.irs.gov/pub/irs-prior/p596--2025.pdf#page=18", + "https://www.irs.gov/pub/irs-prior/p501--2025.pdf#page=11", + ) + + def formula(tax_unit, period, parameters): + person = tax_unit.members + dependent = person("is_dependent_elsewhere_without_filing_exception", period) + filer = person("is_tax_unit_head_or_spouse", period) + return tax_unit.any(dependent & filer) diff --git a/policyengine_us/variables/household/demographic/tax_unit/head_spouse_count_not_dependent_elsewhere.py b/policyengine_us/variables/household/demographic/tax_unit/head_spouse_count_not_dependent_elsewhere.py new file mode 100644 index 00000000000..3d040cf683d --- /dev/null +++ b/policyengine_us/variables/household/demographic/tax_unit/head_spouse_count_not_dependent_elsewhere.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class head_spouse_count_not_dependent_elsewhere(Variable): + value_type = int + entity = TaxUnit + definition_period = YEAR + label = "Head and spouse count not dependent elsewhere" + documentation = ( + "Number of tax unit heads and spouses who are not claimable as a " + "dependent in another tax unit." + ) + + def formula(tax_unit, period, parameters): + person = tax_unit.members + claimable_on_another_return = person( + "claimable_as_dependent_on_another_return", period + ) + filer = person("is_tax_unit_head_or_spouse", period) + return tax_unit.sum(filer & ~claimable_on_another_return) diff --git a/policyengine_us/variables/household/demographic/tax_unit/spouse_is_dependent_elsewhere.py b/policyengine_us/variables/household/demographic/tax_unit/spouse_is_dependent_elsewhere.py index b8fb0bc9c5f..a8e0183e464 100644 --- a/policyengine_us/variables/household/demographic/tax_unit/spouse_is_dependent_elsewhere.py +++ b/policyengine_us/variables/household/demographic/tax_unit/spouse_is_dependent_elsewhere.py @@ -6,12 +6,12 @@ class spouse_is_dependent_elsewhere(Variable): entity = TaxUnit definition_period = YEAR label = "Tax-unit spouse is dependent elsewhere" - documentation = "Whether the spouse of the filer for this tax unit is claimed as a dependent in another tax unit." + documentation = "Whether the spouse of the filer for this tax unit is claimable as a dependent in another tax unit." def formula(tax_unit, period, parameters): person = tax_unit.members - claimed_on_another_return = person( - "claimed_as_dependent_on_another_return", period + claimable_on_another_return = person( + "claimable_as_dependent_on_another_return", period ) is_spouse = person("is_tax_unit_spouse", period) - return tax_unit.any(claimed_on_another_return & is_spouse) + return tax_unit.any(claimable_on_another_return & is_spouse)