Repository navigation
Count Ohio's unreimbursed medical care deduction once per return - #9925
Conversation
oh_unreimbursed_medical_care_expense_deduction_person listed the TaxUnit variable oh_insured_unreimbursed_medical_care_expenses in its adds. policyengine-core evaluates adds with map_to="person", which projects a group value onto every member, so each member deducted the full worksheet line 8 amount and Ohio AGI (the sum over members) fell by n times it. Each spouse's joint filing credit qualifying income also lost the whole amount. Use the existing person-level oh_insured_unreimbursed_medical_care_expenses_person, which prorates line 8 by each member's share of line 5 and sums to the return amount. Also enter federal AGI below zero as zero on worksheet line 6, as every year's instructions say, so line 8 never exceeds line 5. Adds YAML tests that fail on main (person split, total once, Ohio AGI, joint filing credit, negative AGI) and Hypothesis invariants (conservation, an independent worksheet, bounds, once-only accounting). Updates the 2026 retired-couple case, whose Medicare Part B line 8 had been deducted twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The invariants do not vary by year, so run Hypothesis on 2022 and 2025 with four examples and the seeded population on 2024 only. Test time falls from about 50 s to 15 s locally; both bugs still fail it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9925 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 4 2 -2
Lines 76 25 -51
Branches 2 0 -2
=========================================
- Hits 76 25 -51
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Handing off to the US + core hub.
Nothing is pending from the opening session. |
|
US + core hub merge audit, us#9925 at
|
|
Microsim impact (filled in after merge): the 2026 run on the default dataset finished. It compares main at the merge base
The PR body's "Microsim impact" section has the full table. Comparison files: |
Summary
Ohio's unreimbursed medical and health care expense deduction (R.C. 5747.01(A)(10)) was counted once per tax-unit member, so a couple deducted it twice and a couple with a child three times.
Cause.
oh_unreimbursed_medical_care_expense_deduction_person(Person) listed the TaxUnit variableoh_insured_unreimbursed_medical_care_expenses(worksheet line 8) in itsadds. policyengine-core evaluatesaddswithcalculate(..., map_to="person"), andmap_resultprojects a group value onto every member. Each member therefore got the full return amount. It flowed throughoh_deductions(Person) intooh_agi_personand thenoh_agi, the sum over members, so Ohio AGI fell by n × line 8. Each spouse'soh_joint_filing_credit_qualifying_incomealso lost the whole amount, which could deny the joint filing credit.Fix.
oh_insured_unreimbursed_medical_care_expenses_personin theadds. It was tested but had no consumer. It gives each member line 8 × (their line 5 expenses / the return's line 5), so the shares sum to line 8.The changed variables now cite live
dam.assets.ohio.govcopies of the instructions. Thetax.ohio.gov/static/...2022 URL returns 404.Example (2025, joint couple plus a child; head wages 40,000 and medical expenses 6,000; spouse wages 10,000). Line 8 = 6,000 − 7.5% × 50,000 = 2,250.
mainoh_unreimbursed_medical_care_expense_deduction_personoh_unreimbursed_medical_care_expense_deductionoh_agiJoint filing credit (2025; head wages 60,000 and medical expenses 10,000; spouse wages 2,000). On
mainthe spouse's qualifying income is 2,000 − 5,350 = −3,350, so the credit is denied. With this PR it is 2,000, above the $500 threshold, and the credit is 106.53.Tests
New YAML cases. All six fail on
main(checked by restoringmain's two variable files):deductions/medical_expense/oh_unreimbursed_medical_care_expense_deduction.yaml, four 2025 multi-person cases:oh_insured_unreimbursed_medical_care_expenses.yaml, two cases with federal AGI −20,000: expenses 1,000 give 1,000, wheremaingave 2,500; expenses 0 give 0, wheremaingave 1,500.Expectations come from the worksheet lines, the 2025 exemption table (p. 17) and brackets (p. 18), and are derived in each test's comments.
Changed expectation.
integration_2025.yaml, "2026 - Retired couple receives Ohio retirement income credit", had locked in the double count. Each spouse's modeled Medicare Part B premium (2,434.80) is a line 3 amount, so line 5 = 4,869.60. With federal AGI 63,850 (pension 40,000 plus taxable Social Security 23,850), line 8 = 4,869.60 − 4,788.75 = 80.85.maindeducted it once per spouse (161.70). Corrected values:Property-based test,
tests/core/test_oh_unreimbursed_medical_deduction_invariants.py. Hypothesis draws batches of 5–30 tax units: single, joint, head of household, and joint with up to three dependents. Each person has wages, medical expenses, uninsured premiums and long-term care premiums, and some heads have a business loss that makes AGI negative. A seeded population of 200 units adds breadth. Each batch runs as one vectorized simulation, and again with every medical amount zeroed.main's two variable files fails both tests.coregroup, which the Makefile times at 142 s. I have not measured it on Linux CI.Run locally, one file at a time with
policyengine-core test; all pass:integration.yaml,integration_2025.yaml,oh_taxable_income.yaml,oh_educator_expense_deduction.yaml, every joint filing credit file, and every file underdeductions/medical_expense/.states/oh/:salt_refund_integration.yaml,state_sales_tax.yaml,taxsim_state_cdcc.yaml,reform/oh_refundable_eitc.yaml, and the threecontrib/states/ohfiles.The rest is left to CI.
Invariants
These hold for every tax unit and are checked by the property test:
oh_agiby exactly that deduction. It raises each person'soh_agi_personand joint filing credit qualifying income by exactly their own share.Microsim impact
A real microsimulation on the default dataset, main at the merge base
6b80a8e447against this PR's head949dd8d728, for 2026. The runs went one at a time under the shared heavy-job lock. Sums are weighted.oh_income_taxoh_agioh_taxable_incomeoh_unreimbursed_medical_care_expense_deductionoh_insured_unreimbursed_medical_care_expensesoh_joint_filing_creditoh_joint_filing_credit_eligiblestate_income_taxincome_taxhousehold_net_incomehousehold_benefitsWhat the numbers show:
mainclaimed about twice the once-per-return amount. Ohio AGI rises by the same $9.33bn (to within $1,012, from float32 weighted sums).state_income_taxmoves exactly asoh_income_tax.The run finished after the merge (2026-10-13). It is the impact the merge audit refers to.
Comparison files are in
fixes/9925-impact/on the hub host.Methodology note
oh_agi_person, so it lowers the return's Ohio AGI but neither spouse's qualifying income.Coordination
fix-oh-modified-agi-addbacks) editsparameters/gov/states/oh/tax/income/deductions/deductions.yaml, the joint filing credit tests andintegration.yaml. This PR touches none of those files. The list keepsoh_unreimbursed_medical_care_expense_deduction_person, whose name is unchanged.oh_deductionsto a formula over the same list, which still names this variable. The two merge independently.axiom: R.C. 5747.01(A)(10) TheAxiomFoundation/rulespec-us#1523 queued
🤖 Generated with Claude Code