Skip to content

Fix NY IT-214 real property tax credit eligibility - #9301

Merged
hua7450 merged 4 commits into
PolicyEngine:mainfrom
DTrim99:fix/ny-it214-eligibility
Aug 19, 2026
Merged

Fix NY IT-214 real property tax credit eligibility#9301
hua7450 merged 4 commits into
PolicyEngine:mainfrom
DTrim99:fix/ny-it214-eligibility

Conversation

@DTrim99

@DTrim99 DTrim99 commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes #9298.

What

Two fixes to ny_real_property_tax_credit, both surfaced by TAXSIM issue #1135:

  1. Renter cap (IT-214 line 21). The average-monthly-rent cap of $450 (annual $5,400) is applied to the rent itself, not to 25% of the rent. The 25% rent-to-property-tax equivalence (line 22) is only used to size the credit, not to test eligibility. Previously PE compared 0.25 × rent to the $5,400 cap, letting through renters paying up to ~$21,600/yr.

  2. Income measure (IT-214 line 16). Eligibility and the credit maximum are keyed to household gross income — federal AGI plus income that is not taxed but still counts (nontaxable Social Security, SSI, tax-exempt interest) — not federal AGI. Previously PE used AGI, so a household with, e.g., $6,600 pension + $15,506 Social Security had its income read as ~$6,600 instead of ~$22,100 and wrongly qualified.

New variable

ny_household_gross_income implements IT-214 Step 3 (line 16 = lines 9–15): federal AGI + nontaxable Social Security + SSI + tax-exempt interest.

Tests

  • ny_household_gross_income: AGI + nontaxable Social Security.
  • ny_real_property_tax_credit: existing homeowner test still passes (household gross income = AGI there); added a renter-over-cap case, a household-gross-income-over-$18,000 case, and the Add MD income tax to State income tax #1135 elderly filer — all correctly return 0.

Reference: Form IT-214 instructions.

🤖 Generated with Claude Code

Apply the $450/month renter cap (IT-214 line 21) to the rent itself
rather than to 25% of the rent, and gate eligibility on IT-214
household gross income (line 16) — which adds nontaxable Social
Security and other untaxed income to federal AGI — instead of federal
AGI. Adds ny_household_gross_income.

Fixes PolicyEngine#9298

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (8326a14) to head (d1c6523).
⚠️ Report is 55 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##              main     #9301    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files           12         2    -10     
  Lines          161        53   -108     
  Branches         0         1     +1     
==========================================
- Hits           161        53   -108     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@DTrim99
DTrim99 requested a review from PavelMakarchuk August 18, 2026 18:25
@DTrim99
DTrim99 marked this pull request as ready for review August 18, 2026 18:25
@DTrim99
DTrim99 requested a review from hua7450 August 18, 2026 19:47

@hua7450 hua7450 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.

Thanks for this — I checked it out locally, pulled the IT-214 instructions for 2022–2025, the 2024 and 2025 fill-in forms, Tax Law §606(e), and the DTF 2025 legislative summary, and ran the PR's tests plus a couple of probes. Fix 1 is right; fix 2 is right through TY2024 but is a regression for TY2025+, and the cited PDF actually says the opposite of what the code does. Details below.

✅ Renter cap applied to rent itself

Correct in every year I checked. 2024 IT-214-I: "average monthly rent you and other members of your household paid was $450 or less"; the 25% (line 22 in 2024 / line 14 in 2025) only sizes the credit. rent <= max_rent is the right test.

❌ Household gross income is the wrong income measure for TY2025+

The law changed. Part RR of Chapter 59 of the Laws of 2025 amended §606(e) effective for tax years beginning on/after 2025-01-01. DTF's summary: "For tax years beginning on or after January 1, 2025, eligibility for the credit is based on federal adjusted gross income (FAGI) instead of household income, and the calculation of the credit amount is simplified."https://www.tax.ny.gov/legal/2025/pit-corp-changes.htm

The PDF the new variable cites (current_forms/it/it214i.pdf#page=2) is the 2025 form. Its Step 3 is "Determine excess of federal adjusted gross income", line 8 = FAGI, "If line 8 is more than $18,000, stop; you do not qualify." There is no household-gross-income step / line 16 in it. The "Step 3, lines 9–16" comment describes the 2024-and-earlier form: https://www.tax.ny.gov/pdf/2024/inc/it214i_2024.pdf#page=2

Probe (fails on this branch):

- name: 2025 - FAGI 6,000, nontaxable SS 15,000 - 2025 law keys on FAGI, so still qualifies
  period: 2025
  input:
    people:
      head: {age: 71, employment_income: 6_000, social_security: 15_000, rent: 3_000}
    households:
      household: {members: [head], state_code: NY}
  output:
    adjusted_gross_income: 6_000
    ny_household_gross_income: 21_000
    ny_real_property_tax_credit: 300   # branch returns 0; 2025 Table A, FAGI 5,001–7,000 → $300

Before this PR the AGI-based gate was correct on the income measure for 2025+ (which is what the app defaults to); after it, filers with untaxed Social Security are denied.

Ask: year-gate the income measure — a dated formula (formula_2025) or a parameter switch (e.g. uses_household_gross_income: 2000-01-01 true, 2025-01-01 false) — so the credit uses ny_household_gross_income through 2024 and adjusted_gross_income from 2025. Add a 2025 test like the one above, and point the new variable's reference at the year-specific 2024 instructions (the current_forms/ URL always resolves to the latest year).

Should-fix in this PR

  • ny_household_gross_income (pre-2025 concept) omits statutory items PE already models: pensions/annuities not in AGI (line 13), cash public assistance / TANF (line 14), workers' compensation, child support ("support money"), veterans disability pensions (line 11). Either add the ones we have variables for or list the omissions in the docstring. Also, HGI is all household members' income by statute (§606(e)(1)(C)); summing at the tax unit is a reasonable simplification but should be stated.
  • max_agi.yaml says "maximum AGI" — true for 2025+, but pre-2025 the limit is household gross income; a neutral label ("income limit") would avoid the mismatch.
  • The < in household_gross_income < rptc.max_agi should be <= — form says "$18,000 or less" (pre-existing, but the line is being touched).

Pre-existing, surfaced by this review — suggest a follow-up issue rather than expanding this PR

  • The 2025+ credit amount is now a flat table lookup, not 50% of excess: Table A (65+) $375/330/300/260/230/200/150 by FAGI bracket, Table B (<65) $75/70/60/50, with "RPT > FAGI × rate" as a pure gate — https://www.tax.ny.gov/pdf/current_forms/it/it214_fill_in.pdf#page=3. PE's formula and the 18-row cap chart match the 2024 form exactly (I checked), so maximum/*.yaml, rate.yaml, and the formula need 2025-01-01 branches.
  • Elderly tier: both 2024 and 2025 say $375 applies if "you, your spouse, or a dependent claimed was 65 or older" (2025 Line 7). tax_unit.any(~is_dependent & aged) wrongly excludes dependents.

Sources: 2025 IT-214-I · 2024 IT-214-I · 2024 IT-214 · 2025 IT-214 · DTF 2025 PIT changes · Tax Law §606

…om 2025)

- Part RR of Ch. 59 of the Laws of 2025 amended Tax Law 606(e): from TY2025 the
  IT-214 credit keys on federal AGI, not household gross income. The PR's switch
  to ny_household_gross_income regressed 2025+ (filers with untaxed Social
  Security were denied). Add a uses_household_gross_income parameter
  (2000 true, 2025 false) and select the income measure accordingly - HGI
  through 2024, adjusted_gross_income from 2025.
- max_agi: neutral 'income limit' label (the measure differs pre/post-2025).
- Income gate is now <= the limit ('$18,000 or less').
- ny_household_gross_income: point the reference at the year-specific 2024
  instructions (current_forms/ resolves to the 2025 FAGI form) and document the
  omitted statutory line items and the all-household-members vs tax-unit
  simplification.
- Add a 2025 test showing a filer with nontaxable Social Security now qualifies.

Deferred to PolicyEngine#9310 (per review): the 2025+ flat credit-amount tables and the
elderly-tier dependent inclusion. NY IT-214 suite 6/6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@DTrim99

DTrim99 commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed — thanks @hua7450, great catch on the 2025 regression

You were right that switching the income measure to household gross income unconditionally regressed TY2025+. Pushed (NY IT-214 suite 6/6).

The 2025 regression (critical)

Year-gated the income measure via a new uses_household_gross_income parameter (2000-01-01: true, 2025-01-01: false), so the credit uses ny_household_gross_income through 2024 and adjusted_gross_income from 2025 per Part RR of Ch. 59 of the Laws of 2025 (§606(e)). Added your probe as a test — the 2025 filer with $15,000 nontaxable Social Security now qualifies (FAGI $6,000 ≤ $18,000) instead of being denied.

One note: that test asserts $15, not $300 — the income gate is now correct, but the 2025 credit amount still runs through the pre-2025 formula (50% of excess) rather than the flat Table A/B lookup. Per your suggestion I kept the amount change out of this PR and tracked it in the follow-up below, so the point of the test is "no longer zero."

Should-fixes (all applied)

  • ny_household_gross_income omissions — documented in the variable's new docstring: the omitted statutory line items (pensions/annuities not in AGI, cash public assistance/TANF, workers' comp, child support/support money, veterans' disability pensions) and that HGI is statutorily all household members' income while we sum at the tax unit.
  • max_agi label — relabeled to the neutral "income limit" (the measure differs pre/post-2025).
  • <<= — the income gate now matches "$18,000 or less."
  • Reference — repointed ny_household_gross_income at the year-specific 2024 instructions (2024/inc/it214i_2024.pdf), since current_forms/ resolves to the 2025 FAGI form.

Follow-up (per your suggestion): #9310

Opened #9310 for the two pre-existing items you flagged, since both touch the credit amount and are best done together: (1) the 2025+ flat credit-amount tables (Table A/B by FAGI bracket, with the RPT-vs-FAGI gate) replacing 50%-of-excess, and (2) the elderly $375 tier wrongly excluding dependents (~is_dependent & aged should drop the ~is_dependent so a claimed 65+ dependent qualifies).

Fixed with Claude Code assistance.

@hua7450 hua7450 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.

Re-reviewed 98fbf36 locally. The year-gate, <=, relabel, docstring, reference, and changelog all look right, and #9310 captures the two deferred items cleanly. One more thing surfaced while checking the new 2025 test's arithmetic, and I think it should go in this PR because the new test otherwise enshrines it.

❌ New 2025 test asserts $15 — that number is an artifact of a parameter bug, not "the pre-2025 formula applied to FAGI"

Hand calc for the 2025 case: FAGI $6,000 → rate 4.5% → threshold $270; RPT equivalent 25% × $3,000 = $750; excess $480; 50% = $240; elderly cap at $6,000 = $273 → $240.

PE returns $15 because real_property_tax/excess_real_property_tax.yaml has no type: single_amount in its metadata, so Core loads it as a MarginalAmountTaxScale and .calc(income) returns the cumulative sum of the bracket rates:

income:            0   1000  3000  3001  5000  6000  10000  17999
.calc() today:   0.0  0.035 0.035 0.075 0.075 0.12  0.225  0.35
should be:      0.035 0.035 0.035 0.04  0.04  0.045 0.055  0.065

So at $6,000 the threshold is 6,000 × 0.12 = $720, excess $30, credit $15. Above ~$3,000 of income the threshold is 2–5× too high and wipes out most credits — which is the opposite direction from the over-granting this PR fixes. The existing homeowner test never caught it because $25k of real-estate tax blows past the threshold either way and lands on the cap. (Pre-existing — the param dates to Jan 2026 — but this PR is the first thing to write a test that depends on the rate.)

Ask: add type: single_amount to excess_real_property_tax.yaml metadata (same as maximum/elderly.yaml / non_elderly.yaml), change the 2025 expectation to 240, and drop the test comment that explains $15 as the pre-2025 formula. I applied that one-line change locally and ran the NY IT-214 files: the 2025 case becomes $240 and the other four still pass. Changelog: add a line for the rate-scale fix.

Nits (can ride with #9310)

  • maximum/*.yaml single-amount brackets switch at exactly the threshold (.calc(1000) → 358), but the 2024 chart's rows are "$0 to 1,000 → 375", "1,001 to 2,000 → 358" — i.e. the step belongs at 1,001. Same boundary pattern for excess_real_property_tax once it's single_amount ("$3,001 to 5,000 → 0.040"). Off-by-a-dollar; the ny_real_property_tax_credit.py first test is named "Homeowner with $25 rent" but the input is real_estate_taxes: 25_000 — name could say $25k real estate taxes.

Everything else in the response commit checks out; happy to approve once the single_amount fix + 240 expectation are in.

hua7450 and others added 2 commits August 19, 2026 16:41
- excess_real_property_tax.yaml lacked `type: single_amount`, so Core loaded
  it as a MarginalAmountTaxScale and .calc(income) returned the cumulative sum
  of bracket rates (0.12 at $6,000 instead of 0.045), overstating the income
  threshold and zeroing most credits. Mark it single_amount; the 2025 test
  expectation becomes $240 (the pre-2025 formula on FAGI) instead of $15.
- Floor the income measure at zero per IT-214 ("Your federal adjusted gross
  income cannot be an amount less than zero"); negative AGI previously fell
  below the first cap bracket and zeroed the credit. Add a test.
- Note that the renter cap is legally on adjusted rent (PE has gross rent only);
  rename the first test to match its input.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hua7450

hua7450 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Pushed 4d669d1 (+ a merge of upstream/main) to this branch with the items from my second review, so you don't have to round-trip — @DTrim99 please sanity-check. NY IT-214 suite 7/7 locally.

What changed

  • real_property_tax/excess_real_property_tax.yaml — added type: single_amount. Without it Core loaded the rate table as a MarginalAmountTaxScale and .calc(income) returned the cumulative sum of bracket rates (0.12 at $6,000 instead of 0.045; 0.35 at $18k instead of 0.065), inflating the income threshold and zeroing most credits. Pre-existing, but the new 2025 test was the first assertion sensitive to the rate.
  • ny_real_property_tax_credit.yaml — 2025 case expectation 15 → 240 (pre-2025 formula on FAGI: threshold 270, rent equiv 750, excess 480, 50% = 240, cap 273), comment rewritten with the arithmetic and a pointer to NY IT-214: model the 2025+ flat credit-amount tables and fix the elderly tier to include dependents #9310 for the $300 Table A value; renamed the first test to match its real_estate_taxes: 25_000 input.
  • ny_real_property_tax_credit.pyincome = max_(income, 0) per IT-214 line 8/9 ("Your federal adjusted gross income cannot be an amount less than zero … enter 0"). Negative AGI previously fell below the first cap bracket and zeroed the credit. New test: AGI −$20k, SS $15k, rent $3k → $375. Also noted in a comment that the renter cap is legally on adjusted rent (net of heat/utilities/board) while PE only has gross rent.
  • changelog.d/fix-ny-it214-eligibility.fixed.md — two lines added for the above.

Left for #9310 (not touched here): the $X,001 bracket boundaries in the three bracket parameters, and the elderly tier excluding dependents.

Will approve once CI is green.

@hua7450
hua7450 self-requested a review August 19, 2026 21:15
@hua7450
hua7450 merged commit ba4ee19 into PolicyEngine:main Aug 19, 2026
33 checks passed
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.

NY real property tax credit (IT-214) granted to ineligible renters and over-income households

2 participants