Repository navigation
Count property tax and rent refunds paid outside the income tax in household and SPM benefits - #10725
Merged
Merged
Conversation
MaxGhenis
force-pushed
the
nd-renters-refund-net-income
branch
from
November 9, 2026 09:10
cc9a076 to
41ec5a8
Compare
…usehold and SPM benefits North Dakota's renter's refund sat only in state_property_tax_credits, which feeds the TAXSIM comparison and nothing else, so it reached no household net income, SPM resources or poverty measure. Five other members of that list had the same gap: Minnesota's homestead credit refund, Montana's property tax rebate, Pennsylvania's property tax or rent rebate, Vermont's renter credit and the renter part of Utah's homeowner's and renter's relief. Each state pays these on its own claim, outside the income tax return. A new year-gated list, state_property_tax_refunds, holds the six, and a tax-unit total of the same name adds them. household_state_benefits and spm_unit_benefits (with its four reform copies) count the total, so both net incomes move by the same dollar. Utah's relief splits into ut_renters_credit, which the Tax Commission pays, and ut_homeowners_credit, which counties apply against the property tax bill (Utah Code 59-2a-205(5) and 59-2a-302(2)(b)). The other bill reductions in the list (North Dakota's primary residence credit, DC's senior and disabled relief and Indiana's three credits) stay out of both totals, as no net income total subtracts property tax. The 18 remaining members already reach both totals through state income tax credit lists. The parity test gains invariant 7: every member of state_property_tax_credits has exactly one documented route, and a differential simulation over all of them checks that both net incomes move together, by the full amount for a refund and not at all for a bill reduction. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The new test walks every year either list changes, from the refund list's first block, and fails when a refund enters state_property_tax_refunds before it enters state_property_tax_credits. A copy of the list with Pennsylvania's rebate in the 2024 block fails it at 2024. The list's comment no longer says each refund enters in the first year PE-US defines its parameters: North Dakota's cap and income limit start in 2009, and Montana's rebate amount in 2021 at zero. It now says that years before 2021 take the 2021 block, as household_state_benefits' first block covers the years before it, and that policyengine-core reads an empty block as no list, which breaks adds. Vermont's comment names Schedule IN-112. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the whole dollar cc9a076 dropped the empty first block from state_property_tax_refunds and said policyengine-core reads an empty block as no list. That was wrong. An empty list block works with adds. The crash came from my own test loop, which started at 1976, before any block and before PE-US copies parameters back to 2015, so the parameter returned None. Without the block, PE-US copied the 2021 block back to 2015 and counted the Vermont renter credit that the model computes for 2015 to 2020 from its 2021 parameters. The list now opens with an empty block on 1977-01-01, the first date of state_property_tax_credits, and a YAML case keeps the 2020 credit out of both benefit totals. test_property_tax_credits_move_both_net_incomes_together let an income tax credit lose part of its value to federal tax through the SALT deduction. Each of the 18 income tax credits moved both totals by the full amount, at $500 and $4,321, so the test now requires the full amount. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vt_renter_credit had no renter test, so it gave every low-income Vermont tax unit a credit based on fair market rent, homeowners included. Only the TAXSIM comparison read the amount until this branch counted the credit in benefits. The AABD integration case then showed the result: $1,324 more in household_state_benefits for a person who pays no rent. 32 V.S.A. 6066(b)(1) gives the credit to "an eligible claimant who rented the homestead", and 6066(c)(3) requires at least six calendar months of renting. vt_renter_credit_eligible applies the rent test. PE-US has no months-rented input, so rent paid stands in for the six-month test. PE-US #10044 adds the 6066(c)(2) dependent bar with its joint-return reading, so this commit leaves that bar to it. The YAML cases and department-table tests set rent to 0 while checking the credit amount. They now set rent, and new cases and properties cover a tax unit that pays no rent and a tenant whose subsidy covers all the rent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Counting the credit in net income puts its formula on every household's path. Core runs a formula over the whole population whenever any row passes defined_for, and the formula indexes tables by tax unit size and county. A 2026 microsimulation raised ParameterNotFoundError on a tax unit of nine, and a county outside Vermont's tables raises the same way. This takes the Vermont guard from #10116 word for word: tax units above eight people use the eight-person values, and a county outside Vermont's tables falls back to Addison. The department's 2025 calculator looks up IF(Household_Size>8,8,Household_Size) and accepts family sizes 1 to 10. The fallback changes nothing for a household in a Vermont county. #10116's four Vermont YAML cases move to vt_renter_credit_lookups.yaml with rent set, since this branch gives no credit to a tax unit that paid no rent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
force-pushed
the
nd-renters-refund-net-income
branch
from
November 9, 2026 09:37
41ec5a8 to
dc5083e
Compare
MaxGhenis
marked this pull request as ready for review
November 9, 2026 10:08
Contributor
Author
|
This PR needed admin rights to merge at |
This was referenced Nov 9, 2026
MaxGhenis
added a commit
that referenced
this pull request
Nov 9, 2026
#10725 added the refund to household and SPM benefits, so the income changes in this pull request now reach both net incomes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
pushed a commit
that referenced
this pull request
Nov 9, 2026
GitHub reported the branch as conflicting with main. Both conflicts keep both sides: - repeal_state_dependent_exemptions.yaml: main's three California repeal cases from #10053 follow this branch's WV, WI and RI cases. - vt_renter_credit.py: main's #10725 added the rent test, the household size cap and safe_county. The fair market rent now indexes on this branch's exemption count and main's safe_county, while the income limits keep main's capped size. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Nov 9, 2026
…ome and the CBO measures #10725 added state_property_tax_refunds to household benefits. Appendix A leaves out tax refunds, and CBO's lists name no state tax relief, so both concepts leave the refunds out, as they do New Jersey's ANCHOR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
North Dakota pays its renter's refund on its own application (SFN 24777), outside the income tax, yet the refund reached no household net income, SPM resources or poverty measure.
nd_renters_refundsat only instate_property_tax_credits, which feedstaxsim_state_property_tax_creditand its deprecated alias and nothing else. Five other members of that list had the same gap: Minnesota's homestead credit refund, Montana's property tax rebate, Pennsylvania's property tax or rent rebate, Vermont's renter credit and the renter part of Utah's homeowner's and renter's relief.Changes
gov.states.household.state_property_tax_refundslists the six cash refunds by year, and the tax-unit variablestate_property_tax_refundsadds them. Each refund enters in the year it entersstate_property_tax_credits, so the new list stays inside that one in every year. The list opens with an empty block on that list's first date (1977). Without it, the model would copy the 2021 block back to 2015, its first modeled year, and count the Vermont renter credit it computes for 2015 to 2020 from its 2021 parameters.household_state_benefits(2023 to 2026 blocks) andspm_unit_benefits, with its four reform copies, countstate_property_tax_refunds, so each refund raises both net incomes by the same dollar.ut_homeowner_renter_reliefnow adds two new variables. The Tax Commission paysut_renters_creditfrom the General Fund (Utah Code 59-2a-205(5)), and counties applyut_homeowners_creditagainst property taxes accrued (59-2a-302(2)(b) and 59-2a-304). The total keeps its place instate_property_tax_credits, and its amounts don't change.vt_renter_creditnow pays only tax units that paid rent. It gave every low-income Vermont tax unit a credit based on fair market rent, homeowners included, and only the TAXSIM comparison read that amount until this PR. Vermont gives the credit to a claimant "who rented the homestead" and requires six calendar months of renting (32 V.S.A. 6066(b)(1) and (c)(3)). The model has no months-rented input, so the newvt_renter_credit_eligibletests for rent above zero. A tenant whose subsidy covers all the rent gets nothing, because Vermont pays a subsidized tenant a share of the gross rent paid under (b)(1)(D). The 28 YAML cases that setrent: 0while checking the credit amount now set rent, with the same expected amounts.vt_renter_creditnow runs for every household. Counting it in net income puts its formula on every household's path, and core runs a formula over the whole population whenever any row passesdefined_for. The formula indexes tables by tax unit size and county, so tax units of nine or more and counties outside Vermont's tables raisedParameterNotFoundError. This PR takes the Vermont lookup guard from Guard county-keyed lookups in VT renter credit, MN CCAP, WI Shares and MD CCS #10116 word for word. Tax units above eight people use the eight-person values, as the Department of Taxes' calculator does (IF(Household_Size>8,8,Household_Size)), and a county outside Vermont's tables falls back to Addison. Vermont adopts HUD's limits in 32 V.S.A. 6061(19) and (20), and HUD adjusts them for larger families under 42 U.S.C. 1437a, so the eight-person cap stands in until the model encodes HUD's schedule.2026 impact
We estimate these refunds add $525.8 million to household net income and to SPM net income in 2026, on the default Populace release (
populace-us-2024-spm-20260909). Main raises an error when it computesvt_renter_creditfor every household, so our baseline adds only the Vermont lookup guard to main at9960edee31, and the branch atdc5083e7daruns against it. Main's net income never reads that variable, so the baseline's net income matches main's.Each household's and SPM unit's net income moves by its refunds to within $0.02, the rounding of the model's 32-bit totals. No household's net income falls, market income doesn't change, and every other refund and bill credit keeps its baseline amount.
marginal_tax_ratereadshousehold_net_income, so each income-tested refund's phase-out now shows in household marginal tax rates.We estimate SPM poverty stays at 13.75% nationally and doesn't change at two decimal places in any of the six states. The sample holds 245 SPM units with a refund, 36 of them in poverty, and the one that crosses the line has a weight under 0.001. We estimate national deep poverty falls by 1,811 people, all from one Vermont record.
None of the six programs has a take-up variable, so the model pays every eligible tax unit. North Dakota's refund, Pennsylvania's rent rebate, Utah's renter credit and Vermont's credit read
rent, and this release predates PolicyEngine/microcosm#1444, which places each rent draw on its own household's head. For example, we estimate 19% of Vermont's renter tax units and 16% of its owner tax units carry rent, and owner tax units receive 59% of Vermont's credit.We estimate
vt_renter_creditat $28.2 million for 24,100 tax units with the rent test and $178.3 million for 166,700 without it, an amount only the TAXSIM comparison read. The Department of Taxes reports 12,010 recipients and $7.2 million for the credits it paid in 2024 on 2023 income, and our 2026 estimate exceeds those by 101% and 290%. The Vermont lookup guard moves no Vermont amount in this release: every Vermont household has a Vermont county, and the largest Vermont tax unit has seven people.In Act 169, Vermont raised its rate to 12.5% and its cap to $3,250 for claim year 2027, when it takes claims on 2026 income under 32 V.S.A. 6061(9) and (12). Main applies them to 2027, so the Vermont figure here uses the 10% rate and the $2,500 cap.
Every member of
state_property_tax_creditsnd_renters_refundmn_homestead_credit_refundmt_property_tax_rebatepa_property_tax_or_rent_rebatevt_renter_creditut_renters_credit, part ofut_homeowner_renter_reliefnd_primary_residence_creditdc_senior_disabled_property_tax_reliefin_blind_disabled_property_tax_credit,in_over_65_property_tax_creditin_supplemental_homestead_creditut_homeowners_credit, part ofut_homeowner_renter_reliefaz_property_tax_credit,ct_property_tax_credit,dc_ptc,il_property_tax_credit,ma_senior_circuit_breaker,me_property_tax_fairness_credit,mi_homestead_property_tax_credit,mn_renters_credit,mo_property_tax_credit,mt_elderly_homeowner_or_renter_credit,nj_property_tax_credit,nm_property_tax_rebate,ny_real_property_tax_credit,ok_ptc,ri_property_tax_credit,wi_homestead_credit,wi_property_tax_credit,wv_homestead_excess_property_tax_creditmt_refundable_creditsandnj_refundable_creditsNeither net income total subtracts property tax, so a credit that lowers the bill moves neither.
household_net_incomecounts utility bill discounts (CARE, FERA, EZ-SAVE, SHARE) as benefits, and we leave open whether property tax bill credits should follow.Invariants
Tests execute each of these for every input they draw:
state_property_tax_creditstakes exactly one route in every year from 2023 to 2026, and the state lists named for income tax credits hold them (test_every_property_tax_credit_has_one_documented_route,test_property_tax_credit_routes_have_no_stale_entries).state_property_tax_refundsholds nothing outsidestate_property_tax_creditsin any year either list changes (test_refunds_stay_inside_the_credits_list_in_every_year).household_net_incomeandspm_unit_net_incomeby a full dollar for a refund or income tax credit and by nothing for a bill reduction.test_property_tax_credits_move_both_net_incomes_togetherdraws the amount with Hypothesis and runs one simulation with a pair of households for every member.test_a_dollar_of_cash_adds_a_dollar_to_both_totalsdraws the payment fromCASH_PAYMENTS, which now holds the six refunds.HOUSEHOLD_ONLYandSPM_ONLYdocument it. Every reform copy ofspm_unit_benefitskeepsstate_property_tax_refunds(SHARED_CASH_PROGRAMSintest_aggregate_list_integrity.py). The same file checks that each member of the new list names a defined variable with a state gate, and that no later year block drops a member.test_a_household_that_pays_no_rent_gets_no_credit,test_unsubsidized_credit_does_not_depend_on_rent_paid).New YAML cases in
gov/states/tax/property/state_property_tax_refunds.yamlput each refund in both totals, run North Dakota's worked example, start Pennsylvania's rebate in 2025 and Vermont's renter credit in 2021, split a Utah owner who also rents, and keep North Dakota's and Indiana's bill credits out of both totals.vt_renter_credit_eligible.yamlcovers a renter, a homeowner, a tenant whose subsidy covers all the rent, a couple where the spouse pays the rent, and a renter outside Vermont.vt_renter_credit_lookups.yamlruns out-of-state, unknown-county and nine-or-more households in one simulation. Utah's relief cases now assert both parts.Related PRs
spm_unit_benefitsinto a parameter. Whichever PR merges second addsstate_property_tax_refundsto that parameter.nd_renters_refund_incomeas an input, and each test household that computes it fails the age and disability test, so neither PR moves an expectation here.vt_renter_credit, so whichever PR merges second keepssafe_countyand theexemptionsindex.vt_renter_credit_lookups.yamlcarries its four Vermont cases with rent set.Flaky test on main
test_cash_income_never_lowers_spm_net_incomecan fail on main when Hypothesis draws Connecticut with a small amount, because $1 of partnership income at $500,000 of wages raises Connecticut income tax by $50.07 through a recapture step.axiom: TheAxiomFoundation/rulespec-us#1810 queued (32 V.S.A. 6066(b)(1) and (c)(3) rent test); TheAxiomFoundation/rulespec-us#1678 queued (household sizes above the eight-person tables); n/a for the refund lists, Utah's split and the county fallback: aggregation and lookup plumbing, no provision's rules change
🤖 Generated with Claude Code