Skip to content

Encode the 2030 expiry of California's top income tax rates; add Prop 3 (2026) reform - #9601

Draft
MaxGhenis wants to merge 2 commits into
mainfrom
ca-prop3-2030-expiry
Draft

MaxGhenis wants to merge 2 commits into
mainfrom
ca-prop3-2030-expiry

Conversation

@MaxGhenis

Copy link
Copy Markdown
Contributor

What this changes

Baseline fix. California's 10.3%, 11.3% and 12.3% income tax rates (Prop 30 of 2012, extended by Prop 55 of 2016) apply only to "taxable years beginning on or after January 1, 2012, and before January 1, 2031" (Cal. Const. art. XIII, § 36(f)(2)). The rate files carried them with no end date. From 2031 the three brackets now revert to 9.3% in all five filing-status schedules, matching Figure 1 of the Legislative Analyst's Prop 3 analysis in the 2026 voter guide. Thresholds and uprating are unchanged.

New contributed reform. Proposition 3 on the November 3, 2026 ballot would make those rates permanent (LAO: keeps $5 billion to $15 billion a year). gov.contrib.states.ca.prop3.in_effect switches on a parameter-only reform (policyengine_us/reforms/states/ca/prop3) that keeps the three rates from 2031 onward. The 1% Mental Health Services Tax is untouched.

Effect

2031 tax on $1,000,000 of taxable income, single: $88,942.90 under current law, $101,169.10 under Prop 3. Checked through the app-style path (Reform.from_dict on the in_effect parameter): a single $2M earner's 2031 CA tax goes from $181,412 to $223,467.

Any existing analysis that projects California revenue past 2030 will now show the scheduled rate drop.

Tests

  • 3 baseline cases in ca_income_tax_before_credits.yaml: the 2030 vs 2031 boundary, single and joint.
  • 6 reform cases in tests/policy/contrib/states/ca/prop3.yaml: 2031 at $300k, $1M and $2M; 2030 unchanged; MHST unchanged. Expected values are computed by hand from the 2031 bracket thresholds (the arithmetic is in the comments).
  • Locally: CA contrib tests plus the rate and MHST files, 27 passed.

Review

@DTrim99, this is the first piece of the November ballot-measure push. Please check the reversion schedule against the statute and the voter guide, and whether the in_effect switch should default to start in 2026 for app users.

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits September 24, 2026 15:56
… 3 (2026) reform

Under Cal. Const. art. XIII, section 36(f)(2), the 10.3%, 11.3% and 12.3%
rates added by Proposition 30 and extended by Proposition 55 apply to taxable
years before January 1, 2031. The baseline carried them indefinitely. From
2031 the three brackets now revert to 9.3%, matching the Legislative
Analyst's Figure 1 in the 2026 voter guide.

Proposition 3 on the November 3, 2026 ballot would make those rates
permanent. gov.contrib.states.ca.prop3.in_effect switches on a
parameter-only reform that keeps them from 2031 onward. The 1% Mental
Health Services Tax is unaffected.

Tests: 3 baseline boundary cases (2030 vs 2031) and 6 reform cases,
expected values computed by hand from the 2031 thresholds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis requested a review from DTrim99 September 24, 2026 19:56
@DTrim99

DTrim99 commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator

Program Review

PR #9601: Encode the 2030 expiry of California's top income tax rates; add Prop 3 (2026) reform
Head reviewed: ea80e9d0ad577232990679162a1374489a6f4acc

The law is encoded correctly. All five filing-status schedules keep 10.3% / 11.3% / 12.3% through tax year 2030 and fall back to 9.3% from 2031-01-01. The Prop 3 reform restores exactly those three rates, on the right brackets, for all five statuses from 2031. Neither PDF audit found a value or date mismatch. The issues below are two citation and hard-coding problems that must be fixed, a reform activation window that cannot reach Prop 3's operative year, and test coverage for the three filing statuses that aren't tested yet.

Source Documents

Year(s): TY2025 thresholds (FTB); the TY2030 / TY2031 sunset boundary; Prop 3 reform 2031-01-01 to 2100-12-31.
Scope: PR changes only.


Critical (Must Fix)

1. The head-of-household rate file cites the wrong constitutional paragraph: § 36(f)(2) instead of § 36(f)(3)

  • Where: policyengine_us/parameters/gov/states/ca/tax/income/rates/head_of_household.yaml:116. This is the only new reference offered for the 2031 values at lines 73, 85 and 97.
  • Problem:
  • The values are correct. (f)(3) has the same 2031 cutoff, so only the citation is wrong. Four validators flagged this. It is classified critical because the reference title cites the wrong subsection.
  • Fix:
    - 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
  • Same root cause, fix in the same pass. These three places cover heads of household but cite only (f)(2). They are incomplete rather than wrong, so change each to "§ 36(f)(2)-(3)":
    • policyengine_us/parameters/gov/contrib/states/ca/prop3/in_effect.yaml:11
    • the comment at policyengine_us/reforms/states/ca/prop3/ca_prop3_reform.py:5-7
    • changelog.d/ca-prop3-2030-expiry.fixed.md:1

2. The reform hard-codes the restored rates and bracket indexes

  • Where:
    • policyengine_us/reforms/states/ca/prop3/ca_prop3_reform.py:8: TOP_BRACKET_RATES = {6: 0.103, 7: 0.113, 8: 0.123}
    • applied at :23-28
  • Why it is critical:
    • The literals are correct. They equal § 36(f)(2)(A)(i)-(iii) and (f)(3)(A)(i)-(iii), which Prop 3 leaves unamended (https://vig.cdn.sos.ca.gov/2026/general/pdf/prop3-text-proposed-laws.pdf#page=6 and #page=7). So this is not a value error.
    • It is classified critical because the repo standard for contrib reforms is "every amount from a parameter", and these are policy values with no reference anywhere in the repo.
    • They duplicate the baseline rate files. A later correction to those rates, or a user's app edit to them, would not carry into 2031+ under Prop 3.
    • The indexes 6/7/8 are tied to the current 9-bracket layout. Inserting a bracket would silently change the wrong ones, and the tests would only catch that for SINGLE and JOINT.
    • The fix is a few lines.
    • The validators split on severity: code said critical, references said should-address, regulatory said suggestion. There is one weak precedent for literals in modify_parameters: afa_other_dependent_credit.py:226 (value=18).
  • Fix: Prop 3 keeps the rates that apply before the sunset. So copy each bracket's 2030 rate forward and drop both the literals and the indexes. Reading the baseline at an earlier instant inside modify_parameters has precedent: reforms/states/ut/ut_hb210_s2.py:79 and reforms/states/ct/hb5114/ct_hb5114.py:65.
    def modify_parameters(parameters):
        rates = parameters.gov.states.ca.tax.income.rates
        for status in FILING_STATUSES:
            for bracket in getattr(rates, status).brackets:
                pre_sunset_rate = bracket.rate(instant("2030-01-01"))
                if bracket.rate(instant("2031-01-01")) != pre_sunset_rate:
                    bracket.rate.update(
                        start=instant("2031-01-01"),
                        stop=instant("2100-12-31"),
                        value=pre_sunset_rate,
                    )
        return parameters
    Then delete TOP_BRACKET_RATES.
  • Alternative: move the three rates into gov.contrib.states.ca.prop3.* parameters that carry the measure-text references from Should Address item 2. This is heavier, and only worth it if the extended rates should be adjustable in the app.

Should Address

1. The activation scan cannot see Prop 3's operative year, so a toggle that starts in 2029 or later silently does nothing

  • Where: policyengine_us/reforms/states/ca/prop3/ca_prop3_reform.py:44-51, the for i in range(5) lookahead.

  • Problem:

  • Measured via Reform.from_dict, single filer, ca_taxable_income $1M, TY2031:

    in_effect window 2031 ca_income_tax_before_credits
    2026-01-01.2100-12-31 101,169.10 (applied)
    2028-01-01.2100-12-31 101,169.10 (applied)
    2029-01-01.2100-12-31 88,942.90 (silently baseline)
    2031-01-01.2100-12-31 88,942.90 (silently baseline)
    2026-01-01.2026-12-31 only (false in 2031) 101,169.10 (applied anyway)
  • Answer to the PR description's question about the start date: today, an in_effect start date anywhere in 2024-2028 (including 2026) activates the reform, and any start date from 2029 on does not. The last row shows the reverse problem: once loaded, the reform restores 2031-2100 whatever in_effect says in those years.

  • Why this isn't critical: the YAML tests can't catch it, because they use the bypass=True instance (:59), which ignores in_effect. The default app path, starting in the current year, works today.

  • Fix:

    • (a) Detect activation from any dated true value in in_effect.values_list instead of a 5-year scan. Follow _first_true_instant in policyengine_us/reforms/states/id/ctc/id_ctc_reform.py:9-24.
    • (b) Optionally, start the restoration at max(2031-01-01, first true instant) so the toggle's timing is respected (the same file, :60-75).
    • (c) Add a pytest in the style of policyengine_us/tests/policy/contrib/states/test_id_ga_ctc_reform_activation.py:
      • Build Reform.from_dict({"gov.contrib.states.ca.prop3.in_effect": {"2031-01-01.2100-12-31": True}}, country_id="us").
      • Assert 101,169.10 for the single $1M TY2031 case.
      • Assert 88,942.90 with the toggle off.

2. in_effect.yaml does not cite the measure's operative text, and its Figure 1 link has no page anchor

  • Where: policyengine_us/parameters/gov/contrib/states/ca/prop3/in_effect.yaml:8-12
  • Problem:
    • The references are the LAO analysis, an official but secondary summary, and the current (pre-Prop 3) § 36(f)(2). The reform implements SEC. 4 of the Text of Proposed Laws, which isn't cited.
    • The LAO link opens on file page 1. Figure 1 is on file page 2 (printed p. 27).
    • The HOH extension comes from (f)(3), which isn't cited (see Critical item 1).
  • Why this isn't critical: the existing references do corroborate the policy (Figure 1's "Approved" column shows 10.3 / 11.3 / 12.3 after 2030), and the parameter's value is a default-off toggle that doesn't come from a source.
  • Fix: replace the reference block with:
    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

3. The joint and surviving-spouse files don't cite RTC § 17045, so the chain from § 36(f)(2) to their 2031 values is broken

  • Where: policyengine_us/parameters/gov/states/ca/tax/income/rates/joint.yaml:116 and .../rates/surviving_spouse.yaml:116
  • Problem:
    • § 36(f)(2) modifies only the § 17041(a)(1) schedule. Joint and QSS returns reach those rates only through § 17045: "twice the tax ... if the taxable income were cut in one-half", and a surviving spouse return "shall be treated as a joint return".
    • For 2021-2025, the FTB Schedule Y references backed the joint rates directly. No FTB schedule exists for 2031.
    • The (f)(2) citation is right; the chain is just incomplete.
  • Fix: add to both files, after line 117:
    - 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

4. HEAD_OF_HOUSEHOLD, SEPARATE and SURVIVING_SPOUSE are never tested in 2031, under the baseline or the reform

  • Where:

    • policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/ca_income_tax_before_credits.yaml:25-55: SINGLE (2030, 2031) and JOINT (2031) only.
    • policyengine_us/tests/policy/contrib/states/ca/prop3.yaml:4-75: SINGLE and JOINT only.
  • Problem:

    • 9 of the 15 new 2031-01-01: 0.093 entries are never exercised: lines 73, 85 and 97 of separate.yaml, surviving_spouse.yaml and head_of_household.yaml.
    • Three of the five statuses in the reform's FILING_STATUSES loop (ca_prop3_reform.py:9-15) are never exercised either.
    • HOH matters most. It is governed by the separate paragraph (f)(3), its thresholds are not a multiple of single's, and a HOH filer at $1M sits in the 11.3% bracket rather than 12.3%.
    • Sources: FTB 2025 Schedule Z, https://www.ftb.ca.gov/forms/2025/2025-540-tax-rate-schedules.pdf#page=1; Const. § 36(f)(3).
  • Fix: append these cases (period: 2031, state_code: CA, absolute_error_margin: 1). Baseline cases go to the end of ca_income_tax_before_credits.yaml; reform cases go to the end of prop3.yaml, with the reforms: key.

    Filing status ca_taxable_income Baseline 2031 Prop 3 2031
    HEAD_OF_HOUSEHOLD 1,500,000 133,132.32 153,959.95
    SEPARATE 1,000,000 88,942.90 101,169.10
    SURVIVING_SPOUSE 2,000,000 177,885.81 202,338.20
    • Add a 2030 HOH baseline case at $1,500,000 = 154,557.25, so the HOH boundary is covered on both sides.
    • Two validators computed these values independently from the snapshot's uprated thresholds and they agree to the cent. Confirm them by running.
    • The 2031 HOH thresholds are 10.3% at 575,531.95, 11.3% at 690,639.94 and 12.3% at 1,151,065.04.

5. The changelog type covers the baseline fix but not the new contrib reform

  • Where: changelog.d/ca-prop3-2030-expiry.fixed.md:1
  • Problem: the PR also adds a public reform module (policyengine_us.reforms.states.ca.prop3) and a new gov.contrib.states.ca.prop3.in_effect parameter. Contrib-reform PRs use added (e.g. ca-ab2591.added.md). With fixed alone, towncrier makes a patch bump.
  • Fix: keep the .fixed.md fragment for the 2031 expiry, citing § 36(f)(2)-(3). Add changelog.d/ca-prop3-2030-expiry.added.md for the Prop 3 contributed reform. Same-stem multi-type fragments have precedent: ny-ccdf.added.md + ny-ccdf.fixed.md.

6. No test covers the new AMT interaction

  • Where: all new cases assert only ca_income_tax_before_credits or ca_mental_health_services_tax.
  • Problem:
    • ca_amt is max(TMT - ca_income_tax_before_credits, 0) (policyengine_us/variables/gov/states/ca/tax/income/alternative_minimum_tax/ca_amt.py:21-25). The 2031 drop in regular tax makes AMT bind for more high-preference filers, which offsets part of the sunset and part of Prop 3's effect.
    • That behavior is legally correct: RTC § 17062 compares against the § 17041 tax, and § 36(f)(2)(C)(ii) deems the higher rates part of § 17041. But it is new in 2031, and nothing tests it.
  • Fix: add these cases:
    • Baseline: in policyengine_us/tests/policy/baseline/gov/states/ca/tax/income/alternative_minimum_tax/ca_amt.yaml, period 2031, state_code: CA, filing_status: SINGLE, ca_taxable_income: 1_000_000, ca_amti: 1_400_000, ca_amt_exemption: 0. Expected ca_amt = 98,000 - 88,942.90 = 9,057.10.
    • Reform: the same case in prop3.yaml. Expected ca_amt = 0, because regular tax is 101,169.10.

Suggestions

  1. Add assertions that don't depend on the CPI projections.
    • All 9 new dollar expectations depend on CBO C-CPI-U projections (gov/bls/cpi/c_cpi_u.yaml:327-329). A 0.1-point revision moves them by about $1 to $5.50, which is more than the margin of 1.
    • Add a small pytest that asserts brackets 6-8 of all 5 schedules directly:
      • 0.103 / 0.113 / 0.123 at 2030-01-01.
      • 0.093 at 2031-01-01 and 2035-01-01 in the baseline.
      • 0.103 / 0.113 / 0.123 at 2031-01-01 and 2035-01-01 with ca_prop3 applied.
    • That pytest also shows the change is permanent after 2031.
    • The PR description says the arithmetic is in the comments, but only prop3.yaml:14 and ca_income_tax_before_credits.yaml:44 have it. Add one-line derivations to the other cases, noting the factors f2030 = 193.00 / 172.797 and f2031 = 196.85 / 172.797.
  2. Add incomes inside a single surcharge bracket, for diagnosis. 2031 SINGLE cases:
    • $450,000 (10.3% bracket only): baseline 37,792.90, Prop 3 38,061.02.
    • $600,000 (11.3% bracket only): baseline 51,742.90, Prop 3 54,432.80.
    • The $2M single case (prop3.yaml:17-27) only adds the 12.3% slope, which the $1M case already covers. It could be repurposed for one of these incomes.
  3. Make the MHST case able to fail.
    • prop3.yaml:65-75 asserts ca_mental_health_services_tax. That variable reads neither the rate schedules nor the reform, so the case can't fail because of this PR.
    • Assert ca_income_tax_before_refundable_credits instead, with 2031, SINGLE, ca_taxable_income: 2_000_000, ca_non_refundable_credits: 0 and ca_amt: 0. Expected: Prop 3 234,169.10, baseline 191,942.90. This shows MHST stacking on the extended rates.
  4. Test layout and clarity.
    • Move policyengine_us/tests/policy/contrib/states/ca/prop3.yaml to .../contrib/states/ca/prop3/ca_prop3.yaml to match the sibling ca/ab2591/ca_ab2591.yaml.
    • Add a header comment saying:
      • the YAML reforms: key applies the bypass=True instance, so the in_effect: true input is redundant;
      • the baseline cases at ca_income_tax_before_credits.yaml:36-55 are the reform-off controls.
  5. Import and registration style.
    • policyengine_us/reforms/states/ca/__init__.py:2-4: use from .prop3 import create_ca_prop3_reform, to match line 1.
    • policyengine_us/reforms/states/ca/prop3/__init__.py:1: also export create_ca_prop3, as ab2591/__init__.py does.
    • policyengine_us/reforms/reforms.py: move the import at :146 (currently in the RI block) next to the CA import at :291-293. Move the instantiation at :495 next to :566, and the list entry at :662 next to :717.
    • ca_prop3_reform.py:47: for _ in range(5). This is moot if Should Address item 1 replaces the scan.
  6. Harden the rate-file references against Prop 3 passing.
    • The leginfo § 36 page always shows the current text. If Prop 3 passes, it will no longer show "before January 1, 2031".
    • Add a dated source to each of the five rate files: "Proposition 55 (2016), Text of Proposed Law, SEC. 4, amending Cal. Const. art. XIII, § 36(f)(2) and (f)(3)", https://vig.cdn.sos.ca.gov/2016/general/en/pdf/text-proposed-laws.pdf#page=16. In the HOH file, cite (f)(3) only.
    • The line 118 RTC § 17041 reference could also name the subsections: "(a)(1), (h)" for single, separate, joint and surviving spouse; "(c)(1), (h)" for HOH.
  7. Plan the follow-up for after the November 3, 2026 election.
    • If Prop 3 passes, the 2031-01-01: 0.093 entries (lines 73, 85 and 97 of all five rate files) have to be removed, and the contrib reform retired.
    • If it fails, the baseline is already correct.
    • A tracking issue or YAML comment would keep this from being missed.

Pre-existing (out of PR scope)

  • Uprated thresholds aren't rounded to the nearest $1, as RTC § 17041(h)(2)(B) requires. For example, the 2031 single 9.3% threshold is 82,847.04. The tax effect is under $1. If rounding is added, round single and derive joint as 2x, so that joint stays exactly twice single.
  • There is a stale comment at line 120 of all five rate files: "Index according to federal tax parameter rules until we add California CPI trend." The thresholds already uprate with gov.states.ca.cpi.
  • The FTB schedule references at lines 106-115 don't name the schedule (X, Y or Z) and have no #page=1 anchor.
  • ca_income_tax_before_credits.yaml:14 is named "Single filing, income in 3rd tax bracket", but it tests HEAD_OF_HOUSEHOLD at $1M, which is in the 12.3% bracket.
  • The 2021-2024 thresholds weren't re-checked, because those FTB PDFs weren't in scope. The 2026-2030 thresholds are CPI projections with no primary source.

Verified correct

  • Sunset date. 2031-01-01: 0.093 matches "for any taxable year beginning on or after January 1, 2012, and before January 1, 2031" in § 36(f)(2) and (f)(3).
    • So TY2030 is the last year of 10.3 / 11.3 / 12.3.
    • The (D) "inoperative on December 1, 2031" clauses are correctly not used as the switch date.
    • The title's "2030 expiry" and the changelog's "after tax year 2030" agree with Prop 3 SEC. 2(c) and the LAO analysis.
  • All five filing statuses change consistently. Each file sets 2031-01-01: 0.093 on bracket indexes 6, 7 and 8 (lines 73, 85, 97), which hold exactly 0.103 / 0.113 / 0.123. Brackets 0-5 are untouched.
    • The resolved 2031, 2032 and 2035 rates are [.01, .02, .04, .06, .08, .093, .093, .093, .093] for every status. This is the base § 17041(a)(1) / (c)(1) ladder.
    • The redundant 9.3% brackets produce $0.00 difference from a merged schedule. They are needed for the reform.
  • Thresholds.
    • The 2025 thresholds in all five files match FTB 2025 Schedules X, Y and Z.
    • Joint and QSS thresholds are exactly 2x single in every year 2021-2035. MFS equals single, and QSS equals joint (§ 17045).
    • CPI uprating of the thresholds is unaffected by the new rate entries.
  • Prop 3 encoding.
    • The measure only strikes "and before January 1, 2031," from (f)(2) and (f)(3), plus both (D) clauses. No rate or threshold changes; this was confirmed from the page images at prop3-text-proposed-laws.pdf#page=6 and #page=7.
    • The reform restores 10.3 / 11.3 / 12.3 for all five statuses from 2031-01-01. It leaves 2030 unchanged and reproduces LAO Figure 1's "Approved" and "Rejected" columns.
    • The 2100-12-31 stop date follows the repo's horizon convention.
  • Registration and wiring.
    • The reform is registered at reforms/reforms.py:146 (import), :495 (instantiate) and :662 (list).
    • The YAML reforms: path resolves through prop3/__init__.py:1, and all 6 contrib cases use it.
    • in_effect uses the 0000-01-01: false sentinel and has complete metadata.
    • No programs.yaml change is needed.
  • The Mental Health Services Tax is unaffected. RTC § 17043 has its own parameter, which neither the PR nor the reform touches.
  • Downstream consumers pick up the change automatically. The consumers are ca_income_tax_before_credits.py, ca_withheld_income_tax.py (which uses rates.single, so high-earner withholding also drops from 2031 and Prop 3 restores it) and ca_amt.py. Nothing else references these rates or hard-codes 0.103 / 0.113 / 0.123.
  • Test values. All 9 new expected values were checked by hand to the cent.
  • Conflicting measures. Prop 3 SEC. 5 (conflicting measures) has no effect here: the only other November 2026 tax measure, Prop 40 (a one-time billionaire wealth tax), doesn't change § 17041 rates.

PDF Audit Summary

Neither audit reported a value mismatch; only citation and reference items came up. No cross-reference or external-PDF requests were raised, and the PR adds no #page= anchors. So the code-path, 600-DPI, cross-reference / external-document and page-number re-verification steps were not triggered.

Category Count Detail
Confirmed correct 30 items (about 190 individual value checks) Baseline audit: 16 items (the sunset date, 2030 and 2031+ rates for all 5 statuses, brackets 0-5, FTB 2025 thresholds X/Y/Z, the 2x joint relation 2021-2035, uprating). Prop 3 audit: 14 items (the four SEC. 4 strikes, rate values, bracket positions, all statuses, LAO Figure 1 columns, the AG summary thresholds, the 2031 test expectations, MHST).
Mismatches (verified) 0 value / date 3 reference items: the HOH § 36(f)(3) citation (Critical item 1); the missing measure text, #page=2 anchor and (f)(3) in in_effect.yaml (Should Address item 2); the missing § 17045 in the joint and QSS files (Should Address item 3).
Mismatches rejected 1 The reform stops at 2100-12-31 rather than being open-ended. This is accepted as the repo's horizon convention and has no effect within any projection window.
Unmodeled items 5 Correctly out of scope for a household tax model: Prop 3's § 36(e) Education Protection Account timeline; revenue allocation (89% K-12 / 11% community colleges, Medi-Cal, audit and penalties); SEC. 5 conflicting measures; SEC. 1-3 and 6-7 (findings, intent, severability, standing); § 36(f)(1) sales tax (inoperative since 2017).
Pre-existing issues 5 Threshold rounding; the stale indexing comment; FTB references without #page=1; 2021-2024 thresholds not re-checked; 2026-2030 projected thresholds have no primary source.

Validation Summary

Check Result
Regulatory Accuracy Pass. The sunset and the Prop 3 reform are encoded correctly for all 5 filing statuses, with 0 value mismatches. The activation window has a gap (Should Address item 1).
Reference Quality Issues. The HOH file cites (f)(2) instead of (f)(3) (critical). The contrib toggle lacks the measure text and #page=2, and the joint and QSS files lack § 17045.
Code Patterns Issues. The reform hard-codes rates and bracket indexes (critical). The range(5) activation scan misses 2031. The changelog has only the fixed type.
Formatting Pass. Parameter description, label, unit and period follow conventions. There are minor import-order and style nits (Suggestion 5).
Test Coverage Issues. All 9 new values are correct, but HOH, MFS and QSS are untested in 2031, and neither the activation path nor the AMT interaction is tested.
PDF Value Audit Pass. 30 items confirmed, with 0 value mismatches.
Partner contract tests SAFE. None of the 143 partner YAML files under policyengine_us/tests/policy/baseline/partners/** has a period after 2026 (all are 2024, 2025, 2026 or 2026-01). That includes every file with CA tax (amplifi/2025.yaml, amplifi/2026.yaml, and the analytics_coverage CA signatures and edge cases), so none of their outputs can move from a change dated 2031-01-01. The diff touches no partner file, and no partner gate is needed. Of the 20 other YAML files with periods in 2031 or later, none depends on high-earner CA tax.
Local tests A targeted policyengine-core test run of contrib/states/ca/prop3.yaml and baseline/gov/states/ca/tax/income/ca_income_tax_before_credits.yaml at the PR head: 11 passed (6 + 5).
CI Status At review time: 13 pass, 22 pending, 0 failing. The pending shards include Contrib (states), Baseline (states) and Household API Partners. Pending is not a failure.

Out-year impact (informational): from 2031, baseline CA income tax revenue falls for every filer above the 10.3% threshold. The LAO puts the rates at $5 billion to $15 billion a year. Saved app policies that edit brackets 6-8 will show larger 2031+ impacts against the new baseline.

Review Severity: REQUEST_CHANGES

The two critical items are both citation and encoding-hygiene problems with small, mechanical fixes: the HOH citation points to the wrong constitutional paragraph, and the reform hard-codes its rates and bracket indexes. The law and every value are correct. Should Address item 1 is the most substantive functional issue: enabling Prop 3 from its own operative year does nothing, with no warning.

Next Steps

To auto-fix issues: /fix-pr 9601

@DTrim99 DTrim99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes per the program review above (#9601 (comment)). The law is encoded correctly: 2030 is the last year with the 10.3/11.3/12.3% rates ("before January 1, 2031"), all five filing statuses switch on 2031-01-01, there are no value mismatches, and no partner test runs past 2026.

Items to address:

  • Head-of-household is governed by Cal. Const. art. XIII §36(f)(3), not (f)(2). The same (f)(2)-only citation appears in in_effect.yaml, the reform comment and the changelog.
  • ca_prop3_reform.py hard-codes the rates and bracket indexes {6: 0.103, 7: 0.113, 8: 0.123}. The values match the measure, but copying each bracket's 2030 rate forward would be safer.
  • The range(5) activation scan only looks at 2024–2028, so a user who switches in_effect on for 2029 or later silently gets the baseline. A Reform.from_dict pytest would catch this.
  • Prop 3 measure-text anchors are missing, and RTC §17045 is missing on joint/surviving-spouse.
  • HOH, MFS and QSS have no 2031 cases, and nothing tests the 2031 AMT interaction.
  • The changelog needs an .added.md fragment for the reform.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants