Repository navigation
Conversation
- Line 2 reuses #10055's per-person excluded premiums; the new line 3 variable nets the remainder of the self-employed deduction from long-term care premiums (26 U.S.C. 162(l)(2)(C) lets those premiums into that deduction). - The separate-filing variant applies lines 2 and 3 only while the Itemized Deductions Schedule applies; a reform that allows separate filing after 2023 keeps premiums under the floor. - Tests: supply the self-employed deduction where its earnings limit matters, a below-floor dependent case, #10055's Montana cases moved to lines 1-3, and invariants for premium conservation and #10055's applied exclusion. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Interaction with #10109 (self-employed health insurance deduction capped at 401(c) earned income: net profit less the deductible part of SE tax and the plan deduction, per 26 U.S.C. 162(l)(2)(A), 401(c)(2)(A)(v)-(vi) and Form 7206 lines 4-14). Whichever of the two PRs lands second needs these updates. The values below are hand-computed from Form 7206, not yet run against a merge of the two branches.
The other cases I checked are unaffected because premiums are under the new limit or there is a loss: the NJ dependent cases in #10055 (profit 10,000, premiums 1,000), and the Montana cases in #9947 (profits 30,000-50,000, premiums 5,000-6,000). |
Premiums deducted through the self-employed health insurance above-the-line deduction currently remain in the federal Schedule A medical base. For premiums of $6,000, an SE deduction of $1,000, other expenses of $500 and AGI of $30,000, this changes the medical deduction from $4,250 to $3,250.
The code trace confirms the overlap:
medical_expense_health_insurance_premiumssupplies gross direct/decomposed premiums,itemized_medical_expensespreviously added that gross amount, andmedical_expense_deductiononly applied the AGI floor. Meanwhileself_employed_health_insurance_aldsums the head/spouse's earnings-limited person deductions independently.The 2025 Schedule A instructions say: “Reduce the insurance premiums by any self-employed health insurance deduction you claimed on Schedule 1”. IRC 162(l)(3) bars counting those amounts under IRC 213.
Changes and invariants
pre_tax_health_insurance_premiumsinput unchanged.itemized_medical_expensesplus the exclusion the federal subtotal formula actually applied. The read-only, period- and branch-awarehas_input_for_periodhelper makes that applied amount zero when the subtotal was supplied, and the excluded premiums when it was computed. Supplied subtotals therefore remain unchanged, while computed net costs recover the gross paid cost. This PR requires policyengine-core >=3.32.27 so explicit deletion and recalculation of a supplied subtotal also retains reliable provenance. Supplied and derived tax-unit SE deduction inputs remain supported; New Jersey retains its separate per-person dependent cap.State audit: AL, AR, AZ, CA, CO, DC, DE, GA, HI, IA, ID, KS, KY, LA, MA, MD, ME, MN, MO, MS, MT, NC, ND, NE, NJ, NM, NY, OK, OR, SC, UT, VA, VT and WI. Raw-premium consumers OH, PA, MI and WA were also checked. KY removes the medical component entirely. CA's unmodeled worker-classification exception and IA's historical separate premium subtraction are existing issues; this patch does not introduce a blanket addback. Round 2 also removes Missouri premiums already excluded from federal taxable income, including the SE health insurance ALD, from the qualifying pool before applying the medical-overlap ratio. 2025 MO-1040 instructions, page 15 require that exclusion. For $6,000 premiums, $1,000 ALD and $500 other costs at $30,000 AGI, the qualifying pool is $5,000. Existing references show no other general exception to the federal SE exclusion.
Separate Missouri rounding correction: Form 5695, line 12 requires the medical-overlap ratio to be rounded to a whole percent; the 2021 instructions, page 36 contain the same requirement. This changes three existing no-SE expectations: $375 → $350, $525 → $480, and $262.50 → $240. Half-percent ties round up, inferred from the explicit 90.5% → 91% percentage example in the 2025 instructions, page 40; Form 5695 line 12 does not separately state a tie rule. In the SE example above, $3,250 / $5,500 = 59.0909% rounds to 59%, so the subtraction is $5,000 × 41% = $2,050.
Independent state sources: MT 2023 instructions, page 36, NJ PL1999 c222 and Worksheet F, NM senior exemption and credit, ND paid-cost guidance. The ND and NM changes preserve main's existing paid-cost bases and caller-supplied subtotal behavior.
Methodology
itemized_medical_expensesplus the actually applied exclusion. Ifhas_input_for_periodfinds a supplied subtotal for the calculation period and branch, the applied amount is zero, regardless of any accompanying components or SE deduction. Otherwise, add back the excluded premiums to the computed federal net subtotal. A $6,500 supplied subtotal with $30,000 income gives $23,500 both by itself and alongside $6,000 premiums, $500 other costs and a $1,000 SE deduction. Computing those components without a supplied subtotal also gives $23,500. Even a supplied $500 subtotal alongside a $1,000 exclusion retains a $500 state base. The paid-cost guidance remains the existing state basis.Round 2
Fix both P2 findings from review-r1: New Jersey no longer lets one dependent's deduction consume another's premiums, and Missouri removes already-deducted premiums from its eligible pool and applies required full-percent rounding. Add the A/B regression ($2,000 NJ deduction), a generated per-person exclusion property, Missouri pool/rounding controls, and both explicit family-attribution cases. Document payer attribution on every variable this PR changes. The federal correction remains unchanged.
The reviewer's beneficiary-attributed parent $300 / dependent $500 with parent ALD $800 leaves $500 because the exclusion is capped at the parent's $300. Excluded $300 plus eligible $500 accounts for the $800 premium inputs; adding the full supplied ALD gives $1,300, so that inconsistent pattern cannot establish ALD-plus-Schedule-A conservation. Callers must put all parent-paid family premiums on the parent. The two explicit family cases document this distinction. NJ dependent aggregate ALD overrides likewise need corresponding person ALDs to establish each person's exclusion.
Round 3 (historical; supplied-subtotal handling superseded by Round 4)
Round 3 removed round 2's choice to ignore caller-supplied federal medical subtotals in North Dakota and New Mexico, but added the excluded premiums unconditionally. That recovered main's gross costs for computed federal subtotals and preserved supplied subtotals only when the exclusion was zero. Review-r3 identified the remaining regression when a supplied subtotal accompanied premium components and an SE deduction; Round 4 corrects it.
The tax-unit excluded-premium variable exposes the existing federal minimum of combined nondependent premiums and the nonnegative supplied or derived tax-unit SE health insurance deduction; the federal calculation reuses it. The separate per-person
self_employed_health_insurance_ald_excluded_premiumsvariable remains the minimum of that person's paid medical premiums and nonnegative person SE deduction. New Jersey reuses it when summing dependent exclusions, retaining the per-person cap. These caps and payer attribution remain unchanged.Round 4
Round 4 resolves both P2 findings in review-r3 by distinguishing supplied and computed federal medical subtotals through
has_input_for_period. The shared applied exclusion is zero for a supplieditemized_medical_expensesvalue for the calculation period and branch, and the bounded excluded premiums otherwise. North Dakota's renter-refund income and both New Mexico senior medical provisions add only this applied amount. This restores main's results for the three counterexamples: $23,500 ND income for the supplied $6,500 subtotal with components and SE deduction; $0 NM credit and $0 exemption for the supplied $27,999 subtotal with premiums and SE deduction; and a $500 state base for the supplied $500 subtotal with a $1,000 excluded-premium amount.The SE property now generates independent supplied subtotals and components without rewriting the supplied subtotal. It asserts that the state base equals the supplied subtotal whenever it is supplied, and the gross paid cost otherwise, retaining premium conservation assertions for the computed path. YAML regressions cover all three counterexamples. #10023 has merged into main. Its helper supplies the read-only, period- and branch-aware input provenance used here; this branch merges current main so those inherited changes are absent from this PR's diff.
Round 5 (historical; dependency requirement and version gates superseded by Round 6)
Round 5 adds regressions with #10023's existing version gate for North Dakota's renter-refund income and both New Mexico senior medical provisions. Correct provenance after an explicit
set_inputfollowed bydelete_arraysand recalculation requires policyengine-core 3.32.27, the first fixed version identified by #10023 and Core #561. At Round 5, the dependency floor waspolicyengine-core>=3.32.8and the lock was at 3.32.8; Round 6 raises both to the fixed release. On older cores, deleting a supplied array leaves its_user_input_keysmarker behind; if that array is recomputed before the helper runs, the read-only helper cannot distinguish the recomputed value from an intact supplied value. The shared helper and intact-input handling remain unchanged.The two state regressions use public simulation APIs and assert the correct results after supplying and deleting
itemized_medical_expensesfor 2025. For North Dakota, $30,000 income, $6,000 premiums, $500 other expenses and $1,000 ALD, with a supplied then deleted $6,500 subtotal, must produce $23,500 income; affected older cores produce $24,500. For an eligible New Mexico senior with $28,000 gross medical expenses and a supplied then deleted subtotal, both provisions must retain the $2,800 credit and $3,000 exemption; affected older cores produce $0 credit and $0 exemption. At Round 5, both regressions used the same strict conditional xfail as #10023:Version(version("policyengine-core")) < Version("3.32.27"). They ran as ordinary passing regressions on fixed cores; Round 6 removes their version gate and xfail markers because older cores are no longer supported. Normal full-file validation on core 3.32.8 gives 2 passed and 2 strict xfailed: the intact-input controls pass. A separate diagnostic of the two deleted-input cases with--runxfail -k deletedgives 2 expected failures and 2 deselected, reproducing the review's $24,500 ND income and $0/$0 NM benefits. Those intentional diagnostic failures are excluded from the normal validation totals. On core 3.32.27, all 4 cases pass, including the deleted-input results of $23,500 ND income and $2,800/$3,000 NM benefits. Each of the three fresh foreground processes ran onlypolicyengine_us/tests/core/test_state_medical_expense_input_deletion.py, one at a time. Raw failure traces and resource measurements remain untracked inhub-evidence/.make format(one new file formatted, 6,823 unchanged), Ruff lint andgit diff --checkpassed. No partner files or CI configuration changed; no folder/full suite or microsimulation ran.Python coverage is necessary because YAML cannot delete supplied arrays and verify subsequent provenance. Each case uses a fresh single-person, single-year simulation with the existing read-only reference system; the four cases join the existing Rest/core group. This file was absent before Round 5; its added standalone local macOS/Python 3.13.9 cost, including interpreter startup and model initialization, is:
The baseline Linux Rest job, artifact
11620880923, records the core group before these additions at 11:16.36 wall time and 6,757,164 KiB peak RSS. Updated Linux group timing/memory impact remains pending; the local standalone file runs do not establish that impact.Round 6
Round 6 resolves review-r5's supported-core deletion failure by requiring
policyengine-core>=3.32.27and regeneratinguv.lockfor that requirement. Core's tagged changelog, release tags and tagged deletion implementation confirm that 3.32.27 (tag commitb853f4989e973a25160698e28b8b3d57a580c654, released 2026-10-09) is the first release containing Core #561: deleting an input clears its_user_input_keysmarker, so the read-onlyhas_input_for_periodhelper distinguishes subsequent computed values from intact supplied values. The lock update is confined to this dependency requirement and the corresponding core package entry.The North Dakota and New Mexico state deletion regressions now run as ordinary tests with no core-version gate or xfail. They retain the intact-input controls and assert $23,500 ND income and $2,800 NM credit/$3,000 NM exemption after deletion and recalculation. The Round-5 old-core results above are historical diagnostics, not a limitation of the supported dependency range.
This branch first merged
gh/mainat94fca350bff7ae26813f31d6be0e97c25298d64ewith plain merge commit9b38af49de79aea638cd2a206d2426358b15b1a3, then refreshed to main7bd779527ff4dde560bd7c5cafa341467515385bwith plain merge commitba2f3b80ae0bf3dc9ad4d7312eebb41f4ba7f48a. #10023 is already on main, so its Idaho implementation and helper are no longer introduced by this PR. The $134,000 → $129,560 Idaho couple comparison below is explicitly relative to pre-#10023 main.Round-6 validation:
make formatafter the final merge (Ruff 0.15.5; 6,841 files unchanged; lint passed),uv lock --checkwith CI's uv 0.12.13, and working-tree/PR whitespace checks passed. A parsed lock comparison confirms that only the core package record (3.32.8 → 3.32.27, with release URLs/hashes) and the US core requirement changed; all other package records are identical. The final PR diff against main is 31 files, 1,699 additions and 66 deletions. #10023's implementation, helper, Python tests and released changelog fragment are absent from that diff; only the existing Idaho YAML case's federal medical deduction expectation/comments change. The Montana conflict resolution preserves all main cases and suppliesmt_agi_joint: 40_000in this PR's joint premium case, matching main's updated AGI interface. Partner tests are untouched.Round-6 single-file validation: 35 tests passed, using the supplied Python 3.13.9 interpreter and a workspace-only core 3.32.27 overlay. Each file ran alone in a fresh foreground process: the state deletion file through pytest, then the Montana and Idaho files through the standard core CLI. No run reached the 25-minute cutoff.
test_state_medical_expense_input_deletion.pymt_medical_expense_deduction_joint.yamlid_health_insurance_premiums_subtraction.yamlThe state file's BSD
timewrapper returned exit 1 after the 4 passed summary because the sandbox deniedsysctl kern.clockrate; that resource-measurement failure leaves peak RSS unavailable. Both YAML warnings report that the already-importedanyioplugin cannot be assertion-rewritten. Later runs used Python resource measurements. Raw logs and measurements remain untracked inhub-evidence/; these are local standalone measurements, not Linux CI group results.The three runs tested
dfa0863bd694f1c70853c5b68df92838151d11bd. The subsequent clean main refresh changes only SSI resource deeming, a West Virginia deduction, and the US package version. Static comparison confirms that all three tested files and their ND/NM/MT/ID medical code and parameter paths are unchanged; the core-only lock comparison and formatting/PR whitespace checks passed again after that merge. The cached merge diff reports two trailing blank lines already on main in unrelated SSI YAML files; those files match main and are absent from this PR's diff.The final push-triggered PR workflow skipped its jobs because this PR remains draft. Linux CI validation and hub population impact remain pending. No CI configuration, partner tests, local microsimulation, or full/folder suite changed or ran.
#10023's inherited
test_deleted_medical_input_recalculated_federal_firstintest_id_health_insurance_premiums.pystill has a core <3.32.27 xfail condition and itsversion/Versionimports. That condition is redundant under the new floor, but the file matches main and is outside this PR's diff, so it is unchanged.Validation
Round-4 validation: 83 distinct tests passed and one xfailed. Locally, 76 YAML cases passed across eight files, each run separately and serially in the foreground: ND 9, NM credit 10, NM exemption 9, Idaho deductions 7, Idaho tax before credits 4, Idaho itemized deductions 7, Idaho integration 7, and Idaho health-insurance-premium subtraction 23. The standard single-file YAML runner used the fully initialized, unmodified model with Python 3.13.9 and a workspace-only overlay of core 3.32.8 and filelock 3.20.3. The local Idaho Python file also recorded two passes and one xfail for the documented old-core deleted-input limitation; those passes are counted once in the distinct total.
The locked Linux CI run ran both changed Python files serially: premium conservation 5 passed, 1 warning in 7.49s; Idaho 2 passed, 1 xfailed in 3.73s. CI used Python 3.14.7, core 3.32.8 and filelock 3.20.3;
uv syncfollowed the project's Python pin despite the preceding Setup Python 3.13 step. Local premium-conservation attempts were interrupted during collection/imports without reaching assertions; the fresh retry was stopped after CI passed.Round-4 CI tested
380afa50, which included a temporary branch-onlydocs.yamlchange for the exact-file run. The original workflow was restored byte for byte. The historical Round-4 final HEADe6855037bc12a809fe22b61a616b6990fc22d1f6had the same complete tree as implementation commit7c96and the same source as the CI-tested commit; it was pushed as a fast-forward. The PR remains draft.make formatpassed after the dependency merge (7,126 files unchanged). Targeted Ruff formatting and checks passed for six Python files (one formatted, five unchanged), as didgit diff --checkandgit diff --check gh/main...HEAD. No partner test edits, whole-state/folder runs or local microsimulation.Historical Round-3 validation: 42 YAML cases across five files and five Hypothesis properties passed. The YAML counts are ND 6, NM credit 9, NM exemption 8, federal medical deduction 11, and NJ 8. Each property ran 12 generated examples plus one explicit example. The without-SE property covered arbitrary subtotal/component mixes; review-r3 found that the SE property rewrote generated supplied subtotals, so those passing checks did not establish supplied-subtotal compatibility. Round 4 replaces that interpretation with independent subtotal/component generation. No Hypothesis health check was suppressed.
Historical Round-3 runner/environment notes: Each YAML file ran serially as one explicit file per call to the standard core runner, retaining the fully initialized, unmodified model and its runner cache; the Python property file then ran alone through pytest in the same foreground process. This avoids the CLI's duplicate full-model initialization. Validation used the shared Python 3.13.9 interpreter with a workspace-only overlay of the core 3.32.8 and filelock 3.20.3 versions pinned in this checkout's lockfile. The two initial direct CLI attempts were interrupted during initialization or baseline cloning before any assertion results.
make format,git diff --check, andgit diff --check gh/main...HEADpassed. No folder suite or local microsimulation was run.Round-2 validation: all 16 test files then changed by this PR passed, run serially as individual files in fresh foreground processes: 118 YAML cases across 15 files and 3 Hypothesis property tests (12 generated examples plus one explicit example per property). This includes the NJ, MO, MT, NM and ND medical-output files and the federal/state propagation cases. The two federal properties retain their original strategies and assertions; the third checks New Jersey's per-person exclusion bound.
make format(Ruff formatting and checks) passed before each round-2 commit, andgit diff --check gh/main...HEADpassed. No local Hypothesis health-check suppression was needed. No full/folder suite or microsimulation was run.No partner test was edited. A read-only inventory of all 144 partner YAML files (623 cases) found no nonzero premium/SE-ALD inputs or affected combination; the partner suite was not run.
Relationship to merged #10023
#10023 has merged into main. This PR uses its read-only, period- and branch-aware
has_input_for_periodhelper. Merging currentgh/maininto this branch removes #10023's inherited changes from the PR diff; no sequencing requirement remains.Current main already includes #10023's Idaho premium subtraction, claimant-only medical reconciliation, combined deduction/subtraction election, mandatory itemization, and 2026 limitation adjustment. Relative to pre-#10023 main, an enrolled senior couple without reported premium inputs receives a $4,440 Idaho premium subtraction (2 × $185 × 12), reducing Idaho taxable income from $134,000 to $129,560: $200,000 − $60,000 − $6,000 − $4,440. Current main already produces $129,560 in this example; it is historical context for #10023, not a change introduced by this PR. #10023 retains the existing model's assumption that derived out-of-pocket Part B premiums for enrolled taxpayers or spouses were paid by them. Main includes those modeled premiums in the federal Schedule A medical base and makes them available to the Idaho subtraction as well.
In “Derived claimant medical overlap uses premiums excluding pretax payroll payments” in
id_health_insurance_premiums_subtraction.yaml, only the federal expectation changes:medical_expense_deduction: 4_250becomes3_250, with the arithmetic recorded in a comment: 6,000 - 1,000 + 500 - 2,250 = 3,250. This is the renamed case identified in the assignment as “Excluded premiums cannot enter derived claimant medical overlap”. Its Idaho outputs remain unchanged: qualified premiums $5,000, claimant medical deduction $3,250, and premium subtraction $1,750. The other SE-related cases either supply the Schedule A subtotal/deduction, supply Idaho itemization, or have no filer SE ALD; their asserted Idaho values remain unchanged. #10023 is already merged.axiom: TheAxiomFoundation/rulespec-us#1654 queued
The current RuleSpec section 213 module lacks the section 162(l)(3) exclusion and no section 162 module was found. A signed encoder follow-up is needed to encode the cross-section exclusion with companion tests; no billed encoder run was initiated.
Hub microsimulation impact
Pending hub microsimulation. No local microsimulation or full/folder suite was run. Keep this PR in draft until the hub records population impact.