Skip to content

Fix Arizona property tax credit Schedule 2 thresholds - #9779

Merged
MaxGhenis merged 2 commits into
mainfrom
fix-az-ptc-schedule-2-thresholds
Oct 6, 2026
Merged

MaxGhenis merged 2 commits into
mainfrom
fix-az-ptc-schedule-2-thresholds

Conversation

@MaxGhenis

Copy link
Copy Markdown
Contributor

Summary

Arizona's property tax credit table for a claimant who lived with a spouse or other persons (ARS 43-1072(B)(2), Form 140PTC Schedule 2) had every band threshold one dollar low. cohabitating.yaml stored 2,500, 2,650, ..., 5,500 as the lower bounds of the second through last bands, but the statute and the 2021-2025 forms start those bands at 2,501, 2,651, ..., 5,501:

Household income Credit
$0-2,500 $502
2,501-2,650 479
2,651-2,800 457
... ...
5,351-5,500 56
5,501 and up 0

A household with income of exactly $2,500, $2,650, ..., $5,500 therefore got the next band's amount, $22-23 less, and one at $5,500 got nothing instead of $56. ARS 43-1072(A)(3)(b) limits the credit to combined income "less than five thousand five hundred one dollars", so $5,500 qualifies. Every threshold after zero is now one dollar higher, matching Schedule 1 (living_alone.yaml), which already used 1,751, 1,851, ..., 3,751.

Law

  • ARS 43-1072: (A)(3)(a) "less than three thousand seven hundred fifty-one dollars" (living alone); (A)(3)(b) "less than five thousand five hundred one dollars" (living with others); the (B)(1) and (B)(2) tables.
  • Form 140PTC, page 2, Schedules 1 and 2, for 2021, 2022, 2023, 2024 and 2025. I parsed both tables from the statute page and from page 2 of each year's form. All five years match the statute row for row on both schedules, including "3,751 and up" and "5,501 and up" at $0.
  • The 2025 Form 140PTC instructions (lines 11a and 11b, page 5) tell the filer to find the line 10 household income in the schedule.

Incomes with cents

SingleAmountTaxScale.calc uses numpy.digitize with right=False. A band therefore covers its lower bound up to, but not including, the next band's lower bound, and $2,500.50 gets the $0-2,500 amount ($502), as if the cents were dropped. The statute lists whole-dollar bands and leaves the gap between, say, $2,500 and $2,501 unassigned. It does state the income limit as "less than" $5,501 (or $3,751), one dollar above the last band's upper bound, so the last band covers every income below the limit. Reading every band the same way gives this result, and it needs no formula change.

The alternative is to round to the nearest dollar. Form 140PTC line 10 takes whole dollars, and the 2025 Form 140 instructions (page 4) say to round to the nearest whole dollar. The 140PTC instructions have no rounding rule. Rounding would move an income with 50 cents or more into the next band, for example $2,500.50 to $479 and $5,500.50 to $0, which contradicts (A)(3)(b) at the top edge. A comment in both parameter files records this choice, and the tests pin it.

Changes

  • cohabitating.yaml: thresholds after zero become 2_501, 2_651, ..., 5_501.
  • Both schedule files: a comment on band edges and cents, and direct links to each year's form PDF (page 2) in place of the fillable-form landing page. Schedule 1's 2022 reference linked to the 2021 form and now links to the 2022 one. The statute citation names (A)(3) as well as (B).
  • az_property_tax_credit.yaml: the existing "filer at 79 meets criteria" case had household income of $5,500 on Schedule 2 and expected $0. It now expects $56: taxes paid are 100 + 0.15 × 1,500 = 325, so the credit is the table amount.

Tests

  • az_property_tax_credit_schedules.yaml (new, 142 cases), generated from the statute table. For each schedule it covers:

    • $0;
    • both sides of every band edge;
    • $X.50 above each band's upper bound;
    • $0.99 below the (A)(3) limit, and the limit itself ($3,751 and $5,501);
    • 2021 repeats.

    It also has six household-path cases where income and schedule are computed rather than input: a married couple at $2,500 and $2,501, a single claimant living with an adult child at $5,500 and $5,501, and a single claimant living alone at $3,750 and $3,751.

  • test_az_property_tax_credit_schedules.py (new, 65 tests): a differential test against an independent transcription of the statute tables, for every whole-dollar income from $0 to $7,000 and cents around every edge, in each year from 2021 to 2026. It runs through the parameter scales and through az_property_tax_credit in one vectorised Simulation per schedule.

  • On main, 48 of the 153 YAML cases in the two credit test files fail: every Schedule 2 upper edge and the cents cases, the 2021 repeats, the household cases at $2,500 and $5,500, and the corrected $5,500 case. Every Schedule 1 case passes on main, as it should. 19 of the 65 Python tests fail on main, all of them Schedule 2.

  • On this branch, all 625 YAML tests under states/az pass, as do test_parameter_files.py, test_parameter_scale_thresholds.py and the code_health folder.

Invariants

These hold for every income, in every year from 2021 to 2026, on both schedules, and are tested:

  1. Matches the statute. The scale equals the statute table at every whole-dollar income, and at cents near every edge it equals the band that holds the income's whole dollars.
  2. Contiguous transcription. The transcribed bands are contiguous whole-dollar ranges starting at $0, and the last upper bound is one dollar below the (A)(3) limit.
  3. Never rises. The amount never rises as income rises (checked on a $0.25 grid from $0 to $7,000).
  4. Bounds. Below the limit the amount is between $56 and $502; at and above the limit it is $0.
  5. Cents. An income with cents gets the same amount as its whole dollars.

Microsimulation impact

I ran a real microsimulation on the default dataset (populace_us_2024.h5@populace-us-2024-spm-20260909) on policyengine-core 3.32.15. It compared main at 6b0e773 with this branch, one period per process, under the shared heavy-run lock with a 24 GB footprint watchdog. Peak footprints were 9.1-9.4 GB.

2025 2026
Tax units with a changed credit 0 of 79,729 0 of 79,729
az_property_tax_credit, weighted total (both sides) $40,666,618 $40,957,022
Eligible units / eligible on Schedule 2 141 / 92 141 / 92
Eligible Schedule 2 units with income below $5,501 6 6
Eligible Schedule 2 units with income in a moved window [T, T+1), T = 2,500, 2,650, ..., 5,500 0 0

The fix changes the credit only for Schedule 2 incomes in those $1 windows, and the dataset has none. No aggregate moves.

Interaction with #9762 and #9770

Neither PR touches either schedule file. Both edit az_property_tax_credit.yaml, appending cases at the end; this PR changes one case in the middle, and git merges both heads with this branch cleanly.

No test in either PR depends on the old one-dollar-low thresholds.

axiom: us-az:statutes/43-1072#shared_household_credit_band encoded-correct

rulespec-us us-az/statutes/43-1072.yaml (main at 9f38330fb) encodes the Schedule 2 bounds as lower 0, 2501, 2651, ..., 5351 and upper 2500, 2650, ..., 5500, and shared_household_income_limit as 5501. Its companion tests in us-az/statutes/43-1072.test.yaml cover:

  • household income 2,500: band 0, $502;
  • household income 5,500: band 20, $56;
  • household income 5,501: eligible_under_shared_household_income_path does not hold, credit $0.

Two related gaps, neither in this PR's scope:

🤖 Generated with Claude Code

ARS 43-1072(B)(2) and Form 140PTC Schedule 2 (2021-2025) give the bands
for a claimant living with others as $0-2,500 -> $502, 2,501-2,650 -> $479,
..., 5,351-5,500 -> $56, 5,501 and up -> $0. The single_amount scale stored
each band's lower bound one dollar low (2,500, 2,650, ..., 5,500), so incomes
of exactly 2,500, 2,650, ..., 5,500 got the next band's amount and 5,500 got
nothing. Each threshold after zero is now one dollar higher, as Schedule 1
already is.

Both schedule files document how cents between whole-dollar bands are
treated (the lower band, matching the (A)(3) "less than" limits), cite each
year's form PDF directly, and Schedule 1's 2022 reference no longer points
at the 2021 form.

Tests: YAML cases at every band edge of both schedules, the (A)(3) limits,
cents between bands and the household path; a differential test of every
whole-dollar income and of cents around every edge against a transcription
of the statute, 2021-2026, through the scales and a vectorised simulation;
monotonicity and bounds invariants. The existing case at $5,500 expected $0
and now expects $56.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Hand-off to the US + core hub (from session local_b23249a1, which picked this up at the hub's request; the original owner was 7ca6f1d9).

  • Head: dbbe606.
  • Independent review: GPT-6.1 Sol (Subfleet job 20261006-012137-pe9779-review-r1-sol, rerouted from an Opus pin that had no capacity) returned APPROVE at this head. Report: ~/reviews/az-ptc-line-d-fold-2026-10-04/review_9779_r1.md (summary) and review_9779_r1_full.md (full).
    • It checked both schedules against all 42 statutory rows and every 2021-2025 form.
    • Tests: 625 Arizona YAML and 65 Python tests pass; with Count capital gains once in Arizona property tax credit income #9762, 665 YAML and 71 Python tests pass.
    • The old parameters fail as stated (48 YAML, 19 Python, all on Schedule 2).
    • Nits, not blocking:
      • the full-model property test runs 2025 only;
      • "every income" overstates the tested domain (a float32 artefact at $5,500.9999).
    • Pre-existing, outside this PR:
      • az_property_tax_credit_eligible has no income ceiling; the scales still return $0;
      • household income omits co-residents in other tax units.
  • CI: all 35 checks pass on this head.
  • Waiting on: merge order and an approving review. It is independent of Count capital gains once in Arizona property tax credit income #9762: the two merge cleanly in either order and the combined tests pass.
  • Axiom: us-az:statutes/43-1072#shared_household_credit_band encoded-correct (in the body).

🤖 Generated with Claude Code

@MaxGhenis
MaxGhenis merged commit a5f5135 into main Oct 6, 2026
35 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merged by the US + core hub on its merge gates. Audit:

  • Head: dbbe606064, handed off by session b23249a1 for the original owner 7ca6f1d9.
  • Independent review: GPT-6.1 Sol APPROVE at this head (~/reviews/az-ptc-line-d-fold-2026-10-04/review_9779_r1_full.md). It checked both Schedule 2 tables against all 42 statutory rows and every 2021–2025 form. The old parameters fail 48 YAML and 19 Python tests; the new ones pass. Two nits are non-blocking.
  • CI: every check passed at this head.
  • Impact: the default-dataset microsimulation, 2025 and 2026, is in the body. It is independent of Count capital gains once in Arizona property tax credit income #9762: they merge cleanly in either order, and the combined tests pass.

@MaxGhenis
MaxGhenis deleted the fix-az-ptc-schedule-2-thresholds branch October 6, 2026 08:29
MaxGhenis added a commit that referenced this pull request Oct 6, 2026
Brings in #9841 (28 percent rate gain and unrecaptured section 1250 gain
netted against losses), #9801, #9790, #9779, #9768, #9741 and #9630. Only
test_section_911_tax_stacking.py changed on both sides, in different
functions, and git merged it without conflict. #9841 passes Schedule D
lines 18 and 19 entered already netted through unchanged, and this
branch's capital_gains_tax, reforms and tests read the section 911
amounts and Schedule D inputs that #9841 keeps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant