Skip to content

Count veterans' and railroad retirement benefits in household and SPM benefits - #10693

Open
MaxGhenis wants to merge 6 commits into
mainfrom
vet-rrb-income-totals
Open

MaxGhenis wants to merge 6 commits into
mainfrom
vet-rrb-income-totals

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

What changes

On main, $10,000 of veterans_benefits or of railroad_benefits changes neither household_net_income nor spm_unit_net_income, because no benefit or market income list includes either variable. workers_compensation, by contrast, counts in both.

In P60-200 Appendix A, the Census Bureau counts veterans' payments as money income (page 3) and U.S. railroad retirement as a nonmeans-tested government transfer (page 4). This PR adds both variables to gov.household.household_benefits and spm_unit_benefits. Four reforms swap in their own copies of those lists: the BOOST Middle Class Tax Credit, the End Child Poverty Act, that act's version in the Economic Dignity for All Agenda, and the Texas rebate check. The PR adds both benefits to all six copies, so each reform counts them as the baseline does.

Double counting

  • Microcosm fills veterans_benefits from the ASEC veterans' payments field (VET_VAL), and no other model input carries those dollars. It fills disability_benefits from the ASEC disability income fields and educational_assistance from ED_VAL. It leaves survivor_benefits at zero, because its ASEC files hold survivor income only as family and household totals.
  • The pinned Populace file carries no railroad_benefits, so this PR moves no national total through railroad benefits. The variable's documentation tells users to enter Railroad Retirement Board payments only in railroad_benefits, not also as Social Security, pension, disability or survivor income.
  • The documentation of veterans_benefits now covers Combat-Related Special Compensation (CRSC), as military_retirement_pay already directs. The military departments pay CRSC to retirees under 10 U.S.C. 1413a, and the IRS lets them exclude it from income (Publication 525, page 19).
  • The documentation of educational_assistance and survivor_benefits now sends VA education benefits and VA dependency and indemnity compensation to veterans_benefits, and Railroad Retirement Board survivor annuities to railroad_benefits, so a user enters each payment once.

Invariants

  1. In every state, a dollar of veterans' or railroad benefits adds a dollar to household_benefits and spm_unit_benefits, and so to market income plus benefits for the household and the SPM unit. A property test checks this over states and amounts.
  2. Veterans' benefits never change irs_gross_income or adjusted_gross_income, and they leave federal income_tax unchanged for a filer who doesn't itemize (property test over amounts, earnings and states). The IRS bases a filer's row in the optional sales tax tables on AGI plus nontaxable income, veterans' benefits included (2025 Instructions for Schedule A, page 5). The model already adds them there, so they can lower income tax for an itemizer who deducts sales tax. For example, in two new state_sales_tax.yaml cases, $30,000 of veterans' benefits raises the 2025 table amount for a Texas filer with $100,000 of AGI from $931 to $992.
  3. Every reform copy of the household and SPM benefit lists includes both benefits, as test_aggregate_list_integrity.py now requires.
  4. The household and SPM benefit lists still differ only where test_household_spm_resource_parity.py records a reason, so that test keeps passing.

Tests

  • In new cases in household_benefits.yaml and spm_unit_benefits.yaml, both benefits count for one household and for two SPM units in one household. In a new irs_gross_income/veterans_benefits.yaml, VA benefits stay out of gross income with and without earnings. Those three files, with state_sales_tax.yaml and state_sales_tax_income_bracket.yaml, hold 192 cases, and all pass locally.
  • The two property tests at the end of test_household_spm_resource_parity.py check invariants 1 and 2 against a twin household without the benefit. All 63 tests in that file pass locally and in CI run 42509094977.
  • All 31 tests in test_aggregate_list_integrity.py pass, and two of them fail when one reform's copies leave the benefits out. For a Texas adult with $500,000 of earnings in 2027, $10,000 of either benefit adds $10,000 to household_benefits and spm_unit_benefits under each of the four reforms, as it does in the baseline.

The two new parity tests add about 100 seconds to Linux CI: 73.8 and 30.9 seconds in run 42509094977 at this head, and 70.8 and 27.5 seconds in run 42425411534 at f3dc6cd. At this head, the parity file's 63 tests took 369.9 seconds in the rest-python-remaining-2 group, which ran 71 files in 29 minutes 33 seconds and peaked at 6.01 GiB of memory. On main (run 42478927603 at 06553a9), its 61 tests took 196.3 seconds in rest-python-remaining-1, which ran 71 files in 22 minutes 32 seconds and peaked at 6.15 GiB. CI put the file in a different group in each run, so the group figures don't compare directly. The 61 tests that main also runs took 265.2 seconds at this head, against 196.3 on main. On a shared Mac (load about 20), with setup included, the file took 158 seconds and 1.99 GiB at main and 197 seconds and 2.01 GiB at this head. The guard file's 31 tests take 0.6 seconds.

Impact

We ran the 2026 microsimulation on hf://datasets/policyengine/populace-us/populace_us_2024.h5@populace-us-2024-spm-20260909 twice, at main (06553a9) and at this head (e7ddd42). We estimate that counting veterans' benefits adds $130.3 billion to household_benefits, spm_unit_benefits and both net incomes, and leaves every federal and state tax total unchanged. The pinned file carries no railroad benefits, so they add nothing nationally.

SPM poverty rate, 2026 Main This PR Change (points, from unrounded rates)
All people 13.75% 13.55% -0.19
Children 17.56% 17.41% -0.14
Ages 18 to 64 13.17% 12.94% -0.22
Ages 65 and over 10.90% 10.74% -0.16
Deep poverty, all people 2.99% 2.89% -0.10
People in SPM units with veterans' benefits 9.68% 4.77% -4.92

We estimate that SPM net income rises for all 13.6 million people in SPM units with veterans' benefits and stays the same for everyone else. Of them, 671,000 leave SPM poverty, no one enters it, and the poverty gap falls by $4.7 billion, to $258.0 billion.

axiom: n/a: income totals only; no tax or benefit rule changes.

🤖 Generated with Claude Code

… benefits

veterans_benefits and railroad_benefits reached neither household_benefits
nor spm_unit_benefits, so neither net income nor SPM resources counted them.
Census P60-200 Appendix A lists veterans' payments as a source of money income
and counts railroad retirement among government transfers.

Both now sit in household_benefits and spm_unit_benefits. Veterans' benefits
stay out of federal gross income under 38 U.S.C. 5301(a)(1). Railroad benefits'
federal tax treatment follows in a separate change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Nov 7, 2026
… parity test

#10663 made the parity test require every source in gov.irs.gross_income.sources
to name the SPM resource that counts its cash. railroad_benefits, which #10693
adds to spm_unit_benefits, holds the whole annuity; taxable_railroad_pension_benefits
and taxable_railroad_social_security_equivalent_benefits tax its parts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review November 7, 2026 23:28
MaxGhenis and others added 3 commits November 8, 2026 13:15
- Add veterans_benefits and railroad_benefits to the six reform copies of
  the benefit lists (BOOST, End Child Poverty Act, EDAA End Child Poverty
  Act, Texas rebate), which otherwise dropped both benefits and showed a
  false loss under each reform, and to SHARED_CASH_PROGRAMS so the guard
  catches a copy that drops them.
- Narrow the veterans' benefits property test to gross income and AGI,
  checking income tax only when neither household itemizes: the IRS counts
  veterans' benefits as income for the optional sales tax tables. New
  state_sales_tax.yaml cases show the 2025 Texas row moving.
- Keep Combat-Related Special Compensation in veterans_benefits, as
  military_retirement_pay directs, and point VA education benefits and
  dependency and indemnity compensation, and railroad survivor annuities,
  to their own variables.
- Cite the Census appendix once, with its page range.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- veterans_benefits: is_veteran reads this input, so a survivor or
  dependent whose VA payments go here should set is_veteran to false.
- disability_benefits: VA disability compensation goes in veterans_benefits.
- SSI unearned sources note: household net income now counts railroad
  benefits; SNAP, HUD and the other program lists still don't (#10551).
- Parity test docstring: list the two new invariants, and say the
  veterans' income tax check covers filers under 65 without a disability,
  since the model doesn't yet reduce the section 22 credit by VA pensions
  (26 U.S.C. 22(c)(3)(A)(i)(III)).
- Sales tax test comment: the table gives the amount a filer may deduct.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main's property tax credit invariant keeps number 7 in
test_household_spm_resource_parity.py; this branch's two invariants become 8
and 9. test_aggregate_list_integrity.py lists the benefits beside main's
state_property_tax_refunds.

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

DTrim99 commented Nov 13, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Count veterans' and railroad retirement benefits in household and SPM benefits

Summary

The PR adds veterans_benefits and railroad_benefits to gov.household.household_benefits (both year blocks) and to the spm_unit_benefits list. It also adds them to all six reform-side copies of those lists: BOOST has two, the End Child Poverty Act two, the Economic Dignity for All Agenda's version of that act one, and the Texas rebate one. Each benefit is counted once. Neither variable is in market_income, market_income_sources, any nested household list (state, local, health or refundable state credits), or federal gross income at this head. No program formula reads household_benefits, spm_unit_benefits, household_net_income or spm_unit_net_income, so no tax or benefit amount changes.

Census counts both as money income, and the SPM starts from money income, so the treatment is right. I found no double count with #10696, which is stacked on this head, or with #10764. #10662 conflicts textually in six files (see Branch status).

Two items need changes:

  • New documentation sends VA education benefits to a variable that SNAP counts in full. The model deliberately keeps education aid out of SNAP.
  • The two new Hypothesis tests add about two minutes to every CI run, and existing coverage already exercises most of what they test.

I did not run Python. The claims below rest on reading the code at the head, hand traces, the cited primary sources, and CI run 43118653441 at this head. The PR body's microsimulation figures and its account of how Microcosm fills these variables are taken as stated, not re-run.

Critical (must fix)

None.

Should address

1. New documentation sends VA education benefits into a variable SNAP counts as income (variables/household/income/person/general/veterans_benefits.py:13, variables/household/income/person/misc/educational_assistance.py:9)

  • veterans_benefits now lists "education allowances", and educational_assistance now says "VA education benefits go in veterans_benefits."
  • The household and SPM totals don't depend on this routing, since both variables are in both lists. Program results do.
  • The SNAP unearned list counts veterans_benefits in full (gov/usda/snap/income/sources/unearned.yaml:81). It keeps educational_assistance out on purpose: "(iv) educational assistance is countable only after educational exclusions. Keep it out until the excluded share is modeled" (line 111).
  • Federal law excludes these benefits from SNAP income. 7 U.S.C. 2014(d)(3) excludes "all educational loans on which payment is deferred, grants, scholarships, fellowships, veterans' educational benefits, and the like" (https://www.law.cornell.edu/uscode/text/7/2014). 7 CFR 273.9(c)(3)(i) excludes "Educational assistance, including ... veterans' educational benefits and the like" (https://www.law.cornell.edu/cfr/text/7/273.9).
  • So a user who follows the new text gets SNAP that counts GI Bill payments. Entering them as educational_assistance, as the old text suggested, excludes them. The federal TANF, SSI and HUD unearned lists treat the two variables the same split way.

Fix: Drop "education allowances" from the veterans_benefits documentation. Have educational_assistance say that VA education benefits go there, because SNAP excludes them under 7 U.S.C. 2014(d)(3) and both variables count in household and SPM benefits.

Related, and not a finding against this PR: RRB survivor annuities count for SNAP as survivor_benefits but not as railroad_benefits. The railroad_benefits documentation already covered survivor annuities on main, so that routing predates this PR. #10551 tracks the gap, and the PR's updated SSI note points to it.

2. The new property tests add about two minutes per CI run and mostly repeat existing coverage (tests/test_household_spm_resource_parity.py:615-682)

CLAUDE.md, "Test design and CI cost", says: "Do not add a Python test when the existing YAML framework can exercise the same behavior", and "explain the distinct failure the new test detects."

In run 43118653441 at this head (Rest, Python shard 7), the two new tests took 88.0 s and 34.8 s. test_a_dollar_of_federal_cash_benefits_adds_a_dollar_to_both_totals is now the slowest test in the file. The existing test_a_dollar_of_cash_adds_a_dollar_to_both_totals covers 16 payments in 56.6 s.

  • Test 8: it samples states, but with $500,000 of earnings no means-tested program responds. It also checks market income plus benefits, which no state tax touches, so the state dimension adds nothing. The new YAML cases in household_benefits.yaml and spm_unit_benefits.yaml already pin both entries. The parity list test and the SHARED_CASH_PROGRAMS guard pin every list and reform copy. Adding ("veterans_benefits", "person", "TX", 2026) and ("railroad_benefits", "person", "VA", 2026) to CASH_PAYMENTS (line 149) gives the same check at no extra cost, since max_examples stays at 20.
  • Test 9: federal gross income, AGI and a non-itemizer's federal income tax don't vary by state. The gross income and AGI parts duplicate the new irs_gross_income/veterans_benefits.yaml. Only the income tax part is new. Pin income_tax in that YAML file for a twin pair with and without the benefit, or keep the test with its two @examples, no state strategy and a small max_examples.

Suggestions

  1. PR body wording. "On main, $10,000 of veterans_benefits or of railroad_benefits changes neither household_net_income nor spm_unit_net_income" holds only for a household with no offsets. On main:

    • Virginia subtracts the full railroad_benefits from federal AGI (gov/states/va/tax/income/subtractions/subtractions.yaml) although AGI excludes them, which lowers Virginia tax.
    • SNAP and TANF count veterans_benefits.
    • is_veteran (veterans_benefits > 0) turns on veteran-only state credits.

    Suggested wording: "neither total counts them as income."

  2. SPM citation. The list comments and references cite P60-200 Appendix A, the 1998 money income definition. The pages support both entries: page 3 has "Veterans' payments", and page 4 has "U.S. railroad retirement" among nonmeans-tested government cash transfers. spm_unit_benefits could also cite the SPM resource definition, "SPM Resources = Money Income From All Sources" (Census P60-254, https://www.census.gov/content/dam/Census/library/publications/2015/demo/p60-254.pdf#page=4), or the current SPM report.

  3. Track the Section 22 gap. The docstring of test 9 says the model doesn't reduce the credit for the elderly or disabled by VA pensions under 26 U.S.C. 22(c)(3)(A)(i)(III). The citation is correct: "(III) a law administered by the Veterans' Administration". Link an issue for it so the deferral is tracked.

Verified correct

  • Census and SPM treatment. The P60-200 Appendix A text matches the PR:
    • Page 1 lists "Veterans' payments" as a money income source.
    • Page 3 defines it and lists railroad retirement as a source of pension, survivor and disability income.
    • Page 4, definition 9, lists "nonmeans-tested veterans' payments, U.S. railroad retirement" among nonmeans-tested government cash transfers.
    • Census P60-254, page 4: "SPM Resources = Money Income From All Sources", plus noncash benefits, minus taxes and expenses.
  • No double count.
    • Neither variable is in market_income (person), gov.household.market_income_sources, household_state_benefits, household_local_benefits, household_health_benefits, household_refundable_state_credits or gov.irs.gross_income.sources at this head.
    • The only other readers are means-tested countable income lists (SNAP, SSI, TANF, HUD, WIC, school meals, state and county programs), some state tax subtractions, and the optional sales tax table income. None of them feeds the totals as income.
    • household_net_income is read only by household_net_income_including_health_benefits, marginal_tax_rate and the behavioral response measurements. Labor supply income effects therefore now use a base that includes these benefits, which is consistent.
  • Reform copies. All six literal copies are updated. The EDAA household_benefits and the Texas rebate's household total read the parameter, so they inherit the entries. No other reform or contrib file holds a copy, on this head or on main.
  • Mutation coverage.
    • Deleting either entry from the 2024 block fails the household YAML case.
    • Deleting it from the 2022 block fails test_benefit_lists_differ_only_where_documented[2023], which reads the 2022 block.
    • Deleting it from spm_unit_benefits fails both YAML files.
    • Deleting it from any reform copy fails test_reform_aggregates_keep_shared_cash_programs.
  • Hand checks:
    1. household_benefits.yaml, new case (TX, two $500,000 earners, so no means-tested benefit): household_benefits = 12,000 + 30,000 = 42,000.
    2. Same case, one SPM unit: spm_unit_benefits = 42,000.
    3. spm_unit_benefits.yaml, new case (FL, two SPM units): [9,000, 24,000].
    4. Same case: household_benefits = 9,000 + 24,000 = 33,000. Arithmetic expressions are an established YAML test pattern, e.g. spm_unit_fpg: 14_720 + 5_200.
    5. irs_gross_income/veterans_benefits.yaml, case 1: $30,000 of VA benefits only gives irs_gross_income 0. The variable is not in gov.irs.gross_income.sources (38 U.S.C. 5301(a)(1)).
    6. Case 1: adjusted_gross_income = 0.
    7. Case 2: $45,000 of wages plus $20,000 of VA benefits gives irs_gross_income 45,000.
    8. Case 2: AGI = 45,000 − 0. There are no above-the-line deductions, and the 2026 tips, overtime and senior deductions come below the line.
    9. state_sales_tax.yaml, first case: table income = AGI 100,000, so state_sales_tax_income_bracket = 10 (the "$100,000–$120,000" row; the bracket amounts in income_bracket.yaml start at 1).
    10. First case: TX, family size 1, 2025 gives $931. The 2025 Instructions for Schedule A, page 16, Texas column 1, $100,000–$120,000 row prints 931, which matches tax.yaml TX/1/10.
    11. Second case: table income = 100,000 + 30,000 = 130,000, so bracket 11 and $992. Page 16, $120,000–$140,000 row prints 992; tax.yaml TX/1/11 has 992. Page 5 confirms the inclusion: income is "line 11b, plus any nontaxable items, such as ... Veterans' benefits."
    12. Second case: AGI stays 100,000.
    13. Property test examples: $12,000 of veterans' benefits in TX and $30,000 of railroad benefits in VA, each at $500,000 of earnings, move spm_unit_benefits, household_benefits and market income plus benefits by exactly the amount. These totals are before tax, so Virginia's railroad subtraction doesn't enter them.
  • Documentation sources.
    • IRS Pub. 525 (2024), page 19: CRSC "you may exclude ... from your income".
    • Page 16 covers VA benefits.
    • 10 U.S.C. 1413a.
    • The updated SSI note is accurate: the SNAP and HUD unearned lists include social_security and ssi but not railroad_benefits.
  • References and changelog. The list-level reference title ends with #page 3-4, quoted, with the href opening page 3, as CLAUDE.md requires for several pages. Variable references are single-page hrefs. The changelog fragment vet-rrb-income-totals.fixed.md is present.
  • Other checks. Test periods are plain (2025, 2026). No new state-gated int or enum keys. No partner test files changed.

Axiom line assessment

axiom: n/a: income totals only; no tax or benefit rule changes. This is valid. The change only affects which inputs count toward PolicyEngine's household and SPM income totals, which follow the Census statistical definitions; no statute or regulation sets them. I checked that no program formula reads household_benefits, spm_unit_benefits or either net income. The new YAML cases pin existing law: VA benefits stay out of gross income, and they count in the sales tax table income.

CI status

All 36 checks pass at fb34f7c (run 43118653441, started 2026-11-11 23:17 UTC; rechecked 2026-11-13). That run includes the PR validation and guard job, all Baseline and Contrib shards, Python Rest shards 1-9, Microsimulation, and Household API Partners.

Branch status

Verdict: REQUEST_CHANGES

@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.

Requesting changes: 0 critical, 2 should address, 3 suggestions (details in the report above). The substance is right. Census money income counts VA payments and railroad retirement, the SPM starts from money income, each benefit is counted once, and all six reform copies are updated.

  1. The new documentation sends VA education benefits to veterans_benefits, which SNAP counts in full. 7 U.S.C. 2014(d)(3) and 7 CFR 273.9(c)(3)(i) exclude them, and the model keeps educational_assistance out of SNAP, so they belong there.
  2. The two new Hypothesis tests add about 123 s per CI run, and they mostly repeat YAML and existing coverage. That runs against CLAUDE.md's test-design rules. Adding the two benefits to CASH_PAYMENTS and moving the income-tax check to YAML would cover the same ground.

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.

2 participants