Skip to content

Measure benefit-taxation revenue as chapter 1 liability - #10566

Merged
MaxGhenis merged 9 commits into
mainfrom
tob-chapter-1-liability
Nov 1, 2026
Merged

MaxGhenis merged 9 commits into
mainfrom
tob-chapter-1-liability

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Social Security benefit-taxation transfers currently difference income_tax, so they include benefit-triggered NIIT and changes in refundable-credit payments. This changes all three TOB outputs to difference a new income_tax_chapter_1 measure: chapter 1 tax after nonrefundable credits, before refundable credits.

The 42 U.S.C. 401 note, P.L. 98-21 §121(e)(1), as amended appropriates the “aggregate increase in tax liabilities under chapter 1.” Section 1411 imposes NIIT in chapter 2A. Unreported payroll tax is chapter 21 FICA. Both are excluded. Investment-credit recapture (§50(a)) and the retirement penalty (§72(t)) remain chapter 1 components. The new variable honors the federal-income-tax abolition switch. Existing income_tax and income_tax_before_refundable_credits are unchanged.

Refundable credits are measured as payments against liability, not reductions of that liability: 26 U.S.C. 6401(b) applies subpart C credits against tax after nonrefundable credits and treats excess as an overpayment; subpart C also contains withholding. IRM 21.6.3.2(2) agrees with that payment treatment. Treasury’s published 1998 and 2024 reports describe the with/without comparison but do not define tax liability or its refundable-credit treatment. This implements the chapter 1 and refundable-credit rulings; it is not a claim about an unpublished Treasury calculation.

Only the measured variable changes in TOB formulas. Signed unit allocations and branch cleanup are preserved; HI remains total minus OASDI. The premium tax credit remains outside the measure, as it already is outside income_tax.

Hand-calculated witnesses

2026 single filer, age 70, Texas, $40,000 benefits and $190,000 taxable interest:

State Inclusion AGI Taxable income Chapter 1 tax NIIT
None $0 $190,000 $171,850 $33,842 $0
Pre-1993 $20,000 $210,000 $191,850 $38,642 $380
Current $34,000 $224,000 $205,850 $42,328 $912

The deduction is $16,100 + $2,050 = $18,150; the separate senior deduction is fully phased out. Tax through $105,700 is $12,400×10% + $38,000×12% + $55,300×22% = $17,966. None/pre tax adds 24% of income above $105,700. Current tax is $17,966 + $96,075×24% + $4,075×32% = $42,328. NIIT is 3.8% of MAGI above $200,000 here. Refundable credits are zero.

Measure OASDI HI Total
Before $5,180 $4,218 $9,398
After $4,800 $3,686 $8,486
Removed NIIT $380 $532 $912

On the main base used here (2.88.9), the after values agree with the independent 2.61.0 recomputation. Existing $769/$252/$1,021 (2026) and −$17.50/−$12.25/−$29.75 (2024 itemizer) witness inputs and expectations are unchanged. CI run 41316271650 ran those YAML witnesses and passed them at this head. The generated test also exercises the exact negative-itemizer inputs and independent identities, without hardcoding its expected dollar amounts.

Two invented 2024 disabled-worker families pin the refundable-credit ruling:

  • HOH, wages $35,000, benefits $20,000, one child age 17. Zero/pre/current inclusions are $0/$10,000/$13,850. Tax before credits is $1,310/$2,441/$2,903; after the $500 other-dependent credit, chapter 1 liability is $810/$1,941/$2,403. EITC is $4,213 − 15.98%×max(AGI−$22,720,0): $2,250.656/$652.656/$37.426. Total is $2,403−$810 = $1,593; the former income_tax differential is $1,593 + $2,213.23 = $3,806.23.
  • HOH, wages $20,000, benefits $20,000, tax-exempt interest $12,000, one child age 8. Provisional income is $42,000; inclusions are $0/$8,500/$11,300. Tax before credits is $0/$660/$940, all offset by nonrefundable CTC. ACTC falls $1,700/$1,340/$1,060. EITC is zero because investment income exceeds $11,600. Chapter 1 TOB is zero; the former income_tax differential is $640 ($360 OASDI/$280 HI).

Old-law inclusion capped at actual inclusion (reform scoring)

tob_revenue_oasdi taxed the full pre-1993 amount in its old-law branch, whatever a reform did to current inclusion. When a reform cut a unit's inclusion below that amount, OASDI got credit for inclusion the unit never reached. Under a repeal the total came to $0, OASDI positive and HI the same amount negative. Ruling us:tob-oasdi-old-law-bound caps it: the old-law branch now taxes min(pre-1993 amount, actual inclusion). The formula reads actual inclusion from the outer simulation before it creates any branch. tax_unit_taxable_social_security_pre_1993 stays the plain historical counterfactual. tob_revenue_total and HI's total-minus-OASDI identity don't change, and both shares stay signed, with no per-unit floor (us:tob-oasdi-hi-signed-allocation).

At current law the cap changes nothing. Both laws use the same base amounts and the same first tier, and current law only adds inclusion above that tier, so the pre-1993 amount never exceeds actual inclusion. The generated property test now asserts this with no tolerance, and its independent pre-1993 differentials still match OASDI. No existing witness input or expected value changes, and CI passes all of them at this head, including $769/$252/$1,021, −$17.50/−$12.25/−$29.75 and the chapter 1 witnesses.

test_reforms_cap_old_law_inclusion_at_actual_inclusion, in test_tob_revenue.py, scores three reforms for the 2026 single retiree behind the $769/$252/$1,021 witness ($20,000 benefits, $30,000 interest, a $7,500 pre-1993 amount):

Reform Inclusion OASDI HI Total OASDI / HI without the cap
Repeal: all five section 86 rates at zero $0 $0 $0 $0 $769 / −$769
Base $30,000, adjusted base $44,000 $5,000 $500 $0 $500 $769 / −$269
85% of benefits in provisional income $15,550 $769 $966 $1,735 $769 / $966

Under the raised thresholds, $40,000 of provisional income stays in the first tier: min($10,000, 50% × $10,000) = $5,000. Taxable income is $35,000 − $24,150 = $10,850, so tax is $1,085 against $585 with no inclusion. OASDI and the total are both $500, and HI is $0.

The three cases ran as a YAML file, tob_old_law_bound.yaml, until this round. CI run 41277496089 at f21fd89 passed every job with them. Core's YAML runner builds a cloned tax-benefit system for each distinct set of parameter inputs and keeps it until the process ends, so that file held three reform systems. On run 41270134195 it peaked at 8,244 MB alone, above the batch runner's 8,000 MB budget per process. On run 41277496089 its batch process peaked at 13,540 MB, against 7,954 MB for the other three batch 1 files on the main-base run 41228874440. The runner stopped batch 2 for memory and reran it alone, and the ssa-usda job took 32.2 minutes against 19.0.

The Python test runs the same three cases in turn on the same retiree situation and one private copy of the shared system's policy, which owns its parameter nodes and lists and borrows their dated entries. Before each case it restores all eight parameter leaves that any case reforms, applies the case's inputs with the set_parameter modifier the YAML runner uses (over year:2000:40), clears the parameter caches and builds a new simulation. It asserts the same six outputs at the same values to the same cent, and checks that the simulation reads each reformed value and current law for the other leaves. It never writes to the shared default system, and a finally block asserts that system's eight leaves unchanged, after a failure too. It doesn't supply taxable benefits as inputs, so each case still runs its literal reform through the section 86 formula.

Cost: run alone in one process under the required 4 GB and 1,800-second caps, at host load 55 to 70, the test passed. Its call took 1,334.6 seconds of wall time, the whole process used 171 seconds of user CPU, and the process peaked at 3.53 GiB (3,793,649,664 bytes of maximum resident set). That local process imported the country with automatic garbage collection paused and then froze the imported objects; the test itself doesn't. A first version cloned the whole system, and with the TOB branches' own clones the 4 GB cap killed that run, so the test now copies the nodes instead. On CI run 41316271650 at 1cf200d, which passed, the test took 165.2 seconds in Rest Python shard 6's policy group. That group's process ran 26 files, peaking at 11,486,580 kB over 19:21. On round 1's run 41277496089, the policy group that ran this file (shard 7, 25 files) peaked at 11,873,100 kB over 13:54. The added time is this test and #10563's test_oasdi_accounting.py (157.6 seconds), which main added to the group.

The ssa-usda job took 34.3 minutes, against 32.2 in round 1. Its revenue step took 15.7 minutes, against 18.1 in round 1 and 7.4 at the main base. The runner still stopped revenue batch 1 (the two employer files, the pre-1993 file and the HI file) for memory and reran it alone, where it peaked at 11,373 MB. At the main base those four files ran in two processes, at 7,954 and 5,364 MB. Its other SSA step grew from 2.7 to 6.9 minutes, because main added #10563's ssa/oasdi YAML, a 307-second batch that peaked at 8,994 MB.

Mutant: without the cap, the repeal case gives OASDI $769 and HI −$769, and the threshold-rise case $769 and −$269, against expected $0/$0 and $500/$0. The build's own mutant run never reached an assertion. The round 1 review killed the mutant on isolated Core with the exact formula bodies, so the claim rests on that run and the hand values above.

Invariants and CI cost

The existing Hypothesis file checks:

  1. OASDI + HI = total, with signed allocation.
  2. Independent simulations with taxable benefits supplied at zero/pre-1993/current: total and OASDI equal the corresponding chapter 1 differences to $0.01. The oracle uses no branches.
  3. TOB equals the pre-refundable-tax differential minus the NIIT differential; equivalently, the old income_tax differential minus NIIT plus the refundable-credit differential.
  4. Arbitrary unreported-payroll-tax inputs leave all three TOB outputs unchanged.
  5. With abolition off, chapter 1 tax equals pre-refundable tax minus NIIT minus unreported payroll tax.
  6. At current law the pre-1993 amount never exceeds actual inclusion, with no tolerance, so the OASDI cap changes nothing.

The reform test checks two more by example:

  1. A reform that leaves inclusion at or below the pre-1993 amount gives HI exactly $0 and OASDI the whole total. A repeal gives $0 for all three.
  2. A reform that raises inclusion leaves OASDI at its pre-1993 value and gives HI the rest. OASDI + HI = total in every case.

Generated batches retain the existing signed/cache witnesses and add elderly single/joint NIIT threshold crossings, below-threshold controls and beneficiaries with children and earnings in EITC/ACTC ranges. Fresh simulations share unchanged policy while keeping independent populations, holders and caches. Secondary algebraic differential checks use zero-payroll partners to avoid float32 cancellation; the independent chapter 1 oracle, component identity and payroll invariance cover every unit. Python coverage is needed for independent simulation and cache/input invariants; policy examples use YAML, except the three reform cases, which run in Python on one private policy system rather than three cached ones. The file remains in the existing Rest Python policy CI group; no runners or concurrency are added.

At the exact main base 10c7f5a93d472ed05247e4cfae729133112f6b16, the successful CI timing artifact reports 75.508 seconds for the generated test and 73.603 seconds for cache/order isolation: 149.111 seconds total. These are JUnit test times within a shared 25-file process, excluding shared startup/collection/shutdown. At this head, run 41316271650 reports 81.660 and 85.417 seconds for the same two tests (167.077 seconds total) and 165.172 seconds for the moved cap test, in Rest Python shard 6. None of these CI figures compares directly with isolated local process wall times.

CI runs every file. Pull request run 41316271650 passed at this head, every YAML case and Python test included. Local runs under a 4 GB and 1,800-second cap covered only part of the set, so CI is the complete check.

Readers and overlap

The reader audit found no current downstream formula requiring an update beyond HI’s total-minus-OASDI identity. Existing revenue YAML, property tests, IRA branch-isolation tests and stored-column preflight readers do not rely on the old measure. Every case in #10563's OASDI accounting YAML that reads a TOB output keeps its value under chapter 1: the units with benefits owe no NIIT and get no refundable credit, and the rest have no benefits. The preflight now also rejects a stored income_tax_chapter_1, which every TOB branch would keep as an input, freezing each measured tax state and zeroing TOB. None of the five stored-input inventories pinned in Microcosm's fixture (377, 385, 380, 397 and 418 columns) holds it. S.770 documentation combines its separate sources with TOB without defining TOB as including NIIT.

The two employer_*_tax_income_tax_revenue variables are unchanged. They difference income_tax (including NIIT and refundable-credit effects), with a zero floor when the reform is active. Their documentation calls this marginal income-tax revenue from including employer payroll contributions, credited to OASDI/HI; neither has a legal reference or chapter-specific definition. Follow-up scope is left to the hub.

Overlap: open #10561 (chunked-microsimulation-calculate), inspected at 5da5df7893f9e3c69f5a71ee2d5c41a72da5d349, restructures the same total/OASDI formula lines. This PR is based only on main and copies none of that change. The later merge must carry the chapter 1 measure into its counterfactual helpers and current-law read. #10563 merged first, so this PR merges main and corrects #10563's text for the chapter 1 measure: the usage guide's share definition and NIIT section, and the oasdi_income and oasdi_benefit_taxation_revenue documentation, which now also state the actual-inclusion cap.

Hub microsimulation impact

The certified default dataset ran through calculate_chunked in 8 chunks, with these formulas against main at 10c7f5a93d. #10486 and #10563 landed after that base and change none of these outputs at current law.

$B 2026 base 2026 head Change 2035 base 2035 head Change
tob_revenue_oasdi 64.926 63.222 −1.705 (−2.6%) 115.999 113.002 −2.997 (−2.6%)
tob_revenue_medicare_hi 47.007 46.006 −1.001 (−2.1%) 84.695 82.896 −1.798 (−2.1%)
tob_revenue_total 111.934 109.227 −2.706 (−2.4%) 200.694 195.898 −4.796 (−2.4%)

oasdi_income and oasdi_modeled_balance read tob_revenue_oasdi, so they fall by its change. The two-year pair doesn't split the fall between NIIT and refundable credits.

axiom: queued rulespec-us#415 (blocked: corpus re-pin, axiom-rules-engine#58, encoder dispatch). That issue’s encoding model already defines the three liabilities as chapter 1 liabilities; this change moves PE-US toward it.

impact: TOB outputs fall 2.4% (2026: OASDI -$1.70B, HI -$1.00B, total -$2.71B; 2035: -$3.00B, -$1.80B, -$4.80B); OASDI accounting outputs follow; nothing else moves

🤖 Generated with Claude Code

@MaxGhenis
MaxGhenis marked this pull request as ready for review November 1, 2026 02:46
MaxGhenis and others added 2 commits October 31, 2026 23:39
tob_revenue_oasdi taxed the pre-1993 section 86 amount in its old-law
branch whatever a reform did to current inclusion. A reform that cut
inclusion below that amount credited OASDI with inclusion the unit never
reached: under repeal the total was $0, OASDI positive and HI the same
amount negative.

The old-law branch now taxes min(pre-1993 amount, actual inclusion),
read from the outer simulation before any branch exists. At current law
the cap changes nothing, because both laws share the first tier. HI
stays total minus OASDI, with signed shares and no per-unit floor.

Reform scoring cases in tob_old_law_bound.yaml cover repeal, raised
thresholds and higher inclusion. The generated property test now
requires pre-1993 inclusion never to exceed actual inclusion at current
law, with no tolerance.

Ruling: us:tob-oasdi-old-law-bound.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The witness gives no state, so the header no longer says Texas. Say
"counterfactual" where "state" meant the inclusion scenario.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit to PolicyEngine/crfb-tob-impacts that referenced this pull request Nov 1, 2026
PolicyEngine/policyengine-us#10566 makes `income_tax_chapter_1` the input
that freezes the tax states the TOB variables compare, so a stored value
gives zero TOB and raises nothing. The derived-variable guard now names
it, and a test covers every name on that list, which nothing did before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 4 commits November 1, 2026 07:29
Brings in #10563, whose OASDI accounting text this branch's chapter 1
measure makes stale.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The three reform cases in tob_old_law_bound.yaml made Core's YAML runner
build and keep a cloned policy system for each parameter override set.
In CI that file alone peaked at 8,244 MB, above the batch runner's
8,000 MB budget, and took its batch process to 13,540 MB.

One Python test now runs the same three cases in turn on a single clone
of the shared system and the same retiree situation. Before each case it
restores all eight reformed leaves, applies the case's parameter inputs
with the modifier the YAML runner uses, clears the parameter caches and
builds a new simulation, then asserts the same six outputs to a cent.
The shared system's leaves are checked unchanged in a finally block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#10563 described tob_revenue_oasdi as differencing income_tax, so the
benefit-taxation term carried benefit-triggered NIIT and overlapped the
S.770 NIIT transfer. The TOB outputs now difference income_tax_chapter_1,
which leaves NIIT out, so that overlap no longer exists. State the
actual-inclusion cap wherever the text defines the pre-1993 share, and
list the chapter 1 tax among the columns the preflight rejects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The TOB outputs difference income_tax_chapter_1. A stored value is an
input that every counterfactual branch keeps, so it freezes each
measured tax state and zeroes TOB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A full clone rebuilds every dated parameter entry. Together with the TOB
branches' own clones, that took the test's process past a 4 GB cap
locally. Copy the nodes and each leaf's list with copy_parameter_nodes,
borrowing the entries, which Parameter.update replaces rather than
edits; the process then peaked at 3.53 GiB. The shared system's tree is
still never written, and the test checks that each copied leaf holds its
own list.

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

Copy link
Copy Markdown
Contributor Author

US + core hub merge audit, us#10566 at 1cf200db906aee4cfe7c7d63e982656135da7b4f (squash): measure benefit-taxation revenue as chapter 1 liability.

  • Reviews: GPT-6.1 Sol on a Subfleet hard-tier lane approved round 1 at f21fd89a64 and the delta at this head. In round 1 Sol checked the chapter 1 boundary against the appropriation note and section 1411. At this head Sol replayed the moved test's 18 assertions in reverse order and reproduced every unchanged fixture by hand. An isolated real-Core mutant that removes the actual-inclusion cap fails the repeal and raised-threshold cases, and the higher-fraction case serves as the nonbinding control.
  • Gates checked live at merge:
    • gh pr checks exits 0;
    • the latest Pull request run at the head (41316271650) concluded success;
    • MERGEABLE;
    • not a draft;
    • no reviewer's latest review requests changes;
    • head pinned.
  • Methodology: Sol marks a methodology choice. The PR body discloses the chapter 1 boundary and the refundable-credit ruling. Sol also found completeness limits in the existing chapter 1 chain (sections 38 and 53 credits, the AMT foreign tax credit, Form 4972 tax). They predate this PR, and the hub logged them as a follow-up.
  • Impact: a hub pair on the certified dataset, in 8 chunks, compared base 10c7f5a93d with head e0e49ca3ea. No tax formula changed from that head to this one. TOB outputs fall 2.4% (2026: OASDI -$1.70B, HI -$1.00B, total -$2.71B; 2035: -$3.00B, -$1.80B, -$4.80B), and the OASDI accounting outputs follow. The pair doesn't split NIIT from refundable credits.
  • Axiom: queued, rulespec-us#415, with the blockers in the PR's axiom: line. The hub adds the cap's witnesses to that issue after merge.

@MaxGhenis
MaxGhenis deleted the tob-chapter-1-liability branch November 1, 2026 16:20
MaxGhenis pushed a commit that referenced this pull request Nov 2, 2026
#10566 changed main's TOB formulas to difference income_tax_chapter_1 and
to cap old-law inclusion at actual inclusion. This branch had moved those
formulas onto cached counterfactual helpers, so taking either side of the
conflict would have dropped one change.

The shared branch helper now measures income_tax_chapter_1, the total
measures current-state chapter 1 liability, and the old-law helper forms
min(pre-1993 inclusion, actual inclusion) in the outer simulation before
any branch exists. The mixin prepares old-law before no-benefits so the
bound is read before either counterfactual. Main's TOB documentation and
references are kept, and the sequencing and lifecycle oracles follow the
new measure and order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Nov 3, 2026
Add policyengine_us.tools.calculate_chunked. It splits a population into household chunks, runs a factory-built simulation on each chunk in turn, and returns source-order entity results and weighted totals, so full-population taxation-of-benefits runs fit in memory. It reads US entity-table datasets and variable-centric .h5 files. It keeps each tax unit, SPM unit, family and marital unit inside one household's chunk, and rejects the four formulas that reduce across the whole simulation.

Carry #10566: TOB measures chapter 1 liability (income_tax_chapter_1), caps old-law inclusion at actual inclusion, and computes the two counterfactual states once, in the outer simulation, before any branch exists. The signed allocation matches main's.

The tests compare chunked and unchunked results on a 32-household fixture and on the same households as a variable-centric file. They check the guard on direct, dependency, branch, baseline and cross-period routes, and compare TOB sequencing with main's reference algorithm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant