From 7be71c702a194149c3e06fe786bbcf74d5878a0d Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Wed, 13 May 2026 14:59:03 -0400 Subject: [PATCH 1/3] Add DC senior disabled property tax relief --- changelog.d/added/8194.md | 1 + .../age_threshold.yaml | 10 ++ .../income_limit.yaml | 11 ++ .../rate.yaml | 12 ++ .../household/state_property_tax_credits.yaml | 1 + ...c_senior_disabled_property_tax_relief.yaml | 71 +++++++++++ ...disabled_property_tax_relief_eligible.yaml | 110 ++++++++++++++++++ .../dc_senior_disabled_property_tax_relief.py | 21 ++++ ...r_disabled_property_tax_relief_eligible.py | 33 ++++++ ...ior_disabled_property_tax_relief_income.py | 12 ++ 10 files changed, 282 insertions(+) create mode 100644 changelog.d/added/8194.md create mode 100644 policyengine_us/parameters/gov/states/dc/tax/property/senior_disabled_property_tax_relief/age_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/dc/tax/property/senior_disabled_property_tax_relief/income_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/dc/tax/property/senior_disabled_property_tax_relief/rate.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.yaml create mode 100644 policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.py create mode 100644 policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.py create mode 100644 policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_income.py diff --git a/changelog.d/added/8194.md b/changelog.d/added/8194.md new file mode 100644 index 00000000000..fce612e98b7 --- /dev/null +++ b/changelog.d/added/8194.md @@ -0,0 +1 @@ +Add the District of Columbia Senior Citizen or Disabled Property Owner Tax Relief. diff --git a/policyengine_us/parameters/gov/states/dc/tax/property/senior_disabled_property_tax_relief/age_threshold.yaml b/policyengine_us/parameters/gov/states/dc/tax/property/senior_disabled_property_tax_relief/age_threshold.yaml new file mode 100644 index 00000000000..d24b760fb4d --- /dev/null +++ b/policyengine_us/parameters/gov/states/dc/tax/property/senior_disabled_property_tax_relief/age_threshold.yaml @@ -0,0 +1,10 @@ +description: The District of Columbia limits senior eligibility to people at or above this age under the Senior Citizen or Disabled Property Owner Tax Relief program. +values: + 2025-01-01: 65 +metadata: + unit: year + period: year + label: DC senior disabled property tax relief age threshold + reference: + - title: Office of Tax and Revenue Real Property Tax Reliefs, Credits, and Deductions, Senior Citizen or Disabled Property Owner Tax Relief + href: https://otr.cfo.dc.gov/page/real-property-tax-reliefs-credits-and-deductions diff --git a/policyengine_us/parameters/gov/states/dc/tax/property/senior_disabled_property_tax_relief/income_limit.yaml b/policyengine_us/parameters/gov/states/dc/tax/property/senior_disabled_property_tax_relief/income_limit.yaml new file mode 100644 index 00000000000..4ecb7f51b2f --- /dev/null +++ b/policyengine_us/parameters/gov/states/dc/tax/property/senior_disabled_property_tax_relief/income_limit.yaml @@ -0,0 +1,11 @@ +description: The District of Columbia limits household adjusted gross income to this amount under the Senior Citizen or Disabled Property Owner Tax Relief program. +values: + 2025-01-01: 159_750 + 2026-01-01: 163_500 +metadata: + unit: currency-USD + period: year + label: DC senior disabled property tax relief income limit + reference: + - title: Office of Tax and Revenue Real Property Tax Reliefs, Credits, and Deductions, Senior Citizen or Disabled Property Owner Tax Relief + href: https://otr.cfo.dc.gov/page/real-property-tax-reliefs-credits-and-deductions diff --git a/policyengine_us/parameters/gov/states/dc/tax/property/senior_disabled_property_tax_relief/rate.yaml b/policyengine_us/parameters/gov/states/dc/tax/property/senior_disabled_property_tax_relief/rate.yaml new file mode 100644 index 00000000000..668d5332023 --- /dev/null +++ b/policyengine_us/parameters/gov/states/dc/tax/property/senior_disabled_property_tax_relief/rate.yaml @@ -0,0 +1,12 @@ +description: The District of Columbia reduces property tax by this share under the Senior Citizen or Disabled Property Owner Tax Relief program. +values: + 2025-01-01: 0.5 +metadata: + unit: /1 + period: year + label: DC senior disabled property tax relief rate + reference: + - title: Office of Tax and Revenue Real Property Tax Reliefs, Credits, and Deductions, Senior Citizen or Disabled Property Owner Tax Relief + href: https://otr.cfo.dc.gov/page/real-property-tax-reliefs-credits-and-deductions + - title: D.C. Law Library § 47–863. Reduced tax liability for property owners over age 65 and for property owners with disabilities; rules + href: https://code.dccouncil.gov/us/dc/council/code/sections/47-863 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..822c9fbd4a1 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 @@ -5,6 +5,7 @@ values: - 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 + - dc_senior_disabled_property_tax_relief # DC senior disabled property tax relief # 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 diff --git a/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.yaml b/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.yaml new file mode 100644 index 00000000000..8d536ef40bb --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.yaml @@ -0,0 +1,71 @@ +- name: Case 1, senior homeowner receives half of property taxes. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + employment_income: 100_000 + real_estate_taxes: 4_000 + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + takes_up_dc_ptc: false + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: DC + output: + dc_senior_disabled_property_tax_relief: 2_000 + state_property_tax_credit: 2_000 + +- name: Case 2, disabled homeowner receives half of property taxes. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 80_000 + real_estate_taxes: 3_000 + is_disabled: true + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: DC + output: + dc_senior_disabled_property_tax_relief: 1_500 + +- name: Case 3, ineligible homeowner receives no relief. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 64 + employment_income: 40_000 + real_estate_taxes: 4_000 + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: DC + output: + dc_senior_disabled_property_tax_relief: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.yaml new file mode 100644 index 00000000000..c8b1147fa66 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.yaml @@ -0,0 +1,110 @@ +- name: Case 1, senior homeowner with income below the limit is eligible. + period: 2026 + input: + people: + person1: + age: 65 + employment_income: 100_000 + real_estate_taxes: 4_000 + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: DC + output: + dc_senior_disabled_property_tax_relief_eligible: true + +- name: Case 2, disabled homeowner below the senior age threshold is eligible. + period: 2026 + input: + people: + person1: + age: 40 + employment_income: 80_000 + real_estate_taxes: 3_000 + is_disabled: true + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: DC + output: + dc_senior_disabled_property_tax_relief_eligible: true + +- name: Case 3, senior homeowner with income at the limit is ineligible. + period: 2026 + input: + people: + person1: + age: 65 + employment_income: 163_500 + real_estate_taxes: 4_000 + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: DC + output: + dc_senior_disabled_property_tax_relief_eligible: false + +- name: Case 4, senior renter is ineligible. + period: 2026 + input: + people: + person1: + age: 65 + employment_income: 40_000 + rent: 12_000 + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: DC + output: + dc_senior_disabled_property_tax_relief_eligible: false + +- name: Case 5, non-senior homeowner without disability is ineligible. + period: 2026 + input: + people: + person1: + age: 64 + employment_income: 40_000 + real_estate_taxes: 4_000 + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: DC + output: + dc_senior_disabled_property_tax_relief_eligible: false diff --git a/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.py b/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.py new file mode 100644 index 00000000000..68cdbe4aea1 --- /dev/null +++ b/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class dc_senior_disabled_property_tax_relief(Variable): + value_type = float + entity = TaxUnit + label = "DC senior disabled property tax relief" + unit = USD + definition_period = YEAR + reference = ( + "https://otr.cfo.dc.gov/page/" + "real-property-tax-reliefs-credits-and-deductions", + "https://code.dccouncil.gov/us/dc/council/code/sections/47-863", + ) + defined_for = "dc_senior_disabled_property_tax_relief_eligible" + + def formula(tax_unit, period, parameters): + p = parameters( + period + ).gov.states.dc.tax.property.senior_disabled_property_tax_relief + return add(tax_unit, period, ["real_estate_taxes"]) * p.rate diff --git a/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.py b/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.py new file mode 100644 index 00000000000..c85ead0ef9f --- /dev/null +++ b/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.py @@ -0,0 +1,33 @@ +from policyengine_us.model_api import * + + +class dc_senior_disabled_property_tax_relief_eligible(Variable): + value_type = bool + entity = TaxUnit + label = "Eligible for the DC senior disabled property tax relief" + definition_period = YEAR + reference = ( + "https://otr.cfo.dc.gov/page/" + "real-property-tax-reliefs-credits-and-deductions", + "https://code.dccouncil.gov/us/dc/council/code/sections/47-863", + ) + defined_for = StateCode.DC + + def formula(tax_unit, period, parameters): + p = parameters( + period + ).gov.states.dc.tax.property.senior_disabled_property_tax_relief + age_eligible = tax_unit("greater_age_head_spouse", period) >= p.age_threshold + disabled = tax_unit("disabled_tax_unit_head_or_spouse", period) + income = tax_unit.spm_unit( + "dc_senior_disabled_property_tax_relief_income", period + ) + income_eligible = income < p.income_limit + pays_property_taxes = add(tax_unit, period, ["real_estate_taxes"]) > 0 + is_renter = tax_unit("rents", period) + return ( + (age_eligible | disabled) + & income_eligible + & pays_property_taxes + & ~is_renter + ) diff --git a/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_income.py b/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_income.py new file mode 100644 index 00000000000..8c56e79ff49 --- /dev/null +++ b/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_income.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class dc_senior_disabled_property_tax_relief_income(Variable): + value_type = float + entity = SPMUnit + label = "DC senior disabled property tax relief household income" + unit = USD + definition_period = YEAR + defined_for = StateCode.DC + + adds = ["adjusted_gross_income"] From f55abe86b223cf0e1a3cfe704e89e7e4e2ddeaf2 Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Wed, 13 May 2026 16:32:39 -0400 Subject: [PATCH 2/3] Format DC senior disabled property tax relief variables --- .../dc_senior_disabled_property_tax_relief.py | 3 +-- .../dc_senior_disabled_property_tax_relief_eligible.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.py b/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.py index 68cdbe4aea1..f099ab782a2 100644 --- a/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.py +++ b/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.py @@ -8,8 +8,7 @@ class dc_senior_disabled_property_tax_relief(Variable): unit = USD definition_period = YEAR reference = ( - "https://otr.cfo.dc.gov/page/" - "real-property-tax-reliefs-credits-and-deductions", + "https://otr.cfo.dc.gov/page/real-property-tax-reliefs-credits-and-deductions", "https://code.dccouncil.gov/us/dc/council/code/sections/47-863", ) defined_for = "dc_senior_disabled_property_tax_relief_eligible" diff --git a/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.py b/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.py index c85ead0ef9f..94625637fb6 100644 --- a/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.py +++ b/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.py @@ -7,8 +7,7 @@ class dc_senior_disabled_property_tax_relief_eligible(Variable): label = "Eligible for the DC senior disabled property tax relief" definition_period = YEAR reference = ( - "https://otr.cfo.dc.gov/page/" - "real-property-tax-reliefs-credits-and-deductions", + "https://otr.cfo.dc.gov/page/real-property-tax-reliefs-credits-and-deductions", "https://code.dccouncil.gov/us/dc/council/code/sections/47-863", ) defined_for = StateCode.DC From 61c6c076439a1fea24671fc8de8b9e085fa077ae Mon Sep 17 00:00:00 2001 From: Daphne Hansell <128793799+daphnehanse11@users.noreply.github.com> Date: Thu, 14 May 2026 10:50:47 -0400 Subject: [PATCH 3/3] Tighten DC senior disabled relief disability test --- ...c_senior_disabled_property_tax_relief.yaml | 26 ++++++++++++++++++- ...disabled_property_tax_relief_eligible.yaml | 25 +++++++++++++++++- ...r_disabled_property_tax_relief_eligible.py | 14 ++++++++-- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.yaml b/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.yaml index 8d536ef40bb..2776e5c89e0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief.yaml @@ -32,7 +32,7 @@ age: 40 employment_income: 80_000 real_estate_taxes: 3_000 - is_disabled: true + is_permanently_and_totally_disabled: true is_tax_unit_head: true tax_units: tax_unit: @@ -69,3 +69,27 @@ state_code: DC output: dc_senior_disabled_property_tax_relief: 0 + +- name: Case 4, homeowner with generic disability receives no relief. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 80_000 + real_estate_taxes: 3_000 + is_disabled: true + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: DC + output: + dc_senior_disabled_property_tax_relief: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.yaml index c8b1147fa66..330549f59c9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.yaml @@ -28,7 +28,7 @@ age: 40 employment_income: 80_000 real_estate_taxes: 3_000 - is_disabled: true + is_permanently_and_totally_disabled: true is_tax_unit_head: true tax_units: tax_unit: @@ -108,3 +108,26 @@ state_code: DC output: dc_senior_disabled_property_tax_relief_eligible: false + +- name: Case 6, homeowner with generic disability is ineligible. + period: 2026 + input: + people: + person1: + age: 40 + employment_income: 80_000 + real_estate_taxes: 3_000 + is_disabled: true + is_tax_unit_head: true + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: DC + output: + dc_senior_disabled_property_tax_relief_eligible: false diff --git a/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.py b/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.py index 94625637fb6..27bb248a8a6 100644 --- a/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.py +++ b/policyengine_us/variables/gov/states/dc/tax/property/senior_disabled_property_tax_relief/dc_senior_disabled_property_tax_relief_eligible.py @@ -17,7 +17,17 @@ def formula(tax_unit, period, parameters): period ).gov.states.dc.tax.property.senior_disabled_property_tax_relief age_eligible = tax_unit("greater_age_head_spouse", period) >= p.age_threshold - disabled = tax_unit("disabled_tax_unit_head_or_spouse", period) + person = tax_unit.members + head_or_spouse = person("is_tax_unit_head_or_spouse", period) + disabled = person("is_permanently_and_totally_disabled", period) | ( + add( + person, + period, + ["ssi", "social_security_disability", "total_disability_payments"], + ) + > 0 + ) + disability_eligible = tax_unit.any(head_or_spouse & disabled) income = tax_unit.spm_unit( "dc_senior_disabled_property_tax_relief_income", period ) @@ -25,7 +35,7 @@ def formula(tax_unit, period, parameters): pays_property_taxes = add(tax_unit, period, ["real_estate_taxes"]) > 0 is_renter = tax_unit("rents", period) return ( - (age_eligible | disabled) + (age_eligible | disability_eligible) & income_eligible & pays_property_taxes & ~is_renter