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/2] 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/2] 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