Skip to content

Disregard the gross income test for surviving spouse filing status (IRC 2(a)(1)(B)) - #10273

Draft
MaxGhenis wants to merge 3 commits into
mainfrom
surviving-spouse-gross-income-test
Draft

MaxGhenis wants to merge 3 commits into
mainfrom
surviving-spouse-gross-income-test

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

WIP (draft). The microsimulation impact on the default dataset is queued behind free disk on the shared host. A re-review at this head follows.

The bug

surviving_spouse_eligible required tax_unit_child_dependents > 0. That sums is_child_dependent, which accepts a qualifying child, a permanently disabled dependent, or is_qualifying_relative_dependent. That last path applies the IRC 152(d)(1)(B) gross income test (dependent_gross_income < gov.irs.income.exemption.amount, $5,200 in 2025). So an adult child with gross income of $5,200 or more left a widowed parent filing as single.

The same rule also let any low-income dependent qualify the filer, including a parent, a grandparent or an unrelated household member.

The law

26 U.S.C. 2(a)(1)(B) defines the qualifying dependent as one "who (within the meaning of section 152, determined without regard to subsections (b)(1), (b)(2), and (d)(1)(B) thereof) is a son, stepson, daughter, or stepdaughter of the taxpayer".

The 2025 Form 1040 instructions, page 15 (Qualifying Surviving Spouse, item 2) apply it as a child or stepchild (not a foster child) "whom you can claim as a dependent or could claim as a dependent except that, for 2025: a. The child had gross income of $5,200 or more, b. The child filed a joint return, or c. You could be claimed as a dependent on someone else's return."

Clause (ii) ("with respect to whom the taxpayer is entitled to a deduction ... under section 151") does not bring the gross income test back. The REG-137604-07 preamble (I.R.B. 2017-7) says a literal reading "would override the intent of the statutory change in section 2(a)(1)(B)(i)". The proposed regulations treat an individual as a dependent for section 2(a) "if the taxpayer may claim a deduction under section 151 for the individual without applying sections 152(b)(1), (b)(2), and (d)(1)(B)". That regulation is proposed, not final; the current instructions apply the same reading.

The fix

surviving_spouse_eligible now has its own dependency test.

Dependency. Any tax unit dependent counts. With the 152(d)(1)(B) test gone, the three paths of is_child_dependent (qualifying child, disabled dependent, qualifying relative) together cover every tax unit dependent. The model checks neither 152(b)(1) nor 152(b)(2), so disregarding them changes nothing.

Relationship (son, stepson, daughter, stepdaughter). The model represents relationship with parent_1_id / parent_2_id, which name natural, adoptive and step parents. A parent id of 0 means unknown, and two ids cannot list every step parent. So naming other parents never rules a dependent out on its own. Parents are resolved among household members and among tax unit members.

  • The head's child: either of the dependent's ids names the tax unit head.
  • Not the head's child, when the ids show another relationship to the head:
    • the head's parent or grandparent (the head's own ids name the dependent, directly or through a parent in any tax unit);
    • a sibling (the dependent and the head share a parent id, even when that parent lives elsewhere);
    • a grandchild (the dependent's parent names the head);
    • a niece or nephew (the dependent's parent shares a parent id with the head).
  • Otherwise: the dependent counts unless marked is_parent_of_filer_or_spouse, is_grandparent_of_filer_or_spouse, or not is_related_to_head_or_spouse.

tax_unit_child_dependents and is_child_dependent are unchanged. Vermont's EITC, New York's exemptions and Pell still read them.

Limitations.

  • Without parent ids that show the relationship, the model cannot tell a son or daughter from a sibling, niece, nephew or grandchild. It counts any unmarked dependent as a child, as main does.
  • Removing the income test widens that gap. A supported 29-year-old sibling or nephew with $30,000 of wages and no ids or relationship flag now gets surviving spouse status; on main they failed the income test.
  • Not modeled, before or after this PR:

The current default dataset (populace_us_2024, sha256 6496cc43…) has no parent_1_id / parent_2_id columns. It does populate is_related_to_head_or_spouse (0.51% of people false), so in microsimulation the flags decide every unit.

Before and after

New YAML cases, run against main's formula (f9b55fc4dd) and then this branch:

Case Main This PR
Widow, 29-year-old dependent with $6,238 wages (traced household) not eligible, SINGLE eligible, SURVIVING_SPOUSE, basic standard deduction $31,500
Same with $5,200 wages (exactly the exemption amount) not eligible eligible
Adult dependent whose first or second id names the head, $30,000 wages not eligible eligible
Adult dependent naming only the deceased parent (other id unknown), $30,000 wages not eligible eligible
Dependent parent (is_parent_of_filer_or_spouse), no income eligible, SURVIVING_SPOUSE not eligible, HEAD_OF_HOUSEHOLD
Dependent grandparent / unrelated dependent eligible not eligible
Dependent grandchild whose parent names the head eligible, SURVIVING_SPOUSE not eligible, HEAD_OF_HOUSEHOLD
Dependent nephew whose mother shares a parent id with the head eligible not eligible
Dependent sibling sharing a parent with the head (co-resident or absent) eligible not eligible
Dependent mother and grandmother named by the head's own ids, including through a mother in another tax unit eligible not eligible

surviving_spouse_eligible.yaml (27 cases), filing_status.yaml (18) and head_of_household_eligible.yaml (15) hold 60 cases. 16 fail on main and all 60 pass here.

The rest pass on both. They are the existing cases, plus guards that must stay eligible or not as on main:

  • income below the threshold;
  • a disabled adult child;
  • a parent plus a high-income child;
  • a remarried filer;
  • a filer who is not a surviving spouse;
  • the traced household's $6,238 of disability benefits;
  • a head's or housemate's own parent ids;
  • a stepchild naming both biological parents;
  • a widower's daughter naming only her co-resident mother.

The existing case "surviving spouse head with one dependent is eligible" set tax_unit_child_dependents: 1 as an input and gave the child no age. That bypassed the derivation, so the child now has age: 10 and the unused input is gone. It passes on main and here.

Review history

Independent GPT-6.1 Sol reviews. Both agreed that removing the gross income test is correct.

  1. bd9545e83e: REQUEST_CHANGES. That head switched to parent ids for a whole household whenever any member had one, so a child with unknown ids lost the status when the head or a housemate had an id. The axiom line was not queued. 6 of the 60 cases fail on that formula.

  2. 5661605b88: REQUEST_CHANGES. The reviewer confirmed the first findings fixed and Add NYC taxes to net income tree #1814 meeting the queued bar. Two problems remained:

    • That head treated a named other parent (a co-resident one, or two absent ones) as proof that the head is not a parent. A widower's daughter naming her mother, and a stepchild naming both biological parents, lost the status.
    • Ancestor links stopped at tax unit boundaries, so a grandmother linked through a mother filing separately qualified the head.

    4 of the 60 cases fail on that formula.

  3. This head excludes a dependent only on relationship evidence, as described above. All 19 setups in the reviewer's mixed-population probe now give the expected result, in both person orders.

Invariants

test_surviving_spouse_eligible_properties.py builds 1,876 grid units in one vectorized simulation: 2,308 tax units and 5,118 people, counting relatives who file separately. The grid crosses:

  • surviving spouse status;
  • marriage;
  • dependent age (10, 29, 88);
  • income (0, $3,000, $5,199, $5,200, $6,238, $50,000);
  • disability;
  • thirteen relationship setups, each labeled child or not child.

For every unit:

  1. Eligibility equals: surviving spouse head, not married, and a dependent the grid labels as the head's child. The labels are written from the setups, not from the formula.
  2. The dependent's income never changes eligibility. Units are grouped by everything but income.
  3. A dependent labeled not the head's child never makes the filer eligible.
  4. Eligible implies surviving spouse, not married, and a dependent in the unit.
  5. filing_status == SURVIVING_SPOUSE exactly when eligible, and never together with head_of_household_eligible.
  6. Differential against the previous rule, read from tax_unit_child_dependents: among child dependents, every unit main accepted stays eligible. The only units added are adult, non-disabled children with income at or above the exemption amount.

Failures by formula:

  • main: 4 of 6 (1, 2, 3, 6);
  • bd9545e83e: 2 (1, 6);
  • 5661605b88: 3 (1, 3, 6).

Why Python. The relationship examples are YAML cases. This test adds invariants that named YAML cases cannot state: income invariance across grouped units, a reference rule, and a differential against tax_unit_child_dependents, all over a mixed, vectorized population.

Cost. The test reuses the shared policyengine_us.system model. It runs in the test-other-python-rest-policy group, which on #10185's Linux CI run took 8:09 with 11,660,148 KiB peak RSS for 979 tests. Measured locally on macOS (Python 3.14t, not CI), with test_three_digit_zip_code.py (same group) in one process, two runs each:

  • peak memory footprint goes from 1.908 GB to 1.971 GB (+63 MB);
  • pytest time goes from 8.0 to 10.0 s (about +2 s);
  • the grid fixture takes about 1.6 s.

Interaction with #10185

#10185 counts taxable employment disability benefits in gross income. Its impact trace found one 2025 record (tax_unit_id 104233, weight 12,659): a 67-year-old surviving spouse with a 29-year-old dependent whose $6,238 of disability benefits start to count. On main's rule that record goes from SURVIVING_SPOUSE to SINGLE, and its basic standard deduction from $31,500 to $15,750.

With this PR the gross income test no longer affects surviving spouse status, so that record stays SURVIVING_SPOUSE. At this head I merged #10185's head (c10ffcad60) without committing:

  • it merges cleanly;
  • all 60 cases in the three YAML files and the 6 property tests pass;
  • the traced household (its $6,238 now in dependent_gross_income) files as surviving spouse with a $31,500 basic standard deduction.

The two PRs can land in either order. #9932 also appends cases to filing_status.yaml; whichever lands second has an append-only conflict.

Impact

Pending: a full default-dataset run for 2025 and 2026, main f9b55fc4dd vs this head.

Tests run at this head

All one process per command, with thread caps of 4:

  • surviving_spouse_eligible.yaml, filing_status.yaml, head_of_household_eligible.yaml: 60 passed.
  • The whole household/demographic/tax_unit/ YAML folder (34 files): 170 passed.
  • Every other YAML file that sets is_surviving_spouse (6 + 13 + 9 + 2 + 9 + 6 + 4 + 2 passed):
    • federal QBI estate income;
    • California itemized deductions;
    • Indiana over-65 property tax credit;
    • Louisiana surviving spouse exemption;
    • Pennsylvania property tax/rent rebate;
    • Texas over-65 homestead exemption;
    • Wisconsin income tax;
    • Romney Family Security Act.
  • Parent-id YAML (5 + 47 + 11 + 39 + 3 + 13 passed):
    • person parent_ids;
    • Medicaid parent_ids_composition and parent_ids;
    • SSI parental deeming;
    • Missouri TANF parent input contract and parent of dependent child.
  • tests/core (70 passed): test_parent_links.py, test_parent_links_properties.py, test_tax_unit_role_input.py, test_filing_requirement_invariants.py, test_filing_requirement_dependent_invariants.py, test_mo_tanf_dependent_parent_properties.py, test_medicaid_household_income_invariants.py.
  • The property test: 6 passed.
  • The reviewer's 19-setup adversarial probe: all match, forward and reversed.
  • ruff format --check . and ruff check on the changed files: clean.

axiom: TheAxiomFoundation/rulespec-us#1814 queued (26 USC 2(a); the module us/statutes/26/2/a.yaml is deferred with rules: [] and blocked on TheAxiomFoundation/rulespec-us#1399)

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 19, 2026 08:42
IRC 2(a)(1)(B) determines the surviving spouse's son or daughter's
dependency "without regard to subsections (b)(1), (b)(2), and (d)(1)(B)"
of section 152. surviving_spouse_eligible counted tax_unit_child_dependents,
which sums is_child_dependent and so applied the 152(d)(1)(B) qualifying
relative gross income test. An adult child with gross income at or above
the exemption amount ($5,200 in 2025) therefore left the parent filing
single.

The formula now counts any tax unit dependent who is the head's child.
2(a)(1)(B)(i) requires a son, stepson, daughter or stepdaughter. Where the
household has parent ids, the child is a dependent whose parent_1_id or
parent_2_id names the head (natural, adoptive or step). Without parent ids,
it is any dependent not marked as a parent or grandparent of the filer or
as unrelated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of bd9545e found that switching to parent ids for a whole
household removed surviving spouse status from a real child whose own ids
were unknown, whenever the head or a housemate had any parent id. A parent
id of 0 is unknown, so it cannot show that the filer is not the parent.

Each dependent is now judged on its own ids: a dependent is the head's
child when an id names the head, and is not when two different parents are
named and neither is the head, when an id names another household member,
or when the head's own ids name the dependent as the head's parent or
grandparent. Otherwise the relationship flags decide, as before.

Adds YAML regressions for each case the review reproduced, a sibling and a
two-generation ancestor case, and widens the property grid to ten
relationship setups. Fixes the grid's has_dependent field, which counted the
four units without a dependent as having one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of 5661605 found two remaining defects:

- Naming another parent was treated as proof that the head is not a
  parent. A widower's daughter who named only her co-resident mother, and a
  stepchild naming both biological parents, lost the status. A parent id of
  0 is unknown and two ids cannot list every step parent, so neither settles
  the relationship.
- Ancestor links stopped at tax unit boundaries, so a grandmother linked
  through a mother filing separately still qualified the head.

A dependent is still the head's child when an id names the head. The ids
now rule a dependent out only when they show another relationship: the
head's parent or grandparent, a sibling (a shared parent id), a grandchild
(the dependent's parent names the head) or a niece or nephew (the
dependent's parent shares a parent id with the head). Parents are resolved
among both household and tax unit members, and shared ids identify siblings
even when the parent lives elsewhere.

Adds YAML for both review cases, an absent-parent sibling and a nephew, and
widens the property grid to thirteen relationship setups.

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

This branch has not been deployed

No deployments
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