Skip to content

Add Texas school district homestead exemptions#8312

Open
daphnehanse11 wants to merge 5 commits into
PolicyEngine:mainfrom
daphnehanse11:codex/tx-over-65-school-property-tax-exemption
Open

Add Texas school district homestead exemptions#8312
daphnehanse11 wants to merge 5 commits into
PolicyEngine:mainfrom
daphnehanse11:codex/tx-over-65-school-property-tax-exemption

Conversation

@daphnehanse11
Copy link
Copy Markdown
Collaborator

@daphnehanse11 daphnehanse11 commented May 14, 2026

Summary

  • Adds Texas school district residence homestead exemption parameters for the current $140,000 general school-district exemption and additional $60,000 age-65-or-disabled exemption.
  • Adds eligibility and exemption-value variables, including disabled and surviving-spouse eligibility, with combined exempt value capped by assessed property value.
  • Adds focused tests for general, additional, and total school district homestead exemption values.

Closes #8204.

Value Review

  • Texas Comptroller lists a $140,000 residence homestead exemption for school taxes for all residence homestead owners.
  • Texas Comptroller lists an additional $60,000 residence homestead exemption for school taxes for age-65-or-disabled residence homestead owners, making the modeled combined maximum $200,000.
  • TEA's Tax Year 2025 guidance says SB 4 and SB 23 raise the general exemption from $100,000 to $140,000 and the age-65-or-disabled exemption from $10,000 to $60,000 for TY 2025.
  • The surviving-spouse age threshold is 55 per the Comptroller's summary of Tax Code Section 11.13(q). This model approximates continuation eligibility with available filing-status inputs.

Note: this PR models exempt value only, not a property-tax reduction amount, because the statewide exemption applies to school district taxes and PolicyEngine currently has a single real-estate-tax input rather than a school-tax component.

Sources:

Tests

  • uv run policyengine-core test policyengine_us/tests/policy/baseline/gov/states/tx/tax/property/school_district_homestead_exemption -c policyengine_us
  • uv run pytest policyengine_us/tests/test_parameter_files.py policyengine_us/tests/test_system_import.py -q
  • uv run --extra dev ruff check policyengine_us/variables/gov/states/tx/tax/property/school_district_homestead_exemption

@codecov
Copy link
Copy Markdown

codecov Bot commented May 14, 2026

Codecov Report

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

Additional details and impacted files
@@             Coverage Diff              @@
##             main     #8312       +/-   ##
============================================
+ Coverage   78.72%   100.00%   +21.27%     
============================================
  Files        4723         5     -4718     
  Lines       68774        62    -68712     
  Branches      340         0      -340     
============================================
- Hits        54142        62    -54080     
+ Misses      14554         0    -14554     
+ Partials       78         0       -78     
Flag Coverage Δ
unittests 100.00% <100.00%> (+21.27%) ⬆️

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

☔ View full report in Codecov by Sentry.
📢 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.

@daphnehanse11 daphnehanse11 marked this pull request as draft May 14, 2026 20:29
@daphnehanse11 daphnehanse11 marked this pull request as ready for review May 26, 2026 19:50
@daphnehanse11 daphnehanse11 requested a review from hua7450 May 26, 2026 20:15
@hua7450
Copy link
Copy Markdown
Collaborator

hua7450 commented May 26, 2026

Program Review — PR #8312 Texas school district homestead exemptions

Source Documents

  • PDF 1: TEA TAA — Tax Year 2025 Maximum Compressed Tax Rates (3 pp, June 12 2025) — https://tea.texas.gov/sites/default/files/taa-2025-06-12-tax-year-2025-maximum-compressed-tax-rates.pdf
  • PDF 2: Texas Comptroller 96-1740 — Texas Property Tax Exemptions (27 pp) — https://comptroller.texas.gov/taxes/property-tax/docs/96-1740.pdf
  • PDF 3: Texas Comptroller 96-669 — Property Tax Law Changes 2025 (56 pp) — https://comptroller.texas.gov/taxes/property-tax/docs/96-669.pdf
  • Year: 2024–2025 (TY2025 primary target)
  • Scope: PR changes only (4 params + 5 vars + 4 tests + 1 changelog)

Branch Status

⚠ PR branch is 283 commit(s) behind main. Consider rebasing before merging. Review was scoped to the PR's actual changes — staleness did not affect findings.

Critical (Must Fix)

C1. Surviving-spouse arm grants the mandatory §11.13(c) $60,000 exemption, but §11.13(q) only authorizes continuation of the LOCAL OPTION §11.13(d) exemption

  • File: policyengine_us/variables/gov/states/tx/tax/property/school_district_homestead_exemption/tx_over_65_or_disabled_school_district_homestead_exemption_eligible.py:25-29
  • Regulation: Tex. Tax Code §11.13(q), per PDF 2 page 8 (https://comptroller.texas.gov/taxes/property-tax/docs/96-1740.pdf#page=8): "If the age 65 or older homeowner dies, the surviving spouse may continue to receive the local option residence homestead exemption if the surviving spouse is age 55 or older at the time of death and lives in and owns the home." Appendix C (PDF 2 page 26) confirms the §11.13(c) mandatory $60k row has no surviving-spouse rider; the surviving-spouse continuation for school-district taxes is the §11.26(i) tax-ceiling transferability (a ceiling, not an exemption amount).
  • Defect: The PR's eligibility formula ORs surviving-spouse status into the §11.13(c) eligibility gate, granting the full $60k mandatory exemption to any 55+ surviving spouse. §11.13(q) does not authorize this — PolicyEngine does not currently model the §11.13(d) local-option exemption or the §11.26(i) tax ceiling.
  • Code-path + 600 DPI verified: yes (Phase 5 verifier confirmed by reading the formula file directly and PDF 2 p.8 text).
  • Recommended fix: Remove the surviving-spouse arm from tx_over_65_or_disabled_school_district_homestead_exemption_eligible (delete lines 25-29 and Test Case 4 in the corresponding _eligible.yaml). Document the deletion in the variable docstring as a scope exclusion using the user-preferred framing: "we don't model the local-option §11.13(d) exemption or the §11.26(i) school-tax ceiling at the moment, so the §11.13(q) surviving-spouse continuation is out of scope here." If the team prefers to keep an approximation, scope it as such and document the four unmodeled §11.13(q) conditions (see C2).

C2. Surviving-spouse formula omits required §11.13(q) conditions

  • File: tx_over_65_or_disabled_school_district_homestead_exemption_eligible.py:25-29
  • Regulation: Tex. Tax Code §11.13(q), per PDF 2 page 8 (https://comptroller.texas.gov/taxes/property-tax/docs/96-1740.pdf#page=8).
  • Defect: Even if the surviving-spouse path is retained as a modeling approximation, the formula omits three of the four §11.13(q) conditions:
    1. Deceased spouse was age 65+ at death — NOT MODELED (no input for deceased spouse's age at death).
    2. Surviving spouse was age 55+ AT THE TIME OF DEATH — PARTIALLY MODELED: code uses survivor's CURRENT-period age (age >= p.surviving_spouse_age_threshold), not age at the deceased spouse's death.
    3. Survivor lives in the home — PARTIALLY MODELED via assessed_property_value > 0 proxy.
    4. Survivor owns the home — PARTIALLY MODELED via the same proxy.
  • Code-path + 600 DPI verified: yes. The is_surviving_spouse input is a bare Person-level boolean with no link to deceased-spouse age (policyengine_us/variables/household/demographic/marital_unit/is_surviving_spouse.py).
  • Recommended fix: Bundled with C1 — removing the arm resolves this. If the arm is kept, document the three missing conditions with "we don't track ... at the moment" framing in the variable docstring.

C3. References do not cite Tax Code §11.13 subsections directly — primary statutory authority is missing across all 9 files

  • Files (all 9):
    • parameters/.../school_district_homestead_exemption/general_amount.yaml
    • parameters/.../school_district_homestead_exemption/over_65_or_disabled_amount.yaml
    • parameters/.../school_district_homestead_exemption/age_threshold.yaml
    • parameters/.../school_district_homestead_exemption/surviving_spouse_age_threshold.yaml
    • All 5 .py files in variables/gov/states/tx/tax/property/school_district_homestead_exemption/
  • Defect: All 4 YAMLs and all 5 .py files cite only the Comptroller HTML landing page https://comptroller.texas.gov/taxes/property-tax/exemptions/. The HTML landing page does not directly display any parameter values and cannot accept #page= anchors. The permanent statutory authority (Tex. Tax Code §11.13(b), (c), (m)(1), (q)) is not cited anywhere. Two YAMLs additionally cite TEA TY2025 (a session-specific announcement), but the durable statutory anchor is absent.
  • Recommended fix: Replace landing-page citations with deep-linked PDF references (verified page anchors below):
    File Suggested primary reference
    general_amount.yaml Tex. Tax Code §11.13(b) — https://comptroller.texas.gov/taxes/property-tax/docs/96-1740.pdf#page=7 + SB 4 amendment https://comptroller.texas.gov/taxes/property-tax/docs/96-669.pdf#page=9
    over_65_or_disabled_amount.yaml Tex. Tax Code §11.13(c) — 96-1740.pdf#page=8 + SB 23 96-669.pdf#page=10
    age_threshold.yaml Tex. Tax Code §11.13(c) — 96-1740.pdf#page=8
    surviving_spouse_age_threshold.yaml Tex. Tax Code §11.13(q) — 96-1740.pdf#page=8
    All 5 .py files Replace landing-page URL with the most relevant 96-1740 page anchor (page 7 for general/total/eligible; page 8 for over-65 amount/eligible).

Should Address

S1. is_disabled is broader than §11.13(m)(1)'s OASDI-anchored disability definition

  • File: tx_over_65_or_disabled_school_district_homestead_exemption_eligible.py:20, 23
  • Regulation: Tex. Tax Code §11.13(m)(1) — "[a person] who meets the definition of disabled for the purpose of payment of disability insurance benefits under the Federal Old-Age, Survivors and Disability Insurance Act" (cited at PDF 2 p.5 footnote 36 / page 8).
  • Observation: The PR uses the generic is_disabled Person input. No closer PE-native OASDI proxy exists at the household-input level (is_ssi_disabled encodes SSI-disabled, which is narrower than OASDI). This is a documentation/disclosure defect rather than a value mismatch.
  • Recommendation: Add a "we don't track OASDI disability separately from is_disabled at the moment" note to the variable docstring (per feedback_modeling_limitation_framing.md).

S2. Parameter descriptions misname the program

  • Files: age_threshold.yaml:1, over_65_or_disabled_amount.yaml, surviving_spouse_age_threshold.yaml:1
  • Observation: Three descriptions reference an "Age 65 or Older or Disabled Persons program," which is not a separately-named program. These are subsections of the Residence Homestead Exemption (Tex. Tax Code §11.13). general_amount.yaml already uses the correct name.
  • Recommendation: Change "under the Age 65 or Older or Disabled Persons program" to "under the Residence Homestead Exemption program" for consistency with §11.13.

S3. documentation = "..." field is deprecated

  • Files:
    • tx_school_district_homestead_exemption_eligible.py:8
    • tx_over_65_or_disabled_school_district_homestead_exemption_eligible.py:7-8
  • Observation: The variable-patterns skill marks the documentation field as deprecated in favor of reference = (...) plus inline code comments.
  • Recommendation: Convert each documentation string into either an inline comment at the top of the formula method or fold the regulatory-source portion into the reference tuple.

S4. age_threshold.yaml and surviving_spouse_age_threshold.yaml only carry a 2025-01-01 entry while dollar-amount files start at 2024-01-01

  • Files: age_threshold.yaml:3, surviving_spouse_age_threshold.yaml:3
  • Observation: Backward extrapolation makes the calculation correct (age 65 and age 55 have been the §11.13(c)/(q) thresholds for decades), but the metadata implies these thresholds changed in 2025. The §11.13(c) age-65 threshold dates to 1979 (HB 1060, 66th Lege); the §11.13(q) age-55 surviving-spouse threshold dates to 1999 (HB 1135, 76th Lege).
  • Recommendation: Align the threshold start dates with general_amount's 2024-01-01 entry at minimum (e.g., 2024-01-01: 65 and 2024-01-01: 55).

S5. absolute_error_margin is missing from every test YAML

  • Files: all 4 test YAMLs in tests/policy/baseline/gov/states/tx/tax/property/school_district_homestead_exemption/
  • Observation: None of the cases specify absolute_error_margin. Per the global rule (and feedback_error_margin_point_one.md), boolean and currency outputs should set absolute_error_margin: 0.1 so that future regressions are not silently absorbed. Especially important for the eligibility-boolean tests where a false-vs-true mismatch (0 vs 1) would be invisible under a default margin > 0.1.
  • Recommendation: Add absolute_error_margin: 0.1 per-case (or top-level) in each YAML.

S6. No dedicated test file for tx_total_school_district_homestead_exemption

  • File: tx_total_school_district_homestead_exemption.py (no matching tests/.../tx_total_school_district_homestead_exemption.yaml)
  • Observation: The total is exercised indirectly inside tx_over_65_or_disabled_school_district_homestead_exemption.yaml (asserted as a secondary output), so it does have implicit coverage. Because the variable uses adds = [...] with no formula, a dedicated unit test is low-value but explicitly verifies the aggregator.
  • Recommendation: Add tx_total_school_district_homestead_exemption.yaml with cases covering: general-only path, combined path at $200k cap, combined path with remaining-value cap ($180k), and ineligible (no assessed property).

S7. Surviving-spouse and age boundary tests are incomplete

  • File: tx_over_65_or_disabled_school_district_homestead_exemption_eligible.yaml
  • Observation: Existing coverage is age 65 (eligible), age 40+disabled (eligible), age 64 (ineligible), age 55+surviving-spouse (eligible). Missing:
    • Age 54 surviving spouse → ineligible (just-below threshold)
    • Age 56 surviving spouse → eligible (just-above threshold confirms >=)
    • Age 55 non-surviving-spouse → ineligible (confirms is_surviving_spouse is required)
    • Age 66 → eligible (confirms >= not ==)
    • Age 65+ dependent (non-head/non-spouse) → ineligible (confirms is_tax_unit_head_or_spouse gate)
  • Note: If C1's fix removes the surviving-spouse arm, the corresponding test cases here should be deleted instead of expanded.

S8. Missing tax-unit aggregation test (multi-person assessed property)

  • File: tx_over_65_or_disabled_school_district_homestead_exemption.yaml / tx_school_district_homestead_exemption.yaml
  • Observation: None of the current cases place non-zero assessed_property_value on more than one tax-unit member. The formula uses add(tax_unit, period, ["assessed_property_value"]), so multi-member aggregation is unverified.
  • Recommendation: Add a case where head and spouse each have $100k → general exemption $140k, combined property $200k.

S9. Married couple with mixed age qualification is untested

  • File: tx_over_65_or_disabled_school_district_homestead_exemption_eligible.yaml
  • Observation: The formula uses tax_unit.any(...) over head/spouse, so a married couple with one over-65 spouse should be eligible. This scenario is not tested. Add: married, head 40, spouse 65 → eligible; married, both under 65, neither disabled → ineligible.

Suggestions

G1. Add tx_school_district_homestead_exemption to programs.yaml

  • The PR adds a new Texas state tax-relief program but does not update policyengine_us/programs.yaml. Per CLAUDE.md, new programs should be registered so they appear in the metadata API and coverage page.

G2. Wire tx_total_school_district_homestead_exemption into a downstream tax calculation

  • Observation: The PR computes the exempt VALUE but does not connect it to real_estate_taxes or any state-tax variable. The PR description acknowledges this as out-of-scope ("PolicyEngine currently has a single real-estate-tax input rather than a school-tax component"). Confirm this scope is recorded in the PR body's "Not Modeled" section. Microsim default-value bias: while the exempt-value variable is unconnected, it has no behavioral effect; once wired, the assumed-default-zero assessed_property_value will tend to under-state Texas property-tax relief for households where the input is unset.

G3. Add pre-2024 historical entries to dollar-amount parameters

  • general_amount.yaml: $100k took effect for TY2023 under Prop 4 of 2023 (not 2024). Pre-2023 values were $40k (TY2022, Prop 1 of 2022), $25k (TY2015–2022, Prop 1 of 2015), and $15k (1997 onward). Currently $100k extrapolates backward indefinitely, producing phantom large exemptions for pre-2023 simulations.
  • over_65_or_disabled_amount.yaml: $10k has been the long-standing §11.13(c) amount since 1979 — the 2024-01-01: 10_000 entry is correct via backward extrapolation but misleading as documentation.
  • Recommendation: Defer to a separate backdating PR (out of scope here), or push the existing 10_000 and 100_000 entries back to the earliest year PolicyEngine US models (~2015).

G4. Add an explicit assessed_property_value: 0 test case

  • File: tx_school_district_homestead_exemption_eligible.yaml
  • Observation: Current "no property → ineligible" case relies on the default value being 0. An explicit zero is clearer.

G5. Reference durability — add the Tex. Tax Code HTML statute as a corroborating reference

  • Add https://statutes.capitol.texas.gov/Docs/TX/htm/TX.11.htm#11.13 as a secondary entry on each YAML reference list to guard against future Comptroller PDF URL rotation.

PDF Audit Summary

Category Count
Confirmed correct 7
Mismatches (verified) 1 (surviving-spouse arm — §11.13(q) wired to wrong provision; 4 unmodeled conditions bundled within)
Mismatches rejected 2 (both effective-date claims: 2025-01-01: 140_000 and 2025-01-01: 60_000 — investigated and cleared — Prop 13 and Prop 11 passed Nov 2025 with retroactive TY2025 application per SJR temporary provisions, TEA TY2025 MCR letter, and 96-669 verbatim "applies beginning with the 2025 tax year")
Unmodeled items 4 (deceased-spouse age at death; survivor age at time of death; at-death residence; at-death ownership — all §11.13(q) conditions, bundled into C2 if arm is retained, deleted if arm is removed per C1)

Confirmed-correct items:

  1. general_amount.yaml $140k value (PDF 2 p.7, p.26; PDF 3 p.9)
  2. general_amount.yaml 2025-01-01 effective date (verifier authoritative: TY2025 per "applies beginning with the 2025 tax year")
  3. over_65_or_disabled_amount.yaml $60k value (PDF 2 p.8, p.26; PDF 1 p.2)
  4. over_65_or_disabled_amount.yaml 2025-01-01 effective date (verifier authoritative: TY2025 per SJR 85 temporary provision + TEA TY2025 letter)
  5. over_65_or_disabled_amount.yaml $10k prior value (PDF 1 p.2, PDF 3 p.10)
  6. age_threshold.yaml value 65 (PDF 2 p.8, §11.13(c))
  7. surviving_spouse_age_threshold.yaml value 55 (PDF 2 p.8, §11.13(q))

Validation Summary

Check Result
Regulatory Accuracy 1 critical (surviving-spouse arm + §11.13(q) conditions, bundled into C1/C2), 1 should-address (disability definition)
Reference Quality 1 critical (no statute citations across 9 files — C3)
Code Patterns 0 critical, 2 should-address (deprecated documentation field, threshold-date misalignment)
Test Coverage 0 critical, 5 should-address (margin, total-variable test, boundary cases, multi-person aggregation, married mixed-age)
PDF Value Audit 1 mismatch (surviving-spouse arm wiring) / 7 confirmed correct / 2 mismatches rejected (effective dates)
CI Status Passing (2 contrib jobs pending)

Review Severity: REQUEST_CHANGES

Next Steps

  • Fix critical issues (C1, C2, C3) — run /fix-pr 8312 to auto-apply.
  • Resolve should-address items in the same fix pass where appropriate (especially S1, S3, S4, S5 — small mechanical edits).
  • Consider rebasing onto main before merging (branch is 283 commits behind).

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.

Add Texas statewide over-65 property tax relief

2 participants