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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/ca-prop3-2030-expiry.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add California Proposition 3 (2026) as a contributed reform, toggled by gov.contrib.states.ca.prop3.in_effect, that keeps the rates above 9.3% from 2031 onward.
1 change: 1 addition & 0 deletions changelog.d/ca-prop3-2030-expiry.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Encode the expiry of California's 10.3%, 11.3% and 12.3% income tax rates after tax year 2030 in all five filing-status schedules (Cal. Const. art. XIII, § 36(f)(2)-(3)).
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
description: California applies the Proposition 3 (2026) permanent extension of the income tax rates above 9.3% in years from 2031 onward in which this is true.
values:
0000-01-01: false
metadata:
unit: bool
period: year
label: California Proposition 3 (2026) in effect
reference:
- title: California Proposition 3 (2026), Official Voter Information Guide, Legislative Analyst's analysis, Figure 1
href: https://vig.cdn.sos.ca.gov/2026/general/pdf/prop3.pdf#page=2
- title: California Proposition 3 (2026), Text of Proposed Law, SEC. 4, amending Cal. Const. art. XIII, § 36(f)(2) (strikes "and before January 1, 2031,")
href: https://vig.cdn.sos.ca.gov/2026/general/pdf/prop3-text-proposed-laws.pdf#page=6
- title: California Proposition 3 (2026), Text of Proposed Law, SEC. 4, amending Cal. Const. art. XIII, § 36(f)(2)(D), (f)(3) and (f)(3)(D)
href: https://vig.cdn.sos.ca.gov/2026/general/pdf/prop3-text-proposed-laws.pdf#page=7
- title: Cal. Const. art. XIII, § 36(f)(2)-(3)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=CONS&sectionNum=SEC.%2036.&article=XIII
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.103
# Proposition 3 (November 3, 2026 ballot) would repeal this 2031 reversion here and in
# the next two brackets; check the certified result and remove these entries if it passes.
2031-01-01: 0.093
- threshold:
values:
2021-01-01: 510_303
Expand All @@ -81,6 +84,7 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.113
2031-01-01: 0.093
- threshold:
values:
2021-01-01: 850_503
Expand All @@ -92,6 +96,7 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.123
2031-01-01: 0.093

metadata:
threshold_unit: currency_USD
Expand All @@ -110,6 +115,9 @@ metadata:
href: https://www.ftb.ca.gov/forms/2024/2024-540-tax-rate-schedules.pdf
- title: California Income Tax Rate Schedules for 2025
href: https://www.ftb.ca.gov/forms/2025/2025-540-tax-rate-schedules.pdf
- title: Cal. Rev. & Tax. Code § 17041
- title: Cal. Const. art. XIII, § 36(f)(3) (rates above 9.3% apply to taxable years before January 1, 2031)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=CONS&sectionNum=SEC.%2036.&article=XIII
- title: Proposition 55 (2016), Text of Proposed Law, SEC. 4, amending Cal. Const. art. XIII, § 36(f)(3) to end the rates above 9.3% before January 1, 2031
href: https://vig.cdn.sos.ca.gov/2016/general/en/pdf/text-proposed-laws.pdf#page=16
- title: Cal. Rev. & Tax. Code § 17041(c)(1), (h)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=17041.&lawCode=RTC
# Index according to federal tax parameter rules until we add California CPI trend.
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.103
# Proposition 3 (November 3, 2026 ballot) would repeal this 2031 reversion here and in
# the next two brackets; check the certified result and remove these entries if it passes.
2031-01-01: 0.093
- threshold:
values:
2021-01-01: 750_442
Expand All @@ -81,6 +84,7 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.113
2031-01-01: 0.093
- threshold:
values:
2021-01-01: 1_250_738
Expand All @@ -92,6 +96,7 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.123
2031-01-01: 0.093

metadata:
threshold_unit: currency_USD
Expand All @@ -110,6 +115,11 @@ metadata:
href: https://www.ftb.ca.gov/forms/2024/2024-540-tax-rate-schedules.pdf
- title: California Income Tax Rate Schedules for 2025
href: https://www.ftb.ca.gov/forms/2025/2025-540-tax-rate-schedules.pdf
- title: Cal. Rev. & Tax. Code § 17041
- title: Cal. Const. art. XIII, § 36(f)(2) (rates above 9.3% apply to taxable years before January 1, 2031)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=CONS&sectionNum=SEC.%2036.&article=XIII
- title: Proposition 55 (2016), Text of Proposed Law, SEC. 4, amending Cal. Const. art. XIII, § 36(f)(2) to end the rates above 9.3% before January 1, 2031
href: https://vig.cdn.sos.ca.gov/2016/general/en/pdf/text-proposed-laws.pdf#page=16
- title: Cal. Rev. & Tax. Code § 17041(a)(1), (h)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=17041.&lawCode=RTC
# Index according to federal tax parameter rules until we add California CPI trend.
- title: Cal. Rev. & Tax. Code § 17045 (joint and surviving spouse tax is twice the tax on one-half of taxable income)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=17045.&lawCode=RTC
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.103
# Proposition 3 (November 3, 2026 ballot) would repeal this 2031 reversion here and in
# the next two brackets; check the certified result and remove these entries if it passes.
2031-01-01: 0.093
- threshold:
values:
2021-01-01: 375_221
Expand All @@ -81,6 +84,7 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.113
2031-01-01: 0.093
- threshold:
values:
2021-01-01: 625_369
Expand All @@ -92,6 +96,7 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.123
2031-01-01: 0.093

metadata:
threshold_unit: currency_USD
Expand All @@ -110,6 +115,9 @@ metadata:
href: https://www.ftb.ca.gov/forms/2024/2024-540-tax-rate-schedules.pdf
- title: California Income Tax Rate Schedules for 2025
href: https://www.ftb.ca.gov/forms/2025/2025-540-tax-rate-schedules.pdf
- title: Cal. Rev. & Tax. Code § 17041
- title: Cal. Const. art. XIII, § 36(f)(2) (rates above 9.3% apply to taxable years before January 1, 2031)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=CONS&sectionNum=SEC.%2036.&article=XIII
- title: Proposition 55 (2016), Text of Proposed Law, SEC. 4, amending Cal. Const. art. XIII, § 36(f)(2) to end the rates above 9.3% before January 1, 2031
href: https://vig.cdn.sos.ca.gov/2016/general/en/pdf/text-proposed-laws.pdf#page=16
- title: Cal. Rev. & Tax. Code § 17041(a)(1), (h)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=17041.&lawCode=RTC
# Index according to federal tax parameter rules until we add California CPI trend.
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.103
# Proposition 3 (November 3, 2026 ballot) would repeal this 2031 reversion here and in
# the next two brackets; check the certified result and remove these entries if it passes.
2031-01-01: 0.093
- threshold:
values:
2021-01-01: 375_221
Expand All @@ -81,6 +84,7 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.113
2031-01-01: 0.093
- threshold:
values:
2021-01-01: 625_369
Expand All @@ -92,6 +96,7 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.123
2031-01-01: 0.093

metadata:
threshold_unit: currency_USD
Expand All @@ -110,6 +115,9 @@ metadata:
href: https://www.ftb.ca.gov/forms/2024/2024-540-tax-rate-schedules.pdf
- title: California Income Tax Rate Schedules for 2025
href: https://www.ftb.ca.gov/forms/2025/2025-540-tax-rate-schedules.pdf
- title: Cal. Rev. & Tax. Code § 17041
- title: Cal. Const. art. XIII, § 36(f)(2) (rates above 9.3% apply to taxable years before January 1, 2031)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=CONS&sectionNum=SEC.%2036.&article=XIII
- title: Proposition 55 (2016), Text of Proposed Law, SEC. 4, amending Cal. Const. art. XIII, § 36(f)(2) to end the rates above 9.3% before January 1, 2031
href: https://vig.cdn.sos.ca.gov/2016/general/en/pdf/text-proposed-laws.pdf#page=16
- title: Cal. Rev. & Tax. Code § 17041(a)(1), (h)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=17041.&lawCode=RTC
# Index according to federal tax parameter rules until we add California CPI trend.
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.103
# Proposition 3 (November 3, 2026 ballot) would repeal this 2031 reversion here and in
# the next two brackets; check the certified result and remove these entries if it passes.
2031-01-01: 0.093
- threshold:
values:
2021-01-01: 750_442
Expand All @@ -81,6 +84,7 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.113
2031-01-01: 0.093
- threshold:
values:
2021-01-01: 1_250_738
Expand All @@ -92,6 +96,7 @@ brackets:
uprating: gov.states.ca.cpi
rate:
2021-01-01: 0.123
2031-01-01: 0.093

metadata:
threshold_unit: currency_USD
Expand All @@ -110,6 +115,11 @@ metadata:
href: https://www.ftb.ca.gov/forms/2024/2024-540-tax-rate-schedules.pdf
- title: California Income Tax Rate Schedules for 2025
href: https://www.ftb.ca.gov/forms/2025/2025-540-tax-rate-schedules.pdf
- title: Cal. Rev. & Tax. Code § 17041
- title: Cal. Const. art. XIII, § 36(f)(2) (rates above 9.3% apply to taxable years before January 1, 2031)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?lawCode=CONS&sectionNum=SEC.%2036.&article=XIII
- title: Proposition 55 (2016), Text of Proposed Law, SEC. 4, amending Cal. Const. art. XIII, § 36(f)(2) to end the rates above 9.3% before January 1, 2031
href: https://vig.cdn.sos.ca.gov/2016/general/en/pdf/text-proposed-laws.pdf#page=16
- title: Cal. Rev. & Tax. Code § 17041(a)(1), (h)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=17041.&lawCode=RTC
# Index according to federal tax parameter rules until we add California CPI trend.
- title: Cal. Rev. & Tax. Code § 17045 (joint and surviving spouse tax is twice the tax on one-half of taxable income)
href: https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=17045.&lawCode=RTC
5 changes: 5 additions & 0 deletions policyengine_us/reforms/reforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@
from .states.ca.ab2591 import (
create_ca_ab2591_reform,
)
from .states.ca.prop3 import (
create_ca_prop3_reform,
)
from .states.ga.sb520 import (
create_ga_sb520_reform,
)
Expand Down Expand Up @@ -562,6 +565,7 @@ def create_structural_reforms_from_parameters(parameters, period):
parameters, period
)
ca_ab2591 = create_ca_ab2591_reform(parameters, period)
ca_prop3 = create_ca_prop3_reform(parameters, period)
ga_sb520 = create_ga_sb520_reform(parameters, period)
hi_hb2306_cdcc = create_hi_hb2306_cdcc_reform(parameters, period)
nc_eitc = create_nc_eitc_reform(parameters, period)
Expand Down Expand Up @@ -712,6 +716,7 @@ def create_structural_reforms_from_parameters(parameters, period):
tx_rebate,
al_hb527_overtime_deduction,
ca_ab2591,
ca_prop3,
ga_sb520,
hi_hb2306_cdcc,
nc_eitc,
Expand Down
1 change: 1 addition & 0 deletions policyengine_us/reforms/states/ca/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .ab2591 import create_ca_ab2591_reform
from .prop3 import create_ca_prop3_reform
5 changes: 5 additions & 0 deletions policyengine_us/reforms/states/ca/prop3/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .ca_prop3_reform import (
create_ca_prop3,
create_ca_prop3_reform,
ca_prop3,
)
134 changes: 134 additions & 0 deletions policyengine_us/reforms/states/ca/prop3/ca_prop3_reform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import functools

from policyengine_us.model_api import *
from policyengine_core.parameters import load_parameter_file
from policyengine_core.periods import instant

# Cal. Const. art. XIII, § 36(f)(2) (single, separate, and through RTC § 17045
# joint and surviving spouse) and § 36(f)(3) (head of household) apply the
# rates above 9.3% to taxable years before January 1, 2031. Proposition 3
# (2026), SEC. 4, strikes that end date, so the rates in effect for 2030 keep
# applying from 2031 onward.
LAST_PRE_SUNSET_YEAR = instant("2030-01-01")
SUNSET = instant("2031-01-01")
HORIZON_END = instant("2100-12-31")
FILING_STATUSES = [
"single",
"joint",
"separate",
"surviving_spouse",
"head_of_household",
]


def _active_windows(in_effect) -> list:
"""Return the (start, stop) instants within SUNSET..HORIZON_END where the
dated values of ``in_effect`` are true.

``values_list`` holds the user's dated overrides in reverse chronological
order; each value applies from its instant until the next later one.
"""
windows = []
later_start = None
for value_at_instant in in_effect.values_list:
start = instant(value_at_instant.instant_str)
if value_at_instant.value:
window_start = max(start, SUNSET)
window_stop = HORIZON_END
if later_start is not None:
window_stop = min(later_start.offset(-1, "day"), HORIZON_END)
if window_start <= window_stop:
windows.append((window_start, window_stop))
later_start = start
return sorted(windows)


@functools.lru_cache(maxsize=None)
def _enacted_schedule(file_path: str):
# The schedule as enacted, read from the file the rates were loaded from,
# so the reform can tell the statutory sunset apart from a user's edit.
# The YAML must remain readable at this path, including after unpickling
# the system on another machine.
return load_parameter_file(file_path)


def _constant_intervals(start, stop, *parameters) -> list:
"""Split start..stop into the (start, stop) intervals on which every
parameter keeps one value."""
cuts = {start}
for parameter in parameters:
for value_at_instant in parameter.values_list:
cut = instant(value_at_instant.instant_str)
if start < cut <= stop:
cuts.add(cut)
cuts = sorted(cuts)
stops = [cut.offset(-1, "day") for cut in cuts[1:]] + [stop]
return list(zip(cuts, stops))


def _restore_pre_sunset_rates(rates, enacted_rates: dict, windows: list) -> None:
"""Within each window, give each bracket whose enacted rate the sunset
changes its 2030 rate, wherever the enacted post-sunset rate applies.

``enacted_rates`` maps each filing status to its enacted schedule. Brackets
the sunset leaves unchanged keep any edit, including one bounded to 2030,
and so do intervals whose rate differs from the enacted rate, which a user
has set explicitly. Restored intervals no longer match the enacted rate, so
applying the reform again changes nothing.
"""
updates = []
for status in FILING_STATUSES:
brackets = getattr(rates, status).brackets
for bracket, enacted_bracket in zip(brackets, enacted_rates[status].brackets):
rate = bracket.rate
enacted_rate = enacted_bracket.rate
if enacted_rate(SUNSET) == enacted_rate(LAST_PRE_SUNSET_YEAR):
continue
# The 2030 rate, including any rate the user set for 2030.
pre_sunset_rate = rate(LAST_PRE_SUNSET_YEAR)
for window_start, window_stop in windows:
for start, stop in _constant_intervals(
window_start, window_stop, rate, enacted_rate
):
if rate(start) == enacted_rate(start):
updates.append((rate, start, stop, pre_sunset_rate))
# Read every rate before writing any.
for rate, start, stop, value in updates:
rate.update(start=start, stop=stop, value=value)


def create_ca_prop3(respect_in_effect: bool = False) -> Reform:
def modify_parameters(parameters):
if respect_in_effect:
windows = _active_windows(parameters.gov.contrib.states.ca.prop3.in_effect)
else:
windows = [(SUNSET, HORIZON_END)]
rates = parameters.gov.states.ca.tax.income.rates
enacted_rates = {
status: _enacted_schedule(getattr(rates, status).file_path)
for status in FILING_STATUSES
}
_restore_pre_sunset_rates(rates, enacted_rates, windows)
return parameters

class reform(Reform):
def apply(self):
self.modify_parameters(modify_parameters)

return reform


def create_ca_prop3_reform(parameters, period, bypass: bool = False):
# The bypass instance, used by YAML `reforms:` tests, restores the rates
# for 2031-2100 regardless of in_effect. Otherwise the reform applies only
# in the years from 2031 onward in which in_effect is true.
if bypass:
return create_ca_prop3()

if _active_windows(parameters.gov.contrib.states.ca.prop3.in_effect):
return create_ca_prop3(respect_in_effect=True)
else:
return None


ca_prop3 = create_ca_prop3_reform(None, None, bypass=True)
Loading
Loading