Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/codex-issue-7897-taxsim-umbrella-vars.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improved legacy state credit umbrella compatibility for TAXSIM by splitting Oklahoma and Minnesota combined credits into explicit component variables and adding regression coverage.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ values:
- la_refundable_cdcc # Louisiana
- ma_dependent_care_credit # Massachusetts
- md_cdcc # Maryland
- md_refundable_cdcc # Maryland (refundable component)
- me_child_care_credit # Maine
- mn_cdcc # Minnesota
- ms_cdcc # Mississippi
Expand All @@ -26,14 +27,15 @@ values:
- nm_cdcc # New Mexico
- ny_cdcc # New York
- oh_cdcc # Ohio
- ok_child_care_child_tax_credit # Oklahoma Child Care/Child Tax Credit - note, also in state_ctcs.
- ok_child_care_credit_component # Oklahoma Child Care Credit component
- or_working_family_household_and_dependent_care_credit # Oregon
- pa_cdcc # Pennsylvania
- ri_cdcc # Rhode Island
- sc_cdcc # South Carolina
- vt_cdcc # Vermont
- vt_low_income_cdcc # Vermont low-income CDCC
- wi_childcare_expense_credit # Wisconsin
- wv_cdcc # West Virginia

metadata:
unit: list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ values:
- ma_child_and_family_credit_or_dependent_care_credit # Massachusetts Child and Family Tax Credit
- md_ctc # Maryland Child Tax Credit
- me_dependent_exemption_credit # Maine Dependent Exemption Credit
- mn_child_and_working_families_credits # Minnesota Child and Working Family Credits
- mn_child_tax_credit_component # Minnesota Child Tax Credit component
- nc_ctc # North Carolina Child Tax Credit
- ne_refundable_ctc # Nebraska Refundable Child Tax Credit
- nj_ctc # New Jersey Child Tax Credit
- nm_ctc # New Mexico Child Tax Credit
- ny_ctc # New York Child Tax Credit (Empire State Child Credit)
- ok_child_care_child_tax_credit # Oklahoma Child Care/Child Tax Credit - also in state_cdccs.
- ok_child_tax_credit_component # Oklahoma Child Tax Credit component
- or_ctc # Oregon Child Tax Credit (Oregon Kids Credit)
- ri_child_tax_rebate # Rhode Island Child Tax Rebate
- ut_ctc # Utah Child Tax Credit
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
description: All state Earned Income Tax Credits.
description: All state Earned Income Tax Credits and related credits.
values:
0000-01-01:
- ca_eitc # California
Expand All @@ -17,7 +17,7 @@ values:
- md_refundable_eitc # Maryland refundable EITC
- me_eitc # Maine
- mi_eitc # Michigan
- mn_wfc # Minnesota (called "Working Family Credit") repealed in 2023
- mn_wfc # Minnesota (called "Working Family Credit")
- mo_wftc # Missouri (called "Working Families Tax Credit")
- mt_eitc # Montana
- ne_eitc # Nebraska
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ values:
# Exclude ca_renter_credit as it is for renters, not homeowners.
- dc_ptc # DC Property Tax Credit
# Exclude hi_tax_credit_for_low_income_household_renters as it is for renters, not homeowners.
- il_property_tax_credit # Illinois Property Tax Credit
- ma_senior_circuit_breaker # Massachusetts Senior Circuit Breaker Credit
- me_property_tax_fairness_credit # Maine Property Tax Fairness Credit
- mi_homestead_property_tax_credit # Michigan homestead property tax credit
- mo_property_tax_credit # Missouri property tax credit
- mt_elderly_homeowner_or_renter_credit # Montana Elderly Homeowner/Renter Credit
- mt_property_tax_rebate # Montana Property Tax Rebate
- nj_property_tax_credit # New Jersey property tax credit
- nm_property_tax_rebate # New Mexico property tax rebate
- ny_real_property_tax_credit # New York real property tax credit
- ok_ptc # Oklahoma Property Tax Credit
- ri_property_tax_credit # Rhode Island property tax credit
# Omit vt_renter_credit
- wi_homestead_credit # Wisconsin homestead credit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ values:
- nc_taxable_income # North Carolina
- nd_taxable_income # North Dakota
- ne_taxable_income # Nebraska
- nh_taxable_income # New Hampshire
- nj_taxable_income # New Jersey
- nm_taxable_income # New Mexico
- ny_taxable_income # New York
- oh_taxable_income # Ohio
- ok_taxable_income # Oklahoma
- or_taxable_income # Oregon
- pa_total_taxable_income # Pennsylvania
- ri_taxable_income # Rhode Island
- sc_taxable_income # South Carolina
- ut_taxable_income # Utah
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import pytest

from policyengine_us import Simulation
from policyengine_us.system import system


def make_tax_unit_situation(
*,
year: int,
state: str,
primary_age: int = 40,
wages: float = 0.0,
childcare: float = 0.0,
rent: float = 0.0,
dependent_ages: tuple[int, ...] = (),
):
year_str = str(year)
members = ["you", *[f"dependent_{i}" for i in range(1, len(dependent_ages) + 1)]]

people = {
"you": {
"age": {year_str: primary_age},
"employment_income": {year_str: wages},
"is_tax_unit_head": {year_str: True},
"is_tax_unit_spouse": {year_str: False},
"is_tax_unit_dependent": {year_str: False},
"ssi": {year_str: 0},
"head_start": {year_str: 0},
"early_head_start": {year_str: 0},
"commodity_supplemental_food_program": {year_str: 0},
}
}

if rent:
people["you"]["rent"] = {year_str: rent}

for index, age in enumerate(dependent_ages, start=1):
name = f"dependent_{index}"
people[name] = {
"age": {year_str: age},
"employment_income": {year_str: 0},
"is_tax_unit_head": {year_str: False},
"is_tax_unit_spouse": {year_str: False},
"is_tax_unit_dependent": {year_str: True},
"ssi": {year_str: 0},
"head_start": {year_str: 0},
"early_head_start": {year_str: 0},
"commodity_supplemental_food_program": {year_str: 0},
}

tax_unit = {"members": members}
if childcare:
tax_unit["tax_unit_childcare_expenses"] = {year_str: childcare}

marital_units = {"your marital unit": {"members": ["you"]}}
for index in range(1, len(dependent_ages) + 1):
marital_units[f"dependent_{index}_marital_unit"] = {
"members": [f"dependent_{index}"],
"marital_unit_id": {year_str: index},
}

return {
"people": people,
"families": {"your family": {"members": members}},
"households": {
"your household": {
"members": members,
"state_name": {year_str: state},
}
},
"tax_units": {"your tax unit": tax_unit},
"spm_units": {
"your household": {
"members": members,
"snap": {year_str: 0},
"tanf": {year_str: 0},
"free_school_meals": {year_str: 0},
"reduced_price_school_meals": {year_str: 0},
}
},
"marital_units": marital_units,
}


def calculate_sum(situation: dict, year: int, variables: list[str]) -> float:
simulation = Simulation(situation=situation)
total = 0.0

for variable in variables:
result = simulation.calculate(variable, period=str(year))
if result.size != 1:
result = simulation.calculate(variable, period=str(year), map_to="tax_unit")
total += float(result.item())

return total


def configured_component_vars(parameter_name: str, year: int) -> list[str]:
parameter = getattr(system.parameters.gov.states.household, parameter_name)
return list(parameter(f"{year}-01-01"))


LEGACY_UMBRELLA_CASES = [
(
"state_agi",
["ok_agi"],
make_tax_unit_situation(year=2023, state="OK", wages=40_000.0),
),
(
"state_taxable_income",
["ok_taxable_income"],
make_tax_unit_situation(year=2023, state="OK", wages=40_000.0),
),
(
"state_cdcc",
["ok_child_care_credit_component"],
make_tax_unit_situation(
year=2023,
state="OK",
wages=40_000.0,
childcare=2_000.0,
dependent_ages=(5,),
),
),
(
"state_eitc",
["mn_wfc"],
make_tax_unit_situation(
year=2023,
state="MN",
wages=20_050.0,
dependent_ages=(9, 7),
),
),
]


@pytest.mark.parametrize(
("legacy_var", "state_specific_vars", "situation"), LEGACY_UMBRELLA_CASES
)
def test_legacy_state_umbrellas_match_state_specific_components(
legacy_var, state_specific_vars, situation
):
expected = calculate_sum(situation, 2023, state_specific_vars)
actual = calculate_sum(situation, 2023, [legacy_var])
assert actual == pytest.approx(expected, abs=0.01)


def test_state_ctc_matches_configured_component_sum():
situation = make_tax_unit_situation(
year=2023,
state="MN",
wages=20_050.0,
dependent_ages=(9, 7),
)
expected = calculate_sum(
situation, 2023, configured_component_vars("state_ctcs", 2023)
)
actual = calculate_sum(situation, 2023, ["state_ctc"])
assert actual == pytest.approx(expected, abs=0.01)


def test_state_property_tax_credit_matches_configured_component_sum():
situation = make_tax_unit_situation(
year=2023,
state="ME",
primary_age=70,
wages=10_000.0,
rent=12_000.0,
)
expected = calculate_sum(
situation,
2023,
configured_component_vars("state_property_tax_credits", 2023),
)
actual = calculate_sum(situation, 2023, ["state_property_tax_credit"])
assert actual == pytest.approx(expected, abs=0.01)


@pytest.mark.parametrize(
("component_vars", "combined_var", "situation"),
[
(
["ok_child_care_credit_component", "ok_child_tax_credit_component"],
"ok_child_care_child_tax_credit",
make_tax_unit_situation(
year=2023,
state="OK",
wages=40_000.0,
childcare=2_000.0,
dependent_ages=(5,),
),
),
(
["mn_wfc", "mn_child_tax_credit_component"],
"mn_child_and_working_families_credits",
make_tax_unit_situation(
year=2023,
state="MN",
wages=20_050.0,
dependent_ages=(9, 7),
),
),
],
)
def test_decomposed_credit_components_preserve_combined_credit_total(
component_vars, combined_var, situation
):
combined_total = calculate_sum(situation, 2023, [combined_var])
decomposed_total = calculate_sum(situation, 2023, component_vars)
assert decomposed_total == pytest.approx(combined_total, abs=0.01)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from policyengine_us.model_api import *


class mn_child_tax_credit_component(Variable):
value_type = float
entity = TaxUnit
label = "Minnesota child tax credit component"
unit = USD
definition_period = YEAR
defined_for = StateCode.MN

def formula(tax_unit, period, parameters):
combined_credit = tax_unit("mn_child_and_working_families_credits", period)
working_family_credit = tax_unit("mn_wfc", period)
return max_(0, combined_credit - working_family_credit)
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,16 @@ def formula(tax_unit, period, parameters):
us_agi = tax_unit("adjusted_gross_income", period)
agi_eligible = us_agi <= p.child.agi_limit
# Step 2: Calculate OK CDCC amount (20% of federal potential)
# Oklahoma matches the potential federal credit, not the actual credit
us_cdcc = tax_unit("cdcc_potential", period)
ok_cdcc = us_cdcc * p.child.cdcc_fraction
# Step 3: Calculate OK CTC amount (5% of federal CTC)
us_ctc = tax_unit("ctc_value", period)
ok_ctc = us_ctc * p.child.ctc_fraction
# Step 4: Compute proration ratio (OK AGI / Federal AGI)
ok_agi = tax_unit("ok_agi", period)
# Use a mask rather than where to avoid a divide-by-zero warning
agi_ratio = np.zeros_like(us_agi)
mask = us_agi != 0
agi_ratio[mask] = ok_agi[mask] / us_agi[mask]
prorate = min_(1, max_(0, agi_ratio))
# Step 5: Return greater of OK CDCC or OK CTC, prorated, if eligible
# Step 5: Return greater of OK CDCC or OK CTC, prorated
return agi_eligible * prorate * max_(ok_cdcc, ok_ctc)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from policyengine_us.model_api import *


class ok_child_care_credit_component(Variable):
value_type = float
entity = TaxUnit
label = "Oklahoma child care credit component"
unit = USD
definition_period = YEAR
defined_for = StateCode.OK

def formula(tax_unit, period, parameters):
# OK's combined credit is max(CDCC_portion, CTC_portion).
# This extracts the CDCC portion: combined minus CTC component.
combined = tax_unit("ok_child_care_child_tax_credit", period)
ctc = tax_unit("ok_child_tax_credit_component", period)
return max_(0, combined - ctc)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from policyengine_us.model_api import *


class ok_child_tax_credit_component(Variable):
value_type = float
entity = TaxUnit
label = "Oklahoma child tax credit component"
unit = USD
definition_period = YEAR
defined_for = StateCode.OK

def formula(tax_unit, period, parameters):
# OK's combined credit is max(CDCC_portion, CTC_portion).
# This extracts the CTC portion by checking if CTC > CDCC.
p = parameters(period).gov.states.ok.tax.income.credits.child
us_cdcc = tax_unit("cdcc_potential", period)
ok_cdcc = us_cdcc * p.cdcc_fraction
us_ctc = tax_unit("ctc_value", period)
ok_ctc = us_ctc * p.ctc_fraction
ctc_larger_than_cdcc = ok_ctc > ok_cdcc
combined = tax_unit("ok_child_care_child_tax_credit", period)
return where(ctc_larger_than_cdcc, combined, 0)
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class state_cdcc(Variable):
value_type = float
entity = TaxUnit
label = "State Child and Dependent Care Tax Credit"
label = "State child and dependent care tax credit"
unit = USD
definition_period = YEAR
adds = "gov.states.household.state_cdccs"
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class state_ctc(Variable):
value_type = float
entity = TaxUnit
label = "State Child Tax Credit"
label = "State child tax credit"
unit = USD
definition_period = YEAR
adds = "gov.states.household.state_ctcs"
Loading
Loading