Skip to content

Let farm, partnership and S corporation plans set the self-employed health insurance limit - #10120

Merged
MaxGhenis merged 21 commits into
mainfrom
sehi-plan-business-base
Nov 8, 2026
Merged

MaxGhenis merged 21 commits into
mainfrom
sehi-plan-business-base

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Part of #10528.

What and why

The law caps the self-employed health insurance deduction at the earned income of the business the health plan sits under. On main, self_employed_health_insurance_earned_income_limit (#10109) treats the person's Schedule C business as that business in every case. So a farmer or partner whose plan sits under the farm or partnership gets no deduction however large their premiums, and a more-than-2% S corporation shareholder can't use their wages from the corporation.

This PR lets the plan sit under any of the four businesses Form 7206 allows, and computes line 13 for that business alone:

  • Schedule C (total_self_employment_income, SSTB and non-SSTB together, as on main), Schedule F (farm_operations_income) and a partnership (partnership_self_employment_net_earnings, K-1 box 14 code A). Line 4 is that business's net profit, floored at 0. Each business subtracts Schedule 1 line 15 × its share of line 5 (lines 5 to 8), with the same operations main uses for Schedule C. So a filer with only Schedule C income gets main's limit bit for bit.
  • Lines 9 and 10: only the Schedule C business subtracts Schedule 1 line 16, because the model bases the retirement plan deduction on Schedule C income.
  • S corporation: line 11 is the new input s_corp_shareholder_medicare_wages, the W-2 box 5 wages from an S corporation in which the person is a more-than-2% shareholder. They are part of employment_income, not in addition to it.
  • Owners' draw reform: the formula is now the module-level form_7206_line_13(person, period, other_line_5_profits=0). The owners' draw reform (Count the owners' draw in the SEHI limit's line 5 under the owners' draw reform #10571) overrode this variable with a copy of main's Schedule C-only formula. It now calls the same helper with its SECA-taxed draw profits as extra line 5 profits, so the plan business choice holds with the reform on.
  • New input self_employed_health_insurance_plan_business (SCHEDULE_C, SCHEDULE_F, PARTNERSHIP, S_CORPORATION; default UNSPECIFIED) names the business. Without it, the limit is the largest of the four line 13 amounts.

Example (2024): farm profit $20,000 and premiums $25,000. main deducts $0. Form 7206 for a plan under the farm gives 20,000 − 1,412.955 = $18,587.05, which leaves AGI at 0.

Sources

  • 26 U.S.C. 162(l)(2)(A) caps the deduction at earned income "derived by the taxpayer from the trade or business with respect to which the plan providing the medical care coverage is established."
  • 162(l)(5)(A) treats a more-than-2% S corporation shareholder's "wages (as defined in section 3121)" from the corporation as their earned income.
  • 401(c)(2)(A) builds earned income from net earnings from self-employment, which include a farm's profit and a partner's distributive share.
  • Form 7206 (2023): "Use a separate Form 7206 for each trade or business under which an insurance plan is established". Line 4 is the plan business's net profit, line 5 all profitable businesses' net profits, line 9 the line 16 amount "attributable to the same trade or business", and line 11 the S corporation's box 5 Medicare wages. The 2025 form changes only the long-term care amounts.
  • Form 7206 instructions (2023) list who qualifies: Schedule C or F net profit, K-1 box 14 code A earnings, or wages from an S corporation of which the person is a more-than-2% shareholder. A Schedule C or F policy can be in the business's name or the individual's. A partnership or S corporation plan counts only if the entity pays or reimburses the premiums and reports them as guaranteed payments or W-2 box 1 wages. "More than one health plan and business" (pages 1 and 2) requires a separate Form 7206 for each plan established under a different business.
  • Form 7206 instructions (2025): the health insurance the deduction covers "includes medical, dental, and vision insurance and qualified long-term care insurance". So the partnership and S corporation rules above cover long-term care premiums too.
  • 26 U.S.C. 3121(a)(2)(B) leaves premiums paid under a plan for employees generally out of FICA wages, so a shareholder's reimbursed premiums are in box 1 but not box 5.
  • Notice 2008-1 applies this to a more-than-2% shareholder. The corporation's premium payments go in W-2 wages for income tax withholding "but are not wages subject to Social Security and Medicare taxes" when 3121(a)(2)(B) applies (page 2). The plan counts as established by the S corporation only if the corporation pays or reimburses the premiums and reports them as W-2 wages that year (page 3).
  • Form 1065 instructions (2023), worksheet line 4c: guaranteed payments to partners for services they provide to the partnership count as net earnings from self-employment.

The default when the business isn't named

The premium inputs don't say where the plan sits, so the default is a methodology choice: the business with the largest line 13. With no business named, the model takes the business with the largest line 13 amount. That gives the filer the largest deduction, because the deduction is the smaller of line 3 and that business's line 13.

  • Form 7206 limits one plan to one business's earned income, so the default never pools businesses. Summing the four would let one policy use two businesses' earned income, which the form rules out.
  • A Schedule C or F filer can hold the policy in their own name under either business, so a filer with both effectively chooses which Form 7206 to file. The default takes the tax-minimizing choice, which has a closed form here: line 14 is the smaller of lines 3 and 13.
  • It is never below main's Schedule C limit, so no deduction falls.

Where it can be wrong, as the input's documentation says:

Not changed

Invariants

Tested with Hypothesis in policyengine_us/tests/unit/test_self_employed_health_insurance_properties.py. Each drawn filer appears six times in one vectorized simulation over 2022, 2024 and 2026: with no named business, with higher medical premiums, and once naming each business.

  1. Reference. Schedule 1 line 15 equals half of the self-employment tax that the test computes from Schedule SE (0.9235, the $400 floor, the wage base, 12.4% and 2.9%). Each named-business limit equals a closed-form Form 7206 line 13 from that line 15 and the model's line 16, and the unnamed limit equals the largest of the four. Every copy's deduction equals the smaller of its line 3 and that reference limit. Line 3 adds eligible long-term care premiums (line 2: the drawn premiums up to the limit for ages 41 to 50) to the medical premiums (line 1).
  2. Differential. The unnamed limit equals the largest of the model's own named-business limits. With property 1, one plan never pools two businesses.
  3. Bounds. 0 ≤ deduction ≤ line 3, and the limit never falls short of the Schedule C limit, so no deduction falls relative to main.
  4. Premiums. Raising the medical premiums by d raises the deduction by between 0 and d, and leaves the limit unchanged.
  5. AGI floor. For a filer with no business losses, AGI ≥ min(0, Schedule C line 10 before its floor), because the farm and partnership don't subtract the Schedule C plan deduction.
  6. Line 2 and Schedule A. The long-term care part equals min(line 2, deduction − min(line 1, deduction)), and Schedule A keeps line 3 less the deduction, so each premium in line 3 counts once.

The strategies draw losses in each business, SSTB and non-SSTB Schedule C income, S corporation wages, wages above the Social Security wage base, the $400 threshold and large plan deductions. They also draw long-term care premiums up to $2,000, on both sides of the $850 to $930 limit for ages 41 to 50. Comparisons allow float32 rounding (relative 1e-6) on top of a cent.

Test plan

  • YAML expected values come from Form 7206 and Schedule SE, hand-computed with exact fractions and rechecked independently.
    • self_employed_health_insurance_earned_income_limit.yaml, 21 cases. main's Cases 1–10 stay in place. Case 8 now names SCHEDULE_C, because the same inputs without a name give the partnership's $18,940.28 (new Case 11). New Cases 11–21 cover a farm only, a partnership only, a larger farm beside Schedule C and each of the four businesses named. They also cover a Schedule C plan deduction that leaves the partnership larger, and S corporation wages with and without a named Schedule C business.
    • self_employed_health_insurance_ald.yaml, 16 cases: main's 8, then farm only and partnership only (both end at AGI 0), an S corporation shareholder whose box 1 wages include the reimbursed premiums (deduction $10,000, AGI $12,000), and a named farm. Cases 13 to 16 add long-term care premiums under an S corporation, a farm, a partnership and the default (which takes the farm). Each checks the long-term care part and Schedule A as well as the deduction.
    • contrib/ssa/owners_draw_self_employed_health_insurance_earned_income_limit.yaml, 14 cases: Count the owners' draw in the SEHI limit's line 5 under the owners' draw reform #10571's 11, then a named farm beside a draw ($56,147.89), the same filer with no named business (the farm's $56,147.89, not Schedule C's $9,357.98), and a named Schedule C ($9,357.98). The zero-limit case now reads "S corporation profits without box 5 wages leave the limit at zero", since a farm, a partnership or box 5 wages would each give a limit. tests/reforms/test_owners_draw.py names SCHEDULE_C in its pure harness, whose oracle takes the Schedule C business as the plan business.
    • On main (4e71481e19, this PR's test files): the limit file has 12 failures and 9 passes, the ALD file 4 failures and 8 passes. The passes are main's own cases. Value failures include 0 vs 18,940.28, 18,587.05 and 27,880.57; 4,646.76 vs 37,174.09; and 3,587.05 vs 9,293.52. The rest stop at the new inputs.
  • No source conflict: each form line used here follows the statute or fills a gap it leaves (line 7's proportional split of line 15).
  • ruff format and ruff check on the changed Python files.
  • Changelog fragment changelog.d/sehi-plan-business-base.fixed.md.

Results

  • Runs at eddc35a698 (macOS, one file per process): limit YAML 21 passed, ALD YAML 16 passed, test_reference_urls.py 32 passed and test_no_concatenated_reference_urls.py 48 passed; ruff check and ruff format --check pass on both changed files. The commit changes only documentation strings and reference lists: with string constants blanked and the reference assignments dropped, each file's syntax tree matches 031c6bcfda's.

  • Runs at 031c6bcfda (macOS, one file per process): ALD YAML 16 passed, the property test 2 passed and test_source_conflicts.py 103 passed; ruff check and ruff format --check pass. The commit changes only comments and documentation strings: with string constants blanked, each Python file's syntax tree matches 69a8b3b48b's, and the YAML file loads to the same data.

  • Runs at 69a8b3b48b (macOS, one file per process): ALD YAML 16 passed and the property test 2 passed; ruff format --check and ruff check pass on the changed Python files. The owners' draw reform YAML, where only a case name changed, exceeded the session's 6 GB memory cap per process locally, so CI runs it. The commit changes only tests and documentation, so the model code is 577118d432's.

  • Line 2 mutant. With line 2 dropped from self_employed_health_insurance_ald_person.py, Cases 13 to 16 fail (the four cases with long-term care premiums), Cases 1 to 12 pass, and the property test fails at property 1.

  • On main (a8dc8d9067, the merge's main parent), with this head's ALD YAML: 8 cases fail and 8 pass. For Cases 13 to 16, main gives deductions of $0, $0, $0 and $1,858.70, and Schedule A keeps $7,860, $20,880, $12,810 and $19,071.29. Case 13 drops the box 5 input, which main lacks.

  • Runs at 735cb03ef8, which changes only the plan business input's documentation: limit YAML 21 passed, ALD YAML 12 passed and owners' draw reform YAML 14 passed (one file per process). ruff format --check and ruff check pass on the changed file. The property test and test_owners_draw.py weren't rerun.

  • Runs at da6240b489 (Linux, Python 3.14, one file per process): limit YAML 21 passed, ALD YAML 12 passed, property test 2 passed, owners' draw reform YAML 14 passed, test_owners_draw.py 38 passed.

  • Related files at da6240b489: 23 files and 444 items, all passed. They covered every file that mixes self-employed premiums with farm, partnership or S corporation inputs. They also covered the ALD determinism and dependent invariants, the filing requirement and the Michigan household resources tests that main had changed since the previous merge. Earlier, at the merge commit f6d142c533, 23 files passed (381 items). They cover every file that mixes self-employed premiums with farm, partnership or S corporation inputs, plus the files Limit the self-employed health insurance deduction to net profit less half of SE tax and plan deductions #10109 moved. Those are QBI, EITC and standard-deduction earned income, the AK, AZ, CA, ME, MI, MT, ND, NH, OH, UT and WI programs, Schedule A and the premium conservation test. The seven that compute this deduction passed again at this head (116 items). With Limit self-employed plan contributions to the Pub. 560 maximum deduction #10121's head merged in, the health insurance and plan files pass together (71 items).

  • Mutants, each run in its own process with the code restored afterwards:

    • the Schedule C-only default;
    • line 9 subtracted from every business;
    • no line 15 share for the farm or partnership;
    • a pooled default;
    • S corporation wages dropped;
    • every business taking all of line 15.

    All six fail the limit YAML and the property test, and five fail the ALD YAML. A seventh, the reform calling the helper without the draw term, fails 9 of the 14 reform cases.

  • Float32. For 400 Schedule C-only filers, this head's limit equals main's bit for bit. The PR's earlier (1 − rate) form differed on 92 of them by up to $0.03.

  • Cost of the property test. It runs in the Rest job's "remaining" pytest group. In CI run 41834014443 at 735cb03ef8 (Rest, Python shard 5), test_deduction_follows_form_7206 took 1.68 s and test_reviewer_example_and_boundaries 0.13 s. Measured on this session's Linux VM, not CI, two runs each: main's version 40.5–44.0 s and 947 MB peak resident memory; this version 39.9–40.7 s and 950 MB.

  • CI: at eddc35a698, run 42415841679 passed all 35 jobs.

Issue #10528

All 2026 with $10,000 of premiums, as in the issue:

  • Case 1 (farm $30,000 only): fixed. The deduction is $10,000 and AGI $17,880.57; main gives $0 and $27,880.57.
  • Case 2 (Schedule C $2,000 plus farm $30,000, plan under the farm): fixed by the default. The deduction is $10,000 and AGI $19,739.27; main gives $1,858.70 since Limit the self-employed health insurance deduction to net profit less half of SE tax and plan deductions #10109.
  • Case 3 (Schedule C $50,000 plus farm $1,000, plan under the farm): fixed only when the user names SCHEDULE_F, which gives $929.35. The default takes the larger Schedule C business and gives $10,000.
  • Not fixed: a plan under one of several businesses of the same kind. The model pools each kind into one amount per person: SSTB and non-SSTB Schedule C income (two inputs, one plan business, as on main), all Schedule F profit and all K-1 box 14 code A earnings. So it can't limit a plan to an SSTB business apart from a non-SSTB one, or to one of two farms or partnerships. Case 3 also needs SCHEDULE_F named; by default it gives main's $10,000.
  • Proposed follow-up: "Let the self-employed health insurance limit name one business among several of the same kind". The model pools SSTB and non-SSTB Schedule C income, all farms and all partnerships, so it can't limit a plan under one of them to that business's earned income. Per-business profit inputs, or a plan-business profit input, would close it. Witness (2026, $10,000 of premiums): Schedule C $50,000 non-SSTB plus $1,000 SSTB, plan under the SSTB business. Schedule 1 line 15 is 51,000 × 0.9235 × 0.153 / 2 = 3,603.04, so Form 7206 gives 1,000 − 3,603.04 × 1,000 / 51,000 = $929.35. The model's pooled Schedule C limit is 51,000 − 3,603.04 = $47,396.96, so it deducts $10,000.
  • The issue suggested defaulting to Schedule C, as before. This PR defaults to the largest business instead, so no deduction falls and farm-only and partner-only filers get one without naming the business.

Overlap with other PRs

DTrim99's suggestions

DTrim99 approved on 2026-11-05 with five optional suggestions:

  1. Refresh the body after merging main. Done: "Not changed" no longer lists line 2, the Count eligible long-term care premiums in Schedule A medical expenses #10265 and Add annual Social Security earnings histories and per-year reforms #10560 bullets say they landed, and the Let farm and partnership plans take the self-employed plan deduction #10131 bullet names the four files that conflict at this head. git merge-tree of eddc35a698 and Let farm and partnership plans take the self-employed plan deduction #10131's c1401819d6 lists no conflict in the lockfiles or the changelog. "Cost of the property test" now gives the CI timings.
  2. Partnership entry guidance. eddc35a698 adds it to self_employed_health_insurance_plan_business: a partner also enters those guaranteed payments in partnership_income, and in partnership_self_employment_net_earnings when the partnership reports them in K-1 box 14 code A.
  3. Payroll tax on premiums an S corporation pays. "Not changed" now states the gap and sizes it with ALD Case 11. The follow-up stays proposed there.
  4. Notice 2008-1. eddc35a698 cites it in both new inputs, page 2 for the box 1 and box 5 treatment and page 3 for when a plan counts as established by the S corporation. The plan business input also cites the Form 1065 instructions' page 43.
  5. File the pooling follow-up. It stays proposed in "Issue Cap the self-employed health insurance deduction at the earnings of the business that established the plan, including a farm or partnership (26 U.S.C. 162(l)(2)(A)) #10528" above.

Microsimulation impact

We compared main at the merge base a8dc8d9067 with 577118d432 on the default dataset for 2026. 577118d432 merges that main into this branch's 735cb03ef8, and the head's three later commits change only documentation strings, references and tests. The branch raises the self-employed health insurance deduction by $39.05m. Federal income tax falls by $9.35m and state income tax by $282,139, so household net income rises by $9.63m. Benefits don't change.

  • The limit. No record in the dataset names a plan business, so each takes the default: the business with the largest line 13. That default never falls short of main's Schedule C limit, so the limit rises for 1,682 people (5,142,250 weighted) and falls for no one.
  • The deduction. The higher limit binds for 36 tax units (117,598 weighted), which deduct $39.05m more, up to $17,157 each. Everyone else's premiums already fit under main's limit, or they have none.
  • Taxes. 32 tax units (86,754 weighted) pay less federal income tax, up to $3,171 each. 18 tax units pay $282,136 less state income tax and one pays $48 more, up to $515 each.
  • S corporations. This PR adds s_corp_shareholder_medicare_wages as a new input, so the dataset holds none, and no shareholder's limit changes.
  • Long-term care. Every change matches, to the cent, the November 6 measurement against main at abc67b98de, before Count eligible long-term care premiums in Schedule A medical expenses #10265 and Glide CMS health spending upraters to the Trustees' long-range growth rates #10119 merged. So no 2026 record combines a changed limit with the long-term care premiums that Count eligible long-term care premiums in Schedule A medical expenses #10265 adds to line 3.
Output main total, 2026 2026 change Records changed (weighted)
self_employed_health_insurance_earned_income_limit (people) $792.34bn +$191.21bn 1,682 (5,142,250)
self_employed_health_insurance_ald $17.31bn +$39.05m 36 (117,598)
adjusted_gross_income $18,986.03bn -$39.05m 36 (117,598)
income_tax $2,595.28bn -$9.35m 32 (86,754)
state_income_tax $577.49bn -$282,139 19 (56,683)
household_net_income (households) $17,162.02bn +$9.63m 33 (108,660)
household_benefits $2,060.01bn $0 0 (0)

impact: on the default dataset in 2026, the self-employed health insurance deduction rises by $39.05m, federal income tax falls by $9.35m and state income tax by $282,139. Benefits don't change.
axiom: TheAxiomFoundation/rulespec-us#1676 queued, extended with a comment (plan-business limits and companion tests; it waits on IRS source ingestion, corpus release admission and re-pin, and signed encoder approval).

🤖 Generated with Claude Code

MaxGhenis and others added 9 commits October 11, 2026 13:07
…ncome

26 U.S.C. 162(l)(2)(A) caps the deduction at earned income within the
meaning of section 401(c), which section 401(c)(2)(A)(v) and (vi) reduce
by the section 404 plan deduction and the section 164(f) deduction for
half of self-employment tax. Form 7206 (and Pub. 535 Worksheet 6-A before
2023) subtracts the share of Schedule 1 line 15 attributable to the plan
business and the line 16 plan deduction from that business's net profit.
The model used net profit alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…orm 7206

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eduction

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd S corporation plans

Form 7206 allows the plan to be established under a Schedule F farm, a
partnership with K-1 box 14 code A earnings, or an S corporation in which
the person is a more-than-2% shareholder (162(l)(5), line 11), one form per
plan. Add self_employed_health_insurance_plan_business (default: the business
with the largest earned income) and s_corp_shareholder_medicare_wages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n plans

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… limit

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the default's limits

- Limit YAML Cases 18 and 19 name PARTNERSHIP and S_CORPORATION.
- The plan business input says when a partner's or shareholder's own policy
  counts, and that all Schedule C income is one business.
- Cite PDF pages 1-2 of the Form 7206 instructions.
- Drop the sum-of-businesses bound, which the differential property implies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Heads-up from #10109, which this PR is stacked on. #10109 is now at 7713afc88a: it merged current main (bf108e931a) and changed three files this PR also edits.

  • self_employed_health_insurance_earned_income_limit.py: the documentation now says that SSTB and non-SSTB Schedule C income are one plan business, so a loss in one reduces line 4, and that Schedule 1 line 15 is read per person. The formula is unchanged.
  • self_employed_health_insurance_earned_income_limit.yaml: comments now say "Schedule 1 line 15/16". New cases 9 (a plan deduction that floors the limit at 0) and 10 (an SSTB loss netted against non-SSTB profit).
  • tests/unit/test_self_employed_health_insurance_properties.py: Schedule 1 line 15 is now computed in the test from Schedule SE: 0.9235, the $400 floor, SSA wage bases {2022: 147,000, 2024: 168,600, 2026: 184,500}, 12.4% and 2.9%. The strategy draws sstb, the reference's Schedule C is schedule_c + sstb, and comparisons use rtol=1e-6 with atol=0.01. test_reviewer_example_and_boundaries now builds its filers with a filer(...) helper.

Expect conflicts in those three files when you merge #10109's branch or main after #10109 lands. #10109 also updates #10055's two derived Schedule A cases and its conservation tolerance, and the Michigan exclusions test. Expect those too if this PR touched them.

🤖 Generated with Claude Code

Base automatically changed from fix-sehi-earned-income-limit to main October 29, 2026 07:35
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Picking this up for the US hub. I'll post a hand-off comment here when it's ready.


Generated by Claude Code

#10109 squash-merged with later commits this branch did not have. Keep this
branch's per-business limit and add #10109's documentation of the single
Schedule C business and the per-person line 15. In the limit YAML, keep
main's Cases 1-10 in place (Case 8 now names SCHEDULE_C, since an unnamed
business takes the largest) and append this branch's cases as 11-21. In the
ALD YAML, append this branch's four cases as 9-12. In the property test, take
main's independent Schedule SE reference for line 15 and its SSTB draws.
Delete #10109's changelog fragment, which main already released.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The per-business rewrite computed profit x (1 - line 15 / line 5), which
adds two float32 roundings. For one-business filers it moved the limit from
main's value by up to $0.03 (92 of 400 Schedule C-only test filers). Each
business now subtracts line 15 x its own share of line 5, the same
operations main uses, so Schedule C-only limits match main bit for bit.

The limit also documents that each kind of business is one total per
person, and that CRP payments, the optional methods and the
personal-services test are not modeled. The two 162 references are one
source, so they become one entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The plan business input now says that a farm, a partnership and an S
corporation are each one total per person, like the Schedule C business,
and that premiums a partnership or S corporation pays or reimburses go in
health_insurance_premiums. The S corporation input says those premiums are
box 1 wages but not box 5 wages (26 U.S.C. 3121(a)(2)(B)), so they belong
in employment_income but not here, and that is_self_employed must be set
even when the shareholder has no other earned income.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ALD Case 11 kept the reimbursed premiums out of box 1 wages, which the Form
7206 instructions require for the plan to count as established under the
S corporation, so its AGI of 0 couldn't occur. Box 1 wages are now 22,000
and AGI 12,000. The property test compared the deduction with the model's
own limit; it now uses the reference limit for each copy. Limit Cases 15
and 19 gain their hand computations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Picking this up for the US hub. I continue the earlier session's work on this branch (its last commit is 95b566c37a; it stopped before posting a hand-off). I'll post a hand-off comment here when it's ready.


Generated by Claude Code

#10571 overrode self_employed_health_insurance_earned_income_limit with a
copy of main's Schedule C-only formula plus the draw profits in line 5, so
with the reform on, the farm, partnership and S corporation plan businesses
this branch adds were ignored. The baseline formula is now a module-level
Form 7206 line 13 helper that takes extra line 5 profits, and the reform
calls it with the SECA-taxed draw profits. Three new reform cases cover a
named farm, the unnamed default, and a named Schedule C beside a larger
farm. The pure harness names the Schedule C business, which its oracle
assumes, and supplies S corporation wages of zero.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Picking this up for the US hub. I continue the earlier sessions' work on this branch (last commit 95b566c37a; neither posted a hand-off). I'll post a hand-off comment here when it's ready.


Generated by Claude Code

@MaxGhenis

MaxGhenis commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor Author

Ready for hub review

Head: da6240b48953b02d28713610dcbfb55b079a7258. CI passed (see below). The PR was marked ready for review at 21:59:47Z, after this hand-off. I didn't do that: my only edit to the PR was the body.

This continues two earlier sessions' work. Their commits on this branch, f6d142c533 (merge of main after #10109), 4c3a6c79a7, 3019e6c741 and 95b566c37a, all hold up on review, and I kept them unchanged:

  • 4c3a6c79a7 subtracts line 15 × each business's share, using the same operations as main.
  • 3019e6c741 adds the input documentation on where entity-paid premiums go.
  • 95b566c37a puts the S corporation shareholder's reimbursed premiums in box 1 wages, which the Form 7206 instructions require for an S corporation plan.

My commits are 0c191f0deb (merge of origin/main at abc67b98de) and da6240b489.

What the item asked for

Hand computations (2027, owners' draw reform on, the reform's synthetic $200,000 cap, q = 0.9235)

Schedule C $10,000, farm $60,000, s_corp_income $64,970.22 (draw net earnings 64,970.22 × 0.9235 = $59,999.998):

  • SE tax on Schedule C and farm: 70,000 × 0.9235 × 15.3% = $9,890.685. Draw OASDI: 59,999.998 × 12.4% = $7,440.00. Line 15 = half of 17,330.685 = $8,665.34.
  • Line 5: 10,000 + 60,000 + 64,970.22 = $134,970.22.
  • Farm line 13: 60,000 − 8,665.34 × 60,000 / 134,970.22 = $56,147.89.
  • Schedule C line 13: 10,000 − 8,665.34 × 10,000 / 134,970.22 = $9,357.98. Leaving the draw out of line 5 would give 8,762.09.

These are the three new cases at tests/policy/contrib/ssa/owners_draw_self_employed_health_insurance_earned_income_limit.yaml:257, :281 and :300. The reform's pure harness in tests/reforms/test_owners_draw.py:156 and :179 now names SCHEDULE_C and supplies zero S corporation wages, because its oracle takes the Schedule C business as the plan business.

I rechecked #10528's cases and the body's example by hand, all exactly:

  • Case 1: 30,000 × 0.9235 × 0.153 / 2 = 2,119.4325, so the cap is $27,880.57 and AGI $17,880.57.
  • Case 3 (farm named): 51,000 × 0.9235 × 0.153 / 2 = 3,603.035, of which the farm's 1/51 share is 70.648, so the cap is $929.35.
  • The body's example (farm $20,000, 2024): 20,000 − 1,412.955 = $18,587.05.

Tests (Linux, Python 3.14, one file per process)

  • At da6240b489:
    • limit YAML 21 passed;
    • ALD YAML 12 passed;
    • property test 2 passed;
    • owners' draw SEHI YAML 14 passed (11 + 3 new);
    • tests/reforms/test_owners_draw.py 38 passed.
  • Related files: 23 files, 444 items, all passed:
    • every YAML file that mixes self-employed premiums with farm, partnership or S corporation inputs: EITC and standard-deduction earned income, the QBI files, and the AK, AZ, CA, ME, MI, MT, ND, NH, OH, UT and WI programs;
    • taxsim_outputs.yaml;
    • the files main changed since the last merge that read these deductions: ALD determinism, the AL AGI and dependent EITC invariants, tax_unit_is_required_to_file_dependents.yaml, and both Michigan household-resources Python tests.
  • Combined with Limit self-employed plan contributions to the Pub. 560 maximum deduction #10121's new head (trial merge e83e856ab6, no conflicts):
    • SEHI limit 21, SEHI ALD 12, plan limit 20, plan ALD 3;
    • owners' draw SEHI 14 and owners' draw plan earned income 2.
    • All passed. The reform SEHI file was killed once (exit 137) while three test processes ran at once; run alone, it passed 14.
  • Mutant: the reform calling the helper without the draw term (other_line_5_profits=0) fails 9 of the 14 reform cases. Code restored afterwards. The earlier session's six mutants are listed in the body.

CI

The Pull request run at this head passed: 41726791519, conclusion success, every job green, including Household API Partners, all baseline, contrib and Python shards, and the microsimulation. It started when the PR was marked ready. The earlier run at the push, while the PR was a draft, was skipped.

Judgment calls

  1. The owners' draw profits enter line 5 only. They are not a fifth business that can establish the plan, as Count the owners' draw in the SEHI limit's line 5 under the owners' draw reform #10571 had it. The plan business is chosen as in the baseline. Whether a draw from an S corporation or partnership should itself count as earned income for a plan under that entity is a reform-design question for the reform's owner.
  2. The default takes the largest of the four line 13 amounts, as the earlier sessions chose. It never pools businesses and is never below main. It overstates when a partnership or S corporation with the largest limit doesn't pay or reimburse the premiums. The input documentation says to name the business in that case.
  3. No shared plan-business input with Limit self-employed plan contributions to the Pub. 560 maximum deduction #10121 (see above).
  4. Sources. This session's network policy blocked irs.gov, law.cornell.edu, uscode.house.gov, govinfo.gov and web.archive.org, so I couldn't re-fetch 162(l), 401(c), Form 7206 or its instructions. I checked the arithmetic against the form's line structure as the PR describes it and the issue states it. The body's quotes are as the earlier session fetched them, and the hub should spot-check them before landing.

Overlap

Proposed follow-up issue

Let the self-employed health insurance limit name one of several Schedule C businesses. The inputs hold one Schedule C total per person, so a plan under the smaller of two sole proprietorships can't be limited to that business's earned income (#10528's remaining case). Per-business Schedule C inputs, or a plan-business profit input, would close it.


Generated by Claude Code

@MaxGhenis
MaxGhenis marked this pull request as ready for review November 3, 2026 21:59
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Hub review in progress

Reviewing head da6240b48953b02d28713610dcbfb55b079a7258 (unchanged since the hand-off). Interim notes; the final review will follow as a separate comment.

Tests, mutants and the main reproduction are still running.


Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review
VERDICT: APPROVE
da6240b
METHODOLOGY_CHOICE: yes

The head hasn't moved since the hand-off. Main has moved to ce0869c919, and the PR still merges cleanly with it (git merge-tree --write-tree origin/main pr-10120 reports no conflict). The methodology choice is the default plan business: with none named, the PR takes the largest of the four line 13 amounts, treating where the plan sits as the filer's tax-minimizing choice. #10528 instead treats "plan under the farm" as a fact.

There are no P1 findings. The code, hand values, tests and reform integration all hold. The findings below are corrections to the body, the hand-off and one input's documentation, plus a fuller follow-up for #10528.

Findings

P2. The #10528 follow-up leaves out cases the hand-off says are covered

Body, "Issue #10528", the "Not fixed" bullet; hand-off, "Does this close #10528?" and "Proposed follow-up issue".

The hand-off proposes closing #10528 with one follow-up, "a plan under one of two Schedule C businesses", because "the inputs hold one Schedule C total per person". The inputs actually hold two Schedule C amounts, self_employment_income and sstb_self_employment_income. The model pools them into one plan business (form_7206_line_13 line 66, via total_self_employment_income, which adds both), as main does. #10528's own option list names "SSTB Schedule C" as a separate plan business. The issue also says the error applies "to a partnership", and the model has one farm total and one partnership total per person. So these remain open after this PR:

  • SSTB vs non-SSTB. A plan under an SSTB business apart from a non-SSTB one. Witness (2026, $10,000 of premiums): self_employment_income 50,000 and sstb_self_employment_income 1,000, plan under the SSTB business. Form 7206 for that business gives 1,000 − 51,000 × 0.9235 × 0.153 / 2 / 51 = 1,000 − 70.65 = $929.35. The model can only give the pooled Schedule C limit, 51,000 − 3,603.04 = $47,396.96, so it deducts $10,000. main gives the same, so this is a follow-up, not this PR's defect.
  • Several farms or partnerships. A plan under one of two farms, or one of two partnerships.
  • Case 3 by default. It still gives main's $10,000 unless SCHEDULE_F is named. That is the methodology choice above, but the issue states it as a defect.

Replacement for the body's bullet:

  • Not fixed: a plan under one of several businesses of the same kind. The model pools each kind into one amount per person: SSTB and non-SSTB Schedule C income (two inputs, one plan business, as on main), all Schedule F profit and all K-1 box 14 code A earnings. So it can't limit a plan to an SSTB business apart from a non-SSTB one, or to one of two farms or partnerships. Case 3 also needs SCHEDULE_F named; by default it gives main's $10,000.

Replacement follow-up title and summary: "Let the self-employed health insurance limit name one business among several of the same kind." The model pools SSTB and non-SSTB Schedule C income, all farms and all partnerships, so a plan under one of them can't be limited to that business's earned income. Per-business profit inputs, or a plan-business profit input, would close it. Witness: Schedule C $50,000 non-SSTB plus $1,000 SSTB, plan under the SSTB business: the form gives $929.35 and the model $10,000.

P3. The input documentation names only one overstatement case

policyengine_us/variables/household/expense/health/self_employed_health_insurance_plan_business.py:40-44.

The documentation says to name the business "when a partnership or S corporation with the largest earned income does not pay or reimburse the premiums". The body lists a second case where the default overstates, a plan under a smaller business (#10528's Case 3: $10,000 by default against the form's $929.35). The input documentation doesn't mention it. Replacement for the documentation's last sentence:

"...name the business when a partnership or S corporation with the largest earned income does not pay or reimburse the premiums, or when the plan is established under a business other than the one with the largest earned income."

P3. The body's CI line is stale

Body, "Results", the "CI:" bullet: "not run; this is a draft." The PR was marked ready at 21:59Z. Pull request run 41726791519 at da6240b489 completed with every job success: validation, quick feedback, Household API Partners, packaging, Microsimulation, all baseline, contrib and Python shards. I listed them with gh api repos/PolicyEngine/policyengine-us/actions/runs/41726791519/jobs. Replacement:

  • CI: Pull request run 41726791519 at da6240b489 passed every job.

P3. The overlap section misses #10560 and has outdated claims about #10121 and #10122

Body, "Overlap with other open PRs"; hand-off, "Overlap".

P3. Premium documentation conflicts across files (follow-up)

s_corp_shareholder_medicare_wages.py:17-22 and self_employed_health_insurance_plan_business.py:34-38 tell users to put premiums an S corporation pays or reimburses into health_insurance_premiums. main's self_employed_health_insurance_premiums.py, which adds that input, says it "Excludes pretax payroll deductions and employer-paid premiums". A reader of the premium variable gets the opposite guidance. The PR leaves that file alone because #10122 rewrites it. Whoever lands second should add a sentence there: premiums an S corporation pays or reimburses for a more-than-2% shareholder and reports in box 1 count as the shareholder's own.

Checked and sound

  • The defect at main. I ran the same filers at origin/main (ce0869c919) and at the head, each in its own worktree and process, all with $10,000 of premiums unless stated:

    Case Main limit / deduction / AGI Head limit / deduction / AGI
    Farm $30,000 (2026) 0 / 0 / 27,880.57 27,880.57 / 10,000 / 17,880.57
    Schedule C $2,000 + farm $30,000 1,858.70 / 1,858.70 / 27,880.57 27,880.57 / 10,000 / 19,739.27
    Farm $20,000, premiums $25,000 (2024) 0 / 0 / 18,587.04 18,587.04 / 18,587.04 / 0
    Partnership $30,000, premiums $40,000 (2025) 0 / 0 / 27,880.57 27,880.57 / 27,880.57 / 0

    The defect reproduces at main.

  • No reachable result below main, and the default's Schedule C path matches main bit for bit. Over 400 random 2026 filers (Schedule C −20k to 300k, farm and partnership −30k to 100k including zeros), the head's limit with SCHEDULE_C named equalled main's exactly in all 400 (maximum absolute difference 0.0), including the 274 with farm or partnership income. The unnamed default was ≥ main in all 400, and no deduction fell (42 rose). The new inputs aren't in any dataset, so at baseline only the default path runs, and it can only raise the deduction.

  • Line structure (self_employed_health_insurance_earned_income_limit.py:57-124), against the Form 7206 lines the body describes and the hub's reading confirmed:

    • Line 4: each business's profit floored at 0.
    • Line 5: the sum of profitable businesses plus other_line_5_profits.
    • Lines 6–8: each business takes Schedule 1 line 15 × its own share of line 5, never all of it.
    • Lines 9–10: Schedule 1 line 16 comes off Schedule C only. That matches the model's plan deduction, which reads total_self_employment_income (self_employed_pension_contribution_ald_person.py:17).
    • Line 11: S corporation box 5 wages, with no line 15 share, and not in line 5.
    • Line 12 (Form 2555) isn't modeled; the inputs are documented as net of it.
    • Line 13: floored at 0 per business.
    • Line 14: min_(premiums, limit) in self_employed_health_insurance_ald_person.py:23-28.

    The same code runs for every year, filing status and entity the change reaches. Line 15 is per person (self_employment_tax_ald_person), and its base adds Schedule C, farm and partnership (taxable_self_employment_income.py:18-23).

  • Hand values, recomputed with exact rational arithmetic before reading the code:

  • Owners' draw reform (owners_draw.py:312). For a Schedule C plan business, the override reproduces Count the owners' draw in the SEHI limit's line 5 under the owners' draw reform #10571's formula: the line 5 summation order (Schedule C + farm + partnership + draw) and the order of operations are the same. Disabled years and half_seca_deduction: false fall back to the baseline. I recomputed the three new cases exactly:

    • Draw net earnings: 64,970.22 × 0.9235 = 59,999.99817.
    • Line 15: (70,000 × 0.9235 × 0.153 + 59,999.99817 × 0.124) / 2 = 8,665.34239.
    • Line 5: 134,970.22.
    • Farm: 60,000 − 8,665.34239 × 60,000 / 134,970.22 = 56,147.887 (:257 and :281).
    • Schedule C: 9,357.981 (:300). Without the draw in line 5: 8,762.094.

    The reform doc (owners_draw.md:120-124) states judgment call 1: "The draw enters line 5 only: the plan business is chosen as in the baseline".

  • S corporation wages (95b566c37a). Line 11 reads box 5 Medicare wages. ALD Case 11 puts the reimbursed premiums in box 1 (22,000) but not in box 5 (10,000), and gets a deduction of 10,000 and AGI of 12,000. That follows § 162(l)(5)(A)'s "wages (as defined in section 3121)", as the hub read it, and the instructions' requirement that an S corporation plan's premiums be reported as wages. I couldn't fetch § 3121(a)(2)(B) myself.

  • Tests at the head, one file per process on this VM (Linux):

    • limit YAML: 21 passed;
    • ALD YAML: 12 passed;
    • owners' draw SEHI YAML: 14 passed;
    • property test: 2 passed;
    • test_owners_draw.py: 38 passed.

    The property strategies reach losses in every business, the $400 threshold (433/434), wages above the wage base and S corporation wages. Property 1 checks each named limit against an independent closed form and the deduction against the reference limit. That is the full claim, not a weaker one.

  • Mutants. Each ran in its own process on a scratch worktree, which I restored and confirmed clean (git status --porcelain empty) afterwards. The test that kills each:

    Mutant Limit YAML ALD YAML Property test Other
    1. Schedule C-only default 6 fail (Cases 11–14, 17, 18) 3 fail (9–11) both tests fail
    2. Line 9 from every business 1 fail (Case 17) 12 pass both tests fail
    3. No line 15 share for farm or partnership 8 fail 3 fail both tests fail
    4. Pooled default 5 fail 1 fail (Case 4) both tests fail
    5. S corporation wages dropped 2 fail (Cases 18, 21) 1 fail (Case 11) both tests fail
    6. Every business takes all of line 15 7 fail 2 fail both tests fail
    7. Reform without the draw term reform YAML 9 of 14 fail; test_generated_sehi_limit_counts_seca_taxed_draw_in_line_5 fails
    8. Brief's mutant (line 13 subtracts all of line 15), on the Schedule C business 2 fail (Cases 3, 15) 1 fail (Case 4) both tests fail reform YAML 8 of 14 fail
    9. Mine: S corporation wages added to line 5 1 fail (Case 19) 12 pass test_deduction_follows_form_7206 fails
    10. Mine: default ignores the S corporation 1 fail (Case 18) 1 fail (Case 11) both tests fail

    Mutant 6 is the brief's mutant applied to every business, so I ran mutant 8 for the Schedule C business alone. The body's claim ("all six fail the limit YAML and the property test, and five fail the ALD YAML") holds: mutant 2 is the one that passes the ALD file.

  • Readers. self_employed_health_insurance_earned_income_limit has two readers: self_employed_health_insurance_ald_person and the owners' draw override. form_7206_line_13 is called by the baseline formula and the reform. Each new input is read only by form_7206_line_13; the reform harness in test_owners_draw.py pins SCHEDULE_C. Downstream of the per-person deduction (by grep):

    • federal: self_employed_health_insurance_ald, dependents_self_employed_health_insurance_ald, dependent_taxable_ss_magi, and the itemized medical excluded-premium variables;
    • states: MS, OH, MO, MT, NJ, ID and MI, through the tax-unit deduction or the person deduction;
    • parameter lists: the ALD list and student-loan MAGI.

    At baseline the change only raises the deduction, so these readers see a larger, correctly capped deduction. I didn't audit each state formula line by line.

  • Baseline movement. The default moves outputs at baseline: it raises the deduction (and lowers AGI) for self-employed people with premiums whose farm or partnership line 13 exceeds their Schedule C limit. The hub's population check should count tax units with self_employed_health_insurance_premiums > 0 and farm or partnership SE earnings, and report the change in federal and state revenue (MS, OH, MO, MT, NJ, ID and MI read the deduction).

  • Scope. The 11 changed files include nothing under .github/ or policyengine_us/tests/policy/baseline/partners/. The changelog fragment is a top-level changelog.d/sehi-plan-business-base.fixed.md. The body's impact: and axiom: lines are present.

  • Overlap. Let farm and partnership plans take the self-employed plan deduction #10131 conflicts in the limit variable, the limit YAML and the property test (git merge-tree), as the body says. Limit self-employed plan contributions to the Pub. 560 maximum deduction #10121 and Exclude employer-plan-eligible premiums from the self-employed health insurance deduction #10122 are covered in the P3 finding above.

What I couldn't check

  • Primary sources. This VM's proxy refused irs.gov, law.cornell.edu, govinfo.gov, uscode.house.gov, ecfr.gov and web.archive.org (CONNECT 403), and WebFetch couldn't resolve irs.gov or law.cornell.edu. I rely on the hub's 2026-11-03 reading for the quotes from § 162(l)(2)(A) and (5)(A), Form 7206 and its instructions. Not covered by that reading, so unverified:
    • Form 7206 lines 4–13 as printed, word for word;
    • § 3121(a)(2)(B) and § 401(c)(2)(A);
    • the body's claim that the 2025 form "changes only the long-term care amounts";
    • the Pub. 535 Worksheet 6-A that the PR applies to 2022.
  • Population impact. The microsimulation needs data I can't reach; the hub measures it.
  • State readers. I listed them and checked the direction of the change, but didn't read every formula.

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Picking this up for the US hub. I'll post a hand-off comment here when it's ready.


Generated by Claude Code

The default takes the business with the largest earned income, so it
also overstates when the plan sits under a smaller business (issue
#10528's Case 3). The documentation named only the partnership or S
corporation case; it now tells users to name the business in both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6HCapAFW41PEgRBjqB
@MaxGhenis

MaxGhenis commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor Author

Ready for hub review
735cb03

This round answers the r1 review (issuecomment-6618436704). Its one commit, 735cb03ef8, changes documentation only; no formula changes. Before pushing, I confirmed the branch was still at da6240b489, so no one else had pushed.

Items

  1. Cap the self-employed health insurance deduction at the earnings of the business that established the plan, including a farm or partnership (26 U.S.C. 162(l)(2)(A)) #10528 follow-up (P2). Done in the body, "Issue Cap the self-employed health insurance deduction at the earnings of the business that established the plan, including a farm or partnership (26 U.S.C. 162(l)(2)(A)) #10528". The "Not fixed" bullet now uses the review's replacement text: SSTB and non-SSTB Schedule C, all farms and all partnerships are pooled, and Case 3 needs SCHEDULE_F named. A new "Proposed follow-up" bullet gives the review's title, "Let the self-employed health insurance limit name one business among several of the same kind", with its summary and the SSTB witness. I recomputed the witness exactly with fractions: line 15 = 51,000 × 0.9235 × 0.153 / 2 = 3,603.03525. The form gives 1,000 − 3,603.03525 × 1,000 / 51,000 = 929.35225. The pooled Schedule C limit is 51,000 − 3,603.03525 = 47,396.96475, so the model deducts $10,000. I didn't open the issue.

  2. Input documentation (P3). policyengine_us/variables/household/expense/health/self_employed_health_insurance_plan_business.py:40-45: the last sentence now ends "...does not pay or reimburse the premiums, or when the plan is established under a business other than the one with the largest earned income." The rest is unchanged.

  3. Default. Added to the body under "The default when the business isn't named": with no business named, the model takes the business with the largest line 13 amount, which gives the largest deduction. I read the code to support this. form_7206_line_13's select default is max_(max_(schedule_c, farm), max_(partnership, s_corporation)) (self_employed_health_insurance_earned_income_limit.py:114-124), and the deduction is min_(premiums, earned_income_limit) (self_employed_health_insurance_ald_person.py:23-28).

  4. CI line (P3). It now cites run 41726791519 at da6240b489 (every job passed) and this head's run 41834014443. See CI below.

  5. Overlap (P3). I checked each PR at its current head against main 25c4253483:

  6. Premium documentation (P3). Added as an overlap bullet; I didn't edit the file. I confirmed the conflict on main: self_employed_health_insurance_premiums.py:11-12 says it "Excludes pretax payroll deductions and employer-paid premiums". s_corp_shareholder_medicare_wages.py and self_employed_health_insurance_plan_business.py point S corporation premiums to health_insurance_premiums. Exclude employer-plan-eligible premiums from the self-employed health insurance deduction #10122 edits the premiums file.

  7. Runs at 735cb03ef8, one file per process on Linux:

    • self_employed_health_insurance_earned_income_limit.yaml: 21 passed;
    • self_employed_health_insurance_ald.yaml: 12 passed;
    • contrib/ssa/owners_draw_self_employed_health_insurance_earned_income_limit.yaml: 14 passed;
    • ruff format --check and ruff check on the changed file: both clean.

    The plan ALD YAML doesn't exist on this branch, only on Limit self-employed plan contributions to the Pub. 560 maximum deduction #10121, so I ran it in the merged tree above. I kept the impact: and axiom: lines unchanged. There were no mutants: this round changes no formula.

CI

Pull request run https://github.com/PolicyEngine/policyengine-us/actions/runs/41834014443 at 735cb03ef8, started 12:59Z. At 13:59Z, 60 minutes after the push, every job had passed except Contrib (other-shard-1), still running (started 13:31Z). The jobs that passed include validation, quick feedback, Household API Partners, packaging, Microsimulation, every baseline shard and every Python shard. It hasn't concluded, so this round's CI isn't finished.

Judgment calls

Proposed follow-up

  • Let the self-employed health insurance limit name one business among several of the same kind. The model pools SSTB and non-SSTB Schedule C income, all farms and all partnerships, so a plan under one of them can't be limited to that business's earned income. Witness (2026, $10,000 of premiums, $50,000 non-SSTB plus $1,000 SSTB, plan under the SSTB business): the form gives $929.35 and the model $10,000.

Generated by Claude Code

@MaxGhenis

MaxGhenis commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor Author

Hub review in progress

Round 2 delta review of 735cb03ef8237cb00951eaad57a14116098a3cd4 (head unchanged since the brief). Interim findings so far:

  • The diff from da6240b489 changes only self_employed_health_insurance_plan_business.py:43-45 (documentation). No formula change.

  • The default claim matches the code: form_7206_line_13 returns the largest of the four line 13 amounts when no business is named (self_employed_health_insurance_earned_income_limit.py:114-124), and the ALD is the smaller of premiums and that limit (self_employed_health_insurance_ald_person.py:28).

  • Cap the self-employed health insurance deduction at the earnings of the business that established the plan, including a farm or partnership (26 U.S.C. 162(l)(2)(A)) #10528 witness reproduced: hand line 15 = 3,603.04, Form 7206 line 13 for the SSTB plan = $929.35, model limit $47,396.96 and deduction $10,000 (with no business named and with SCHEDULE_C named).

  • CI: Pull request run 41834014443 at this head has now finished, and all 36 jobs passed. The body's CI line still says Contrib other-shard-1 is running (stale).

  • Let farm and partnership plans take the self-employed plan deduction #10131's stacking point is 47bba5e893, not b03f96f65f. A merge with this head also conflicts in test_no_group_variables_in_person_adds.py, beyond the three files the body names.

  • Test runs at this head, one file per process: limit YAML 21 passed, ALD YAML 12 passed, owners' draw reform YAML 14 passed, property test 2 passed, test_owners_draw.py 38 passed; ruff format --check and ruff check on the changed file are clean.

  • Count eligible long-term care premiums in Schedule A medical expenses #10265 (head cb662a9476) isn't in the overlap section, but it edits self_employed_health_insurance_ald_person.py, the reader of this PR's limit. With each PR merged onto main 25c4253483, the two combine without conflict (git merge-tree --merge-base=origin/main). In that tree the limit (21), ALD (12), self-employed long-term care (3) and itemized medical (17) YAML files and both property tests (10, 2) pass.

Still to do: mutants and the final verdict.


Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review
VERDICT: APPROVE
735cb03
METHODOLOGY_CHOICE: yes

Round 2 delta review. The head hasn't moved past 735cb03ef8, the one commit since the round 1 review's head da6240b489. That commit changes only a documentation string (self_employed_health_insurance_plan_business.py:43-45), and the rest of the round is body edits. The methodology choice is unchanged from round 1: with no business named, the limit takes the business with the largest line 13 amount.

There are no P1 or P2 findings. Every round 1 item is done. The findings below are P3 corrections to the body, plus one overlap the body leaves out.

Findings

P3. #10265 is missing from "Overlap with other open PRs"

#10265 ("Count eligible long-term care premiums in Schedule A medical expenses", head cb662a9476) edits self_employed_health_insurance_ald_person.py, the one baseline reader of this PR's limit. It changes the ALD's premiums from line 1 alone to line 1 plus eligible long-term care premiums (line 2), still capped at self_employed_health_insurance_earned_income_limit. Its tests also read this limit. I found it with gh api "search/issues?q=repo:PolicyEngine/policyengine-us+is:pr+is:open+self_employed_health_insurance_earned_income_limit".

The two compose. A raw git merge-tree of the two heads reports one conflict, in itemized_medical_expenses.py, a file this PR doesn't edit; it comes from a criss-cross history with two merge bases (25c4253483, 23285ce622). With each PR merged onto main 25c4253483, git merge-tree --write-tree --merge-base=origin/main is clean. In that tree, one file per process, these passed:

  • the limit YAML (21);
  • the ALD YAML (12);
  • self_employed_long_term_care_premiums.yaml (3);
  • itemized_medical_expenses.yaml (17);
  • test_long_term_care_premium_properties.py (10);
  • test_self_employed_health_insurance_properties.py (2).

The default stays the largest-deduction choice, because the deduction is still min(line 3, line 13). Proposed bullet:

  • Count eligible long-term care premiums in Schedule A medical expenses #10265 (long-term care premiums, head cb662a9476) edits self_employed_health_insurance_ald_person.py, which reads this PR's limit: the deduction becomes the smaller of line 3 (line 1 plus eligible long-term care, line 2) and line 13. With each PR merged onto main, the two merge without conflict, and the limit, ALD, self-employed long-term care and itemized medical YAML files and both property tests pass in the merged tree. Whichever lands second drops "Line 2 (long-term care)" from this PR's "Not changed" list.

P3. The CI line is stale

Body, "Results", the "CI:" bullet: run 41834014443 "had passed every job but Contrib (other-shard-1), still running". That run has since completed with conclusion success, and all 36 jobs passed, including Contrib (other-shard-1). I listed them with gh api --paginate repos/PolicyEngine/policyengine-us/actions/runs/41834014443/jobs. The round 2 brief's item 4 asked for "the latest run at your final head ... with its conclusion". Replacement:

  • CI: Pull request run 41834014443 at 735cb03ef8 passed every job (36 of 36).

P3. The #10131 bullet names the wrong stacking point and undercounts its conflicts

Body, "Overlap", #10131: "stacked on this PR's old head b03f96f65f" and "conflicts in three files". #10131 is at c1401819d6. Its merge base with this PR is 47bba5e893, and git merge-base --is-ancestor b03f96f65f pr-10131 is false. git merge-tree --write-tree pr-10120 pr-10131 conflicts in:

The hand-off's judgment calls already note this, but the body still carries the old text. Replacement for the opening: "#10131 (draft, head c1401819d6, stacked on this PR's 47bba5e893): conflicts in four files besides CHANGELOG.md, pyproject.toml and uv.lock." Then add test_no_group_variables_in_person_adds.py to its list.

P3 (for the hub, not the author). impact: and axiom: hold placeholders

Both lines exist, as "impact: the hub will measure" and "axiom: (hub files pe-parity before landing)". Neither is one of the forms the repo's guide requires (<legal id> encoded-correct | <PR> encoded | <issue> queued | n/a: <reason>). The brief left them to the hub, so this is a landing gate, not an author defect.

Checked and sound

  • No formula change. git diff --stat da6240b489 735cb03ef8 shows one file with 2 insertions and 1 deletion, all inside the documentation string of self_employed_health_insurance_plan_business.py. It's the round 1 review's replacement text verbatim. At this head, ruff format --check gives "1 file already formatted" and ruff check gives "All checks passed!".

  • The default. I read form_7206_line_13 (self_employed_health_insurance_earned_income_limit.py:114-124). The select default is max_(max_(schedule_c, farm), max_(partnership, s_corporation)). The deduction is min_(premiums, earned_income_limit) (self_employed_health_insurance_ald_person.py:28). Because min(p, max Lᵢ) = max min(p, Lᵢ), the body's sentence "takes the business with the largest line 13 amount, which gives the filer the largest deduction" is exact. The input's documentation ("largest earned income") and the limit's documentation say the same, since line 13 is that business's earned income.

  • The new documentation sentence ("or when the plan is established under a business other than the one with the largest earned income") is true. When a business is named, the code returns that business's own line 13, and the default can only be at or above it.

  • The Cap the self-employed health insurance deduction at the earnings of the business that established the plan, including a farm or partnership (26 U.S.C. 162(l)(2)(A)) #10528 text and witness. By hand, with exact fractions: line 15 = 51,000 × 0.9235 × 0.153 / 2 = 3,603.03525. Form 7206 for the SSTB plan gives 1,000 − 3,603.03525 × 1,000 / 51,000 = 929.35225. The pooled Schedule C line 13 is 51,000 − 3,603.03525 = 47,396.96475. I then ran the model (2026, self_employment_income 50,000, sstb_self_employment_income 1,000, premiums 10,000, is_self_employed true). With UNSPECIFIED and with SCHEDULE_C it gives self_employment_tax_ald_person 3,603.0352, a limit of 47,396.965 and a deduction of 10,000. total_self_employment_income adds both inputs, which confirms the pooling the body describes. Cases 1 to 3 and the "Not fixed" bullet match round 1's replacement text.

  • Overlap bullets, at current heads:

  • The premium documentation bullet. It quotes main's premium variable, and Exclude employer-plan-eligible premiums from the self-employed health insurance deduction #10122's file list includes that file.

  • CI. Pull request run 41834014443 at this head concluded success, with 36 of 36 jobs passing. The Documentation run 41834014132 also passed.

  • Tests at this head, one file per process on Linux, Python 3.14:

    • limit YAML: 21 passed;
    • ALD YAML: 12 passed;
    • owners' draw reform YAML: 14 passed, about 2 minutes and about 10 GB resident;
    • test_self_employed_health_insurance_properties.py: 2 passed, 44 s wall time including setup, 963 MB peak;
    • test_owners_draw.py: 38 passed.

    These assert the full claim, as round 1 found: property 1 checks each named limit against an independent closed form.

  • Mutants. I ran the body's seven plus one of my own, each in its own process on a scratch worktree, restoring the code after each; git status --porcelain was empty after every one. Every mutant is killed:

    Mutant Limit YAML ALD YAML Reform YAML Property test test_owners_draw.py
    1. Schedule C-only default 6 fail 3 fail 1 fail 2 fail 38 pass
    2. Line 9 from every business 1 fail pass pass 2 fail pass
    3. No line 15 share, farm or partnership 8 fail 3 fail 2 fail 2 fail pass
    4. Pooled default 5 fail 1 fail 2 fail 2 fail pass
    5. S corporation wages dropped 2 fail 1 fail pass 2 fail pass
    6. Every business takes all of line 15 7 fail 2 fail 10 fail 2 fail 1 fail
    7. Reform without the draw term pass pass 9 fail pass 1 fail (test_generated_sehi_limit_counts_seca_taxed_draw_in_line_5)
    8. Mine: line 5 leaves out the partnership's profit 5 fail 1 fail pass 2 fail 2 fail (test_already_se_partnership_income_cannot_add_a_second_draw, test_generated_sehi_limit_counts_seca_taxed_draw_in_line_5)

    The property test's failures are test_deduction_follows_form_7206 and test_reviewer_example_and_boundaries in every row where it fails. The counts for mutants 1 to 7 match round 1's table. The body's mutant claims hold: all six formula mutants fail the limit YAML and the property test, five fail the ALD YAML (mutant 2 passes it), and mutant 7 fails 9 of the 14 reform cases.

  • Readers.

    • self_employed_health_insurance_plan_business and s_corp_shareholder_medicare_wages are read only in form_7206_line_13.
    • form_7206_line_13 is called by the limit variable and by reforms/ssa/owners_draw.py.
    • The limit is read by self_employed_health_insurance_ald_person and the owners' draw override.
    • The per-person deduction is read by:
      • federal: self_employed_health_insurance_ald, dependents_self_employed_health_insurance_ald, dependent_taxable_ss_magi and self_employed_health_insurance_ald_excluded_premiums;
      • states: MS, OH, MO and MT;
      • parameter lists: the QBI deduction definition and South Carolina's two-wage-earner subtractions.

    This round's commit changes none of their inputs. The PR as a whole can move baseline outputs, as round 1 found: the default raises the deduction where a farm, partnership or S corporation line 13 exceeds the Schedule C limit. This round adds no new movement, so the population check round 1 called for stands unchanged.

  • Scope. The 11 files include nothing under .github/ or policyengine_us/tests/policy/baseline/partners/. The changelog fragment is a top-level changelog.d/sehi-plan-business-base.fixed.md.

  • Brief coverage. Items 1, 2, 3, 5, 6 and 7 are done as asked. Item 4 cites the head's run but not its conclusion, because it hadn't finished at hand-off (see the P3 above).

What I couldn't check

  • Sources. From this session, irs.gov, uscode.house.gov, govinfo.gov, ecfr.gov, law.cornell.edu and web.archive.org all failed: the proxy refused the tunnel or the host didn't resolve. So I confirmed no statute or form text this round. This round adds no legal claim; its new statements are about the code and the arithmetic, which I checked against the code and a model run. The witness's 0.9235 and 15.3% rates are the Schedule SE figures the PR's tests already use.
  • Defect at main. This round fixes no defect. I didn't rerun round 1's main-versus-PR comparison.
  • The Limit self-employed plan contributions to the Pub. 560 maximum deduction #10121 merged tree. I didn't rerun the owners' draw reform YAML there. It takes about 10 GB, and the mutant runs were using that memory.
  • Population impact. I can't reach the microdata.

Generated by Claude Code

@DTrim99

DTrim99 commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Let farm, partnership and S corporation plans set the self-employed health insurance limit

Summary

The PR replaces main's Schedule C-only earned income limit (#10109) with a module-level form_7206_line_13(person, period, other_line_5_profits=0). It computes Form 7206 line 13 separately for four possible plan businesses:

  • Schedule C (total_self_employment_income).
  • Schedule F (farm_operations_income).
  • The partnership (partnership_self_employment_net_earnings, K-1 box 14 code A).
  • The S corporation, from a new input, s_corp_shareholder_medicare_wages (W-2 box 5).

A second new enum input, self_employed_health_insurance_plan_business, names the plan business. With no business named, the limit is the largest of the four line 13 amounts. The owners' draw reform now calls the same helper and passes its draw profits as extra line 5 profits.

I read the law first, and the structure follows it:

  • Statute. 26 U.S.C. 162(l)(2)(A) caps the deduction at "the taxpayer's earned income (within the meaning of section 401(c)) derived by the taxpayer from the trade or business with respect to which the plan providing the medical care coverage is established." 162(l)(5) applies the subsection to "any individual treated as a partner under section 1372(a)", and (5)(A) treats "such individual's wages (as defined in section 3121) from the S corporation" as earned income.
  • Form 7206 (2023, 2024, 2025; only the long-term care amounts differ) says "Use a separate Form 7206 for each trade or business under which an insurance plan is established." Its lines:
    • Line 4 is the plan business's net profit ("If the business is an S corporation, skip to line 11").
    • Line 5 is the "total of all net profits from Schedule C ... line 31; Schedule F ... line 34; or Schedule K-1 (Form 1065), box 14, code A", and "Don't include any net losses".
    • Lines 6–8 subtract Schedule 1 line 15 times line 4 ÷ line 5.
    • Line 9 subtracts the line 16 plan deduction "attributable to the same trade or business".
    • Line 11 is "your Medicare wages (box 5 of Form W-2) from an S corporation in which you are a more-than-2% shareholder and in which the insurance plan is established".
    • Line 13 is "line 10 or 11, whichever applies".
  • Before 2023. Pub. 535 (2022) Worksheet 6-A (PDF p. 23) has the same lines and the same note: "Use a separate worksheet for each trade or business under which an insurance plan is established."
  • Who may establish a plan. The Form 7206 instructions (2023–2025, same text) say:
    • A Schedule C or F policy "can be either in the name of the business or in the name of the individual."
    • A partnership or S corporation plan counts only if the entity pays or reimburses the premiums and reports them as guaranteed payments (K-1) or as box 1 wages. "Otherwise, the insurance plan won't be considered to be established under your business."
  • S corporation guidance. Notice 2008-1 (citing Rev. Rul. 91-26) says such premiums are "included in wages for income tax withholding purposes on the shareholder-employee's Form W-2, ... but are not wages subject to Social Security and Medicare taxes if the requirements for exclusion under section 3121(a)(2)(B) are" met. A plan is "established by the S corporation" only if the corporation pays the premiums, or reimburses the shareholder, and reports them as W-2 wages.
  • Partnership guidance. Rev. Rul. 91-26 makes partnership-paid premiums 707(c) guaranteed payments, which are includible in the partner's income and are net earnings from self-employment, so they sit in box 14 code A.

The code applies these lines per business:

  • Line 15 is apportioned by each business's share of line 5.
  • Losses are left out of line 5.
  • Only the Schedule C business subtracts line 16. That is consistent because the model caps self_employed_pension_contribution_ald_person at Schedule C income.
  • The S corporation line 13 is box 5 wages, with no self-employment tax share.
  • Form 4835 farm rent (farm_rent_income) stays out of both line 4 and line 5. That is correct: it is not net earnings from self-employment, so it isn't earned income.

The unnamed-business default is a documented methodology choice for missing data, not a legal rule. It never lowers a deduction relative to main. It can overstate the deduction when a partnership or S corporation with the larger limit doesn't pay or reimburse the premiums, and the input documentation says to name the business in that case.

There are no critical or should-address findings. The suggestions are housekeeping. CI is green at the head (37 pass, 1 skipped). The branch is 28 commits behind main. It merges cleanly, but #10265 and #10560 have landed since the PR's CI ran, so it should merge main before landing.

Critical

None.

Should address

None.

Suggestions

  1. Refresh the PR body after merging main.
  2. Partnership entry guidance (self_employed_health_insurance_plan_business.py, documentation).
    • For S corporations, s_corp_shareholder_medicare_wages tells users to put reimbursed premiums in employment_income as well as in health_insurance_premiums.
    • The partnership case has no parallel sentence. Under Rev. Rul. 91-26, premiums a partnership pays or reimburses are 707(c) guaranteed payments, includible in the partner's gross income and in K-1 box 14 code A.
    • Suggest adding: "include those guaranteed payments in partnership_income and partnership_self_employment_net_earnings."
  3. Payroll tax on S corporation-paid premiums (documented limitation; follow-up).
    • The model has no box-1-only wage input. Following the documentation therefore puts reimbursed premiums into payroll_tax_gross_wages. Notice 2008-1 and IRS practice leave them out of boxes 3 and 5.
    • ALD Case 11 is an example: FICA wages are 22,000 instead of 10,000, so employee payroll tax is overstated by 12,000 × 7.65% = $918.
    • The documentation already says this. A follow-up could add an input for shareholder premiums reported as wages and subtract it in fica_pre_tax_contributions, which already removes pre_tax_health_insurance_premiums.
  4. Reference. Consider adding Notice 2008-1 to s_corp_shareholder_medicare_wages and self_employed_health_insurance_plan_business. It is the authority for "established by the S corporation" and for the box 1 vs box 5 treatment that both documentation strings describe.
  5. File the proposed follow-up. The body's "Let the self-employed health insurance limit name one business among several of the same kind" (SSTB witness: Form 7206 gives $929.35, the model $10,000) is not yet an issue. File it so the pooling limitation is tracked.

Verified correct

  • Law vs code, per line:
    • Line 4 floors each business at 0.
    • Line 5 sums the positive profits plus other_line_5_profits.
    • Lines 6–8 use np.divide(..., where=line_5 > 0), so a wages-only S corporation filer has no division by zero.
    • Line 9 applies to Schedule C only.
    • Line 11 is box 5 wages.
    • The select returns the named business, or the largest line 13.
  • Earned income for each kind of plan:
    • Farm: Schedule F only.
    • Partnership: box 14 code A, which includes guaranteed payments.
    • S corporation: box 5 wages from that corporation, not distributions (s_corp_income), and no line 15 share.
  • The default. min(p, max Lᵢ) = max min(p, Lᵢ), so "largest line 13" is the largest deduction one plan can take. A Schedule C or F filer can hold the policy in their own name under either business. The default stays at or above main's Schedule C limit, which the property test pins with at_least(copy(limit, "u"), line_13["SCHEDULE_C"]).
  • No reinvention. No existing variable holds S corporation shareholder wages. s_corp_income is the K-1 distributive share, and partnership_s_corp_income and the TAXSIM scorp input are pass-through income. The enum is new.
  • is_self_employed gate. It is read only by self_employed_health_insurance_premiums, so a shareholder who sets it, as both new inputs instruct, triggers nothing else.
  • Vectorization and entity. All computation is per person and annual. The enum comparisons in select are vectorized. The enum is not state-gated, so the NH Add New Hampshire state supplementation for 2026 #10156 default-key pattern doesn't apply.
  • Hand-checks (r = 0.9235 × 0.153 / 2 = 0.07064775), checked with exact fractions:
    1. Limit Case 11 (2025): line 15 = 15,000 r = 1,059.71625. The partnership takes all of it (line 5 = 20,000): 20,000 − 1,059.71625 = 18,940.28375.
    2. Limit Case 12 (2024): 20,000 r = 1,412.955; 20,000 − 1,412.955 = 18,587.045.
    3. Limit Case 13 (2025): 30,000 r = 2,119.4325; 27,880.5675.
    4. Limit Case 14 (2024): 45,000 r = 3,179.14875. Farm: 40,000 − (40/45) × 3,179.14875 = 37,174.09. Schedule C: 5,000 − 353.23875 = 4,646.76125. The default takes 37,174.09.
    5. Limit Case 15: named Schedule C gives 4,646.76125.
    6. Limit Case 16 (2024): 40,000 r = 2,825.91; 10,000 − 0.25 × 2,825.91 = 9,293.5225.
    7. Limit Case 17 (2023): 30,000 r = 2,119.4325. Schedule C: 20,000 − (2/3) × 2,119.4325 − 15,000 = 3,587.045. Partnership: 10,000 − 706.4775 = 9,293.5225. The default takes 9,293.5225.
    8. Limit Cases 18/19 (2025): the S corporation gives 50,000. Schedule C gives 10,000 − 706.4775 = 9,293.5225.
    9. Limit Case 20 (2025): 50,000 r = 3,532.3875; 10,000 − 0.2 × 3,532.3875 = 9,293.5225.
    10. Limit Case 21: named S corporation gives 10,000 (Schedule C would give 50,000 − 3,532.3875 = 46,467.6125).
    11. ALD Case 9 (2024): min(25,000, 18,587.045) = 18,587.045. AGI = 20,000 − 1,412.955 − 18,587.045 = 0.
    12. ALD Case 10 (2025): min(40,000, 27,880.5675). AGI = 30,000 − 2,119.4325 − 27,880.5675 = 0.
    13. ALD Case 11 (2025): min(12,000, 10,000) = 10,000. AGI = 22,000 − 10,000 = 12,000, with no self-employment tax.
    14. ALD Case 12 (2024): named farm gives 9,293.5225.
    15. Owners' draw reform (2027):
      • SE tax = 70,000 × 0.9235 × 0.153 = 9,890.685.
      • Draw OASDI = 59,999.998 × 0.124 = 7,440.00.
      • Line 15 = 8,665.342.
      • Line 5 = 134,970.22.
      • Farm: 60,000 − 8,665.342 × 60,000 / 134,970.22 = 56,147.887, which matches 56,147.89 within the 0.02 margin.
      • Named Schedule C: 10,000 − 642.02 = 9,357.98.
    16. Fixed property example (2022): farm 50,000 beside Schedule C 20,000 with a 20,000 plan deduction. Line 15 = 70,000 r = 4,945.3425. Farm: 50,000 − (5/7) × 4,945.3425 = 46,467.6125. The Schedule C line 10 is negative and floors at 0.
  • Mutation coverage.
    • Each named branch is pinned: SCHEDULE_C by Cases 8, 15 and 19; SCHEDULE_F by Case 16 and ALD 12; PARTNERSHIP by Case 20; S_CORPORATION by Case 21.
    • The default is pinned by Cases 11, 14, 17 and 18, the line 9 restriction by Case 17, and the draw term by the three new reform cases.
    • Property 1 also ties every named copy to an independent closed-form Form 7206.
    • The max_(0, …) floors on the farm and partnership line 13 can't bind: line 15 ≤ 0.0765 × 0.9235 × line 5, so each business keeps at least 93% of its profit. Their being unpinned is not a gap.
  • Changelog. changelog.d/sehi-plan-business-base.fixed.md is top-level, and fixed is a sensible type.
  • References. Each reference is a single source and corroborates its text: 162(l), 401(c)(2)(A), 1372, 3121(a)(2), Form 7206 (2023) p. 1, the instructions (2023) with a # PDF pages 1-2 comment above a #page=1 href, and Pub. 535 (2022) #page=23, the worksheet's PDF page. They follow the CLAUDE.md variable-reference rule.
  • Source-conflict ratchet. No added or removed comment line matches the Tie source-conflict markers to the register shared with Axiom #10287 conflict-comment pattern, and no source conflict arises: line 7's proportional split and line 11's box 5 reading fill gaps in the statute.
  • Tests. They are in variable-named YAML files, with no generic names. The Python property file already existed and adds what YAML can't (the differential, bounds, monotonicity and AGI floor). CI shows it is cheap (see Suggestion 1). No partner contract test files and nothing under .github/ changed.
  • Readers of the limit. self_employed_health_insurance_ald_person and the owners' draw override read it. The per-person deduction feeds federal ALD aggregation, MS, OH, MO and MT, QBI and South Carolina's lists. All are unchanged in form. Baseline values rise only where a farm, partnership or S corporation line 13 exceeds the Schedule C limit.

Axiom line assessment

axiom: TheAxiomFoundation/rulespec-us#1676 queued, extended with a comment is valid:

  • State. Integrate pension income input variables #1676 is OPEN and labelled pe-parity.
  • The extension comment (2026-11-05 04:42 UTC) names this head, 735cb03ef8. It gives:
    • the module path us/statutes/26/162/l.yaml and corpus citations us/statute/26/162/l and us/statute/26/401/c/2/A;
    • verbatim 162(l)(2)(A), (l)(5) and 401(c)(2)(A)(v)–(vi), plus Form 7206 lines 4–14 and the plan-establishment rules;
    • the required outputs, with the business-specific limit and the S corporation branch;
    • companion tests hand-computed from Form 7206 for every changed YAML expectation, plus a same-kind-business boundary case.
  • The comment encodes the law, not PE's choices. It tells the encoder not to encode the unspecified-business maximum or PE's pooling.
  • Blockers are recorded: corpus release admission, IRS form ingestion, re-pin, and signed-encoder approval.

CI status

gh pr checks 10120 gives 37 pass and 1 skipping. The skip is "Deploy documentation to GitHub Pages", which is expected on a pull request. Pull request run 41834014443 at 735cb03ef8 passed every job.

That run predates the merges of #10265 and #10560 into main. I checked the merged tree statically (see Branch status). CI hasn't run it.

Branch status

Verdict: APPROVE

@DTrim99 DTrim99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving: 0 critical, 0 should. The per-business § 162(l)(2)(A) limit and the (l)(5) S-corp wages route match Form 7206 line by line, and every branch is pinned. Branch note: merge main and rerun (#10265 and #10560 landed since CI ran). Full report in the comment above.

MaxGhenis and others added 4 commits November 7, 2026 13:20
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since #10265, the deduction is the smaller of Form 7206 line 3 (the
medical premiums plus eligible long-term care premiums) and line 13.
The property test still capped it at the medical premiums, and no test
put long-term care premiums under a farm, partnership or S corporation
plan.

- ALD YAML Cases 13 to 16 add long-term care premiums under an S
  corporation, a farm, a partnership and the default business. Each
  checks the long-term care part and Schedule A as well as the
  deduction.
- The property test draws long-term care premiums, checks the
  deduction against line 3 and adds property 6: the long-term care part
  and Schedule A.
- The plan business, S corporation wage and long-term care premium
  inputs say that long-term care premiums a partnership or S
  corporation pays or reimburses go in
  long_term_health_insurance_premiums, on the insured person.
- The reform case with S corporation profits but no box 5 wages now
  says so in its name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The S corporation wage input's documentation now says the model's payroll
tax wages start from employment_income, so they include the long-term care
premiums it routes there. Three test comments name the year of the $850
limit, the premiums property 6 counts, and both zero lines in the owners'
draw case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The plan business input now says a partner also enters premium
guaranteed payments in partnership_income, and in
partnership_self_employment_net_earnings when the partnership reports
them in K-1 box 14 code A, matching the S corporation input's
employment_income sentence. Both inputs cite Notice 2008-1 for when a
plan is established by the S corporation and for the box 1 vs box 5
treatment, and the plan business input cites the Form 1065
instructions' line 4c note that guaranteed payments are net earnings
from self-employment. Documentation and references only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Nov 8, 2026
Resolves the conflicts with #10120's shared form_7206_line_13 helper, which
the owners' draw reform also calls. Line 8 now uses #10120's per-business
share of line 15, and line 9 keeps this branch's split of line 16 across
the retirement plan's businesses. #10120's new SEHI cases (13 to 16 in the
deduction file, 17, 20 and 21 in the limit file) keep their numbers, and
this branch's cases follow them (deduction Case 17; limit Cases 22 to 25).
The property test takes #10120's version here; the next commit adds the
retirement plan business and its line 9 reference back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis merged commit da23c78 into main Nov 8, 2026
37 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

US + core hub merge audit, us#10120 at eddc35a698de9650691a027011e59c62b885f0d4 (squash): Let farm, partnership and S corporation plans set the self-employed health insurance limit.

  • Reviews:
    • An Opus 5.5 reviewer in a cloud session approved da6240b489 in round 1. Its one P2 and four P3s asked for changes to the body, the hand-off and one input's documentation. Round 2 approved 735cb03ef8 with P3s only.
    • DTrim99 approved on November 5, before the main merge, with no critical or should-address findings and five optional suggestions. The body's "DTrim99's suggestions" section answers each one.
    • An in-session Opus 5.5 reviewer approved the main merge at 577118d432 in round 3. Its one P2 found that Count eligible long-term care premiums in Schedule A medical expenses #10265 had put long-term care premiums on Form 7206 line 3. So the body's invariants and the property test no longer held, and no test covered line 2 under a farm, partnership or S corporation plan.
    • Round 4 approved 69a8b3b48b, which adds ALD Cases 13 to 16, long-term care premiums under each plan business, and property 6. The reviewer computed every expected value by hand, and three mutants each fail the property test. Its P2, the body's stale invariants, the body now fixes.
    • Round 5 approved 031c6bcfda and eddc35a698, which change only documentation strings and references: with the reference tuples dropped, each file gives the same ast.dump as its parent.
  • Methodology choice the body discloses: with no plan business named, the limit takes the business with the largest line 13.
  • Main merge and the overlap guard: 577118d432 merged main a8dc8d9067 with no hand resolution. Since then, main's Model the claim of right repayment deduction and credit (26 U.S.C. 1341) and North Carolina's rules that depend on it #10038 has changed claim_of_right_deduction and tax_unit_itemizes in the area this PR changes, so the guard flags it. A local merge of this head with main 7acea8ee63 matches git merge-tree's tree and passes all 12 test files, one process each. They cover the PR's five files (91 tests), main's files for claim of right, itemizing, medical expenses, Arizona's property tax credit income and market income (82), and two code-health guards (113).
  • Gates checked live at merge:
    • gh pr checks exits 0;
    • the latest Pull request run at the head concluded success (42415841679, 35 of 35 jobs);
    • MERGEABLE;
    • not a draft;
    • no reviewer's latest review requests changes;
    • the semantic-overlap guard, with the combination verified at main 7acea8ee63;
    • the merge pins the head.
  • Impact: measured at 577118d432 on the default dataset in 2026, against main at the merge base a8dc8d9067. The head's three later commits change only documentation strings, references and tests. The self-employed health insurance deduction rises by $39.05m for 36 tax units (117,598 weighted). Federal income tax falls by $9.35m and state income tax by $282,139, and benefits don't change. The body's impact section has the table.
  • Follow-ups: the body proposes two. One would let the limit name one business among several of the same kind; the other would take premiums an S corporation pays out of payroll tax wages. A third, a dependent's medical premiums counting on two returns, comes from main's design and waits on a methodology decision.
  • Axiom: Encode IRC §162(l): the self-employed health insurance deduction and its 401(c) earned-income limit TheAxiomFoundation/rulespec-us#1676 queues the plan-business limits, extended with a comment.

🤖 Generated with Claude Code

@MaxGhenis
MaxGhenis deleted the sehi-plan-business-base branch November 8, 2026 01:38
MaxGhenis added a commit that referenced this pull request Nov 8, 2026
…anch

Main's copies of the seven conflicting files match #10120's head
(eddc35a) exactly, so this branch's later versions stand. Every other
file takes main's side or a three-way merge on #10120's head, and
source_conflicts/candidates.yaml merged cleanly on that base. Main's
release compiled #10120's changelog fragment, so the merge removes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis pushed a commit that referenced this pull request Nov 9, 2026
Brings in #10120, which shares four files with this branch: the owners'
draw reform and its doc, the health insurance limit YAML and the reform's
Python test. Git merged each file without conflicts, keeping both sides.
On the merged tree all 13 test files the two PRs change under
above_the_line_deductions, the owners' draw tests and both property tests
pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N2tyHT12N9L3WVu8rJokf1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants