Skip to content

QBID: add SSTB income variable and per-category computation per IRC §199A #7939

@PavelMakarchuk

Description

@PavelMakarchuk

Summary

PE currently computes QBID with a single qualified_business_income per person and a single business_is_sstb boolean flag. IRC §199A and Form 8995-A require per-business QBID computation with separate SSTB classification, W-2 wages, and UBIA for each business.

This causes two problems:

  1. pprofinc/sprofinc (SSTB income) can't be mapped from TAXSIM — currently treated as zero
  2. Mixed SSTB/non-SSTB filers get wrong QBID — the all-or-nothing business_is_sstb flag forces all QBI into one treatment

Legal Basis

IRC §199A(b)(2): QBID is the lesser of 20% of QBI or the W-2/UBIA cap, computed for each qualified trade or business.

IRC §199A(d)(2)-(3): SSTB income is fully excluded from QBID above the threshold ($197,300 single / $394,600 joint for 2025). In the phaseout range, only an "applicable percentage" of SSTB QBI counts.

Form 8995-A: Columns A, B, C — each business has separate QBI (line 2), W-2 wages (line 4), UBIA (line 7), and SSTB checkbox (line 1b). Per-business caps are computed in Part II, then summed on line 16.

Form 8995 (simplified, below threshold): No SSTB distinction needed — all QBI treated the same. Works fine with current PE model.

The distinction matters above the threshold:

  • SSTB business: QBID phases to $0 (QBI itself reduced by applicable percentage)
  • Non-SSTB business: QBID = min(20% QBI, W-2/UBIA cap) — can be non-zero with sufficient wages/property

Current PE Implementation

qualified_business_income (person) — single aggregated amount
business_is_sstb (person) — single boolean, all-or-nothing
w2_wages_from_qualified_business (person) — single aggregated amount
qbid_amount (person) — single computation

A doctor (SSTB) who also owns a rental property (non-SSTB) can't be modeled correctly — setting business_is_sstb = True would phase out the rental QBID too.

Proposed Change

Add a second QBI category for SSTB income, keeping the current variable for non-SSTB:

New variables

  • sstb_self_employment_income (Person) — self-employment income from specified service trades or businesses. Subject to SECA. Gets SSTB phaseout treatment for QBID.

Modified variables

  • qualified_business_income — exclude SSTB self-employment income (only non-SSTB sources)
  • qbid_amount — compute two QBID components:
    • Non-SSTB: 20% of non-SSTB QBI, subject to W-2/UBIA cap above threshold
    • SSTB: 20% of SSTB QBI × applicable percentage (phases to $0 above threshold)
    • Return sum of both

TAXSIM alignment

Once implemented, policyengine-taxsim can map:

TAXSIM Input PE Variable SECA QBID Treatment
psemp self_employment_income Yes Non-SSTB
pprofinc sstb_self_employment_income (new) Yes SSTB (phaseout)
pbusinc partnership_s_corp_income (reroute) No Non-SSTB
scorp partnership_s_corp_income No Non-SSTB

Integration Tests

# Below threshold — SSTB distinction doesn't matter
- name: qbid_below_threshold_sstb_gets_full_deduction
  absolute_error_margin: 1
  period: 2025
  input:
    people:
      person1:
        sstb_self_employment_income: 100_000
        is_tax_unit_head: true
    tax_units:
      tax_unit:
        members: [person1]
    families:
      family:
        members: [person1]
    spm_units:
      spm_unit:
        members: [person1]
    households:
      household:
        members: [person1]
        state_fips: 6
  output:
    qualified_business_income_deduction: 20_000

# Above threshold — SSTB gets $0, non-SSTB gets W-2 capped amount
- name: qbid_above_threshold_mixed_sstb_and_non_sstb
  absolute_error_margin: 1
  period: 2025
  input:
    people:
      person1:
        employment_income: 400_000
        self_employment_income: 50_000
        sstb_self_employment_income: 50_000
        w2_wages_from_qualified_business: 100_000
        is_tax_unit_head: true
    tax_units:
      tax_unit:
        members: [person1]
    families:
      family:
        members: [person1]
    spm_units:
      spm_unit:
        members: [person1]
    households:
      household:
        members: [person1]
        state_fips: 6
  output:
    # Non-SSTB: min(20% × $50K, 50% × $100K) = min($10K, $50K) = $10K
    # SSTB: $0 (fully above threshold)
    # Total: $10K (subject to taxable income cap)
    qualified_business_income_deduction: 10_000

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions