Fix NY IT-214 real property tax credit eligibility - #9301
Conversation
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 Report✅ All modified and coverable lines are covered by tests. 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
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
hua7450
left a comment
There was a problem hiding this comment.
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 → $300Before 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.yamlsays "maximum AGI" — true for 2025+, but pre-2025 the limit is household gross income; a neutral label ("income limit") would avoid the mismatch.- The
<inhousehold_gross_income < rptc.max_agishould 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>
Addressed — thanks @hua7450, great catch on the 2025 regressionYou 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 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)
Follow-up (per your suggestion): #9310Opened #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 ( Fixed with Claude Code assistance. |
hua7450
left a comment
There was a problem hiding this comment.
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/*.yamlsingle-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 forexcess_real_property_taxonce it's single_amount ("$3,001 to 5,000 → 0.040"). Off-by-a-dollar; theny_real_property_tax_credit.pyfirst test is named "Homeowner with $25 rent" but the input isreal_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.
- 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>
|
Pushed What changed
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. |
Fixes #9298.
What
Two fixes to
ny_real_property_tax_credit, both surfaced by TAXSIM issue #1135: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 × rentto the $5,400 cap, letting through renters paying up to ~$21,600/yr.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_incomeimplements 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