From d210aa58840e053eba18638e233340597ce08796 Mon Sep 17 00:00:00 2001 From: David Trimmer Date: Wed, 12 Aug 2026 15:53:13 -0400 Subject: [PATCH 1/5] Book Connecticut child tax rebate in 2021 eligibility year MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Connecticut 2022 child tax rebate (PA 22-118) is determined by the 2021 return, claimed by a separate application, and paid in fall 2022 — it is not a line on the CT-1040. PolicyEngine was applying it as a 2022 non-refundable income-tax credit, reducing 2022 CT income tax and computing eligibility from 2022 data, while it books every other prior-year rebate (ri_child_tax_rebate, nm_2021_income_rebate) in the eligibility year. Move ct_child_tax_rebate to the 2021 refundable-credit list (removed in 2022) and shift its parameters to 2021, mirroring ri_child_tax_rebate. 2022 CT income tax no longer includes the rebate, matching the CT-1040. Zero ct_child_tax_rebate in the two 2021 CT integration tests (TAXSIM35 does not model it), following the ri_child_tax_rebate convention. Fixes #9270. Surfaced by PolicyEngine/policyengine-taxsim#1127. Co-Authored-By: Claude Fable 5 --- changelog.d/ct-child-rebate-2021.fixed.md | 1 + .../states/ct/tax/income/credits/non_refundable.yaml | 1 - .../gov/states/ct/tax/income/credits/refundable.yaml | 6 ++++++ .../gov/states/ct/tax/income/rebate/amount.yaml | 2 +- .../gov/states/ct/tax/income/rebate/child_cap.yaml | 2 +- .../ct/tax/income/rebate/reduction/increment.yaml | 2 +- .../states/ct/tax/income/rebate/reduction/rate.yaml | 2 +- .../states/ct/tax/income/rebate/reduction/start.yaml | 10 +++++----- .../baseline/gov/states/ct/tax/income/integration.yaml | 2 ++ .../ct/tax/income/rebate/ct_child_tax_rebate.yaml | 6 +++--- 10 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 changelog.d/ct-child-rebate-2021.fixed.md diff --git a/changelog.d/ct-child-rebate-2021.fixed.md b/changelog.d/ct-child-rebate-2021.fixed.md new file mode 100644 index 00000000000..a07077b9c65 --- /dev/null +++ b/changelog.d/ct-child-rebate-2021.fixed.md @@ -0,0 +1 @@ +Move the Connecticut child tax rebate to the 2021 eligibility year as a refundable credit, matching how the analogous Rhode Island and New Mexico prior-year rebates are booked, so it no longer reduces 2022 Connecticut income tax. diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/credits/non_refundable.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/credits/non_refundable.yaml index 09d4e8ecbd1..7786570685a 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/credits/non_refundable.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/credits/non_refundable.yaml @@ -9,7 +9,6 @@ values: - ct_property_tax_credit 2022-01-01: - ct_property_tax_credit - - ct_child_tax_rebate - ct_stillborn_credit 2023-01-01: - ct_property_tax_credit diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/credits/refundable.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/credits/refundable.yaml index 91783feb1c7..3d4a3e95570 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/credits/refundable.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/credits/refundable.yaml @@ -5,5 +5,11 @@ metadata: label: Connecticut refundable credits values: + # The 2022 child tax rebate (PA 22-118) is a refundable rebate keyed to the + # 2021 return, booked in the eligibility year like other prior-year rebates + # (cf. ri_child_tax_rebate, nm_2021_income_rebate). 2021-01-01: - ct_eitc + - ct_child_tax_rebate + 2022-01-01: + - ct_eitc diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml index 74bcc8fe41b..e4c1c3a367f 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml @@ -12,4 +12,4 @@ metadata: href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 # The legal code section has been repealed values: - 2022-01-01: 250 + 2021-01-01: 250 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml index 901d9bbbea4..86b411e6ac1 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml @@ -12,4 +12,4 @@ metadata: href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 # The legal code section has been repealed values: - 2022-01-01: 3 + 2021-01-01: 3 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml index 04f2413998c..902e879067d 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml @@ -8,4 +8,4 @@ metadata: href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 # The legal code section has been repealed values: - 2022-01-01: 1_000 + 2021-01-01: 1_000 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml index 4a369e19e49..7bb9887aa70 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml @@ -8,4 +8,4 @@ metadata: href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 # The legal code section has been repealed values: - 2022-01-01: .1 + 2021-01-01: .1 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml index 718a2e17398..a75a94e1ad7 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml @@ -12,12 +12,12 @@ metadata: href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 # The legal code section has been repealed SINGLE: - 2022-01-01: 100_000 + 2021-01-01: 100_000 HEAD_OF_HOUSEHOLD: - 2022-01-01: 160_000 + 2021-01-01: 160_000 JOINT: - 2022-01-01: 200_000 + 2021-01-01: 200_000 SURVIVING_SPOUSE: - 2022-01-01: 200_000 + 2021-01-01: 200_000 SEPARATE: - 2022-01-01: 100_000 + 2021-01-01: 100_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/integration.yaml index 2c51c277e41..c9e8e9aa9ce 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/integration.yaml @@ -15,6 +15,7 @@ tax_unit: members: [person1, person2] aca_ptc: 0 # not in TAXSIM35 + ct_child_tax_rebate: 0 # not in TAXSIM35 spm_units: spm_unit: members: [person1, person2] @@ -44,6 +45,7 @@ tax_unit: members: [person1, person2, person3, person4] aca_ptc: 0 # not in TAXSIM35 + ct_child_tax_rebate: 0 # not in TAXSIM35 spm_units: spm_unit: members: [person1, person2, person3, person4] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml index 87c522ea73c..6d061a257b4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml @@ -1,5 +1,5 @@ - name: Single with $101,000 AGI and 2 dependents - period: 2022 + period: 2021 input: state_code: CT ct_agi: 101_000 @@ -9,7 +9,7 @@ ct_child_tax_rebate: 400 - name: Joint with $180,000 AGI and 1 dependent - period: 2022 + period: 2021 input: state_code: CT ct_agi: 180_000 @@ -19,7 +19,7 @@ ct_child_tax_rebate: 250 - name: Head of household with $170,000 AGI and 5 dependents - period: 2022 + period: 2021 input: state_code: CT ct_agi: 165_000 From bb45710fd5e1e06754741047cfd6db7aa72fd72c Mon Sep 17 00:00:00 2001 From: David Trimmer Date: Mon, 17 Aug 2026 09:26:38 -0400 Subject: [PATCH 2/5] Address @PavelMakarchuk review: CT child tax rebate federal-AGI phase-out, age gate, sunset Booking this credit into the live 2021 baseline surfaced three formula/parameter issues: - F1: the phase-out read ct_agi; PA 22-118 phased out on FEDERAL AGI from the 2021 return. Switch the income measure to adjusted_gross_income. - F2: the count used tax_unit_count_dependents (all dependents); the program required a dependent child age 18 or younger. Count only age<=18 tax-unit dependents, RI-style, with a new ct rebate age_limit parameter (18). - F3: the rebate parameters started 2021 with no sunset, so the variable returned phantom nonzero values for 2022+. Sunset amount and child_cap to 0 at 2022-01-01 (one-time rebate). - F4/tests: the prior cases injected ct_agi and tax_unit_count_dependents, masking F1 and F2. Rewrite them to drive federal AGI + real dependents with ages (and fix the 70k/165k name mismatch), and add age-gate, federal-AGI-vs-ct_agi, and 2023-sunset cases. CT tax suite 140/140. Co-Authored-By: Claude Opus 4.8 --- .../ct/tax/income/rebate/age_limit.yaml | 14 ++ .../states/ct/tax/income/rebate/amount.yaml | 3 +- .../ct/tax/income/rebate/child_cap.yaml | 3 +- .../income/rebate/ct_child_tax_rebate.yaml | 185 ++++++++++++++++-- .../tax/income/rebate/ct_child_tax_rebate.py | 10 +- 5 files changed, 195 insertions(+), 20 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml new file mode 100644 index 00000000000..ec6f895785b --- /dev/null +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml @@ -0,0 +1,14 @@ +description: Connecticut limits its child tax rebate to dependent children this age or younger under the Child Tax Rebate program. +values: + 2021-01-01: 18 +metadata: + unit: year + period: year + label: Connecticut child tax rebate age limit + reference: + - title: 2022 Child Tax Rebate + href: https://portal.ct.gov/drs/credit-programs/child-tax-rebate/overview + - title: OLR Report 2026-R-0020 + href: https://cga.ct.gov/2026/rpt/pdf/2026-R-0020.pdf + - title: House Bill No. 5506 Public Act No. 22-118 Sec. 410 (xxvi) + href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml index e4c1c3a367f..a8e3003c90a 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml @@ -10,6 +10,7 @@ metadata: href: https://portal.ct.gov/-/media/drs/publications/tssb/2022/tssb-2022-5.pdf#page=1 - title: House Bill No. 5506 Public Act No. 22-118 Sec. 410 (xxvi) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 - # The legal code section has been repealed + # The legal code section has been repealed; the rebate was a one-time 2021 payment under PA 22-118, so it sunsets in 2022. values: 2021-01-01: 250 + 2022-01-01: 0 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml index 86b411e6ac1..b3e764c3745 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml @@ -10,6 +10,7 @@ metadata: href: https://portal.ct.gov/-/media/drs/publications/tssb/2022/tssb-2022-5.pdf#page=1 - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411 (b) (1) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 - # The legal code section has been repealed + # The legal code section has been repealed; the rebate was a one-time 2021 payment under PA 22-118, so it sunsets in 2022. values: 2021-01-01: 3 + 2022-01-01: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml index 6d061a257b4..8b10cdb2780 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml @@ -1,29 +1,184 @@ -- name: Single with $101,000 AGI and 2 dependents +- name: Single with $101,000 federal AGI and 2 dependent children period: 2021 input: - state_code: CT - ct_agi: 101_000 - filing_status: SINGLE - tax_unit_count_dependents: 2 + people: + parent: + age: 40 + is_tax_unit_dependent: false + child1: + age: 10 + is_tax_unit_dependent: true + child2: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child1, child2] + adjusted_gross_income: 101_000 + filing_status: SINGLE + households: + household: + members: [parent, child1, child2] + state_code: CT output: + # 2 * 250 = 500; excess 1,000 over 100,000 -> 1 increment * 100 = 100 reduction. ct_child_tax_rebate: 400 -- name: Joint with $180,000 AGI and 1 dependent +- name: Joint with $180,000 federal AGI and 1 dependent child period: 2021 input: - state_code: CT - ct_agi: 180_000 - filing_status: JOINT - tax_unit_count_dependents: 1 + people: + parent1: + age: 40 + is_tax_unit_dependent: false + parent2: + age: 38 + is_tax_unit_dependent: false + child1: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent1, parent2, child1] + adjusted_gross_income: 180_000 + filing_status: JOINT + households: + household: + members: [parent1, parent2, child1] + state_code: CT output: + # 1 * 250 = 250; 180,000 below joint threshold of 200,000 -> no reduction. ct_child_tax_rebate: 250 -- name: Head of household with $170,000 AGI and 5 dependents +- name: Head of household with $165,000 federal AGI and 5 dependent children period: 2021 input: - state_code: CT - ct_agi: 165_000 - filing_status: HEAD_OF_HOUSEHOLD - tax_unit_count_dependents: 5 + people: + parent: + age: 45 + is_tax_unit_dependent: false + child1: + age: 15 + is_tax_unit_dependent: true + child2: + age: 13 + is_tax_unit_dependent: true + child3: + age: 11 + is_tax_unit_dependent: true + child4: + age: 9 + is_tax_unit_dependent: true + child5: + age: 7 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child1, child2, child3, child4, child5] + adjusted_gross_income: 165_000 + filing_status: HEAD_OF_HOUSEHOLD + households: + household: + members: [parent, child1, child2, child3, child4, child5] + state_code: CT output: + # 5 children capped at 3 -> 750; excess 5,000 over 160,000 HoH threshold + # -> 5 increments * 100 = 500 reduction; 750 - 500 = 250. ct_child_tax_rebate: 250 + +- name: Only dependent is age 21 - no eligible child (age gate) + period: 2021 + input: + people: + parent: + age: 50 + is_tax_unit_dependent: false + dependent: + age: 21 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, dependent] + adjusted_gross_income: 50_000 + filing_status: SINGLE + households: + household: + members: [parent, dependent] + state_code: CT + output: + # Sole dependent exceeds the age 18 limit -> 0 eligible children -> rebate 0. + ct_child_tax_rebate: 0 + +- name: Mixed minor and adult dependents - only the minor counts + period: 2021 + input: + people: + parent: + age: 50 + is_tax_unit_dependent: false + minor: + age: 10 + is_tax_unit_dependent: true + adult_dependent: + age: 21 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, minor, adult_dependent] + adjusted_gross_income: 50_000 + filing_status: SINGLE + households: + household: + members: [parent, minor, adult_dependent] + state_code: CT + output: + # Only the age 10 dependent qualifies (age <= 18) -> 1 * 250 = 250, not 500. + ct_child_tax_rebate: 250 + +- name: Federal AGI above threshold while CT AGI below it - federal phase-out applies + period: 2021 + input: + people: + parent: + age: 40 + is_tax_unit_dependent: false + child1: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 130_000 + ct_agi: 90_000 + filing_status: SINGLE + households: + household: + members: [parent, child1] + state_code: CT + output: + # Phase-out reads federal AGI (130,000), not ct_agi (90,000). 1 * 250 = 250; + # excess 30,000 over 100,000 -> 30 increments * 100 = 3,000 reduction -> 0. + ct_child_tax_rebate: 0 + +- name: Sunset - 2023 tax unit with a qualifying child receives no rebate + period: 2023 + input: + people: + parent: + age: 40 + is_tax_unit_dependent: false + child1: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 50_000 + filing_status: SINGLE + households: + household: + members: [parent, child1] + state_code: CT + output: + # amount and child_cap sunset to 0 at 2022-01-01 -> one-time 2021 rebate only. + ct_child_tax_rebate: 0 diff --git a/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py b/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py index e9d043d1d6d..60dafdaf642 100644 --- a/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py +++ b/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py @@ -10,7 +10,7 @@ class ct_child_tax_rebate(Variable): defined_for = StateCode.CT def formula(tax_unit, period, parameters): - income = tax_unit("ct_agi", period) + income = tax_unit("adjusted_gross_income", period) filing_status = tax_unit("filing_status", period) p = parameters(period).gov.states.ct.tax.income.rebate @@ -22,8 +22,12 @@ def formula(tax_unit, period, parameters): increments = np.ceil(excess / increment) total_reduction_amount = increments * reduction_per_increment - count_dependents = tax_unit("tax_unit_count_dependents", period) - capped_children = min_(count_dependents, p.child_cap) + person = tax_unit.members + age = person("age", period) + dependent = person("is_tax_unit_dependent", period) + eligible_child = (age <= p.age_limit) & dependent + count_children = tax_unit.sum(eligible_child) + capped_children = min_(count_children, p.child_cap) total_rebate = capped_children * p.amount return max_(total_rebate - total_reduction_amount, 0) From f79bd77e180c0c06adec269dc4dc394426d15c01 Mon Sep 17 00:00:00 2001 From: David Trimmer Date: Tue, 18 Aug 2026 14:46:46 -0400 Subject: [PATCH 3/5] Address @PavelMakarchuk follow-up: fix CT child tax rebate phase-out mechanics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Phase-out was subtracting a flat $100 per $1,000 over the income limit; PA 22-118 §411(b)(2) and DRS TSSB 2022-5 Q12 phase the REBATE out by 10% per $1,000, so every filer is fully phased out at threshold + $10,000 regardless of child count. Rewrite to reduction_share = min(ceil(excess/1000) * rate, 1); rebate * (1 - share). - Update expected values: single $101k/2 children 400 -> 450; HoH $165k/3-capped 250 -> 375. Add boundary cases (threshold + $10,000 -> 0; partial band -> 10% of rebate) and a 2021 refundable-flow case + a 2022 sunset case. - Add a reference (PA 22-118 §411, TSSB 2022-5) to ct_child_tax_rebate.py. - Fix stale parameter descriptions (federal, not state, AGI; rate = phase-out share) and correct the section cites from Sec. 410 to Sec. 411. No parameter values changed. CT tax suite 144/144. Co-Authored-By: Claude Opus 4.8 --- .../ct/tax/income/rebate/age_limit.yaml | 2 +- .../states/ct/tax/income/rebate/amount.yaml | 4 +- .../ct/tax/income/rebate/child_cap.yaml | 2 +- .../income/rebate/reduction/increment.yaml | 4 +- .../ct/tax/income/rebate/reduction/rate.yaml | 4 +- .../ct/tax/income/rebate/reduction/start.yaml | 4 +- .../income/rebate/ct_child_tax_rebate.yaml | 111 +++++++++++++++++- .../tax/income/rebate/ct_child_tax_rebate.py | 16 +-- 8 files changed, 125 insertions(+), 22 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml index ec6f895785b..e058f45cef1 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml @@ -10,5 +10,5 @@ metadata: href: https://portal.ct.gov/drs/credit-programs/child-tax-rebate/overview - title: OLR Report 2026-R-0020 href: https://cga.ct.gov/2026/rpt/pdf/2026-R-0020.pdf - - title: House Bill No. 5506 Public Act No. 22-118 Sec. 410 (xxvi) + - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(a)(1) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml index a8e3003c90a..15040a5f13d 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml @@ -8,8 +8,8 @@ metadata: href: https://portal.ct.gov/drs/credit-programs/child-tax-rebate/overview - title: TSSB 2022-5 - Frequently Asked Questions Concerning the Child Tax Rebate (4) href: https://portal.ct.gov/-/media/drs/publications/tssb/2022/tssb-2022-5.pdf#page=1 - - title: House Bill No. 5506 Public Act No. 22-118 Sec. 410 (xxvi) - href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 + - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(2) + href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 # The legal code section has been repealed; the rebate was a one-time 2021 payment under PA 22-118, so it sunsets in 2022. values: 2021-01-01: 250 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml index b3e764c3745..427070fe902 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml @@ -8,7 +8,7 @@ metadata: href: https://portal.ct.gov/drs/credit-programs/child-tax-rebate/overview - title: TSSB 2022-5 - Frequently Asked Questions Concerning the Child Tax Rebate (4) href: https://portal.ct.gov/-/media/drs/publications/tssb/2022/tssb-2022-5.pdf#page=1 - - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411 (b) (1) + - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(1) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 # The legal code section has been repealed; the rebate was a one-time 2021 payment under PA 22-118, so it sunsets in 2022. values: diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml index 902e879067d..48f774bf793 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml @@ -1,10 +1,10 @@ -description: Connecticut reduces the child tax rebate amount for each of these increments of state adjusted gross income exceeding the threshold. +description: Connecticut reduces the child tax rebate amount for each of these increments of federal adjusted gross income exceeding the threshold. metadata: period: year unit: currency-USD label: Connecticut child tax rebate reduction increment reference: - - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411 (b)(2) + - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(2) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 # The legal code section has been repealed values: diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml index 7bb9887aa70..0b961a5a3cf 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml @@ -1,10 +1,10 @@ -description: Connecticut reduces the personal exemption amount by this rate for each increment of state adjusted gross income exceeding the threshold. +description: Connecticut reduces the child tax rebate by this share for each increment of federal adjusted gross income exceeding the threshold. metadata: period: year unit: /1 label: Connecticut child tax rebate reduction rate reference: - - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411 (b)(2) + - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(2) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 # The legal code section has been repealed values: diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml index a75a94e1ad7..77417d8bc89 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml @@ -1,4 +1,4 @@ -description: Connecticut reduces the child tax rebate for filers with state adjusted gross income above this amount, based on filing status. +description: Connecticut reduces the child tax rebate for filers with federal adjusted gross income above this amount, based on filing status. metadata: period: year unit: currency-USD @@ -8,7 +8,7 @@ metadata: reference: - title: TSSB 2022-5 - Frequently Asked Questions Concerning the Child Tax Rebate (11) href: https://portal.ct.gov/-/media/drs/publications/tssb/2022/tssb-2022-5.pdf#page=2 - - title: House Bill No. 5506 Public Act No. 22-118 Sec. 410 (xxvi) + - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(2) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 # The legal code section has been repealed SINGLE: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml index 8b10cdb2780..3b68b6707ed 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml @@ -21,8 +21,9 @@ members: [parent, child1, child2] state_code: CT output: - # 2 * 250 = 500; excess 1,000 over 100,000 -> 1 increment * 100 = 100 reduction. - ct_child_tax_rebate: 400 + # 2 * 250 = 500; excess 1,000 over 100,000 -> ceil(1,000/1,000) = 1 increment + # -> reduction share min(1 * 0.1, 1) = 0.1; 500 * (1 - 0.1) = 450. + ct_child_tax_rebate: 450 - name: Joint with $180,000 federal AGI and 1 dependent child period: 2021 @@ -83,8 +84,9 @@ state_code: CT output: # 5 children capped at 3 -> 750; excess 5,000 over 160,000 HoH threshold - # -> 5 increments * 100 = 500 reduction; 750 - 500 = 250. - ct_child_tax_rebate: 250 + # -> ceil(5,000/1,000) = 5 increments -> reduction share min(5 * 0.1, 1) = 0.5; + # 750 * (1 - 0.5) = 375. + ct_child_tax_rebate: 375 - name: Only dependent is age 21 - no eligible child (age gate) period: 2021 @@ -157,7 +159,8 @@ state_code: CT output: # Phase-out reads federal AGI (130,000), not ct_agi (90,000). 1 * 250 = 250; - # excess 30,000 over 100,000 -> 30 increments * 100 = 3,000 reduction -> 0. + # excess 30,000 over 100,000 -> ceil(30,000/1,000) = 30 increments + # -> reduction share min(30 * 0.1, 1) capped at 1.0; 250 * (1 - 1) = 0. ct_child_tax_rebate: 0 - name: Sunset - 2023 tax unit with a qualifying child receives no rebate @@ -182,3 +185,101 @@ output: # amount and child_cap sunset to 0 at 2022-01-01 -> one-time 2021 rebate only. ct_child_tax_rebate: 0 + +- name: Single at threshold plus exactly $10,000 - fully phased out + period: 2021 + input: + people: + parent: + age: 40 + is_tax_unit_dependent: false + child1: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 110_000 + filing_status: SINGLE + households: + household: + members: [parent, child1] + state_code: CT + output: + # 1 * 250 = 250; excess 10,000 over 100,000 -> ceil(10,000/1,000) = 10 increments + # -> reduction share min(10 * 0.1, 1) = 1.0; 250 * (1 - 1) = 0. + ct_child_tax_rebate: 0 + +- name: Single in the partial phase-out band at threshold plus $9,000 + period: 2021 + input: + people: + parent: + age: 40 + is_tax_unit_dependent: false + child1: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 109_000 + filing_status: SINGLE + households: + household: + members: [parent, child1] + state_code: CT + output: + # 1 * 250 = 250; excess 9,000 over 100,000 -> ceil(9,000/1,000) = 9 increments + # -> reduction share min(9 * 0.1, 1) = 0.9; 250 * (1 - 0.9) = 25. + ct_child_tax_rebate: 25 + +- name: 2021 rebate flows through the refundable credits aggregate + period: 2021 + input: + people: + parent: + age: 40 + is_tax_unit_dependent: false + child1: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 50_000 + filing_status: SINGLE + households: + household: + members: [parent, child1] + state_code: CT + output: + # 1 * 250 = 250, AGI 50,000 below 100,000 threshold -> no reduction. + ct_child_tax_rebate: 250 + # No earned income -> ct_eitc 0, so the refundable aggregate equals the rebate. + ct_eitc: 0 + ct_refundable_credits: 250 + +- name: 2022 tax unit with a qualifying child receives no rebate (sunset) + period: 2022 + input: + people: + parent: + age: 40 + is_tax_unit_dependent: false + child1: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child1] + adjusted_gross_income: 50_000 + filing_status: SINGLE + households: + household: + members: [parent, child1] + state_code: CT + output: + # amount and child_cap sunset to 0 at 2022-01-01 -> rebate 0; also dropped from + # the refundable list at 2022-01-01. + ct_child_tax_rebate: 0 diff --git a/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py b/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py index 60dafdaf642..02660e673ed 100644 --- a/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py +++ b/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py @@ -8,6 +8,10 @@ class ct_child_tax_rebate(Variable): unit = USD definition_period = YEAR defined_for = StateCode.CT + reference = ( + "https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549", + "https://portal.ct.gov/-/media/drs/publications/tssb/2022/tssb-2022-5.pdf", + ) def formula(tax_unit, period, parameters): income = tax_unit("adjusted_gross_income", period) @@ -15,12 +19,6 @@ def formula(tax_unit, period, parameters): p = parameters(period).gov.states.ct.tax.income.rebate reduction_start = p.reduction.start[filing_status] - increment = p.reduction.increment - reduction_per_increment = p.reduction.rate * increment - - excess = max_(income - reduction_start, 0) - increments = np.ceil(excess / increment) - total_reduction_amount = increments * reduction_per_increment person = tax_unit.members age = person("age", period) @@ -30,4 +28,8 @@ def formula(tax_unit, period, parameters): capped_children = min_(count_children, p.child_cap) total_rebate = capped_children * p.amount - return max_(total_rebate - total_reduction_amount, 0) + excess = max_(income - reduction_start, 0) + increments = np.ceil(excess / p.reduction.increment) + reduction_share = min_(increments * p.reduction.rate, 1) + + return total_rebate * (1 - reduction_share) From 3e8aad417e9bcbc0c6888dd0f73364f0e23e462b Mon Sep 17 00:00:00 2001 From: David Trimmer Date: Mon, 24 Aug 2026 09:46:48 -0400 Subject: [PATCH 4/5] Address @PavelMakarchuk review: fix phantom pre-2021 rebate, references, coverage (CT child tax rebate) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - C1 (critical): parameter backdating re-dated the rebate's earliest entry to 2015-01-01, paying a phantom rebate for 2015-2020. Add explicit 2015-01-01: 0 to amount.yaml and child_cap.yaml (verified: a 2020 CT household with a child now gets $0; 2021 unchanged). Add a 2020 regression-guard test. - A1/A6/S2/S4/S6: add PA 22-118 §411(b)(1)/(b)(4) refs to refundable.yaml; drop the non-corroborating OLR citation on age_limit; add page anchors + booking-rationale notes. - A5: child_cap unit currency-USD -> person. A7: reword the false 'repealed' comment in 5 files to uncodified session law. A8/A9/S1: document the take-up, domicile, and dependency approximations. S3/S5: fix garbled child_cap wording/label, amount comma, .1->0.1, YAML order. - A2/A3/A4: phase-out ceil + threshold-boundary tests; age-18/19 and non-dependent-minor gates; SEPARATE/SURVIVING_SPOUSE/JOINT threshold pins; $750 HOH max; positive-EITC refundable e2e. S8: margins, newborn/negative-AGI/non-CT cases. Only new param value is the 2015-01-01: 0 sunset floor. CT child tax rebate suite 28/28. Co-Authored-By: Claude Opus 4.8 --- .../ct/tax/income/credits/refundable.yaml | 13 +- .../ct/tax/income/rebate/age_limit.yaml | 6 +- .../states/ct/tax/income/rebate/amount.yaml | 16 +- .../ct/tax/income/rebate/child_cap.yaml | 14 +- .../income/rebate/reduction/increment.yaml | 3 +- .../ct/tax/income/rebate/reduction/rate.yaml | 5 +- .../ct/tax/income/rebate/reduction/start.yaml | 5 +- .../income/rebate/ct_child_tax_rebate.yaml | 461 +++++++++++++++++- .../tax/income/rebate/ct_child_tax_rebate.py | 16 +- 9 files changed, 513 insertions(+), 26 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/credits/refundable.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/credits/refundable.yaml index 3d4a3e95570..12c92357bea 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/credits/refundable.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/credits/refundable.yaml @@ -3,11 +3,18 @@ metadata: unit: list period: year label: Connecticut refundable credits - + reference: + - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(1) + href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 + - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(4) + href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 values: - # The 2022 child tax rebate (PA 22-118) is a refundable rebate keyed to the + # The child tax rebate (PA 22-118 Sec. 411) is a refundable rebate keyed to the # 2021 return, booked in the eligibility year like other prior-year rebates - # (cf. ri_child_tax_rebate, nm_2021_income_rebate). + # (cf. ri_child_tax_rebate, nm_2021_income_rebate). TSSB 2022-5 Q5 states the + # rebate "is not a credit"; booking it as a refundable credit follows the RI/NM + # convention and is the correct cash treatment (it raises household_net_income + # and does not touch SALT or ct_withheld_income_tax). 2021-01-01: - ct_eitc - ct_child_tax_rebate diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml index e058f45cef1..70ae1cbf50d 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml @@ -1,6 +1,4 @@ description: Connecticut limits its child tax rebate to dependent children this age or younger under the Child Tax Rebate program. -values: - 2021-01-01: 18 metadata: unit: year period: year @@ -8,7 +6,7 @@ metadata: reference: - title: 2022 Child Tax Rebate href: https://portal.ct.gov/drs/credit-programs/child-tax-rebate/overview - - title: OLR Report 2026-R-0020 - href: https://cga.ct.gov/2026/rpt/pdf/2026-R-0020.pdf - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(a)(1) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 +values: + 2021-01-01: 18 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml index 15040a5f13d..ad8ea569c34 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml @@ -1,4 +1,4 @@ -description: Connecticut provides a child tax rebate of this amount, for each eligible child. +description: Connecticut provides a child tax rebate of this amount for each eligible child under the Child Tax Rebate program. metadata: period: year unit: currency-USD @@ -6,11 +6,17 @@ metadata: reference: - title: 2022 Child Tax Rebate href: https://portal.ct.gov/drs/credit-programs/child-tax-rebate/overview - - title: TSSB 2022-5 - Frequently Asked Questions Concerning the Child Tax Rebate (4) + - title: TSSB 2022-5 - Frequently Asked Questions Concerning the Child Tax Rebate Q4 href: https://portal.ct.gov/-/media/drs/publications/tssb/2022/tssb-2022-5.pdf#page=1 - - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(2) - href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 - # The legal code section has been repealed; the rebate was a one-time 2021 payment under PA 22-118, so it sunsets in 2022. + - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(1) + href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 + # PA 22-118 Sec. 411 is uncodified session law, keyed to TY2021, never added to + # the General Statutes; it sunsets to 0 in 2022. The one-time character is stated + # in Sec. 411(b)(1) (p. 548). TSSB 2022-5 cites this as H.B. 5506 Sec. 415; the + # enrolled act renumbers it Sec. 411 (same provision). values: + # No rebate before the 2021 tax year; the explicit 0 blocks backdating from + # phantoming the 2021 value into prior years at system build. + 2015-01-01: 0 2021-01-01: 250 2022-01-01: 0 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml index 427070fe902..3f05ca262b7 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/child_cap.yaml @@ -1,16 +1,20 @@ -description: Connecticut caps the child for tax rebate at this number. +description: Connecticut caps its child tax rebate at this number of children under the Child Tax Rebate program. metadata: period: year - unit: currency-USD - label: Connecticut tax rebate child cap + unit: person + label: Connecticut child tax rebate child cap reference: - title: 2022 Child Tax Rebate href: https://portal.ct.gov/drs/credit-programs/child-tax-rebate/overview - - title: TSSB 2022-5 - Frequently Asked Questions Concerning the Child Tax Rebate (4) + - title: TSSB 2022-5 - Frequently Asked Questions Concerning the Child Tax Rebate Q4 href: https://portal.ct.gov/-/media/drs/publications/tssb/2022/tssb-2022-5.pdf#page=1 - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(1) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 - # The legal code section has been repealed; the rebate was a one-time 2021 payment under PA 22-118, so it sunsets in 2022. + # PA 22-118 Sec. 411 is uncodified session law, keyed to TY2021, never added to + # the General Statutes; it sunsets to 0 in 2022. values: + # No rebate before the 2021 tax year; the explicit 0 blocks backdating from + # phantoming the 2021 value into prior years at system build. + 2015-01-01: 0 2021-01-01: 3 2022-01-01: 0 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml index 48f774bf793..4cfbc1ba62f 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml @@ -6,6 +6,7 @@ metadata: reference: - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(2) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 - # The legal code section has been repealed + # PA 22-118 Sec. 411 is uncodified session law, keyed to TY2021, never added to + # the General Statutes; it sunsets to 0 in 2022. values: 2021-01-01: 1_000 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml index 0b961a5a3cf..80a8d3500da 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml @@ -6,6 +6,7 @@ metadata: reference: - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(2) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 - # The legal code section has been repealed + # PA 22-118 Sec. 411 is uncodified session law, keyed to TY2021, never added to + # the General Statutes; it sunsets to 0 in 2022. values: - 2021-01-01: .1 + 2021-01-01: 0.1 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml index 77417d8bc89..48ebdfb9259 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml @@ -6,11 +6,12 @@ metadata: breakdown: - filing_status reference: - - title: TSSB 2022-5 - Frequently Asked Questions Concerning the Child Tax Rebate (11) + - title: TSSB 2022-5 - Frequently Asked Questions Concerning the Child Tax Rebate Q11 href: https://portal.ct.gov/-/media/drs/publications/tssb/2022/tssb-2022-5.pdf#page=2 - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(2) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 - # The legal code section has been repealed + # PA 22-118 Sec. 411 is uncodified session law, keyed to TY2021, never added to + # the General Statutes; it sunsets to 0 in 2022. SINGLE: 2021-01-01: 100_000 HEAD_OF_HOUSEHOLD: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml index 3b68b6707ed..43cb65be665 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml @@ -280,6 +280,463 @@ members: [parent, child1] state_code: CT output: - # amount and child_cap sunset to 0 at 2022-01-01 -> rebate 0; also dropped from - # the refundable list at 2022-01-01. + # amount and child_cap sunset to 0 at 2022-01-01 -> rebate 0. The list-drop at + # 2022-01-01 is not observable here (the rebate is already 0 from the sunset); + # ct_refundable_credits below equals ct_eitc alone, with the rebate contributing 0. ct_child_tax_rebate: 0 + ct_eitc: 0 + ct_refundable_credits: 0 + +# --------------------------------------------------------------------------- +# A2 - phase-out boundary (locks np.ceil "or fraction thereof") +# --------------------------------------------------------------------------- + +- name: Case 13, SINGLE $1 over threshold takes one full increment. + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 100_001 + filing_status: SINGLE + households: + household: + members: [person1, person2] + state_code: CT + output: + # 1 * 250 = 250; excess 1 over 100,000 -> ceil(1/1,000) = 1 increment + # -> reduction share min(1 * 0.1, 1) = 0.1; 250 * (1 - 0.1) = 225. + ct_child_tax_rebate: 225 + absolute_error_margin: 0.01 + +- name: Case 14, SINGLE exactly at threshold takes no reduction. + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 100_000 + filing_status: SINGLE + households: + household: + members: [person1, person2] + state_code: CT + output: + # 1 * 250 = 250; excess max(100,000 - 100,000, 0) = 0 -> no increments; + # reduction only applies to AGI OVER the threshold. 250 * (1 - 0) = 250. + ct_child_tax_rebate: 250 + absolute_error_margin: 0.01 + +- name: Case 15, SINGLE mid-fraction rounds up to one increment. + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 10 + is_tax_unit_dependent: true + person3: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2, person3] + adjusted_gross_income: 100_500 + filing_status: SINGLE + households: + household: + members: [person1, person2, person3] + state_code: CT + output: + # 2 * 250 = 500; excess 500 over 100,000 -> ceil(500/1,000) = 1 increment + # -> reduction share min(1 * 0.1, 1) = 0.1; 500 * (1 - 0.1) = 450. + ct_child_tax_rebate: 450 + absolute_error_margin: 0.01 + +# --------------------------------------------------------------------------- +# A3 - age + dependency boundary +# --------------------------------------------------------------------------- + +- name: Case 16, dependent aged exactly 18 counts. + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 18 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 50_000 + filing_status: SINGLE + households: + household: + members: [person1, person2] + state_code: CT + output: + # age 18 <= age_limit 18 and dependent -> 1 eligible child; AGI below + # threshold -> 1 * 250 = 250. + ct_child_tax_rebate: 250 + absolute_error_margin: 0.01 + +- name: Case 17, dependent aged 19 does not count. + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 19 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 50_000 + filing_status: SINGLE + households: + household: + members: [person1, person2] + state_code: CT + output: + # age 19 > age_limit 18 -> 0 eligible children -> rebate 0. + ct_child_tax_rebate: 0 + absolute_error_margin: 0.01 + +- name: Case 18, non-dependent minor does not count (& dependent conjunction). + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 17 + is_tax_unit_dependent: false + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 50_000 + filing_status: SINGLE + households: + household: + members: [person1, person2] + state_code: CT + output: + # age 17 <= 18 but is_tax_unit_dependent false -> fails the & dependent + # conjunction -> 0 eligible children -> rebate 0. + ct_child_tax_rebate: 0 + absolute_error_margin: 0.01 + +# --------------------------------------------------------------------------- +# A4 - filing status thresholds + refundable aggregate +# --------------------------------------------------------------------------- + +- name: Case 19, SEPARATE $1 under 100,000 threshold takes no reduction. + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 99_999 + filing_status: SEPARATE + households: + household: + members: [person1, person2] + state_code: CT + output: + # SEPARATE threshold 100,000; 99,999 below -> no reduction -> 1 * 250 = 250. + ct_child_tax_rebate: 250 + absolute_error_margin: 0.01 + +- name: Case 20, SEPARATE $1 over 100,000 threshold takes one increment. + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 100_001 + filing_status: SEPARATE + households: + household: + members: [person1, person2] + state_code: CT + output: + # SEPARATE threshold 100,000; excess 1 -> ceil(1/1,000) = 1 increment + # -> 250 * (1 - 0.1) = 225. Pins the SEPARATE threshold at 100,000. + ct_child_tax_rebate: 225 + absolute_error_margin: 0.01 + +- name: Case 21, SURVIVING_SPOUSE $1 under 200,000 threshold takes no reduction. + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 199_999 + filing_status: SURVIVING_SPOUSE + households: + household: + members: [person1, person2] + state_code: CT + output: + # SURVIVING_SPOUSE threshold 200,000; 199,999 below -> no reduction + # -> 1 * 250 = 250. + ct_child_tax_rebate: 250 + absolute_error_margin: 0.01 + +- name: Case 22, SURVIVING_SPOUSE $1 over 200,000 threshold takes one increment. + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 200_001 + filing_status: SURVIVING_SPOUSE + households: + household: + members: [person1, person2] + state_code: CT + output: + # SURVIVING_SPOUSE threshold 200,000; excess 1 -> ceil(1/1,000) = 1 increment + # -> 250 * (1 - 0.1) = 225. Pins the SURVIVING_SPOUSE threshold at 200,000. + ct_child_tax_rebate: 225 + absolute_error_margin: 0.01 + +- name: Case 23, JOINT $1 over 200,000 threshold pins the JOINT threshold. + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 38 + is_tax_unit_dependent: false + person3: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2, person3] + adjusted_gross_income: 200_001 + filing_status: JOINT + households: + household: + members: [person1, person2, person3] + state_code: CT + output: + # JOINT threshold 200,000; excess 1 -> ceil(1/1,000) = 1 increment + # -> 250 * (1 - 0.1) = 225. Would change if the JOINT threshold moved. + ct_child_tax_rebate: 225 + absolute_error_margin: 0.01 + +- name: Case 24, HEAD_OF_HOUSEHOLD headline maximum rebate of 750. + period: 2021 + input: + people: + person1: + age: 45 + is_tax_unit_dependent: false + person2: + age: 15 + is_tax_unit_dependent: true + person3: + age: 13 + is_tax_unit_dependent: true + person4: + age: 11 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + adjusted_gross_income: 160_000 + filing_status: HEAD_OF_HOUSEHOLD + households: + household: + members: [person1, person2, person3, person4] + state_code: CT + output: + # 3 children capped at 3 -> 750; AGI exactly at HoH threshold 160,000 + # -> excess 0 -> no reduction -> 750. Headline statutory maximum. + ct_child_tax_rebate: 750 + absolute_error_margin: 0.01 + +- name: Case 25, positive EITC and rebate flow through the refundable aggregate. + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 50_000 + eitc: 2_000 + filing_status: SINGLE + households: + household: + members: [person1, person2] + state_code: CT + output: + # Rebate: 1 * 250 = 250, AGI 50,000 below 100,000 -> no reduction. + ct_child_tax_rebate: 250 + # ct_eitc = federal eitc 2,000 * 2021 match 0.305 = 610 (nonzero, unlike the + # degenerate line-237 case where ct_eitc is 0). + ct_eitc: 610 + # Refundable aggregate = ct_eitc 610 + ct_child_tax_rebate 250 = 860. + ct_refundable_credits: 860 + absolute_error_margin: 0.01 + +# --------------------------------------------------------------------------- +# S8 - polish: newborn, negative AGI, non-CT, 2020 phantom-rebate guard +# --------------------------------------------------------------------------- + +- name: Case 26, newborn age 0 dependent counts. + period: 2021 + input: + people: + person1: + age: 30 + is_tax_unit_dependent: false + person2: + age: 0 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 40_000 + filing_status: SINGLE + households: + household: + members: [person1, person2] + state_code: CT + output: + # age 0 <= 18 and dependent -> 1 eligible child; AGI below threshold + # -> 1 * 250 = 250. + ct_child_tax_rebate: 250 + absolute_error_margin: 0.01 + +- name: Case 27, negative AGI floors the excess to zero (full rebate). + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: -20_000 + filing_status: SINGLE + households: + household: + members: [person1, person2] + state_code: CT + output: + # excess = max(-20,000 - 100,000, 0) = 0 -> no reduction -> 1 * 250 = 250. + ct_child_tax_rebate: 250 + absolute_error_margin: 0.01 + +- name: Case 28, non-CT household receives no rebate (defined_for CT). + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 50_000 + filing_status: SINGLE + households: + household: + members: [person1, person2] + state_code: NY + output: + # defined_for StateCode.CT -> non-CT household gets 0 regardless of children. + ct_child_tax_rebate: 0 + absolute_error_margin: 0.01 + +- name: Case 29, 2020 phantom-rebate regression guard (C1 backdating fix). + period: 2020 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + adjusted_gross_income: 50_000 + filing_status: SINGLE + households: + household: + members: [person1, person2] + state_code: CT + output: + # Explicit 2015-01-01: 0 in amount.yaml/child_cap.yaml blocks backdating from + # phantoming the 2021 value into 2020 -> rebate 0 despite a qualifying child. + ct_child_tax_rebate: 0 + absolute_error_margin: 0.01 diff --git a/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py b/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py index 02660e673ed..aaefe4f28d2 100644 --- a/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py +++ b/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py @@ -7,13 +7,20 @@ class ct_child_tax_rebate(Variable): label = "Connecticut child tax rebate" unit = USD definition_period = YEAR + # Assumes 100% take-up: PA 22-118 Sec. 411(b)(3) required an electronic + # application to DRS by 2022-07-31 (TSSB 2022-5 Q5), which PolicyEngine does + # not model, so the 2021 aggregate is an upper bound. DRS's offset of the + # rebate against outstanding tax debts (Q19) is likewise unmodeled. defined_for = StateCode.CT reference = ( - "https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549", - "https://portal.ct.gov/-/media/drs/publications/tssb/2022/tssb-2022-5.pdf", + "https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548", + "https://portal.ct.gov/-/media/drs/publications/tssb/2022/tssb-2022-5.pdf#page=1", ) def formula(tax_unit, period, parameters): + # Statutory domicile test is 2022 domicile at application time + # (Sec. 411(a)(2); TSSB 2022-5 Q10/Q18), approximated here by 2021 CT + # residence via defined_for, matching the RI analogue. income = tax_unit("adjusted_gross_income", period) filing_status = tax_unit("filing_status", period) p = parameters(period).gov.states.ct.tax.income.rebate @@ -21,7 +28,12 @@ def formula(tax_unit, period, parameters): reduction_start = p.reduction.start[filing_status] person = tax_unit.members + # Age is measured at the period, not "as of December 31, 2021" + # (Sec. 411(a)(1)); PE's age has no within-year date (PE-wide limitation). age = person("age", period) + # is_tax_unit_dependent (structurally ~head & ~spouse) proxies + # Sec. 411(b)(1)'s requirement that the child be validly claimed as a + # dependent on the 2021 federal return. dependent = person("is_tax_unit_dependent", period) eligible_child = (age <= p.age_limit) & dependent count_children = tax_unit.sum(eligible_child) From c30153ed1b6ee018f0d26806ae4f09cb205b7922 Mon Sep 17 00:00:00 2001 From: David Trimmer Date: Tue, 25 Aug 2026 10:15:02 -0400 Subject: [PATCH 5/5] Address 8/25 review: fix $250 citation, comments, and tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Applies the Critical, Should-Address, and Suggestion items from PavelMakarchuk's 2026-08-25 review of the CT child tax rebate re-timing. No parameter value or formula logic changed. - C1: correct the $250 amount citation in rebate/amount.yaml to Sec. 411(b)(2)/p.549 (the clause that states the amount), keeping the (b)(1)/p.548 cite as an additional reference for the TY2021 character. - A1: reword the misleading "sunsets to 0 in 2022" comments on reduction/{increment,rate,start} — the sunset is carried by amount.yaml and child_cap.yaml; note increment is deliberately never zeroed to avoid a divide-by-zero in the phase-out. - A2: add an end-to-end 2021 integration case (single parent, one child, AGI 50,000) asserting ct_child_tax_rebate 250, ct_refundable_credits 250, and ct_income_tax 1,820 so the rebate booking flows through. - A3: restore the "…under the Child Tax Rebate program." description suffix on reduction/{increment,rate,start}. - S1: fix the TSSB deadline citation (Q5 -> Q6) in the variable comment. - S2: document the deliberate sentinel asymmetry on age_limit.yaml. - S5: add a JOINT exactly-at-threshold ($200,000) case -> full 500. - S6: add a child-cap boundary at exactly 4 children -> capped 3 -> 750. - S7: reorder reduction/start filing-status keys to FilingStatus enum order. - S8: replace the "line-237" comment reference with a domain description. - S9: record that at $110,000 the statute yields 100% reduction ($0), reconciling TSSB Q12's loose "<= $110,000" wording. S3 (no single authoritative source for the non-refundable list) and S4 (rebate cites on the refundable list) left as-is by design. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01YCwrSsGY7vPCpKYGfV1xRr --- .../ct/tax/income/rebate/age_limit.yaml | 3 + .../states/ct/tax/income/rebate/amount.yaml | 9 ++- .../income/rebate/reduction/increment.yaml | 8 +- .../ct/tax/income/rebate/reduction/rate.yaml | 6 +- .../ct/tax/income/rebate/reduction/start.yaml | 14 ++-- .../gov/states/ct/tax/income/integration.yaml | 45 +++++++++++ .../income/rebate/ct_child_tax_rebate.yaml | 76 ++++++++++++++++++- .../tax/income/rebate/ct_child_tax_rebate.py | 5 +- 8 files changed, 151 insertions(+), 15 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml index 70ae1cbf50d..c1788f34ad1 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/age_limit.yaml @@ -8,5 +8,8 @@ metadata: href: https://portal.ct.gov/drs/credit-programs/child-tax-rebate/overview - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(a)(1) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 + # The sentinel asymmetry with amount.yaml / child_cap.yaml is deliberate: a + # leaked/backdated age_limit is inert while the amount is 0 (rebate = + # capped_children * amount = 0), so age_limit need not carry a 2015/2022 sentinel. values: 2021-01-01: 18 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml index ad8ea569c34..809fda31ca6 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/amount.yaml @@ -8,12 +8,15 @@ metadata: href: https://portal.ct.gov/drs/credit-programs/child-tax-rebate/overview - title: TSSB 2022-5 - Frequently Asked Questions Concerning the Child Tax Rebate Q4 href: https://portal.ct.gov/-/media/drs/publications/tssb/2022/tssb-2022-5.pdf#page=1 + - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(2) + href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(1) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=548 # PA 22-118 Sec. 411 is uncodified session law, keyed to TY2021, never added to - # the General Statutes; it sunsets to 0 in 2022. The one-time character is stated - # in Sec. 411(b)(1) (p. 548). TSSB 2022-5 cites this as H.B. 5506 Sec. 415; the - # enrolled act renumbers it Sec. 411 (same provision). + # the General Statutes; it sunsets to 0 in 2022. The $250 amount is set in the + # opening clause of Sec. 411(b)(2) (p. 549); the one-time/TY2021 character is + # stated in Sec. 411(b)(1) (p. 548). TSSB 2022-5 cites this as H.B. 5506 + # Sec. 415; the enrolled act renumbers it Sec. 411 (same provision). values: # No rebate before the 2021 tax year; the explicit 0 blocks backdating from # phantoming the 2021 value into prior years at system build. diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml index 4cfbc1ba62f..f6a117c9250 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/increment.yaml @@ -1,4 +1,4 @@ -description: Connecticut reduces the child tax rebate amount for each of these increments of federal adjusted gross income exceeding the threshold. +description: Connecticut reduces the child tax rebate amount for each of these increments of federal adjusted gross income exceeding the threshold under the Child Tax Rebate program. metadata: period: year unit: currency-USD @@ -7,6 +7,10 @@ metadata: - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(2) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 # PA 22-118 Sec. 411 is uncodified session law, keyed to TY2021, never added to - # the General Statutes; it sunsets to 0 in 2022. + # the General Statutes. This file does NOT carry the 2022 sunset: that is carried + # by amount.yaml / child_cap.yaml (rebate = capped_children * amount, both 0 + # outside 2021), so this reduction increment is inert outside 2021. `increment` + # is deliberately NEVER zeroed because a 0 here divides by zero in + # ct_child_tax_rebate.py (np.ceil(excess / increment)). values: 2021-01-01: 1_000 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml index 80a8d3500da..b2274720a55 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/rate.yaml @@ -1,4 +1,4 @@ -description: Connecticut reduces the child tax rebate by this share for each increment of federal adjusted gross income exceeding the threshold. +description: Connecticut reduces the child tax rebate by this share for each increment of federal adjusted gross income exceeding the threshold under the Child Tax Rebate program. metadata: period: year unit: /1 @@ -7,6 +7,8 @@ metadata: - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(2) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 # PA 22-118 Sec. 411 is uncodified session law, keyed to TY2021, never added to - # the General Statutes; it sunsets to 0 in 2022. + # the General Statutes. This file does NOT carry the 2022 sunset: that is carried + # by amount.yaml / child_cap.yaml (rebate = capped_children * amount, both 0 + # outside 2021), so this reduction rate is inert outside 2021. values: 2021-01-01: 0.1 diff --git a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml index 48ebdfb9259..0b2773e8b12 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/income/rebate/reduction/start.yaml @@ -1,4 +1,4 @@ -description: Connecticut reduces the child tax rebate for filers with federal adjusted gross income above this amount, based on filing status. +description: Connecticut reduces the child tax rebate for filers with federal adjusted gross income above this amount, based on filing status, under the Child Tax Rebate program. metadata: period: year unit: currency-USD @@ -11,14 +11,16 @@ metadata: - title: House Bill No. 5506 Public Act No. 22-118 Sec. 411(b)(2) href: https://cga.ct.gov/2022/ACT/PA/PDF/2022PA-00118-R00HB-05506-PA.PDF#page=549 # PA 22-118 Sec. 411 is uncodified session law, keyed to TY2021, never added to - # the General Statutes; it sunsets to 0 in 2022. + # the General Statutes. This file does NOT carry the 2022 sunset: that is carried + # by amount.yaml / child_cap.yaml (rebate = capped_children * amount, both 0 + # outside 2021), so this reduction start is inert outside 2021. SINGLE: 2021-01-01: 100_000 -HEAD_OF_HOUSEHOLD: - 2021-01-01: 160_000 JOINT: 2021-01-01: 200_000 -SURVIVING_SPOUSE: - 2021-01-01: 200_000 SEPARATE: 2021-01-01: 100_000 +HEAD_OF_HOUSEHOLD: + 2021-01-01: 160_000 +SURVIVING_SPOUSE: + 2021-01-01: 200_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/integration.yaml index c9e8e9aa9ce..7b53b9c598d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/integration.yaml @@ -134,3 +134,48 @@ ct_social_security_benefit_adjustment: 12_246 ct_agi: 100_559 ct_income_tax: 4_671 + +- name: CT 2021 single parent, one child - child tax rebate flows through ct_income_tax + period: 2021 + absolute_error_margin: 0.01 + input: + people: + parent: + age: 40 + is_tax_unit_dependent: false + child: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [parent, child] + adjusted_gross_income: 50_000 + filing_status: SINGLE + households: + household: + members: [parent, child] + state_code: CT + output: + # --- Rebate (booked in the 2021 eligibility year; the chain this PR fixes) --- + # 1 eligible child (age 8 <= 18, dependent); AGI 50,000 < SINGLE threshold + # 100,000 -> no phase-out -> 1 * 250 = 250. + ct_child_tax_rebate: 250 + # --- Refundable credits = ct_eitc + ct_child_tax_rebate --- + # No earned income -> federal EITC 0 -> ct_eitc 0; so aggregate = rebate = 250. + ct_refundable_credits: 250 + # --- Baseline ct_income_tax, hand-derived from 2021 CT parameters --- + # ct_agi = adjusted_gross_income 50,000 (no CT additions/subtractions). + # Personal exemption (SINGLE): max 15,000; reduction start 30,000; + # excess 20,000 -> ceil(20,000/1,000)=20 increments * 1,000 = 20,000 reduction + # -> max(15,000 - 20,000, 0) = 0 (fully phased out). + # ct_taxable_income = max(50,000 - 0, 0) = 50,000. + # Tax (SINGLE 2021 brackets): 10,000 @ 3% = 300; 40,000 @ 5% = 2,000 + # (50,000 is the start of the 5.5% bracket, 0 there) -> 2,300. + # Phase-out add-back: SINGLE start 56,500 > 50,000 -> 0. + # Recapture: low bracket not in effect in 2021; middle start 200,000 -> 0. + # Personal credit rate at ct_agi 50,000 (SINGLE agi table, bracket + # [33,300, 60,000)) = 0.10 -> credit 0.10 * 2,300 = 230. + # ct_income_tax_after_personal_credits = max(0, 2,300 - 230) = 2,070. + # ct_amt 0; non-refundable credits 0 (no property tax) -> before-refundable 2,070. + # ct_income_tax = 2,070 - ct_refundable_credits 250 = 1,820. + ct_income_tax: 1_820 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml index 43cb65be665..048f7b445ec 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.yaml @@ -633,7 +633,7 @@ # Rebate: 1 * 250 = 250, AGI 50,000 below 100,000 -> no reduction. ct_child_tax_rebate: 250 # ct_eitc = federal eitc 2,000 * 2021 match 0.305 = 610 (nonzero, unlike the - # degenerate line-237 case where ct_eitc is 0). + # zero-earned-income rebate-only case above where ct_eitc is 0). ct_eitc: 610 # Refundable aggregate = ct_eitc 610 + ct_child_tax_rebate 250 = 860. ct_refundable_credits: 860 @@ -740,3 +740,77 @@ # phantoming the 2021 value into 2020 -> rebate 0 despite a qualifying child. ct_child_tax_rebate: 0 absolute_error_margin: 0.01 + +# --------------------------------------------------------------------------- +# S5 - JOINT exactly at threshold takes no reduction (full rebate) +# --------------------------------------------------------------------------- + +- name: Case 30, JOINT exactly at 200,000 threshold takes no reduction. + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 38 + is_tax_unit_dependent: false + person3: + age: 10 + is_tax_unit_dependent: true + person4: + age: 8 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + adjusted_gross_income: 200_000 + filing_status: JOINT + households: + household: + members: [person1, person2, person3, person4] + state_code: CT + output: + # JOINT threshold 200,000; excess max(200,000 - 200,000, 0) = 0 -> no increments; + # reduction only applies to AGI OVER the threshold. 2 * 250 = 500 * (1 - 0) = 500. + # Mirrors the SINGLE at-threshold precedent (Case 14) for the JOINT threshold. + ct_child_tax_rebate: 500 + absolute_error_margin: 0.01 + +# --------------------------------------------------------------------------- +# S6 - child-cap boundary at exactly 4 children (first count over the cap) +# --------------------------------------------------------------------------- + +- name: Case 31, exactly 4 children caps to 3 (750, no phase-out). + period: 2021 + input: + people: + person1: + age: 40 + is_tax_unit_dependent: false + person2: + age: 12 + is_tax_unit_dependent: true + person3: + age: 10 + is_tax_unit_dependent: true + person4: + age: 8 + is_tax_unit_dependent: true + person5: + age: 6 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2, person3, person4, person5] + adjusted_gross_income: 50_000 + filing_status: HEAD_OF_HOUSEHOLD + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: CT + output: + # 4 eligible children capped at child_cap 3 -> 3 * 250 = 750; AGI 50,000 below + # HoH threshold 160,000 -> excess 0 -> no reduction -> 750. Pins the child cap. + ct_child_tax_rebate: 750 + absolute_error_margin: 0.01 diff --git a/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py b/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py index aaefe4f28d2..b9c8ceefdcf 100644 --- a/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py +++ b/policyengine_us/variables/gov/states/ct/tax/income/rebate/ct_child_tax_rebate.py @@ -8,7 +8,7 @@ class ct_child_tax_rebate(Variable): unit = USD definition_period = YEAR # Assumes 100% take-up: PA 22-118 Sec. 411(b)(3) required an electronic - # application to DRS by 2022-07-31 (TSSB 2022-5 Q5), which PolicyEngine does + # application to DRS by 2022-07-31 (TSSB 2022-5 Q6), which PolicyEngine does # not model, so the 2021 aggregate is an upper bound. DRS's offset of the # rebate against outstanding tax debts (Q19) is likewise unmodeled. defined_for = StateCode.CT @@ -42,6 +42,9 @@ def formula(tax_unit, period, parameters): excess = max_(income - reduction_start, 0) increments = np.ceil(excess / p.reduction.increment) + # At exactly AGI $110,000 a single filer hits 10 increments x 10% = 100% + # reduction = $0, which Sec. 411(b)(2) controls; TSSB 2022-5 Q12's "less + # than or equal to $110,000" wording reads loosely but is not a discrepancy. reduction_share = min_(increments * p.reduction.rate, 1) return total_rebate * (1 - reduction_share)