Repository navigation
Count the owners' draw in the SEHI limit's line 5 under the owners' draw reform - #10571
Conversation
With the owners' draw reform on, the deductible SE tax on Form 7206 line 7 includes the draw's SECA, but line 5 left out the draw's profits, so the Schedule C plan business took too large a share of that tax and the limit fell (40,000 Schedule C with a 60,000 net-earnings draw: 33,454.09 instead of 37,505.61). The reform now overrides the limit, adding the draw's gross profit to line 5 when the reform is in effect; the baseline formula is untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Disabled, the reform's limit must equal the baseline formula; enabled, it must match an independent lines 4-13 oracle with the draw's gross profit in line 5, sit at or above main's draw-free result, and never exceed line 4 less the line 6 share of deductible SE tax. The pure harness now stores integer money inputs as floats, as Core does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Ready for hub review Head: What the item asked and how it's resolved
Judgment calls
Tests (one file per process)
Mutants (each in its own process; restored and checked with
|
|
Picking this up for the US hub. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
Line 5 apportions line 7's deductible SE tax by business profits. Adding the whole gross draw raised the limit above main when the draw's SECA was not in line 7: with half_seca_deduction off, and for draw profits beyond the OASDI room with HI off. Line 5 now adds owners_draw_niit_exclusion, the gross profits that bear SECA, only when half_seca_deduction is on. YAML cases cover the three setups, the generated test varies half_seca_deduction, the cap, room_cap_basis and phase_in_share with an oracle that derives the draw term from the rule, and the docs describe the override. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6H6zhX5KYCDLztuSH4
|
Ready for hub review Head: FindingsP2-1, line 5 counts draw profits whose SECA isn't in line 7. Fixed in P2-2, nothing tests these setups.
P3 items.
Hand valuesAll five setups use 2027, $40,000 Schedule C, $64,970.22 S-corp profit, $200,000 caps and q = 0.9235. They match the review's table.
How the $150k case works out:
The existing hand case (37,505.61) and the four existing YAML values are unchanged. Tests (one file per process)
Mutants (each applied, run and reverted)
CIPull request run https://github.com/PolicyEngine/policyengine-us/actions/runs/41397745379 was still Judgment calls
Follow-upOwners' draw: count the draw in earned-income readers that subtract SE tax ALD. Generated by Claude Code |
|
Ready for hub review Independent round-2 review. The head hasn't moved past SummaryThe code is right. I hand-computed ten setups from the Form 7206 rule before reading the code, including the two this round asks about ( The one blocking gap is in the tests. Neither test file pins the limit with HI on and FindingsP2-1: no test pins the limit with HI on and
- name: With HI on, nondeductible draw SECA still keeps the draw out of line 5
period: 2027
absolute_error_margin: 0.02
reforms: policyengine_us.reforms.ssa.owners_draw.owners_draw
input:
gov.contrib.ssa.owners_draw.current_law_cap: 200_000
gov.contrib.ssa.owners_draw.in_effect: true
gov.contrib.ssa.owners_draw.phase_in_share: 1
gov.contrib.ssa.owners_draw.include_hi: true
gov.contrib.ssa.owners_draw.half_seca_deduction: false
gov.irs.payroll.social_security.cap: 200_000
gov.simulation.aime_lookback_years: 0
payroll_tax_gross_wages: 300_000
self_employment_income: 40_000
s_corp_income: 64_970.22
output:
# 59,999.998 x 2.9% = 1,740.00 of draw HI, none of it deductible.
owners_draw_hi_tax: 1_740
# Schedule C HI only: 36,940 x 2.9% / 2 = 535.63.
self_employment_tax_ald_person: 535.63
# Line 5 is 40,000: 40,000 - 535.63. Counting the draw would give 39,795.89.
self_employed_health_insurance_earned_income_limit: 39_464.37
- name: With HI on and no OASDI room, the whole gross draw is in line 5
period: 2027
absolute_error_margin: 0.02
reforms: policyengine_us.reforms.ssa.owners_draw.owners_draw
input:
gov.contrib.ssa.owners_draw.current_law_cap: 200_000
gov.contrib.ssa.owners_draw.in_effect: true
gov.contrib.ssa.owners_draw.phase_in_share: 1
gov.contrib.ssa.owners_draw.include_hi: true
gov.irs.payroll.social_security.cap: 200_000
gov.simulation.aime_lookback_years: 0
payroll_tax_gross_wages: 300_000
self_employment_income: 40_000
s_corp_income: 64_970.22
output:
owners_draw_oasdi_base: 0
owners_draw_hi_tax: 1_740
owners_draw_niit_exclusion: 64_970.22
# (1,071.26 + 1,740.00) / 2 = 1,405.63.
self_employment_tax_ald_person: 1_405.63
# Line 6: 40,000 / 104,970.22 = 0.3810605; 40,000 - 535.63 = 39,464.37.
# Main (draw left out of line 5) gives 38,594.37.
self_employed_health_insurance_earned_income_limit: 39_464.37
- name: A half phase-in counts the same half in line 5 as line 7 taxes
period: 2027
absolute_error_margin: 0.02
reforms: policyengine_us.reforms.ssa.owners_draw.owners_draw
input:
gov.contrib.ssa.owners_draw.current_law_cap: 200_000
gov.contrib.ssa.owners_draw.in_effect: true
gov.contrib.ssa.owners_draw.phase_in_share: 0.5
gov.irs.payroll.social_security.cap: 200_000
gov.simulation.aime_lookback_years: 0
self_employment_income: 40_000
s_corp_income: 64_970.22
output:
owners_draw_gross: 32_485.11
owners_draw_oasdi_base: 30_000
owners_draw_niit_exclusion: 32_485.11
# (5,651.82 + 30,000 x 12.4%) / 2 = 4,685.91.
self_employment_tax_ald_person: 4_685.91
# Line 5: 72,485.11; line 6: 0.5518375; 40,000 - 2,585.86 = 37,414.14.
# Main gives 35,314.09; the whole S-corp profit in line 5 would give 38,214.38.
self_employed_health_insurance_earned_income_limit: 37_414.14P3-1: the new docs section takes over a paragraph about the cap.
P3-2: the hand-off's CI line is stale. It says run 41397745379 was still r1 findings at this head
The questions this round asked
So line 5 never counts more draw than line 7 taxes. Counting only the phased-in half, rather than the whole S-corp profit, is a methodology choice; see below. HI on with OASDI room used up. Witness (wages $300,000, HI on): The oracle. It now derives line 5's draw term from the rule (
Those are covered by other tests in the file, so I don't count this as a finding. The two remaining checks against main's formula ( Is this a methodology choice? Yes. Form 7206 line 5 counts the net profits of businesses subject to SE tax, and a real business above the wage base still counts its whole profit. The PR instead counts only the draw profits whose SECA is in line 7, which makes line 6 allocate the deductible tax at matching per-dollar rates. The HI-on witnesses above show that this reproduces each business's own tax exactly when rates match. That choice has no statute behind it either way. I think it's the defensible reading for a parallel draw base, but the hub should own it. Checked and sound
What I couldn't check
Generated by Claude Code |
|
Picking this up for the US hub. I'll post a hand-off comment here when it's ready. Generated by Claude Code |
Bring the branch up to date with main before the round-2 test and docs fixes. No conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The round-2 review found that no test reached HI on with half_seca_deduction false, HI on with OASDI room used, or phase_in_share 0.5 with HI off, so a mutant counting the whole draw whenever HI is on survived. Add the three YAML cases and matching @examples so each setup is pinned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The section sat above the paragraph that closes the cap-priority section. Also say the OASDI base is divided by the net-earnings factor (q by default), since an explicit net_earnings_factor overrides q. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Ready for hub review Head: Round-2 fix round on the review at #10571 (comment). MergeFast-forwarded to Findings1 (P2): HI on with the deduction off, and a half phase-in with HI off.
2 (P3): docs section placement. Moved "Self-employed health insurance limit" to just before 3 (P3): 4: the body. Written with the PATCH call from a file and checked against GitHub's readback. Every line matches except the last: the write path replaced the closing "🤖 Generated with [Claude Code]" line with its own
Tests at head (one file per process)
MutantsEach ran in its own process: the YAML file, then
CIPull request run 41537180716 at Judgment calls
No new follow-up beyond the earned-income readers the body already lists. Generated by Claude Code |
|
Hub review in progress (superseded) The round-3 review is complete. See #10571 (comment). Generated by Claude Code |
|
Ready for hub review Independent round-3 review. The head hasn't moved past SummaryEvery round-2 finding is closed at this head. The merge adds nothing beyond main, FindingsP3-1: no test reaches HI on with OASDI room left, and mutant M9 survives there.
- name: With HI on and part of the draw in the OASDI room, the whole gross draw is in line 5
period: 2027
absolute_error_margin: 0.02
reforms: policyengine_us.reforms.ssa.owners_draw.owners_draw
input:
gov.contrib.ssa.owners_draw.current_law_cap: 200_000
gov.contrib.ssa.owners_draw.in_effect: true
gov.contrib.ssa.owners_draw.phase_in_share: 1
gov.contrib.ssa.owners_draw.include_hi: true
gov.irs.payroll.social_security.cap: 200_000
gov.simulation.aime_lookback_years: 0
payroll_tax_gross_wages: 150_000
self_employment_income: 40_000
s_corp_income: 64_970.22
output:
# Room 200,000 - 150,000 - 36,940 = 13,060 of the draw's 59,999.998.
owners_draw_oasdi_base: 13_060
owners_draw_hi_tax: 1_740
owners_draw_niit_exclusion: 64_970.22
# (4,580.56 + 1,071.26 + 1,619.44 + 1,740.00) / 2 = 4,505.63.
self_employment_tax_ald_person: 4_505.63
# Line 5: 104,970.22; line 6: 0.3810605; 40,000 - 1,716.92 = 38,283.08.
# Counting only the OASDI-taxed 14,141.85 would give 36,671.24; main 35,494.37.
self_employed_health_insurance_earned_income_limit: 38_283.08P3-2: three small wording slips in the body and one YAML comment.
r2 findings at this head
Checked and sound
What I couldn't check
Generated by Claude Code |
The round 3 review's witness: with HI on, line 5 holds the whole gross draw even when 13,060 of OASDI room remains. A mutant that counts only the OASDI-taxed part passed every earlier test and fails this one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
US + core hub merge audit, us#10571 at
|
#10571, now merged from main, reworded owners_draw.md to say the OASDI base is divided by the net-earnings factor (q by default), because an explicit net_earnings_factor overrides q. The history page still said draw_oasdi_base / q, and never defines q. Use the same wording there. The shared kernel divides by the net_earnings_factor stage, which takes the override. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main moved 59 commits past the branch. Three files changed on both sides and merged without a conflict. owners_draw.py keeps #10571's self_employed_health_insurance_earned_income_limit override in reform.apply. That override reads owners_draw_niit_exclusion, which this branch now computes through the shared kernel, and the kernel takes the same disabled, HI-on and OASDI-only branches as main's formula. The owners' draw docs keep #10571's line 5 section next to this branch's annual-history text. The differential test keeps main's leaf-level classification and adds gov.contrib.ssa.history to NEW_PARAMETER_NODES. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#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>
#10571 added the SECA-taxed draw profits to the profits that the SEHI limit splits Schedule 1 line 15 over, but the plan's earned income still split line 15 over Schedule C, farm and partnership profits only, so under the reform the Schedule C plan business took the draw's deductible SECA as well (40,000 Schedule C with a 60,000 net-earnings draw: 33,454.09 instead of 37,505.61). Step 3 is now a module-level helper that takes extra line 5 profits, and the reform overrides self_employed_pension_earned_income to pass the same draw term the SEHI override uses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…10560) * Add annual earnings histories and conventional Social Security AIME Add explicit complete-history inputs, annual cap/indexing ledger and claim-year freeze, reusing the supplied-record PIA/payment pipeline. Share legacy-compatible indexing and highest-years helpers and add conventional, SSA-example and legacy differential tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Reuse owners draw arithmetic for annual history benefit credit Extract one staged per-year kernel shared by reform Variables and history records, preserving intermediate overrides and lazy parameter reads. Add adjusted draw before each ordinary benefit cap and retain tax-room and NIIT-exclusion diagnostics separately. Freeze the pre-extraction arithmetic in differential and property tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Compute annual mini PIAs and eligibility-cohort phase-in Apply the shared eligibility-year formula to annual indexed earnings divided by 12, select the highest 40 mini PIAs and divide by 37. Blend with conventional PIA using a neutral-by-default 2032–2036 parameter path, retaining exact rational intermediates until final dime truncation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add named annual donut tax and AIME-plus credit paths Keep separate fixed-threshold OACT 2025 variants and a configurable neutral custom path. Tax and optionally credit only the covered stream above max(ordinary cap, threshold), index and select its own highest 35 years, and add the eligibility-cohort AIME-plus component after the mini blend. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Expose annual earnings and PIA reconciliation ledgers Expose exact annual earnings, E1, donut, indexing and mini-PIA diagnostics through the household report. Preserve complete JSON sources through export, document archived OACT rules and modeling conventions, and isolate new engine/differential files on existing Rest runners. Add future-cohort, source-isolation, reporting and full SSA payment examples. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Verify exact reform composition and document annual history use Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Support early covered earnings in annual donut policy lookups Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Release owners draw accessors after annual evaluation Break the recursive local-function cycle after each selected-stage or complete annual calculation so Person accessors do not retain entire simulations until cyclic collection. Preserve all arithmetic and lazy dependency behavior; add three GC-disabled weakref regressions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Select history AIME computation years by eligibility cohort Cohorts first eligible before 1991 have fewer than 35 computation years under 42 U.S.C. 415(b)(2), so a fixed 35/420 understated their AIME (a 1990 witness gave $895 instead of $912). The ordinary history AIME now selects min(35, E - 1956) years and divides by that count times 12; AIME+ and the mini-PIA keep their own rules. The ledger JSON also names the donut credit coefficient and the year that selected it, the January diagnostic PIA's period, and the computation-year count the ordinary flags follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Document cohort computation years, conventions and source edition State the cohort selection rule and its 1990 witness, the combined dime rounding and cohort-selected donut coefficient conventions, Case B's dime floor of SSA's formula result, and that the E2.13/E2.14/B3.12 dates come from the 2025 Trustees Report edition. No parameter value changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge main into ss-household-calculator-4a2 Main shipped the public calculator source selectors and the COLA means test. Keep both import sets in engine.py, and take main's selector text in the calculator guide; this branch's "modes remain reserved" text is now false, so only the history-specific guidance survives. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Classify gov.contrib.ssa.history as calculator-only Main's namespace-classification check fails on any unlisted child of gov.contrib.ssa. Only the household calculator's history route reads this node (history_parameters_at via donut.py and mini_pia.py), so the reference model drops it and the differential can still catch a legacy formula that reads it by accident. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge main into ss-household-calculator-4a2 Brings the branch up to date with main (18 commits behind) before the 1984 benchmark fix round. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Start the annual history route at eligibility year 1984 42 U.S.C. 415(a)(4)(B)(i) keeps the December 1978 computation, when larger, for workers with pre-1979 earnings who become eligible before 1984. The history route computes only the wage-indexed 415(a)(1) formula, so it now refuses E = 1983 at computation_years, compute_history, history_pia_details and SuppliedRecord.benchmark (history source only; supplied AIME and PIA keep their 1983 start). The boundary case moves to E = 1984 (28 years, divisor 336), and the docs note that the route assumes no covered wages before 1951, which the 415(a)(4)(B)(ii) subsection (d) guarantee counts. Also names the 2025 Trustees Report edition beside two E2.13/E2.14 mentions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge main into ss-household-calculator-4a2 Main moved 59 commits past the branch. Three files changed on both sides and merged without a conflict. owners_draw.py keeps #10571's self_employed_health_insurance_earned_income_limit override in reform.apply. That override reads owners_draw_niit_exclusion, which this branch now computes through the shared kernel, and the kernel takes the same disabled, HI-on and OASDI-only branches as main's formula. The owners' draw docs keep #10571's line 5 section next to this branch's annual-history text. The differential test keeps main's leaf-level classification and adds gov.contrib.ssa.history to NEW_PARAMETER_NODES. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Give the 415(a)(4)(B)(i) reason at every pre-1984 history benchmark SuppliedRecord.benchmark ran the shared 1983 check before the history route's own 1984 check, so a history record at E = 1982 got "Computation benchmarks before 1983 are unsupported", which implies 1983 works. The history check now runs first, so calculate_year and the engine give the 415(a)(4)(B)(i) reason at E <= 1983, as computation_years, compute_history and history_pia_details already did. Supplied AIME, PIA and survivor records keep the shared 1983 start. The tests now pin both sides of this boundary at the main door: a January 1, 1922 birth attains 62 on December 31, 1983 and is refused, and a January 2 birth benchmarks at 1984, so changing the history check to <= fails. They also check that a supplied PIA, not only a supplied AIME, keeps 1983, and that annual records cannot begin before 1951, the limit the docs rely on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * State the 415(a)(4) and 415(d)(2) conditions in the history docs The paragraph on why the history route starts at 1984 said "before 1984" without (B)'s condition that the worker first becomes eligible after 1978, could be read as if (B)(ii) also stopped at 1984, and did not name the subsection. It also left out that 415(d)(2)(A) limits subsection (d) to a worker with a quarter of coverage before 1951, which is what makes the no-pre-1951-wages assumption sufficient. It now also states the route's other assumption: no disability-benefit eligibility before January 1979, the case 415(a)(4)(A) takes outside paragraph (1). Own retirement records have no prior-disability input. The wording follows the delta review's reading of the statute; the build session could not reach a copy of 42 U.S.C. 415 to recheck it. Also rewraps the 100-column donut-coefficient line. Only whitespace changes there, so the rendered page is the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge main into the Social Security earnings history route Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ealth insurance limit (#10120) * Limit the self-employed health insurance deduction to 401(c) earned income 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> * Test the self-employed health insurance earned income limit against Form 7206 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add Form 7206 property tests for the self-employed health insurance deduction Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Update SSTB and Ohio expectations for the 401(c) earned income limit Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Widen the self-employed health insurance limit to farm, partnership and 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> * Extend the Form 7206 properties to farm, partnership and S corporation plans Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add changelog fragment Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * State the property 5 floor without depending on the plan contribution limit Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Clarify the default plan business and the S corporation premium gate Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address review: name partnership and S corporation in YAML, document 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> * Merge main into the plan business branch after #10109 landed #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> * Allocate line 15 by each business's share, as main does 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> * Say where entity-paid premiums go and that every business kind is pooled 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> * Make the S corporation case a valid return and check the reference limit 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> * Merge remote-tracking branch 'origin/main' into pr-10120 * Carry the plan business choice into the owners' draw reform's SEHI limit #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> * Name the smaller-plan-business case in the plan business input's docs 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> * Merge main into sehi-plan-business-base Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Test long-term care premiums under every plan business 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> * Say the model taxes reimbursed long-term care premiums as payroll wages 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> * Tell partners where guaranteed payments go and cite Notice 2008-1 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>
With the owners' draw reform on, the self-employed health insurance earned income limit now counts in Form 7206 line 5 the draw profits whose SECA enters the deductible SE tax, so the plan business's share of that tax no longer absorbs the draw's SECA.
The interaction
self_employed_health_insurance_earned_income_limit(#10109) follows Form 7206 lines 4–13:total_self_employment_income);self_employment_tax_ald_personby that share.The owners' draw reform (#10483) overrides
self_employment_tax_ald_person, so with the reform on (andhalf_seca_deductionat its default, true), line 7 includes the draw's SECA. Line 5 left out the draw's profits, so the Schedule C business took too large a share of that tax and the limit fell.Hand check
Single filer, 2027, synthetic $200,000 caps:
The change
policyengine_us/reforms/ssa/owners_draw.pyinstalls an override of the limit variable:where(half_seca_deduction, owners_draw_niit_exclusion, 0)to line 5.The reform computes
owners_draw_niit_exclusion, its "gross owners' profits subject to SECA", asowners_draw_oasdi_basedivided by the net-earnings factor (q by default) with HI off, and as the wholeowners_draw_grosswithinclude_hion. Line 5 counts only these, and only whenhalf_seca_deductionputs their SECA intoself_employment_tax_ald_person(line 7). An earlier head of this PR added the wholeowners_draw_gross, which raised the limit above main in three setups where line 7 holds none or only part of the draw's SECA:half_seca_deduction: falseForm 7206 line 5 counts the net profit of every business subject to SE tax, and a real business above the wage base counts all of its profit. The draw becomes SE income only through this reform, so we chose to count in line 5 the part of it whose SECA line 7 carries. Line 6 then splits the deductible tax at matching rates per dollar of profit: with HI on and no OASDI room, the limit equals line 4 less Schedule C's own deductible tax (39,464.37).
We don't change the baseline variable file.
Line 5 sums net profits before the 0.9235 net-earnings factor, so the override counts gross profits, not net earnings: line 4's Schedule C profit and the K-1 partnership SE amount both come before the factor.
owners_draw_niit_exclusionholds a gross profit amount (the OASDI base divided back by q), andowners_draw_net_earningsholds gross × 0.9235, the Schedule SE line 4a analogue. Using net earnings would give share 0.4 and a limit of 37,381.64 in the hand check.We added a section on this override to
docs/contributed_reforms/owners_draw.md, after the cap-priority section.Invariants (tested with Hypothesis, plus explicit examples)
max(0, line4 − ALD × line4 / line5 − pension). The oracle derives line 5's draw term from the rule rather than from the reform's own variables: with HI on, the gross draw; with HI off,min(gross × q, room) / q, where q comes from the rates and room from the cap less taxable wages and existing capped SE earnings (or no limit withroom_cap_basis1); zero whenhalf_seca_deductionis off. The generated inputs vary the rates,include_hi,half_seca_deduction,room_cap_basis,phase_in_shareand the cap, with the hand case, the three setups above, HI on with the deduction off and $300,000 of wages, HI on with $300,000 of wages, HI on with $150,000 of wages, and a half phase-in with HI off as explicit examples.The earlier upper bounds (line 4 less line 8, and line 4 less the pension deduction) followed from the oracle's equality, so the tests drop them.
The invariant "never exceeds line 4 less the plan business's own deductible SE tax" fails under Form 7206's pro-rata rule. In the hand check, the Schedule C business's own deductible SE tax comes to 2,825.91, which puts that bound at 37,174.09, while the limit reaches 37,505.61. Line 6 allocates the total deductible tax by profit share. The draw bears 12.4% × 0.9235 per dollar of profit, against Schedule C's 15.3% × 0.9235, so its profit share exceeds its tax share. The tests use the line 6 share instead.
Readers of the deductible SE tax or SE profit shares
self_employed_health_insurance_earned_income_limitqualified_business_income(QBID)self_employment_tax_ald_person(viaqbi.deduction_definition) across SSTB and non-SSTB QBI;qbi.income_definitionincludespartnership_s_corp_incomeself_employed_pension_contribution_ald_person(SEP/pension)eitc_earned_incomeca_eitc_earned_incomeira_compensationstandard_deduction_worksheet_earned_income_personnd_mpcmn_marriage_creditsc_gross_earned_income(two-wage-earner credit)earned_income(wages, Schedule C) − subtractions including SE tax ALDself_employment_tax_ald, the ALD lists,dependent_taxable_ss_magi, student-loan MAGI, MO AGI, IA adjustments, MI/MA/AL listssocial_security.addOther overrides in the reform:
self_employment_social_security_taxandself_employment_medicare_taxadd the draw's own taxes.ss_aimeadds credited draw earnings.Neither applies an SE profit share. We leave the earned-income readers marked "same kind" for a follow-up. Treating the draw's net earnings as SE earnings under those definitions takes a larger policy decision than this fix.
Tests
policyengine_us/tests/policy/contrib/ssa/owners_draw_self_employed_health_insurance_earned_income_limit.yaml: 11 cases. They are the hand check, premiums above the old limit, no draw, no Schedule C, the three setups in the table above, and four more:owners_draw_niit_exclusion64,970.22, line 7 1,405.63, limit 39,464.37 (main 38,594.37).owners_draw_niit_exclusion64,970.22, line 7 1,716.92, limit 38,283.08 (counting only the OASDI-taxed 14,141.85 of draw would give 36,671.24; main 35,494.37).phase_in_share0.5 with HI off: gross draw 32,485.11, OASDI base 30,000, line 7 4,685.91, limit 37,414.14 (main 35,314.09; the whole S-corp profit in line 5 would give 38,214.38).policyengine_us/tests/reforms/test_owners_draw.py:@examplefor each YAML case with both a draw and a Schedule C business. Those cases include three with HI on (the deduction off, no OASDI room, and some OASDI room) and a half phase-in with HI off.BASELINE_VARIABLESincludes the baseline limit, so the existing disabled-equality tests, including the generated real-Simulation one, also compare it.bed691b7ff, run in its own process.policyengine_us/tests/code_health/test_source_conflicts.py: 103 passed.Mutants on the line 5 draw term at
owners_draw.py:304-305, each in its own process, with the code restored after each:test_owners_draw.py -k "sehi or disabled"(5 tests)half_seca_deduction | include_hitest_generated_sehi_limit_counts_seca_taxed_draw_in_line_5faileds_corp_incomein place of the draw terminclude_hiin place ofhalf_seca_deductionThe tests killed the round-1 mutants (ignore the gate, whole
owners_draw_gross) at an earlier head, and the code they mutate hasn't changed.Overlap
self_employed_health_insurance_earned_income_limitformula. This PR copies that formula into the reform's override, so whichever lands second must carry the change into the copy.policyengine_us/reforms/ssa/owners_draw.pyand editsdocs/contributed_reforms/owners_draw.md.impact: none at baseline.
create_structural_reforms_from_parameterscallscreate_owners_draw_reform(reforms.py:372), which returns the reform only when somegov.contrib.ssa.owners_draw.in_effectvalue is true and otherwiseNone, whichreforms.py:754filters out;in_effectdefaults to false.axiom: n/a: contributed reform
CI: Pull request run 41537180716 at
bed691b7ffcompleted with conclusion success (35/35 jobs succeeded; Documentation run 41537180467 also succeeded).🤖 Generated with Claude Code