Skip to content

Commit 0900111

Browse files
Create phaseout for NYC school credit for NYC CTC proposal (#5510)
* Include the New York 2025 inflation rebate in the net income tree Fixes #5507 * format * docstring, reference and format * minor * readme
1 parent 7443123 commit 0900111

File tree

9 files changed

+204
-0
lines changed

9 files changed

+204
-0
lines changed

changelog_entry.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- bump: minor
2+
changes:
3+
added:
4+
- NYC school tax credit phase out reform.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
description: The NYC school tax credit phases out with state adjusted gross income, if this is true.
2+
3+
values:
4+
0000-01-01: false
5+
6+
metadata:
7+
unit: bool
8+
period: year
9+
label: NYC school tax credit phase out in effect
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
description: New York reduces the NYC school tax credit for joint filers and surviving spouses at this rate, based on state adjusted gross income.
2+
metadata:
3+
type: marginal_rate
4+
threshold_unit: currency-USD
5+
rate_unit: /1
6+
period: year
7+
label: NYC school tax credit joint and surviving spouse reduction rate
8+
reference:
9+
- title: New York Senate Bill S2238 §1(4-c)(B)
10+
href: https://www.nysenate.gov/legislation/bills/2025/S2238
11+
12+
brackets:
13+
- threshold:
14+
2025-01-01: 0
15+
rate:
16+
2025-01-01: 0
17+
- threshold:
18+
2025-01-01: 150_000
19+
rate:
20+
2025-01-01: 0.05
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
description: New York reduces the NYC school tax credit for single, separate, and head of household filers, based on state adjusted gross income.
2+
metadata:
3+
type: marginal_rate
4+
threshold_unit: currency-USD
5+
rate_unit: /1
6+
period: year
7+
label: NYC school tax credit other reduction rate
8+
reference:
9+
- title: New York Senate Bill S2238 §1(4-c)(A)
10+
href: https://www.nysenate.gov/legislation/bills/2025/S2238
11+
12+
brackets:
13+
- threshold:
14+
2025-01-01: 0
15+
rate:
16+
2025-01-01: 0
17+
- threshold:
18+
2025-01-01: 75_000
19+
rate:
20+
2025-01-01: 0.05
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## NYC School Tax Credit Reform with Phase-Out
2+
3+
# This code defines a policy reform for implementing a New York City School Tax Credit with a phase-out mechanism, as outlined in [Senate Bill S2238](https://www.nysenate.gov/legislation/bills/2025/S2238).
4+
5+
# The credit is phased out based on state adjusted gross income (AGI) and filing status.
6+
7+
# The phase-out start threshold is doubled for joint filers and surviving spouses.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .nyc_school_tax_credit_with_phase_out import (
2+
create_nyc_school_tax_credit_with_phase_out_reform,
3+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
from policyengine_us.model_api import *
2+
from policyengine_core.periods import period as period_
3+
4+
5+
def create_nyc_school_tax_credit_with_phase_out() -> Reform:
6+
class nyc_school_tax_credit_phase_out(Variable):
7+
value_type = float
8+
unit = USD
9+
entity = TaxUnit
10+
label = "NYC School Tax Credit Phase Out"
11+
definition_period = YEAR
12+
defined_for = "in_nyc"
13+
reference = "https://www.nysenate.gov/legislation/bills/2025/S2238"
14+
15+
def formula(tax_unit, period, parameters):
16+
agi = tax_unit("ny_agi", period)
17+
filing_status = tax_unit("filing_status", period)
18+
joint = filing_status == filing_status.possible_values.JOINT
19+
surviving_spouse = (
20+
filing_status == filing_status.possible_values.SURVIVING_SPOUSE
21+
)
22+
joint_filers = joint | surviving_spouse
23+
p = parameters(period).gov.contrib.local.nyc.stc.phase_out.rate
24+
return where(
25+
joint_filers,
26+
p.joint_and_surviving_spouse.calc(agi),
27+
p.other.calc(agi),
28+
)
29+
30+
class nyc_school_tax_credit(Variable):
31+
value_type = float
32+
entity = TaxUnit
33+
label = "NYC School Tax Credit"
34+
unit = USD
35+
definition_period = YEAR
36+
defined_for = "in_nyc"
37+
reference = "https://www.nysenate.gov/legislation/bills/2025/S2238"
38+
39+
def formula(tax_unit, period, parameters):
40+
base_amount = add(
41+
tax_unit,
42+
period,
43+
[
44+
"nyc_school_tax_credit_fixed_amount",
45+
"nyc_school_tax_credit_rate_reduction_amount",
46+
],
47+
)
48+
phase_out = tax_unit("nyc_school_tax_credit_phase_out", period)
49+
return max_(0, base_amount - phase_out)
50+
51+
class reform(Reform):
52+
def apply(self):
53+
self.update_variable(nyc_school_tax_credit_phase_out)
54+
self.update_variable(nyc_school_tax_credit)
55+
56+
return reform
57+
58+
59+
def create_nyc_school_tax_credit_with_phase_out_reform(
60+
parameters, period, bypass: bool = False
61+
):
62+
if bypass:
63+
return create_nyc_school_tax_credit_with_phase_out()
64+
65+
p = parameters.gov.contrib.local.nyc.stc.phase_out
66+
67+
reform_active = False
68+
current_period = period_(period)
69+
70+
for i in range(5):
71+
if p(current_period).in_effect:
72+
reform_active = True
73+
break
74+
current_period = current_period.offset(1, "year")
75+
76+
if reform_active:
77+
return create_nyc_school_tax_credit_with_phase_out()
78+
else:
79+
return None
80+
81+
82+
nyc_school_tax_credit_with_phase_out = (
83+
create_nyc_school_tax_credit_with_phase_out_reform(None, None, bypass=True)
84+
)

policyengine_us/reforms/reforms.py

+8
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@
8282
create_limit_salt_deduction_to_property_taxes_reform,
8383
)
8484

85+
from .local.nyc.stc.phase_out import (
86+
create_nyc_school_tax_credit_with_phase_out_reform,
87+
)
88+
8589
from policyengine_core.reforms import Reform
8690
import warnings
8791

@@ -181,6 +185,9 @@ def create_structural_reforms_from_parameters(parameters, period):
181185
parameters, period
182186
)
183187
)
188+
nyc_school_tax_credit_with_phase_out = (
189+
create_nyc_school_tax_credit_with_phase_out_reform(parameters, period)
190+
)
184191

185192
reforms = [
186193
afa_reform,
@@ -218,6 +225,7 @@ def create_structural_reforms_from_parameters(parameters, period):
218225
dc_property_tax_credit,
219226
ny_2025_inflation_rebates,
220227
limit_salt_deduction_to_property_taxes,
228+
nyc_school_tax_credit_with_phase_out,
221229
]
222230
reforms = tuple(filter(lambda x: x is not None, reforms))
223231

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
- name: Joint, with AGI below phase out threshold
2+
period: 2025
3+
reforms: policyengine_us.reforms.local.nyc.stc.phase_out.nyc_school_tax_credit_with_phase_out.nyc_school_tax_credit_with_phase_out
4+
input:
5+
gov.contrib.local.nyc.stc.phase_out.in_effect: true
6+
in_nyc: True
7+
ny_agi: 150_000
8+
filing_status: JOINT
9+
output:
10+
nyc_school_tax_credit_phase_out: 0
11+
12+
- name: Single, with AGI above phase out threshold
13+
period: 2025
14+
reforms: policyengine_us.reforms.local.nyc.stc.phase_out.nyc_school_tax_credit_with_phase_out.nyc_school_tax_credit_with_phase_out
15+
input:
16+
gov.contrib.local.nyc.stc.phase_out.in_effect: true
17+
in_nyc: True
18+
ny_agi: 150_000
19+
filing_status: SINGLE
20+
output:
21+
nyc_school_tax_credit_phase_out: 3_750
22+
23+
- name: Single, with AGI above phase out threshold, with credit amount, fully reduced
24+
period: 2025
25+
reforms: policyengine_us.reforms.local.nyc.stc.phase_out.nyc_school_tax_credit_with_phase_out.nyc_school_tax_credit_with_phase_out
26+
input:
27+
gov.contrib.local.nyc.stc.phase_out.in_effect: true
28+
in_nyc: True
29+
ny_agi: 150_000
30+
filing_status: SINGLE
31+
nyc_school_tax_credit_fixed_amount: 1_000
32+
nyc_school_tax_credit_rate_reduction_amount: 500
33+
output:
34+
nyc_school_tax_credit_phase_out: 3_750
35+
nyc_school_tax_credit: 0
36+
37+
- name: Single, with AGI above phase out threshold, with credit amount, partially reduced
38+
period: 2025
39+
reforms: policyengine_us.reforms.local.nyc.stc.phase_out.nyc_school_tax_credit_with_phase_out.nyc_school_tax_credit_with_phase_out
40+
input:
41+
gov.contrib.local.nyc.stc.phase_out.in_effect: true
42+
in_nyc: True
43+
ny_agi: 160_000
44+
filing_status: SURVIVING_SPOUSE
45+
nyc_school_tax_credit_fixed_amount: 1_000
46+
nyc_school_tax_credit_rate_reduction_amount: 600
47+
output:
48+
nyc_school_tax_credit_phase_out: 500
49+
nyc_school_tax_credit: 1_100

0 commit comments

Comments
 (0)