diff --git a/changelog.d/il-sb3567.added.md b/changelog.d/il-sb3567.added.md new file mode 100644 index 00000000000..e92dda0be77 --- /dev/null +++ b/changelog.d/il-sb3567.added.md @@ -0,0 +1 @@ +- Add an Illinois SB3567 (104th General Assembly) contributed reform, opt-in via `gov.contrib.states.il.sb3567.in_effect`, that boosts the child tax credit for low-AGI filers. diff --git a/policyengine_us/parameters/gov/contrib/states/il/sb3567/in_effect.yaml b/policyengine_us/parameters/gov/contrib/states/il/sb3567/in_effect.yaml new file mode 100644 index 00000000000..7476c9c8387 --- /dev/null +++ b/policyengine_us/parameters/gov/contrib/states/il/sb3567/in_effect.yaml @@ -0,0 +1,12 @@ +description: Illinois SB3567 modifies the child tax credit formula and makes the credit nonrefundable if this is true. + +values: + 0000-01-01: false + +metadata: + unit: bool + period: year + label: Illinois SB3567 child tax credit reform in effect + reference: + - title: Illinois SB3567 (104th General Assembly) full text + href: https://ilga.gov/Legislation/BillStatus/FullText?DocNum=3567&DocTypeID=SB&GAID=18&LegId=166617&Print=1&SessionID=114 diff --git a/policyengine_us/reforms/reforms.py b/policyengine_us/reforms/reforms.py index 10091708b63..b3e3bfb5800 100644 --- a/policyengine_us/reforms/reforms.py +++ b/policyengine_us/reforms/reforms.py @@ -236,6 +236,9 @@ from .states.id.s1450 import ( create_id_s1450_reform, ) +from .states.il.sb3567 import ( + create_il_sb3567_reform, +) from .states.ky.eitc import ( create_ky_eitc_reform, ) @@ -440,6 +443,7 @@ def create_structural_reforms_from_parameters(parameters, period): ga_eitc = create_ga_eitc_reform(parameters, period) id_eitc = create_id_eitc_reform(parameters, period) id_s1450 = create_id_s1450_reform(parameters, period) + il_sb3567 = create_il_sb3567_reform(parameters, period) ky_eitc = create_ky_eitc_reform(parameters, period) ms_eitc = create_ms_eitc_reform(parameters, period) nd_eitc = create_nd_eitc_reform(parameters, period) @@ -553,6 +557,7 @@ def create_structural_reforms_from_parameters(parameters, period): ga_eitc, id_eitc, id_s1450, + il_sb3567, ky_eitc, ms_eitc, nd_eitc, diff --git a/policyengine_us/reforms/states/il/__init__.py b/policyengine_us/reforms/states/il/__init__.py new file mode 100644 index 00000000000..3a068874f77 --- /dev/null +++ b/policyengine_us/reforms/states/il/__init__.py @@ -0,0 +1 @@ +from .sb3567 import create_il_sb3567_reform diff --git a/policyengine_us/reforms/states/il/sb3567/__init__.py b/policyengine_us/reforms/states/il/sb3567/__init__.py new file mode 100644 index 00000000000..8956a31b1e3 --- /dev/null +++ b/policyengine_us/reforms/states/il/sb3567/__init__.py @@ -0,0 +1,5 @@ +from .il_sb3567_reform import ( + create_il_sb3567, + create_il_sb3567_reform, + il_sb3567, +) diff --git a/policyengine_us/reforms/states/il/sb3567/il_sb3567_reform.py b/policyengine_us/reforms/states/il/sb3567/il_sb3567_reform.py new file mode 100644 index 00000000000..f9e2b3520c7 --- /dev/null +++ b/policyengine_us/reforms/states/il/sb3567/il_sb3567_reform.py @@ -0,0 +1,78 @@ +from policyengine_core.periods import period as period_ +from policyengine_us.model_api import * + + +def create_il_sb3567() -> Reform: + class il_ctc(Variable): + value_type = float + entity = TaxUnit + label = "Illinois Child Tax Credit" + unit = USD + definition_period = YEAR + reference = ( + "https://ilga.gov/Legislation/BillStatus/FullText?DocNum=3567&DocTypeID=SB&GAID=18&LegId=166617&Print=1&SessionID=114", + "https://www.ilga.gov/legislation/ilcs/fulltext.asp?DocName=003500050K244", + ) + defined_for = StateCode.IL + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.il.tax.income.credits + ctc = p.ctc + person = tax_unit.members + age = person("age", period) + age_eligible_child = age < ctc.age_limit + federal_ctc_eligible_child = person("ctc_qualifying_child", period) + eligible_child = age_eligible_child & federal_ctc_eligible_child + eligible_child_present = tax_unit.any(eligible_child) + + actual_credit = tax_unit("il_eitc", period) * ctc.rate + + # SB3567 keys the maximum credit amount to the dependent count. + # The bill cites IRC ยง 152, but here we use the tax unit's child + # dependent count, capped at 3 to match the federal EITC schedule. + dependent_count = min_(tax_unit("tax_unit_child_dependents", period), 3) + federal_eitc = parameters(period).gov.irs.credits.eitc + federal_maximum = federal_eitc.max.calc(dependent_count) + phase_in_rate = federal_eitc.phase_in_rate.calc(dependent_count) + + # The bill's "income threshold to qualify for the maximum federal + # EITC" is the end of the phase-in range (start of the plateau). + max_federal_eitc_threshold = federal_maximum / phase_in_rate + max_credit = federal_maximum * p.eitc.match * ctc.rate + + agi = tax_unit("adjusted_gross_income", period) + return eligible_child_present * where( + agi <= max_federal_eitc_threshold, + max_credit, + actual_credit, + ) + + class reform(Reform): + def apply(self): + self.update_variable(il_ctc) + + return reform + + +def create_il_sb3567_reform(parameters, period, bypass: bool = False): + if bypass: + return create_il_sb3567() + + p = parameters.gov.contrib.states.il.sb3567 + + reform_active = False + current_period = period_(period) + + for _ 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_il_sb3567() + else: + return None + + +il_sb3567 = create_il_sb3567_reform(None, None, bypass=True) diff --git a/policyengine_us/tests/policy/contrib/states/il/sb3567/il_sb3567.yaml b/policyengine_us/tests/policy/contrib/states/il/sb3567/il_sb3567.yaml new file mode 100644 index 00000000000..e25c534bcef --- /dev/null +++ b/policyengine_us/tests/policy/contrib/states/il/sb3567/il_sb3567.yaml @@ -0,0 +1,256 @@ +- name: SB3567 boosts phase-in filers to the maximum one-child credit + period: 2025 + absolute_error_margin: 0.01 + reforms: policyengine_us.reforms.states.il.sb3567.il_sb3567 + input: + gov.contrib.states.il.sb3567.in_effect: true + people: + filer: + age: 30 + child: + age: 8 + ctc_qualifying_child: true + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child] + adjusted_gross_income: 12_000 + il_eitc: 200 + households: + household: + members: [filer, child] + state_code: IL + output: + il_ctc: 346.24 + +- name: SB3567 uses the three-child EITC maximum for larger dependent counts + period: 2025 + absolute_error_margin: 0.01 + reforms: policyengine_us.reforms.states.il.sb3567.il_sb3567 + input: + gov.contrib.states.il.sb3567.in_effect: true + people: + filer: + age: 32 + child1: + age: 9 + ctc_qualifying_child: true + is_tax_unit_dependent: true + child2: + age: 7 + is_tax_unit_dependent: true + child3: + age: 5 + is_tax_unit_dependent: true + child4: + age: 3 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child1, child2, child3, child4] + adjusted_gross_income: 15_000 + il_eitc: 400 + households: + household: + members: [filer, child1, child2, child3, child4] + state_code: IL + output: + il_ctc: 643.68 + +- name: SB3567 keeps plateau filers on the actual Illinois EITC amount + period: 2025 + absolute_error_margin: 0.01 + reforms: policyengine_us.reforms.states.il.sb3567.il_sb3567 + input: + gov.contrib.states.il.sb3567.in_effect: true + people: + filer: + age: 33 + child: + age: 6 + ctc_qualifying_child: true + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child] + adjusted_gross_income: 18_000 + il_eitc: 865.6 + households: + household: + members: [filer, child] + state_code: IL + output: + il_ctc: 346.24 + +- name: SB3567 keeps phase-out filers on 40 percent of actual Illinois EITC + period: 2025 + absolute_error_margin: 0.01 + reforms: policyengine_us.reforms.states.il.sb3567.il_sb3567 + input: + gov.contrib.states.il.sb3567.in_effect: true + people: + filer: + age: 34 + child: + age: 4 + ctc_qualifying_child: true + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child] + adjusted_gross_income: 30_000 + il_eitc: 300 + households: + household: + members: [filer, child] + state_code: IL + output: + il_ctc: 120 + +- name: SB3567 keeps the age-under-12 eligibility gate + period: 2025 + absolute_error_margin: 0.01 + reforms: policyengine_us.reforms.states.il.sb3567.il_sb3567 + input: + gov.contrib.states.il.sb3567.in_effect: true + people: + filer: + age: 35 + child: + age: 12 + ctc_qualifying_child: true + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child] + adjusted_gross_income: 10_000 + il_eitc: 200 + households: + household: + members: [filer, child] + state_code: IL + output: + il_ctc: 0 + +- name: SB3567 keeps the Illinois CTC refundable when EITC is zero + period: 2025 + absolute_error_margin: 0.01 + reforms: policyengine_us.reforms.states.il.sb3567.il_sb3567 + input: + gov.contrib.states.il.sb3567.in_effect: true + people: + filer: + age: 36 + child: + age: 5 + ctc_qualifying_child: true + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child] + adjusted_gross_income: 10_000 + il_eitc: 0 + il_income_tax_before_non_refundable_credits: 0 + il_property_tax_credit: 0 + il_k12_education_expense_credit: 0 + il_pass_through_withholding: 0 + il_pass_through_entity_tax_credit: 0 + il_use_tax: 0 + households: + household: + members: [filer, child] + state_code: IL + # AGI below 1-child phase-in threshold so boost applies; il_ctc stays + # refundable per existing 35 ILCS 5/244(b), so it flows through to + # il_refundable_credits even with no tax liability. + output: + il_ctc: 346.24 + il_refundable_credits: 346.24 + il_income_tax: -346.24 + +- name: Non-Illinois filers do not receive the reform CTC + period: 2025 + absolute_error_margin: 0.01 + reforms: policyengine_us.reforms.states.il.sb3567.il_sb3567 + input: + gov.contrib.states.il.sb3567.in_effect: true + people: + filer: + age: 30 + child: + age: 8 + ctc_qualifying_child: true + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child] + adjusted_gross_income: 12_000 + il_eitc: 200 + households: + household: + members: [filer, child] + state_code: CA + output: + il_ctc: 0 + +- name: SB3567 boosts a two-child phase-in filer to the two-child maximum + period: 2025 + absolute_error_margin: 0.01 + reforms: policyengine_us.reforms.states.il.sb3567.il_sb3567 + input: + gov.contrib.states.il.sb3567.in_effect: true + people: + filer: + age: 31 + child1: + age: 7 + ctc_qualifying_child: true + is_tax_unit_dependent: true + child2: + age: 5 + ctc_qualifying_child: true + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child1, child2] + adjusted_gross_income: 14_000 + il_eitc: 250 + households: + household: + members: [filer, child1, child2] + state_code: IL + # 2025 federal EITC max for 2 children = 7,152; IL match = 0.20; CTC rate = 0.4 + # Boosted credit = 7,152 * 0.20 * 0.4 = 572.16 + output: + il_ctc: 572.16 + +- name: SB3567 applies the boost at the two-child phase-in threshold + period: 2025 + absolute_error_margin: 0.01 + reforms: policyengine_us.reforms.states.il.sb3567.il_sb3567 + input: + gov.contrib.states.il.sb3567.in_effect: true + people: + filer: + age: 32 + child1: + age: 6 + ctc_qualifying_child: true + is_tax_unit_dependent: true + child2: + age: 4 + ctc_qualifying_child: true + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [filer, child1, child2] + # Phase-in threshold for 2 children = 7,152 / 0.40 = 17,880 + adjusted_gross_income: 17_880 + il_eitc: 1_430.4 + households: + household: + members: [filer, child1, child2] + state_code: IL + # AGI <= threshold so boost applies; max credit = 572.16 + output: + il_ctc: 572.16