From e70f411ca5d421db51384189778ad16815b7f0fa Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Thu, 14 May 2026 15:28:32 -0400 Subject: [PATCH 1/8] Add Ohio homestead property tax exemption --- changelog.d/8200.added.md | 1 + .../household/state_property_tax_credits.yaml | 20 ++++ .../homestead_exemption/age_threshold.yaml | 10 ++ .../property/homestead_exemption/amount.yaml | 13 +++ .../homestead_exemption/income_limit.yaml | 12 +++ .../surviving_spouse_age_threshold.yaml | 10 ++ .../oh_homestead_exemption.yaml | 53 +++++++++++ .../oh_homestead_exemption_eligible.yaml | 91 +++++++++++++++++++ .../oh_homestead_property_tax_reduction.yaml | 56 ++++++++++++ .../oh_homestead_exemption.py | 17 ++++ .../oh_homestead_exemption_eligible.py | 32 +++++++ .../oh_homestead_property_tax_reduction.py | 17 ++++ 12 files changed, 332 insertions(+) create mode 100644 changelog.d/8200.added.md create mode 100644 policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/age_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml create mode 100644 policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/income_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/surviving_spouse_age_threshold.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml create mode 100644 policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.py create mode 100644 policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py create mode 100644 policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.py diff --git a/changelog.d/8200.added.md b/changelog.d/8200.added.md new file mode 100644 index 00000000000..d70de04aa31 --- /dev/null +++ b/changelog.d/8200.added.md @@ -0,0 +1 @@ +Added the Ohio Homestead Exemption property tax reduction. diff --git a/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml b/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml index b5c719c31cf..11cece2b3f0 100644 --- a/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml +++ b/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml @@ -114,6 +114,26 @@ values: - wi_homestead_credit - wi_property_tax_credit - wv_homestead_excess_property_tax_credit + 2025-01-01: + - az_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 + - mo_property_tax_credit + - mt_elderly_homeowner_or_renter_credit + - mt_property_tax_rebate + - nj_property_tax_credit + - nm_property_tax_rebate + - ny_real_property_tax_credit + - oh_homestead_property_tax_reduction + - ok_ptc + - ri_property_tax_credit + - wi_homestead_credit + - wi_property_tax_credit + - wv_homestead_excess_property_tax_credit metadata: unit: list diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/age_threshold.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/age_threshold.yaml new file mode 100644 index 00000000000..2eb6dab9860 --- /dev/null +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/age_threshold.yaml @@ -0,0 +1,10 @@ +description: Ohio limits age-based eligibility to filers at or above this age under the Homestead Exemption program. +values: + 2025-01-01: 65 +metadata: + unit: year + period: year + label: Ohio homestead exemption age threshold + reference: + - title: Ohio Revised Code Section 323.152 | Reductions in taxable value + href: https://codes.ohio.gov/ohio-revised-code/section-323.152 diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml new file mode 100644 index 00000000000..d8a7dc8745a --- /dev/null +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml @@ -0,0 +1,13 @@ +description: Ohio provides this amount as a homestead exemption under the Homestead Exemption program. +values: + 2025-01-01: 29_000 + 2026-01-01: 29_700 +metadata: + unit: currency-USD + period: year + label: Ohio homestead exemption amount + reference: + - title: Ohio Revised Code Section 323.152 | Reductions in taxable value + href: https://codes.ohio.gov/ohio-revised-code/section-323.152 + - title: Ohio Legislative Service Commission, Bill Analysis for House Bill 186, 136th General Assembly + href: https://www.legislature.ohio.gov/download?key=24920&format=pdf diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/income_limit.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/income_limit.yaml new file mode 100644 index 00000000000..446bb039284 --- /dev/null +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/income_limit.yaml @@ -0,0 +1,12 @@ +description: Ohio limits modified adjusted gross income to this amount under the Homestead Exemption program. +values: + 2025-01-01: 41_000 +metadata: + unit: currency-USD + period: year + label: Ohio homestead exemption income limit + reference: + - title: Ohio Revised Code Section 323.152 | Reductions in taxable value + href: https://codes.ohio.gov/ohio-revised-code/section-323.152 + - title: Ohio Legislative Service Commission, Bill Analysis for House Bill 186, 136th General Assembly + href: https://www.legislature.ohio.gov/download?key=24920&format=pdf diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/surviving_spouse_age_threshold.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/surviving_spouse_age_threshold.yaml new file mode 100644 index 00000000000..cb44c8567e5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/surviving_spouse_age_threshold.yaml @@ -0,0 +1,10 @@ +description: Ohio limits surviving spouse eligibility to filers at or above this age under the Homestead Exemption program. +values: + 2025-01-01: 59 +metadata: + unit: year + period: year + label: Ohio homestead exemption surviving spouse age threshold + reference: + - title: Ohio Revised Code Section 323.152 | Reductions in taxable value + href: https://codes.ohio.gov/ohio-revised-code/section-323.152 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml new file mode 100644 index 00000000000..47e487c7703 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml @@ -0,0 +1,53 @@ +- name: Case 1, exemption uses the 2026 indexed amount. + period: 2026 + input: + people: + person1: + age: 65 + assessed_property_value: 200_000 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption: 29_700 + +- name: Case 2, exemption is limited to assessed property value. + period: 2026 + input: + people: + person1: + age: 65 + assessed_property_value: 20_000 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption: 20_000 + +- name: Case 3, exemption uses the 2025 amount. + period: 2025 + input: + people: + person1: + age: 65 + assessed_property_value: 200_000 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption: 29_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml new file mode 100644 index 00000000000..2e275c569b9 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml @@ -0,0 +1,91 @@ +- name: Case 1, senior homeowner under the income limit is eligible. + period: 2026 + input: + people: + person1: + age: 65 + assessed_property_value: 200_000 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: 41_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption_eligible: true + +- name: Case 2, disabled homeowner under age 65 is eligible. + period: 2026 + input: + people: + person1: + age: 40 + is_disabled: true + assessed_property_value: 200_000 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption_eligible: true + +- name: Case 3, senior homeowner above the income limit is ineligible. + period: 2026 + input: + people: + person1: + age: 65 + assessed_property_value: 200_000 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: 41_001 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption_eligible: false + +- name: Case 4, non-senior homeowner without disability is ineligible. + period: 2026 + input: + people: + person1: + age: 64 + assessed_property_value: 200_000 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption_eligible: false + +- name: Case 5, surviving spouse at the surviving spouse age threshold is eligible. + period: 2026 + input: + people: + person1: + age: 59 + assessed_property_value: 200_000 + tax_units: + tax_unit: + members: [person1] + filing_status: SURVIVING_SPOUSE + oh_modified_agi: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml new file mode 100644 index 00000000000..c0ede38dd77 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml @@ -0,0 +1,56 @@ +- name: Case 1, reduction equals the property tax on the exempt share of value. + period: 2026 + input: + people: + person1: + age: 65 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_property_tax_reduction: 297 + +- name: Case 2, reduction cannot exceed property taxes. + period: 2026 + input: + people: + person1: + age: 65 + assessed_property_value: 20_000 + real_estate_taxes: 400 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_property_tax_reduction: 400 + +- name: Case 3, ineligible filer gets no reduction. + period: 2026 + input: + people: + person1: + age: 64 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_property_tax_reduction: 0 diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.py new file mode 100644 index 00000000000..208bdfa2bd9 --- /dev/null +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class oh_homestead_exemption(Variable): + value_type = float + entity = TaxUnit + label = "Ohio homestead exemption" + unit = USD + definition_period = YEAR + reference = "https://codes.ohio.gov/ohio-revised-code/section-323.152" + defined_for = "oh_homestead_exemption_eligible" + + def formula(tax_unit, period, parameters): + return min_( + add(tax_unit, period, ["assessed_property_value"]), + parameters(period).gov.states.oh.tax.property.homestead_exemption.amount, + ) diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py new file mode 100644 index 00000000000..190dd98eac6 --- /dev/null +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py @@ -0,0 +1,32 @@ +from policyengine_us.model_api import * + + +class oh_homestead_exemption_eligible(Variable): + value_type = bool + entity = TaxUnit + label = "Eligible for the Ohio Homestead Exemption" + definition_period = YEAR + reference = "https://codes.ohio.gov/ohio-revised-code/section-323.152" + defined_for = StateCode.OH + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.states.oh.tax.property.homestead_exemption + filing_status = tax_unit("filing_status", period) + person = tax_unit.members + head_or_spouse = person("is_tax_unit_head_or_spouse", period) + age = person("age", period.this_year) + is_disabled = person("is_disabled", period) + aged_or_disabled = tax_unit.any( + ((age >= p.age_threshold) | is_disabled) & head_or_spouse, + ) + surviving_spouse = ( + filing_status == filing_status.possible_values.SURVIVING_SPOUSE + ) & tax_unit.any( + (age >= p.surviving_spouse_age_threshold) & head_or_spouse, + ) + + return ( + (aged_or_disabled | surviving_spouse) + & (tax_unit("oh_modified_agi", period) <= p.income_limit) + & (add(tax_unit, period, ["assessed_property_value"]) > 0) + ) diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.py new file mode 100644 index 00000000000..8471944c654 --- /dev/null +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class oh_homestead_property_tax_reduction(Variable): + value_type = float + entity = TaxUnit + label = "Ohio homestead property tax reduction" + unit = USD + definition_period = YEAR + reference = "https://codes.ohio.gov/ohio-revised-code/section-323.152" + defined_for = "oh_homestead_exemption_eligible" + + def formula(tax_unit, period, parameters): + assessed_value = add(tax_unit, period, ["assessed_property_value"]) + return add(tax_unit, period, ["real_estate_taxes"]) * ( + tax_unit("oh_homestead_exemption", period) / max_(assessed_value, 1) + ) From 9e251e41cf41af513ba9dea11d0b7b5480bafca7 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Thu, 14 May 2026 16:53:52 -0400 Subject: [PATCH 2/8] Rename changelog fragment for PR 8310 --- changelog.d/{8200.added.md => 8310.added.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog.d/{8200.added.md => 8310.added.md} (100%) diff --git a/changelog.d/8200.added.md b/changelog.d/8310.added.md similarity index 100% rename from changelog.d/8200.added.md rename to changelog.d/8310.added.md From cc5913bf3d6351297a6eea0b67a340fae2fb8578 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Thu, 21 May 2026 16:11:06 -0400 Subject: [PATCH 3/8] Keep property tax relief household-only --- .../household/state_property_tax_credits.yaml | 153 +++--------------- 1 file changed, 19 insertions(+), 134 deletions(-) diff --git a/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml b/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml index 11cece2b3f0..6a9b8dfc6a4 100644 --- a/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml +++ b/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml @@ -1,139 +1,24 @@ description: All state property tax credits and circuit breaker programs. values: - # Year-gated: each credit appears from the year its - # parameters are first defined in PE-US. - 1977-01-01: - - ri_property_tax_credit - 1996-01-01: - - nj_property_tax_credit - - ri_property_tax_credit - 1997-01-01: - - mo_property_tax_credit - - nj_property_tax_credit - - ri_property_tax_credit - 2000-01-01: - - mo_property_tax_credit - - nj_property_tax_credit - - ny_real_property_tax_credit - - ri_property_tax_credit - - wi_property_tax_credit - 2001-01-01: - - ma_senior_circuit_breaker - - mo_property_tax_credit - - nj_property_tax_credit - - ny_real_property_tax_credit - - ri_property_tax_credit - - wi_property_tax_credit - 2008-01-01: - - ma_senior_circuit_breaker - - mo_property_tax_credit - - nj_property_tax_credit - - ny_real_property_tax_credit - - ri_property_tax_credit - - wi_property_tax_credit - - wv_homestead_excess_property_tax_credit - 2009-01-01: - - ma_senior_circuit_breaker - - mo_property_tax_credit - - mt_elderly_homeowner_or_renter_credit - - nj_property_tax_credit - - ny_real_property_tax_credit - - ri_property_tax_credit - - wi_property_tax_credit - - wv_homestead_excess_property_tax_credit - 2011-01-01: - - ct_property_tax_credit - - ma_senior_circuit_breaker - - mo_property_tax_credit - - mt_elderly_homeowner_or_renter_credit - - nj_property_tax_credit - - ny_real_property_tax_credit - - ri_property_tax_credit - - wi_homestead_credit - - wi_property_tax_credit - - wv_homestead_excess_property_tax_credit - 2014-01-01: - - ct_property_tax_credit - - ma_senior_circuit_breaker - - me_property_tax_fairness_credit - - mo_property_tax_credit - - mt_elderly_homeowner_or_renter_credit - - nj_property_tax_credit - - ny_real_property_tax_credit - - ri_property_tax_credit - - wi_homestead_credit - - wi_property_tax_credit - - wv_homestead_excess_property_tax_credit - 2016-01-01: - - ct_property_tax_credit - - ma_senior_circuit_breaker - - me_property_tax_fairness_credit - - mi_homestead_property_tax_credit - - mo_property_tax_credit - - mt_elderly_homeowner_or_renter_credit - - nj_property_tax_credit - - ny_real_property_tax_credit - - ri_property_tax_credit - - wi_homestead_credit - - wi_property_tax_credit - - wv_homestead_excess_property_tax_credit - 2021-01-01: - - az_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 - - 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_credit - 2022-01-01: - - az_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 - - mo_property_tax_credit - - mt_elderly_homeowner_or_renter_credit - - mt_property_tax_rebate - - 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_credit - 2025-01-01: - - az_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 - - mo_property_tax_credit - - mt_elderly_homeowner_or_renter_credit - - mt_property_tax_rebate - - nj_property_tax_credit - - nm_property_tax_rebate - - ny_real_property_tax_credit - - oh_homestead_property_tax_reduction - - ok_ptc - - ri_property_tax_credit - - wi_homestead_credit - - wi_property_tax_credit - - wv_homestead_excess_property_tax_credit + 0000-01-01: + - az_property_tax_credit # Arizona Property Tax Credit + - ct_property_tax_credit # Connecticut Property Tax Credit + # Exclude ca_renter_credit as it is for renters, not homeowners. + - dc_ptc # DC Property Tax Credit + # Exclude hi_tax_credit_for_low_income_household_renters as it is for renters, not homeowners. + - ma_senior_circuit_breaker # Massachusetts Senior Circuit Breaker Credit + - me_property_tax_fairness_credit # Maine Property Tax Fairness Credit + - mi_homestead_property_tax_credit # Michigan homestead property tax credit + - mo_property_tax_credit # Missouri property tax credit + - mt_elderly_homeowner_or_renter_credit # Montana Elderly Homeowner/Renter Credit + - nj_property_tax_credit # New Jersey property tax credit + - nm_property_tax_rebate # New Mexico property tax rebate + - ny_real_property_tax_credit # New York real property tax credit + - ri_property_tax_credit # Rhode Island property tax credit + # Omit vt_renter_credit + - wi_homestead_credit # Wisconsin homestead credit + - wi_property_tax_credit # Wisconsin property tax credit + - wv_homestead_excess_property_tax_credit # West Virginia metadata: unit: list From 83e38c8a07c704183552a0c9731b5b79c643abbb Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Thu, 21 May 2026 16:14:53 -0400 Subject: [PATCH 4/8] Restore property tax aggregate base --- .../household/state_property_tax_credits.yaml | 178 ++++++++++++++++-- 1 file changed, 159 insertions(+), 19 deletions(-) diff --git a/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml b/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml index 6a9b8dfc6a4..5fc7a8116bf 100644 --- a/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml +++ b/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml @@ -1,24 +1,164 @@ description: All state property tax credits and circuit breaker programs. values: - 0000-01-01: - - az_property_tax_credit # Arizona Property Tax Credit - - ct_property_tax_credit # Connecticut Property Tax Credit - # Exclude ca_renter_credit as it is for renters, not homeowners. - - dc_ptc # DC Property Tax Credit - # Exclude hi_tax_credit_for_low_income_household_renters as it is for renters, not homeowners. - - ma_senior_circuit_breaker # Massachusetts Senior Circuit Breaker Credit - - me_property_tax_fairness_credit # Maine Property Tax Fairness Credit - - mi_homestead_property_tax_credit # Michigan homestead property tax credit - - mo_property_tax_credit # Missouri property tax credit - - mt_elderly_homeowner_or_renter_credit # Montana Elderly Homeowner/Renter Credit - - nj_property_tax_credit # New Jersey property tax credit - - nm_property_tax_rebate # New Mexico property tax rebate - - ny_real_property_tax_credit # New York real property tax credit - - ri_property_tax_credit # Rhode Island property tax credit - # Omit vt_renter_credit - - wi_homestead_credit # Wisconsin homestead credit - - wi_property_tax_credit # Wisconsin property tax credit - - wv_homestead_excess_property_tax_credit # West Virginia + # Year-gated: each credit appears from the year its + # parameters are first defined in PE-US. + 1977-01-01: + - ri_property_tax_credit + 1996-01-01: + - nj_property_tax_credit + - ri_property_tax_credit + 1997-01-01: + - mo_property_tax_credit + - nj_property_tax_credit + - ri_property_tax_credit + 2000-01-01: + - mo_property_tax_credit + - nj_property_tax_credit + - ny_real_property_tax_credit + - ri_property_tax_credit + - wi_property_tax_credit + 2001-01-01: + - ma_senior_circuit_breaker + - mo_property_tax_credit + - nj_property_tax_credit + - ny_real_property_tax_credit + - ri_property_tax_credit + - wi_property_tax_credit + 2008-01-01: + - ma_senior_circuit_breaker + - mo_property_tax_credit + - nj_property_tax_credit + - ny_real_property_tax_credit + - ri_property_tax_credit + - wi_property_tax_credit + - wv_homestead_excess_property_tax_credit + 2009-01-01: + - ma_senior_circuit_breaker + - mo_property_tax_credit + - mt_elderly_homeowner_or_renter_credit + - nj_property_tax_credit + - ny_real_property_tax_credit + - ri_property_tax_credit + - wi_property_tax_credit + - wv_homestead_excess_property_tax_credit + 2011-01-01: + - ct_property_tax_credit + - ma_senior_circuit_breaker + - mo_property_tax_credit + - mt_elderly_homeowner_or_renter_credit + - nj_property_tax_credit + - ny_real_property_tax_credit + - ri_property_tax_credit + - wi_homestead_credit + - wi_property_tax_credit + - wv_homestead_excess_property_tax_credit + 2014-01-01: + - ct_property_tax_credit + - ma_senior_circuit_breaker + - me_property_tax_fairness_credit + - mo_property_tax_credit + - mt_elderly_homeowner_or_renter_credit + - nj_property_tax_credit + - ny_real_property_tax_credit + - ri_property_tax_credit + - wi_homestead_credit + - wi_property_tax_credit + - wv_homestead_excess_property_tax_credit + 2016-01-01: + - ct_property_tax_credit + - ma_senior_circuit_breaker + - me_property_tax_fairness_credit + - mi_homestead_property_tax_credit + - mo_property_tax_credit + - mt_elderly_homeowner_or_renter_credit + - nj_property_tax_credit + - ny_real_property_tax_credit + - ri_property_tax_credit + - wi_homestead_credit + - wi_property_tax_credit + - wv_homestead_excess_property_tax_credit + 2021-01-01: + - az_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 + - 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_credit + 2022-01-01: + - az_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 + - mo_property_tax_credit + - mt_elderly_homeowner_or_renter_credit + - mt_property_tax_rebate + - 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_credit + 2024-01-01: + - az_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 + - mt_property_tax_rebate + - nd_renters_refund + - 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_credit + 2025-01-01: + - az_property_tax_credit + - ct_property_tax_credit + - dc_ptc + - dc_senior_disabled_property_tax_relief + - 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 + - mt_property_tax_rebate + - nd_renters_refund + - nj_property_tax_credit + - nm_property_tax_rebate + - ny_real_property_tax_credit + - ok_ptc + - pa_property_tax_or_rent_rebate + - ri_property_tax_credit + - ut_homeowner_renter_relief + - wi_homestead_credit + - wi_property_tax_credit + - wv_homestead_excess_property_tax_credit metadata: unit: list From 5c622d703658893b71d2a441f811c970ae8ed35e Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Thu, 21 May 2026 16:17:30 -0400 Subject: [PATCH 5/8] Drop property tax aggregate diff --- .../household/state_property_tax_credits.yaml | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml b/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml index 5fc7a8116bf..b5c719c31cf 100644 --- a/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml +++ b/policyengine_us/parameters/gov/states/household/state_property_tax_credits.yaml @@ -114,51 +114,6 @@ values: - wi_homestead_credit - wi_property_tax_credit - wv_homestead_excess_property_tax_credit - 2024-01-01: - - az_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 - - mt_property_tax_rebate - - nd_renters_refund - - 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_credit - 2025-01-01: - - az_property_tax_credit - - ct_property_tax_credit - - dc_ptc - - dc_senior_disabled_property_tax_relief - - 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 - - mt_property_tax_rebate - - nd_renters_refund - - nj_property_tax_credit - - nm_property_tax_rebate - - ny_real_property_tax_credit - - ok_ptc - - pa_property_tax_or_rent_rebate - - ri_property_tax_credit - - ut_homeowner_renter_relief - - wi_homestead_credit - - wi_property_tax_credit - - wv_homestead_excess_property_tax_credit metadata: unit: list From 52d37c30d3b87104ddaa079f19dd5e7709fcec69 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Fri, 5 Jun 2026 15:51:15 -0400 Subject: [PATCH 6/8] Fix Ohio homestead review issues --- .../property/homestead_exemption/amount.yaml | 4 +- .../homestead_exemption/income_limit.yaml | 4 +- .../oh_homestead_exemption.yaml | 9 +- .../oh_homestead_exemption_eligible.yaml | 101 ++++++++++++++++-- .../oh_homestead_property_tax_reduction.yaml | 6 +- .../oh_homestead_exemption_eligible.py | 25 +++-- ...d_exemption_qualifying_surviving_spouse.py | 9 ++ .../oh_homestead_exemption_total_income.py | 14 +++ 8 files changed, 144 insertions(+), 28 deletions(-) create mode 100644 policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_qualifying_surviving_spouse.py create mode 100644 policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_total_income.py diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml index d8a7dc8745a..f99ce82aa6a 100644 --- a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml @@ -9,5 +9,5 @@ metadata: reference: - title: Ohio Revised Code Section 323.152 | Reductions in taxable value href: https://codes.ohio.gov/ohio-revised-code/section-323.152 - - title: Ohio Legislative Service Commission, Bill Analysis for House Bill 186, 136th General Assembly - href: https://www.legislature.ohio.gov/download?key=24920&format=pdf + - title: Ohio Legislative Service Commission, Fiscal Note for House Bill 261, 136th General Assembly + href: https://www.legislature.ohio.gov/download?key=27544 diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/income_limit.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/income_limit.yaml index 446bb039284..e8530311c59 100644 --- a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/income_limit.yaml +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/income_limit.yaml @@ -8,5 +8,5 @@ metadata: reference: - title: Ohio Revised Code Section 323.152 | Reductions in taxable value href: https://codes.ohio.gov/ohio-revised-code/section-323.152 - - title: Ohio Legislative Service Commission, Bill Analysis for House Bill 186, 136th General Assembly - href: https://www.legislature.ohio.gov/download?key=24920&format=pdf + - title: Ohio Legislative Service Commission, Fiscal Note for House Bill 261, 136th General Assembly + href: https://www.legislature.ohio.gov/download?key=27544 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml index 47e487c7703..43448a2d07a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml @@ -5,10 +5,11 @@ person1: age: 65 assessed_property_value: 200_000 + real_estate_taxes: 2_000 tax_units: tax_unit: members: [person1] - oh_modified_agi: 30_000 + oh_homestead_exemption_total_income: 30_000 households: household: members: [person1] @@ -23,10 +24,11 @@ person1: age: 65 assessed_property_value: 20_000 + real_estate_taxes: 400 tax_units: tax_unit: members: [person1] - oh_modified_agi: 30_000 + oh_homestead_exemption_total_income: 30_000 households: household: members: [person1] @@ -41,10 +43,11 @@ person1: age: 65 assessed_property_value: 200_000 + real_estate_taxes: 2_000 tax_units: tax_unit: members: [person1] - oh_modified_agi: 30_000 + oh_homestead_exemption_total_income: 30_000 households: household: members: [person1] diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml index 2e275c569b9..5c46a2830a9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml @@ -5,10 +5,11 @@ person1: age: 65 assessed_property_value: 200_000 + real_estate_taxes: 2_000 tax_units: tax_unit: members: [person1] - oh_modified_agi: 41_000 + oh_homestead_exemption_total_income: 41_000 households: household: members: [person1] @@ -16,18 +17,19 @@ output: oh_homestead_exemption_eligible: true -- name: Case 2, disabled homeowner under age 65 is eligible. +- name: Case 2, permanently and totally disabled homeowner under age 65 is eligible. period: 2026 input: people: person1: age: 40 - is_disabled: true + is_permanently_and_totally_disabled: true assessed_property_value: 200_000 + real_estate_taxes: 2_000 tax_units: tax_unit: members: [person1] - oh_modified_agi: 30_000 + oh_homestead_exemption_total_income: 30_000 households: household: members: [person1] @@ -42,10 +44,11 @@ person1: age: 65 assessed_property_value: 200_000 + real_estate_taxes: 2_000 tax_units: tax_unit: members: [person1] - oh_modified_agi: 41_001 + oh_homestead_exemption_total_income: 41_001 households: household: members: [person1] @@ -60,10 +63,11 @@ person1: age: 64 assessed_property_value: 200_000 + real_estate_taxes: 2_000 tax_units: tax_unit: members: [person1] - oh_modified_agi: 30_000 + oh_homestead_exemption_total_income: 30_000 households: household: members: [person1] @@ -71,21 +75,100 @@ output: oh_homestead_exemption_eligible: false -- name: Case 5, surviving spouse at the surviving spouse age threshold is eligible. +- name: Case 5, qualifying surviving spouse at the age threshold is eligible. period: 2026 input: people: person1: age: 59 assessed_property_value: 200_000 + real_estate_taxes: 2_000 + oh_homestead_exemption_qualifying_surviving_spouse: true tax_units: tax_unit: members: [person1] - filing_status: SURVIVING_SPOUSE - oh_modified_agi: 30_000 + oh_homestead_exemption_total_income: 30_000 households: household: members: [person1] state_code: OH output: oh_homestead_exemption_eligible: true + +- name: Case 6, generic disability alone is ineligible. + period: 2026 + input: + people: + person1: + age: 40 + is_disabled: true + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1] + oh_homestead_exemption_total_income: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption_eligible: false + +- name: Case 7, federal surviving spouse filing status alone is ineligible. + period: 2026 + input: + people: + person1: + age: 59 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1] + filing_status: SURVIVING_SPOUSE + oh_homestead_exemption_total_income: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption_eligible: false + +- name: Case 8, prior-year total income controls eligibility. + period: 2026 + input: + people: + person1: + age: 65 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: 0 + oh_homestead_exemption_total_income: 41_001 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption_eligible: false + +- name: Case 9, homeowner without property tax proxy is ineligible. + period: 2026 + input: + people: + person1: + age: 65 + assessed_property_value: 200_000 + tax_units: + tax_unit: + members: [person1] + oh_homestead_exemption_total_income: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml index c0ede38dd77..dc3a2d319c2 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml @@ -9,7 +9,7 @@ tax_units: tax_unit: members: [person1] - oh_modified_agi: 30_000 + oh_homestead_exemption_total_income: 30_000 households: household: members: [person1] @@ -28,7 +28,7 @@ tax_units: tax_unit: members: [person1] - oh_modified_agi: 30_000 + oh_homestead_exemption_total_income: 30_000 households: household: members: [person1] @@ -47,7 +47,7 @@ tax_units: tax_unit: members: [person1] - oh_modified_agi: 30_000 + oh_homestead_exemption_total_income: 30_000 households: household: members: [person1] diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py index 190dd98eac6..e1457bda7b7 100644 --- a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py @@ -11,22 +11,29 @@ class oh_homestead_exemption_eligible(Variable): def formula(tax_unit, period, parameters): p = parameters(period).gov.states.oh.tax.property.homestead_exemption - filing_status = tax_unit("filing_status", period) person = tax_unit.members - head_or_spouse = person("is_tax_unit_head_or_spouse", period) + head = person("is_tax_unit_head", period) + spouse_in_joint = person("is_tax_unit_spouse", period) & person.tax_unit( + "tax_unit_is_joint", period + ) + head_or_spouse = head | spouse_in_joint age = person("age", period.this_year) - is_disabled = person("is_disabled", period) + is_disabled = person("is_permanently_and_totally_disabled", period) aged_or_disabled = tax_unit.any( ((age >= p.age_threshold) | is_disabled) & head_or_spouse, ) - surviving_spouse = ( - filing_status == filing_status.possible_values.SURVIVING_SPOUSE - ) & tax_unit.any( - (age >= p.surviving_spouse_age_threshold) & head_or_spouse, + surviving_spouse = tax_unit.any( + (age >= p.surviving_spouse_age_threshold) + & person("oh_homestead_exemption_qualifying_surviving_spouse", period) + & head_or_spouse, ) + owns_and_occupies_homestead = add(tax_unit, period, ["real_estate_taxes"]) > 0 return ( (aged_or_disabled | surviving_spouse) - & (tax_unit("oh_modified_agi", period) <= p.income_limit) - & (add(tax_unit, period, ["assessed_property_value"]) > 0) + & ( + tax_unit("oh_homestead_exemption_total_income", period) + <= p.income_limit + ) + & owns_and_occupies_homestead ) diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_qualifying_surviving_spouse.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_qualifying_surviving_spouse.py new file mode 100644 index 00000000000..9874ce1fcfe --- /dev/null +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_qualifying_surviving_spouse.py @@ -0,0 +1,9 @@ +from policyengine_us.model_api import * + + +class oh_homestead_exemption_qualifying_surviving_spouse(Variable): + value_type = bool + entity = Person + label = "Ohio homestead exemption qualifying surviving spouse" + definition_period = YEAR + reference = "https://codes.ohio.gov/ohio-revised-code/section-323.152" diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_total_income.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_total_income.py new file mode 100644 index 00000000000..ff7802896b3 --- /dev/null +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_total_income.py @@ -0,0 +1,14 @@ +from policyengine_us.model_api import * + + +class oh_homestead_exemption_total_income(Variable): + value_type = float + entity = TaxUnit + label = "Ohio homestead exemption total income" + unit = USD + documentation = "Modified adjusted gross income of the owner and spouse for the year preceding the homestead exemption application year." + definition_period = YEAR + reference = "https://codes.ohio.gov/ohio-revised-code/section-323.151" + + def formula(tax_unit, period, parameters): + return tax_unit("oh_modified_agi", period.last_year) From 90fe20de5abfff739d6c3a4ccea2f7fef168b90e Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Mon, 15 Jun 2026 15:37:37 -0400 Subject: [PATCH 7/8] Fix Ohio homestead assessed value --- .../property/homestead_exemption/amount.yaml | 2 +- .../homestead_exemption/assessment_rate.yaml | 12 +++++++ .../oh_homestead_exemption.yaml | 36 ++++++++++++++++--- .../oh_homestead_exemption_eligible.yaml | 22 ++++++++++++ .../oh_homestead_property_tax_reduction.yaml | 32 +++++++++++++++-- .../oh_homestead_exemption.py | 14 ++++++-- .../oh_homestead_exemption_eligible.py | 4 ++- .../oh_homestead_property_tax_reduction.py | 16 +++++++-- 8 files changed, 126 insertions(+), 12 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/assessment_rate.yaml diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml index f99ce82aa6a..91dfce31125 100644 --- a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml @@ -1,4 +1,4 @@ -description: Ohio provides this amount as a homestead exemption under the Homestead Exemption program. +description: Ohio provides this market value amount as a homestead exemption under the Homestead Exemption program. values: 2025-01-01: 29_000 2026-01-01: 29_700 diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/assessment_rate.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/assessment_rate.yaml new file mode 100644 index 00000000000..89a54dfb1d4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/assessment_rate.yaml @@ -0,0 +1,12 @@ +description: Ohio uses this share of market value as assessed value under the Homestead Exemption program. +values: + 2025-01-01: 0.35 +metadata: + unit: /1 + period: year + label: Ohio homestead exemption assessment rate + reference: + - title: Ohio Revised Code Section 323.152 | Reductions in taxable value + href: https://codes.ohio.gov/ohio-revised-code/section-323.152 + - title: Ohio Revised Code Section 5715.01 | Tax commissioner to supervise assessments by county auditors + href: https://codes.ohio.gov/ohio-revised-code/section-5715.01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml index 43448a2d07a..8e8585a85ff 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml @@ -1,4 +1,5 @@ - name: Case 1, exemption uses the 2026 indexed amount. + absolute_error_margin: 0.01 period: 2026 input: people: @@ -15,15 +16,16 @@ members: [person1] state_code: OH output: - oh_homestead_exemption: 29_700 + oh_homestead_exemption: 10_395 - name: Case 2, exemption is limited to assessed property value. + absolute_error_margin: 0.01 period: 2026 input: people: person1: age: 65 - assessed_property_value: 20_000 + assessed_property_value: 8_000 real_estate_taxes: 400 tax_units: tax_unit: @@ -34,9 +36,10 @@ members: [person1] state_code: OH output: - oh_homestead_exemption: 20_000 + oh_homestead_exemption: 8_000 - name: Case 3, exemption uses the 2025 amount. + absolute_error_margin: 0.01 period: 2025 input: people: @@ -53,4 +56,29 @@ members: [person1] state_code: OH output: - oh_homestead_exemption: 29_000 + oh_homestead_exemption: 10_150 + +- name: Case 4, exemption excludes non-joint adult property value. + absolute_error_margin: 0.01 + period: 2026 + input: + people: + person1: + age: 65 + assessed_property_value: 8_000 + real_estate_taxes: 400 + person2: + age: 40 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: SINGLE + oh_homestead_exemption_total_income: 30_000 + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_homestead_exemption: 8_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml index 5c46a2830a9..b2730a1a58c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml @@ -172,3 +172,25 @@ state_code: OH output: oh_homestead_exemption_eligible: false + +- name: Case 10, senior filer with only non-joint adult property tax is ineligible. + period: 2026 + input: + people: + person1: + age: 65 + person2: + age: 40 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: SINGLE + oh_homestead_exemption_total_income: 30_000 + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_homestead_exemption_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml index dc3a2d319c2..782f3c9fbae 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml @@ -1,4 +1,5 @@ - name: Case 1, reduction equals the property tax on the exempt share of value. + absolute_error_margin: 0.01 period: 2026 input: people: @@ -15,15 +16,16 @@ members: [person1] state_code: OH output: - oh_homestead_property_tax_reduction: 297 + oh_homestead_property_tax_reduction: 103.95 - name: Case 2, reduction cannot exceed property taxes. + absolute_error_margin: 0.01 period: 2026 input: people: person1: age: 65 - assessed_property_value: 20_000 + assessed_property_value: 8_000 real_estate_taxes: 400 tax_units: tax_unit: @@ -37,6 +39,7 @@ oh_homestead_property_tax_reduction: 400 - name: Case 3, ineligible filer gets no reduction. + absolute_error_margin: 0.01 period: 2026 input: people: @@ -54,3 +57,28 @@ state_code: OH output: oh_homestead_property_tax_reduction: 0 + +- name: Case 4, reduction excludes non-joint adult property tax. + absolute_error_margin: 0.01 + period: 2026 + input: + people: + person1: + age: 65 + assessed_property_value: 8_000 + real_estate_taxes: 400 + person2: + age: 40 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: SINGLE + oh_homestead_exemption_total_income: 30_000 + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_homestead_property_tax_reduction: 400 diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.py index 208bdfa2bd9..a0dbd4af495 100644 --- a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.py +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.py @@ -11,7 +11,17 @@ class oh_homestead_exemption(Variable): defined_for = "oh_homestead_exemption_eligible" def formula(tax_unit, period, parameters): + person = tax_unit.members + head = person("is_tax_unit_head", period) + spouse_in_joint = person("is_tax_unit_spouse", period) & person.tax_unit( + "tax_unit_is_joint", period + ) + assessed_value = tax_unit.sum( + person("assessed_property_value", period) * (head | spouse_in_joint) + ) + p = parameters(period).gov.states.oh.tax.property.homestead_exemption + assessed_exemption_amount = p.amount * p.assessment_rate return min_( - add(tax_unit, period, ["assessed_property_value"]), - parameters(period).gov.states.oh.tax.property.homestead_exemption.amount, + assessed_value, + assessed_exemption_amount, ) diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py index e1457bda7b7..5728d48f28f 100644 --- a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py @@ -27,7 +27,9 @@ def formula(tax_unit, period, parameters): & person("oh_homestead_exemption_qualifying_surviving_spouse", period) & head_or_spouse, ) - owns_and_occupies_homestead = add(tax_unit, period, ["real_estate_taxes"]) > 0 + owns_and_occupies_homestead = tax_unit.any( + (person("real_estate_taxes", period) > 0) & head_or_spouse + ) return ( (aged_or_disabled | surviving_spouse) diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.py index 8471944c654..86896edb75c 100644 --- a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.py +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.py @@ -11,7 +11,19 @@ class oh_homestead_property_tax_reduction(Variable): defined_for = "oh_homestead_exemption_eligible" def formula(tax_unit, period, parameters): - assessed_value = add(tax_unit, period, ["assessed_property_value"]) - return add(tax_unit, period, ["real_estate_taxes"]) * ( + person = tax_unit.members + head = person("is_tax_unit_head", period) + spouse_in_joint = person("is_tax_unit_spouse", period) & person.tax_unit( + "tax_unit_is_joint", period + ) + head_or_spouse = head | spouse_in_joint + assessed_value = tax_unit.sum( + person("assessed_property_value", period) * head_or_spouse + ) + real_estate_taxes = tax_unit.sum( + person("real_estate_taxes", period) * head_or_spouse + ) + + return real_estate_taxes * ( tax_unit("oh_homestead_exemption", period) / max_(assessed_value, 1) ) From 91d9afba1e4fd0f5f99ac088a24c63e9abcda94d Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Tue, 16 Jun 2026 09:35:40 -0400 Subject: [PATCH 8/8] Address Ohio homestead review feedback --- .../homestead_exemption/age_threshold.yaml | 2 +- .../property/homestead_exemption/amount.yaml | 2 +- .../homestead_exemption/assessment_rate.yaml | 4 +- .../homestead_exemption/income_limit.yaml | 7 +- .../surviving_spouse_age_threshold.yaml | 2 +- .../oh_homestead_exemption.yaml | 45 ++++++++++ .../oh_homestead_exemption_eligible.yaml | 82 +++++++++++++++++++ .../oh_homestead_exemption_total_income.yaml | 41 ++++++++++ .../oh_homestead_property_tax_reduction.yaml | 65 +++++++++++++++ .../oh_homestead_exemption_eligible.py | 3 + ...d_exemption_qualifying_surviving_spouse.py | 2 + .../oh_homestead_exemption_total_income.py | 2 +- .../oh_homestead_property_tax_reduction.py | 7 +- 13 files changed, 254 insertions(+), 10 deletions(-) create mode 100644 policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_total_income.yaml diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/age_threshold.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/age_threshold.yaml index 2eb6dab9860..10b468ee46b 100644 --- a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/age_threshold.yaml +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/age_threshold.yaml @@ -6,5 +6,5 @@ metadata: period: year label: Ohio homestead exemption age threshold reference: - - title: Ohio Revised Code Section 323.152 | Reductions in taxable value + - title: Ohio Revised Code Section 323.152(A)(1)(a)(ii) | Reductions in taxable value href: https://codes.ohio.gov/ohio-revised-code/section-323.152 diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml index 91dfce31125..cbc436f5da7 100644 --- a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/amount.yaml @@ -7,7 +7,7 @@ metadata: period: year label: Ohio homestead exemption amount reference: - - title: Ohio Revised Code Section 323.152 | Reductions in taxable value + - title: Ohio Revised Code Section 323.152(A)(1)(c)(i) | Reductions in taxable value href: https://codes.ohio.gov/ohio-revised-code/section-323.152 - title: Ohio Legislative Service Commission, Fiscal Note for House Bill 261, 136th General Assembly href: https://www.legislature.ohio.gov/download?key=27544 diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/assessment_rate.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/assessment_rate.yaml index 89a54dfb1d4..e4919e27d3d 100644 --- a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/assessment_rate.yaml +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/assessment_rate.yaml @@ -6,7 +6,7 @@ metadata: period: year label: Ohio homestead exemption assessment rate reference: - - title: Ohio Revised Code Section 323.152 | Reductions in taxable value + - title: Ohio Revised Code Section 323.152(A)(1)(c)(ii) | Reductions in taxable value href: https://codes.ohio.gov/ohio-revised-code/section-323.152 - - title: Ohio Revised Code Section 5715.01 | Tax commissioner to supervise assessments by county auditors + - title: Ohio Revised Code Section 5715.01(B) | Tax commissioner to supervise assessments by county auditors href: https://codes.ohio.gov/ohio-revised-code/section-5715.01 diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/income_limit.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/income_limit.yaml index e8530311c59..876ef02b8ca 100644 --- a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/income_limit.yaml +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/income_limit.yaml @@ -1,12 +1,15 @@ description: Ohio limits modified adjusted gross income to this amount under the Homestead Exemption program. values: - 2025-01-01: 41_000 + 2025-01-01: 40_000 + 2026-01-01: 41_000 metadata: unit: currency-USD period: year label: Ohio homestead exemption income limit reference: - - title: Ohio Revised Code Section 323.152 | Reductions in taxable value + - title: Ohio Revised Code Section 323.152(A)(1)(b)(iii) | Reductions in taxable value href: https://codes.ohio.gov/ohio-revised-code/section-323.152 + - title: Ohio Legislative Service Commission, Fiscal Note for House Bill 103, 136th General Assembly + href: https://www.legislature.ohio.gov/download?key=25178 - title: Ohio Legislative Service Commission, Fiscal Note for House Bill 261, 136th General Assembly href: https://www.legislature.ohio.gov/download?key=27544 diff --git a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/surviving_spouse_age_threshold.yaml b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/surviving_spouse_age_threshold.yaml index cb44c8567e5..e98d3a4c260 100644 --- a/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/surviving_spouse_age_threshold.yaml +++ b/policyengine_us/parameters/gov/states/oh/tax/property/homestead_exemption/surviving_spouse_age_threshold.yaml @@ -6,5 +6,5 @@ metadata: period: year label: Ohio homestead exemption surviving spouse age threshold reference: - - title: Ohio Revised Code Section 323.152 | Reductions in taxable value + - title: Ohio Revised Code Section 323.152(A)(1)(a)(iii) | Reductions in taxable value href: https://codes.ohio.gov/ohio-revised-code/section-323.152 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml index 8e8585a85ff..2c22e35249a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption.yaml @@ -82,3 +82,48 @@ state_code: OH output: oh_homestead_exemption: 8_000 + +- name: Case 5, filer over the income limit receives no exemption. + absolute_error_margin: 0.01 + period: 2026 + input: + people: + person1: + age: 65 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1] + oh_homestead_exemption_total_income: 41_001 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption: 0 + +- name: Case 6, joint spouse property value qualifies. + absolute_error_margin: 0.01 + period: 2026 + input: + people: + person1: + age: 40 + is_tax_unit_head: true + person2: + age: 65 + is_tax_unit_spouse: true + assessed_property_value: 8_000 + real_estate_taxes: 400 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + oh_homestead_exemption_total_income: 30_000 + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_homestead_exemption: 8_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml index b2730a1a58c..1e2f2cc6dae 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.yaml @@ -194,3 +194,85 @@ state_code: OH output: oh_homestead_exemption_eligible: false + +- name: Case 11, 2025 senior homeowner at the income limit is eligible. + period: 2025 + input: + people: + person1: + age: 65 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1] + oh_homestead_exemption_total_income: 40_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption_eligible: true + +- name: Case 12, 2025 senior homeowner above the income limit is ineligible. + period: 2025 + input: + people: + person1: + age: 65 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1] + oh_homestead_exemption_total_income: 40_001 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption_eligible: false + +- name: Case 13, qualifying surviving spouse below the age threshold is ineligible. + period: 2026 + input: + people: + person1: + age: 58 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + oh_homestead_exemption_qualifying_surviving_spouse: true + tax_units: + tax_unit: + members: [person1] + oh_homestead_exemption_total_income: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_exemption_eligible: false + +- name: Case 14, joint spouse property tax can satisfy ownership proxy. + period: 2026 + input: + people: + person1: + age: 40 + is_tax_unit_head: true + person2: + age: 65 + is_tax_unit_spouse: true + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + oh_homestead_exemption_total_income: 30_000 + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_homestead_exemption_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_total_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_total_income.yaml new file mode 100644 index 00000000000..e62a7dbcf78 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_total_income.yaml @@ -0,0 +1,41 @@ +- name: Case 1, prior-year Ohio modified adjusted gross income controls total income. + period: 2026 + input: + people: + person1: + age: 65 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: + 2025: 35_000 + 2026: 99_000 + households: + household: + members: [person1] + state_code: + 2025: OH + 2026: OH + output: + oh_homestead_exemption_total_income: 35_000 + +- name: Case 2, current-year Ohio modified adjusted gross income is ignored. + period: 2026 + input: + people: + person1: + age: 65 + tax_units: + tax_unit: + members: [person1] + oh_modified_agi: + 2025: 39_000 + 2026: 60_000 + households: + household: + members: [person1] + state_code: + 2025: OH + 2026: OH + output: + oh_homestead_exemption_total_income: 39_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml index 782f3c9fbae..8ed2d79415e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.yaml @@ -82,3 +82,68 @@ state_code: OH output: oh_homestead_property_tax_reduction: 400 + +- name: Case 5, filer over the income limit receives no reduction. + absolute_error_margin: 0.01 + period: 2026 + input: + people: + person1: + age: 65 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1] + oh_homestead_exemption_total_income: 41_001 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_property_tax_reduction: 0 + +- name: Case 6, reduction uses the 2025 exemption amount. + absolute_error_margin: 0.01 + period: 2025 + input: + people: + person1: + age: 65 + assessed_property_value: 200_000 + real_estate_taxes: 2_000 + tax_units: + tax_unit: + members: [person1] + oh_homestead_exemption_total_income: 30_000 + households: + household: + members: [person1] + state_code: OH + output: + oh_homestead_property_tax_reduction: 101.5 + +- name: Case 7, joint spouse property tax qualifies for reduction. + absolute_error_margin: 0.01 + period: 2026 + input: + people: + person1: + age: 40 + is_tax_unit_head: true + person2: + age: 65 + is_tax_unit_spouse: true + assessed_property_value: 8_000 + real_estate_taxes: 400 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + oh_homestead_exemption_total_income: 30_000 + households: + household: + members: [person1, person2] + state_code: OH + output: + oh_homestead_property_tax_reduction: 400 diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py index 5728d48f28f..b434246e9c3 100644 --- a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_eligible.py @@ -22,11 +22,14 @@ def formula(tax_unit, period, parameters): aged_or_disabled = tax_unit.any( ((age >= p.age_threshold) | is_disabled) & head_or_spouse, ) + # Surviving spouses age 65+ already qualify through the age path. surviving_spouse = tax_unit.any( (age >= p.surviving_spouse_age_threshold) & person("oh_homestead_exemption_qualifying_surviving_spouse", period) & head_or_spouse, ) + # PolicyEngine has no principal-residence input, so real estate tax + # paid by the qualifying owner proxies for ownership and occupancy. owns_and_occupies_homestead = tax_unit.any( (person("real_estate_taxes", period) > 0) & head_or_spouse ) diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_qualifying_surviving_spouse.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_qualifying_surviving_spouse.py index 9874ce1fcfe..df29e629cab 100644 --- a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_qualifying_surviving_spouse.py +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_qualifying_surviving_spouse.py @@ -1,6 +1,8 @@ from policyengine_us.model_api import * +# PolicyEngine does not observe the deceased spouse's qualification status +# or the surviving spouse's age when the spouse died, so this is an input. class oh_homestead_exemption_qualifying_surviving_spouse(Variable): value_type = bool entity = Person diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_total_income.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_total_income.py index ff7802896b3..6e1052f5ee8 100644 --- a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_total_income.py +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_exemption_total_income.py @@ -6,9 +6,9 @@ class oh_homestead_exemption_total_income(Variable): entity = TaxUnit label = "Ohio homestead exemption total income" unit = USD - documentation = "Modified adjusted gross income of the owner and spouse for the year preceding the homestead exemption application year." definition_period = YEAR reference = "https://codes.ohio.gov/ohio-revised-code/section-323.151" def formula(tax_unit, period, parameters): + # Ohio uses modified adjusted gross income from the year before application. return tax_unit("oh_modified_agi", period.last_year) diff --git a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.py b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.py index 86896edb75c..bbe48a162e9 100644 --- a/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.py +++ b/policyengine_us/variables/gov/states/oh/tax/property/homestead_exemption/oh_homestead_property_tax_reduction.py @@ -24,6 +24,9 @@ def formula(tax_unit, period, parameters): person("real_estate_taxes", period) * head_or_spouse ) - return real_estate_taxes * ( - tax_unit("oh_homestead_exemption", period) / max_(assessed_value, 1) + return where( + assessed_value > 0, + real_estate_taxes + * (tax_unit("oh_homestead_exemption", period) / assessed_value), + 0, )