diff --git a/changelog.d/refundable-credit-conversion.added.md b/changelog.d/refundable-credit-conversion.added.md new file mode 100644 index 00000000000..d4cc8d510a0 --- /dev/null +++ b/changelog.d/refundable-credit-conversion.added.md @@ -0,0 +1 @@ +Added `gov.contrib.refundable_credit_conversion` reform: a configurable refundable per-taxpayer / per-dependent / per-household / wage credit that swaps out federal CTC, CDCC, EITC, standard deduction, itemized deductions, above-the-line deductions, and Head of Household filing status while preserving the underlying variables for state programs to read. diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/credit/dependent_definition.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/credit/dependent_definition.yaml new file mode 100644 index 00000000000..2aa298ff3ac --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/credit/dependent_definition.yaml @@ -0,0 +1,12 @@ +description: | + Definition of "dependent" used to count dependents for the per-dependent + flat credit. Encoded as an integer: + 0 = EITC-qualifying children (most generous; default) + 1 = CTC-qualifying children + 2 = all claimed tax-unit dependents (children plus other dependents) +metadata: + unit: /1 + period: year + label: Dependent definition for flat credit (0=EITC child, 1=CTC child, 2=all) +values: + 0000-01-01: 0 diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/credit/per_dependent.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/credit/per_dependent.yaml new file mode 100644 index 00000000000..822e1bbdf7d --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/credit/per_dependent.yaml @@ -0,0 +1,7 @@ +description: Flat refundable credit amount per dependent under the refundable credit conversion reform. The set of dependents counted is controlled by gov.contrib.refundable_credit_conversion.credit.dependent_definition. +metadata: + unit: currency-USD + period: year + label: Flat credit amount per dependent +values: + 0000-01-01: 0 diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/credit/per_household.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/credit/per_household.yaml new file mode 100644 index 00000000000..cbf814da1d3 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/credit/per_household.yaml @@ -0,0 +1,7 @@ +description: Flat refundable credit amount per tax filing unit (household credit) under the refundable credit conversion reform. +metadata: + unit: currency-USD + period: year + label: Flat credit amount per tax filing unit +values: + 0000-01-01: 0 diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/credit/per_taxpayer.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/credit/per_taxpayer.yaml new file mode 100644 index 00000000000..5ae46928ade --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/credit/per_taxpayer.yaml @@ -0,0 +1,7 @@ +description: Flat refundable credit amount per taxpayer (head of tax unit and spouse if filing jointly) under the refundable credit conversion reform. +metadata: + unit: currency-USD + period: year + label: Flat credit amount per taxpayer +values: + 0000-01-01: 0 diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/in_effect.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/in_effect.yaml new file mode 100644 index 00000000000..f16403023fa --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/in_effect.yaml @@ -0,0 +1,7 @@ +description: The refundable credit conversion contrib reform is in effect when this is true. +metadata: + unit: bool + period: year + label: Refundable credit conversion in effect +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/above_the_line_deductions.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/above_the_line_deductions.yaml new file mode 100644 index 00000000000..8aab5afa9fe --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/above_the_line_deductions.yaml @@ -0,0 +1,7 @@ +description: The refundable credit conversion reform repeals federal above-the-line deductions (adjustments to gross income) when this is true. +metadata: + unit: bool + period: year + label: Repeal federal above-the-line deductions +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/cdcc.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/cdcc.yaml new file mode 100644 index 00000000000..ff7fb4b44fa --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/cdcc.yaml @@ -0,0 +1,7 @@ +description: The refundable credit conversion reform repeals the federal Child and Dependent Care Credit when this is true. +metadata: + unit: bool + period: year + label: Repeal federal Child and Dependent Care Credit +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/ctc.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/ctc.yaml new file mode 100644 index 00000000000..53b78a94374 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/ctc.yaml @@ -0,0 +1,7 @@ +description: The refundable credit conversion reform repeals the federal Child Tax Credit (both refundable and non-refundable portions) when this is true. +metadata: + unit: bool + period: year + label: Repeal federal Child Tax Credit +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/eitc.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/eitc.yaml new file mode 100644 index 00000000000..d6ceb16af5f --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/eitc.yaml @@ -0,0 +1,7 @@ +description: The refundable credit conversion reform repeals the federal Earned Income Tax Credit when this is true. +metadata: + unit: bool + period: year + label: Repeal federal Earned Income Tax Credit +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/head_of_household.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/head_of_household.yaml new file mode 100644 index 00000000000..5d057ac0027 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/head_of_household.yaml @@ -0,0 +1,7 @@ +description: The refundable credit conversion reform repeals the federal Head of Household filing status when this is true. Filers who would otherwise qualify for HoH default to the SINGLE filing status. +metadata: + unit: bool + period: year + label: Repeal federal Head of Household filing status +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/itemized.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/itemized.yaml new file mode 100644 index 00000000000..d346f5050ac --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/itemized.yaml @@ -0,0 +1,7 @@ +description: The refundable credit conversion reform repeals federal itemized deductions when this is true. +metadata: + unit: bool + period: year + label: Repeal federal itemized deductions +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/standard_deduction.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/standard_deduction.yaml new file mode 100644 index 00000000000..3ed08c348a2 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/repeals/standard_deduction.yaml @@ -0,0 +1,7 @@ +description: The refundable credit conversion reform repeals the federal standard deduction when this is true. +metadata: + unit: bool + period: year + label: Repeal federal standard deduction +values: + 0000-01-01: false diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/wage_credit/cap.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/wage_credit/cap.yaml new file mode 100644 index 00000000000..fbeaf4cafc7 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/wage_credit/cap.yaml @@ -0,0 +1,7 @@ +description: Per-wage-earner cap on earnings counted for the refundable credit conversion reform's wage credit. The credit per wage earner equals min(earnings, cap) times the wage credit rate. +metadata: + unit: currency-USD + period: year + label: Wage credit per-worker earnings cap +values: + 0000-01-01: 0 diff --git a/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/wage_credit/rate.yaml b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/wage_credit/rate.yaml new file mode 100644 index 00000000000..05a411389b4 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/refundable_credit_conversion/wage_credit/rate.yaml @@ -0,0 +1,7 @@ +description: Rate at which earnings are credited under the refundable credit conversion reform's wage credit. Applied to each wage earner's earnings up to the per-worker cap. +metadata: + unit: /1 + period: year + label: Wage credit rate +values: + 0000-01-01: 0 diff --git a/policyengine_us/reforms/reforms.py b/policyengine_us/reforms/reforms.py index 10091708b63..d441a972492 100644 --- a/policyengine_us/reforms/reforms.py +++ b/policyengine_us/reforms/reforms.py @@ -198,6 +198,9 @@ from .states.nj.anchor import ( create_nj_anchor_reform, ) +from .refundable_credit_conversion import ( + create_refundable_credit_conversion_reform, +) from .states.ca.ab2591 import ( @@ -454,6 +457,9 @@ def create_structural_reforms_from_parameters(parameters, period): working_parents_tax_relief_act = create_working_parents_tax_relief_act_reform( parameters, period ) + refundable_credit_conversion = create_refundable_credit_conversion_reform( + parameters, period + ) reforms = [ afa_reform, @@ -563,6 +569,7 @@ def create_structural_reforms_from_parameters(parameters, period): nj_stay_nj, nj_anchor, working_parents_tax_relief_act, + refundable_credit_conversion, ] reforms = tuple(filter(lambda x: x is not None, reforms)) diff --git a/policyengine_us/reforms/refundable_credit_conversion/__init__.py b/policyengine_us/reforms/refundable_credit_conversion/__init__.py new file mode 100644 index 00000000000..dfd51b7e62c --- /dev/null +++ b/policyengine_us/reforms/refundable_credit_conversion/__init__.py @@ -0,0 +1,9 @@ +from .refundable_credit_conversion import ( + refundable_credit_conversion, + create_refundable_credit_conversion_reform, +) + +__all__ = [ + "refundable_credit_conversion", + "create_refundable_credit_conversion_reform", +] diff --git a/policyengine_us/reforms/refundable_credit_conversion/refundable_credit_conversion.py b/policyengine_us/reforms/refundable_credit_conversion/refundable_credit_conversion.py new file mode 100644 index 00000000000..b7bb7c03212 --- /dev/null +++ b/policyengine_us/reforms/refundable_credit_conversion/refundable_credit_conversion.py @@ -0,0 +1,245 @@ +from policyengine_us.model_api import * + + +def create_refundable_credit_conversion() -> Reform: + """Refundable credit conversion reform. + + Repeals (configurable) the federal standard deduction, itemized + deductions, above-the-line deductions, Head of Household filing + status, CTC, CDCC, and EITC, and replaces them with a flat + refundable credit composed of per-taxpayer, per-dependent, + per-household, and wage-credit components. + + The repeals operate at the federal computation level: the underlying + ``ctc``, ``eitc``, ``cdcc``, ``standard_deduction``, + ``itemized_taxable_income_deductions``, ``above_the_line_deductions``, + and ``head_of_household_eligible`` variables continue to compute their + baseline values so that state programs that read them still work. + Repeal is achieved by (a) overriding deduction/HoH variables to + return 0 / False at the federal level, and (b) filtering the + repealed credit names out of the federal refundable / non-refundable + credit lists. + """ + + class flat_refundable_credit(Variable): + value_type = float + entity = TaxUnit + definition_period = YEAR + label = "Refundable credit conversion flat credit" + unit = USD + documentation = ( + "Flat refundable credit replacing federal CTC, CDCC, EITC, " + "standard deduction, itemized deductions, above-the-line " + "deductions, and Head of Household filing status." + ) + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.contrib.refundable_credit_conversion + + person = tax_unit.members + is_filer = person("is_tax_unit_head_or_spouse", period) + taxpayer_count = tax_unit.sum(is_filer) + + # 0 = EITC-qualifying children (default), 1 = CTC-qualifying + # children, 2 = all claimed tax-unit dependents. + definition = int(p.credit.dependent_definition) + if definition == 1: + dependent_count = tax_unit("ctc_qualifying_children", period) + elif definition == 2: + dependent_count = tax_unit("tax_unit_count_dependents", period) + else: + dependent_count = tax_unit("eitc_child_count", period) + + taxpayer_amount = taxpayer_count * p.credit.per_taxpayer + dependent_amount = dependent_count * p.credit.per_dependent + household_amount = p.credit.per_household + + earnings = person("earned_income", period) + capped_earnings = min_(max_(earnings, 0), p.wage_credit.cap) + person_wage_credit = capped_earnings * p.wage_credit.rate + wage_credit_amount = tax_unit.sum(person_wage_credit) + + return ( + taxpayer_amount + + dependent_amount + + household_amount + + wage_credit_amount + ) + + class standard_deduction(Variable): + value_type = float + entity = TaxUnit + label = "Standard deduction" + unit = USD + definition_period = YEAR + reference = "https://www.law.cornell.edu/uscode/text/26/63#c" + + def formula(tax_unit, period, parameters): + if parameters( + period + ).gov.contrib.refundable_credit_conversion.repeals.standard_deduction: + return 0 + return add( + tax_unit, + period, + [ + "basic_standard_deduction", + "additional_standard_deduction", + "bonus_guaranteed_deduction", + ], + ) + + class itemized_taxable_income_deductions(Variable): + value_type = float + entity = TaxUnit + label = "Itemized taxable income deductions" + unit = USD + definition_period = YEAR + + def formula(tax_unit, period, parameters): + if parameters( + period + ).gov.contrib.refundable_credit_conversion.repeals.itemized: + return 0 + total_deductions = tax_unit( + "total_itemized_taxable_income_deductions", period + ) + reduction = tax_unit("itemized_taxable_income_deductions_reduction", period) + return max_(0, total_deductions - reduction) + + class above_the_line_deductions(Variable): + value_type = float + entity = TaxUnit + label = "Above-the-line deductions" + unit = USD + documentation = ( + "Deductions applied to reach adjusted gross income from gross income." + ) + definition_period = YEAR + reference = "https://www.law.cornell.edu/uscode/text/26/62" + + def formula(tax_unit, period, parameters): + if parameters( + period + ).gov.contrib.refundable_credit_conversion.repeals.above_the_line_deductions: + return 0 + ald_variables = list(parameters(period).gov.irs.ald.deductions) + return add(tax_unit, period, ald_variables) + + class head_of_household_eligible(Variable): + value_type = bool + entity = TaxUnit + definition_period = YEAR + label = "Qualifies for head of household filing status" + reference = "https://www.law.cornell.edu/uscode/text/26/2#b" + + def formula(tax_unit, period, parameters): + if parameters( + period + ).gov.contrib.refundable_credit_conversion.repeals.head_of_household: + return False + married = tax_unit("tax_unit_married", period) + person = tax_unit.members + is_qualifying_child = person("is_qualifying_child_dependent", period) + is_disabled_dependent = person( + "is_permanently_and_totally_disabled", period + ) & person("is_tax_unit_dependent", period) + is_qualifying_relative = person("is_qualifying_relative_dependent", period) + is_related = person("is_related_to_head_or_spouse", period) + is_hoh_qualifying = ( + is_qualifying_child + | is_disabled_dependent + | (is_qualifying_relative & is_related) + ) + has_qualifying_person = tax_unit.sum(is_hoh_qualifying) > 0 + return ( + has_qualifying_person + & ~married + & ~tax_unit("surviving_spouse_eligible", period) + ) + + class income_tax_refundable_credits(Variable): + value_type = float + entity = TaxUnit + definition_period = YEAR + label = "federal refundable income tax credits" + unit = USD + + def formula(tax_unit, period, parameters): + repeals = parameters( + period + ).gov.contrib.refundable_credit_conversion.repeals + base = list(parameters(period).gov.irs.credits.refundable) + CREDITS = [] + for c in base: + if c == "eitc" and repeals.eitc: + continue + if c == "refundable_ctc" and repeals.ctc: + continue + if c == "cdcc" and repeals.cdcc: + continue + CREDITS.append(c) + CREDITS.append("flat_refundable_credit") + return add(tax_unit, period, CREDITS) + + class income_tax_non_refundable_credits(Variable): + value_type = float + entity = TaxUnit + definition_period = YEAR + label = "federal non-refundable income tax credits" + unit = USD + + def formula(tax_unit, period, parameters): + repeals = parameters( + period + ).gov.contrib.refundable_credit_conversion.repeals + base = list(parameters(period).gov.irs.credits.non_refundable) + CREDITS = [] + for c in base: + if c == "non_refundable_ctc" and repeals.ctc: + continue + if c == "cdcc" and repeals.cdcc: + continue + CREDITS.append(c) + return add(tax_unit, period, CREDITS) + + class reform(Reform): + def apply(self): + self.update_variable(flat_refundable_credit) + self.update_variable(standard_deduction) + self.update_variable(itemized_taxable_income_deductions) + self.update_variable(above_the_line_deductions) + self.update_variable(head_of_household_eligible) + self.update_variable(income_tax_refundable_credits) + self.update_variable(income_tax_non_refundable_credits) + + return reform + + +def create_refundable_credit_conversion_reform( + parameters, period, bypass: bool = False +): + """Auto-application function for the refundable credit conversion reform.""" + if bypass: + return create_refundable_credit_conversion() + + from policyengine_core.periods import period as period_ + + p = parameters.gov.contrib.refundable_credit_conversion + + reform_active = False + current_period = period_(period) + + for i in range(5): + if p(current_period).in_effect: + reform_active = True + break + current_period = current_period.offset(1, "year") + + if reform_active: + return create_refundable_credit_conversion() + else: + return None + + +refundable_credit_conversion = create_refundable_credit_conversion() diff --git a/policyengine_us/tests/policy/contrib/refundable_credit_conversion/dependent_definition.yaml b/policyengine_us/tests/policy/contrib/refundable_credit_conversion/dependent_definition.yaml new file mode 100644 index 00000000000..e799c6802c7 --- /dev/null +++ b/policyengine_us/tests/policy/contrib/refundable_credit_conversion/dependent_definition.yaml @@ -0,0 +1,67 @@ +- name: Dependent definition eitc_child counts EITC-qualifying children only + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.credit.per_taxpayer: 0 + gov.contrib.refundable_credit_conversion.credit.per_dependent: 1_000 + gov.contrib.refundable_credit_conversion.credit.dependent_definition: 0 + people: + filer: + age: 35 + child: + age: 5 + tax_units: + tax_unit: + members: [filer, child] + filing_status: SINGLE + output: + flat_refundable_credit: 1_000 + +- name: Dependent definition all_dependents counts every claimed dependent + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.credit.per_taxpayer: 0 + gov.contrib.refundable_credit_conversion.credit.per_dependent: 1_000 + gov.contrib.refundable_credit_conversion.credit.dependent_definition: 2 + people: + filer: + age: 35 + child: + age: 5 + is_tax_unit_dependent: true + adult_dependent: + age: 22 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child, adult_dependent] + filing_status: SINGLE + output: + flat_refundable_credit: 2_000 # both dependents counted + +- name: Dependent definition ctc_child counts CTC-qualifying children + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.credit.per_taxpayer: 0 + gov.contrib.refundable_credit_conversion.credit.per_dependent: 1_000 + gov.contrib.refundable_credit_conversion.credit.dependent_definition: 1 + people: + filer: + age: 35 + child: + age: 5 + is_tax_unit_dependent: true + adult_dependent: + age: 22 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child, adult_dependent] + filing_status: SINGLE + output: + flat_refundable_credit: 1_000 # only the CTC-qualifying child counted diff --git a/policyengine_us/tests/policy/contrib/refundable_credit_conversion/flat_credit.yaml b/policyengine_us/tests/policy/contrib/refundable_credit_conversion/flat_credit.yaml new file mode 100644 index 00000000000..32f7bd484dc --- /dev/null +++ b/policyengine_us/tests/policy/contrib/refundable_credit_conversion/flat_credit.yaml @@ -0,0 +1,62 @@ +- name: Single filer with no dependents — taxpayer credit only + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.credit.per_taxpayer: 1_000 + gov.contrib.refundable_credit_conversion.credit.per_dependent: 500 + gov.contrib.refundable_credit_conversion.credit.per_household: 0 + people: + filer: + age: 35 + tax_units: + tax_unit: + members: [filer] + filing_status: SINGLE + output: + flat_refundable_credit: 1_000 + +- name: MFJ couple with no dependents — taxpayer credit doubles + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.credit.per_taxpayer: 1_000 + gov.contrib.refundable_credit_conversion.credit.per_dependent: 500 + gov.contrib.refundable_credit_conversion.credit.per_household: 0 + people: + filer: + age: 35 + spouse: + age: 33 + tax_units: + tax_unit: + members: [filer, spouse] + filing_status: JOINT + output: + flat_refundable_credit: 2_000 + +- name: MFJ with two children and household credit — full credit math + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.credit.per_taxpayer: 1_000 + gov.contrib.refundable_credit_conversion.credit.per_dependent: 500 + gov.contrib.refundable_credit_conversion.credit.per_household: 200 + gov.contrib.refundable_credit_conversion.credit.dependent_definition: 0 + people: + filer: + age: 35 + spouse: + age: 33 + child1: + age: 5 + child2: + age: 8 + tax_units: + tax_unit: + members: [filer, spouse, child1, child2] + filing_status: JOINT + output: + flat_refundable_credit: 3_200 # 2 * 1_000 + 2 * 500 + 200 diff --git a/policyengine_us/tests/policy/contrib/refundable_credit_conversion/integration.yaml b/policyengine_us/tests/policy/contrib/refundable_credit_conversion/integration.yaml new file mode 100644 index 00000000000..e7d6b6405cd --- /dev/null +++ b/policyengine_us/tests/policy/contrib/refundable_credit_conversion/integration.yaml @@ -0,0 +1,48 @@ +- name: Full reform — all repeals on, $3k per filer/dep, $0 household, no wage credit + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.repeals.itemized: true + gov.contrib.refundable_credit_conversion.repeals.standard_deduction: true + gov.contrib.refundable_credit_conversion.repeals.head_of_household: true + gov.contrib.refundable_credit_conversion.repeals.above_the_line_deductions: true + gov.contrib.refundable_credit_conversion.repeals.ctc: true + gov.contrib.refundable_credit_conversion.repeals.cdcc: true + gov.contrib.refundable_credit_conversion.repeals.eitc: true + gov.contrib.refundable_credit_conversion.credit.per_taxpayer: 3_000 + gov.contrib.refundable_credit_conversion.credit.per_dependent: 3_000 + gov.contrib.refundable_credit_conversion.credit.per_household: 0 + people: + filer: + age: 35 + employment_income: 40_000 + spouse: + age: 33 + child: + age: 5 + tax_units: + tax_unit: + members: [filer, spouse, child] + filing_status: JOINT + output: + standard_deduction: 0 + itemized_taxable_income_deductions: 0 + above_the_line_deductions: 0 + flat_refundable_credit: 9_000 # 2 * 3_000 + 1 * 3_000 + +- name: Reform inactive (in_effect false) — baseline behavior preserved + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: false + people: + filer: + age: 35 + employment_income: 40_000 + tax_units: + tax_unit: + members: [filer] + filing_status: SINGLE + output: + flat_refundable_credit: 0 diff --git a/policyengine_us/tests/policy/contrib/refundable_credit_conversion/repeals.yaml b/policyengine_us/tests/policy/contrib/refundable_credit_conversion/repeals.yaml new file mode 100644 index 00000000000..b09bd511846 --- /dev/null +++ b/policyengine_us/tests/policy/contrib/refundable_credit_conversion/repeals.yaml @@ -0,0 +1,106 @@ +- name: Standard deduction repeal sets it to zero + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.repeals.standard_deduction: true + people: + filer: + age: 35 + tax_units: + tax_unit: + members: [filer] + filing_status: SINGLE + output: + standard_deduction: 0 + +- name: Itemized deductions repeal sets them to zero + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.repeals.itemized: true + people: + filer: + age: 35 + tax_units: + tax_unit: + members: [filer] + filing_status: SINGLE + total_itemized_taxable_income_deductions: 30_000 + output: + itemized_taxable_income_deductions: 0 + +- name: Above-the-line deductions repeal sets them to zero + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.repeals.above_the_line_deductions: true + people: + filer: + age: 35 + student_loan_interest: 2_000 + tax_units: + tax_unit: + members: [filer] + filing_status: SINGLE + output: + above_the_line_deductions: 0 + +- name: Head of Household repeal makes filer ineligible + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.repeals.head_of_household: true + people: + filer: + age: 35 + child: + age: 5 + tax_units: + tax_unit: + members: [filer, child] + output: + head_of_household_eligible: false + +- name: CTC repeal removes both refundable and non-refundable CTC from federal credit lists + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.repeals.ctc: true + people: + filer: + age: 35 + employment_income: 40_000 + child: + age: 5 + tax_units: + tax_unit: + members: [filer, child] + filing_status: SINGLE + output: + income_tax_refundable_credits: 0 + income_tax_non_refundable_credits: 0 + +- name: EITC repeal removes EITC from federal refundable credits + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.repeals.eitc: true + gov.contrib.refundable_credit_conversion.repeals.ctc: true + people: + filer: + age: 35 + employment_income: 20_000 + child: + age: 5 + tax_units: + tax_unit: + members: [filer, child] + filing_status: SINGLE + output: + income_tax_refundable_credits: 0 diff --git a/policyengine_us/tests/policy/contrib/refundable_credit_conversion/wage_credit.yaml b/policyengine_us/tests/policy/contrib/refundable_credit_conversion/wage_credit.yaml new file mode 100644 index 00000000000..ad1366cd5fb --- /dev/null +++ b/policyengine_us/tests/policy/contrib/refundable_credit_conversion/wage_credit.yaml @@ -0,0 +1,44 @@ +- name: Wage credit applies per wage earner up to the per-worker cap + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.credit.per_taxpayer: 0 + gov.contrib.refundable_credit_conversion.credit.per_dependent: 0 + gov.contrib.refundable_credit_conversion.credit.per_household: 0 + gov.contrib.refundable_credit_conversion.wage_credit.rate: 0.20 + gov.contrib.refundable_credit_conversion.wage_credit.cap: 5_000 + people: + filer: + age: 35 + employment_income: 3_000 + spouse: + age: 33 + employment_income: 10_000 + tax_units: + tax_unit: + members: [filer, spouse] + filing_status: JOINT + output: + flat_refundable_credit: 1_600 # 0.20 * (3_000 + 5_000) = 1_600 + +- name: Wage credit with zero rate produces no credit + period: 2026 + reforms: policyengine_us.reforms.refundable_credit_conversion.refundable_credit_conversion + input: + gov.contrib.refundable_credit_conversion.in_effect: true + gov.contrib.refundable_credit_conversion.credit.per_taxpayer: 0 + gov.contrib.refundable_credit_conversion.credit.per_dependent: 0 + gov.contrib.refundable_credit_conversion.credit.per_household: 0 + gov.contrib.refundable_credit_conversion.wage_credit.rate: 0 + gov.contrib.refundable_credit_conversion.wage_credit.cap: 5_000 + people: + filer: + age: 35 + employment_income: 50_000 + tax_units: + tax_unit: + members: [filer] + filing_status: SINGLE + output: + flat_refundable_credit: 0