Repository navigation
Conversation
State benefit programs that list Social Security as income often leave out Railroad Retirement Act benefits, whose tier 1 share replaces Social Security for railroad workers. This adds `railroad_benefits` to 50 income lists and to Missouri's Supplemental Nursing Care income variable, where the program's rule names railroad retirement, counts pensions, annuities or retirement benefits, or counts all income it doesn't exclude. Each program's own rule was read against the sources the parameter cites. Tests: a property test checks that railroad benefits raise each program's income by the amount received, and a YAML case pins each program whose rule names railroad retirement. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Passing runs cost about a tenth of a second per example, so the extra examples add little to CI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
marked this pull request as ready for review
November 9, 2026 11:46
An independent review found that the first sweep skipped any file that mentioned railroad retirement, even in a comment, and hid child care lists whose rules name those benefits. Sweep parsed values instead, add the programs whose rules reach the benefits (HI, MA, MT, PA, UT and WY child care and seven California county programs), and record the disability and Medicare limits in the lists' comments. Add R3, which fails on any state or county reader of Social Security that neither counts railroad benefits nor explains why, and R4, which rejects a repeated entry. Run R1 from the first dollar, over the programs that already counted the benefits too, and extend R2 to every list with a pension line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Louisiana CCAP (LAC 28:CLXV.509.A.3.b), North Dakota CCAP (NDAC 75-02-01.3-08 disregards no recurring railroad benefit), Oregon ERDC (OAR 414-175-0035(52)), South Dakota CCA (subsidy manual, section 4) and Washington ECEAP (DCYF 05-006, section 9) now count railroad_benefits, each with a YAML case and an R1 row that fails without the entry. The R3 check now reads each list, and each function or class body, on its own, and counts the railroad total or any of its parts. R4 also fails when a list holds railroad_benefits with one of its parts. R5 finds state and local programs that read the federal TANF or SNAP lists, which leave out railroad benefits (#10551). Los Angeles County General Relief cites GR policy 44-101. Massachusetts CCFA's list explains why railroad payments count as "Retirement income". Utah's case drops a citation that governs the assistance unit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Record Washington's new disability retirement test (#10330) as a yes-or-no signal, so R3 passes after the merge of main. - R3 also scans each variable file's top level, so a module-level list of Social Security names no longer passes unseen. - R4 checks variable adds lists as well as parameter lists, and fails on any railroad amount listed twice or with a part it holds. - R5 follows federal lists through the variables that add or read them and up to two more formulas, which finds the school meals ratio and the Medicaid and ACA MAGI measures that state programs read. Its entries end when their source counts railroad benefits or no state code reads them. - State SC LIHEAP's reason as the guide's wording, and fix the docstring's R1 range. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The R1 and R5 docstrings and the FEDERAL_GAPS comments now match the PR body: agencies and taxpayers act under each cited rule, R5's docstring says why it stops at two formula steps, and the group descriptions list federal benefits beside pensions, annuities and retirement benefits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both sides added a ninth Hawaii CCAP case. This keeps main's eight Hawaii TANF cases as 9 to 16 and renumbers the railroad case to 17. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Hawaii CCAP counts Hawaii TANF since #10332, so its R1 and R2 rows set wages above the aid limits, as the other eight rows with cash aid do. R5 starts from one more kind of federal source: a variable whose own code names a Social Security amount and no railroad amount, the check R3 runs on state code. That finds is_medicare_eligible, which tests Social Security disability for 24 months and leaves out the disabled railroad annuitants 42 U.S.C. 426(b)(2)(B) covers. FEDERAL_GAPS lists it and the seven premiums and tests state code reads within two steps of it. R5 reads a parameter path through names assigned in the same module or function, and a list named in a string. R4 maps each railroad amount to the dollars it holds and fails when two entries of a list share any, so the tier 1 amount beside the taxable total fails too. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This was referenced Nov 14, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Many of PolicyEngine's income lists for state and county benefit programs count Social Security and leave out Railroad Retirement Act benefits, including the tier 1 social security equivalent, which the IRS taxes as a Social Security benefit under IRC 86(d)(1)(B). I audited 109 income lists and variables in those programs and added
railroad_benefitsto the 69 whose rules cover it. That fixes part of #10551; the issue also covers the federal SNAP, HUD, TANF and school meals lists, which I left alone.R3 (below) parses every state and county list and variable outside the tax code and flags each one that reads a Social Security amount without
railroad_benefits. I also audited three files that a text search flagged although they don't readsocial_security: DC CCSP, MN CCAP unearned income and TX TWC child care.This PR doesn't depend on #10696 or #10722. On
main, users enterrailroad_benefitsdirectly; under #10696, the model builds it from the railroad parts. These lists read the total either way. The model keeps the railroad variables apart fromsocial_securityandpension_income, so a payment entered once counts once. Users who follow #10696's documentation enter these payments only under the railroad variables.Changes
I added
railroad_benefitsto 68 income lists underpolicyengine_us/parameters/gov/states/andpolicyengine_us/parameters/gov/local/, in every dated block of each list, and to Missouri'smo_snc_countable_incomevariable. I sorted the rules into three groups, and each row quotes its rule.Rules that name railroad retirement
Rules that list pensions, annuities, retirement benefits or federal benefits
Rules that define income as everything outside their exclusions
Programs that inherit the change
These programs read one of the changed income totals, so railroad benefits count there too:
dc_tanf_countable_income.ma_tcap_gross_unearned_income.il_isbe_countable_income.il_aabd_countable_unearned_income.mo_snc_countable_income.Federal sources that state programs read
Within two formula steps of a federal source, state and county code reads 17 federal totals, lists and tests that count Social Security, or test for Social Security disability, and leave out railroad benefits:
tanf_gross_unearned_income.school_meal_fpg_ratio.medicaid_magi,tax_unit_medicaid_income_level,medicaid_income_level,aca_magiandaca_magi_fraction. Under IRC 36B(d)(2)(B)(iii), taxpayers add to AGI the untaxed share of "social security benefits (as defined in section 86(d))", tier 1 included. Onmain, neither AGI nor the MAGI additions list counts railroad benefits, and Tax railroad retirement benefits under IRC 86 and 72(r) and subtract them from state income #10696 adds the taxable amounts to AGI and the tax-free tier 1 amount to the additions list.is_usda_disabled, which energy aid in North Carolina, Nevada, New York and Oklahoma reads. Under 7 U.S.C. 2012(j)(7), SNAP agencies count a member who receives a railroad disability annuity as disabled if the member's railroad service would have counted as Social Security employment and the member applied for disability benefits.railroad_benefitsdoesn't separate disability annuities.is_medicare_eligible, and seven premiums and tests built on it. The model tests age 65 or 24 months of Social Security disability. Under 42 U.S.C. 426(b)(2)(B), a person under 65 also gets Medicare Part A after 24 months as "a disabled qualified railroad retirement beneficiary". Illinois SMIB and the CTA and RTA reduced fare, the MBTA's TAP CharlieCard, Mississippi's Healthier Mississippi Waiver and Dallas DART read the test. Energy aid in 28 states and Washington's property tax exemption readmedicare_part_b_premium, and energy aid in eight states readsmedicare_part_a_premium. Illinois SMIB readsbase_part_b_premium, Rhode Island Medicaid readsmedicare_enrolled, California CCHIP and Colorado CHP+ readis_medicaid_eligible, and the Mississippi waiver readsis_adult_for_medicaidandmedicaid_optional_senior_or_disabled_countable_income.These programs leave railroad benefits out until PolicyEngine fixes the federal sources. Issue #10551 covers the TANF, SNAP and school meals lists, #10804 covers the Medicare test, and #9330 records the SNAP disability test's gap.
FEDERAL_GAPSlists all 17, and R5 checks that list.Where the whole benefit counts
railroad_benefitsholds retirement, disability, spouse and survivor annuities in one amount, the limit #10540 describes for California's Working Disabled Program. Where an agency treats one kind differently, the list counts the whole amount, and I say so in its comment.Under CAPS 8.4.2, DECAL excludes the disability and survivors benefits "received by the Social Security Administration", so DECAL still counts railroad disability and survivor annuities.
New Jersey LIHEAP's handbook names Social Security alone in its Medicare Part B deduction (2.3.F.7) and its exclusion for children (2.3.E.9), and it has no railroad line. So the model counts railroad benefits before the premium deduction and at every age, as it counts pensions. Two YAML cases pin the premium and age results.
In Illinois TANF's list, a comment marks
pension_incomeexempt, and the AABD and HBWD lists have no pension line. So the model counts railroad benefits in all three and leaves pensions out. 112.110 lists no pension exemption, and I opened #10784 on that line.How I read the rules
Audited, no change
social_securitywhile the program's unearned list names railroad benefits: GA, IA, ID, IN, KY, LA, MT, NV, OH, SD, TN, WA and WY LIHEAP; CT CEAP; CO LEAP. R1 runs on each.railroad_benefitsdoesn't separate disability annuities, so it can't stand in for SSDI in these checks. They read SSDI or Social Security as a yes or no signal: AZ LIHEAP points, CA WDP disability, Contra Costa GA eligibility, DC CCSP need, HI LIHEAP points, IL HBWD disability, IN EAP, LA LIHEAP, MD PAA, MS WD disability, NM LIHEAP, PA LIHEAP, VA EAP disability, WI SSP (HUD) and WI WHEAP household size.rsdi_sourcestakes RSDI only. CalWORKs'db_unearnedholds disability income, whichrailroad_benefitscan't isolate, and CalWORKs counts railroad benefits with its other unearned income (ca_tanf_other_unearned_income, an R1 row). SC LIHEAP'sminor_unearned_sourcesholds the two kinds of a minor's income that South Carolina counts under the program's guide: Social Security and disability income. The guide doesn't name railroad benefits, and a minor who gets a railroad annuity gets it as a child or survivor, not as a disabled worker. California WDP's exempt list leaves railroad benefits out, per California 250% Working Disabled Program counts Railroad Retirement disability annuities #10540.Not resolved (no change)
I couldn't settle these 6 from the sources, or the sources wouldn't load, so I left them unchanged.
Invariants
policyengine_us/tests/test_state_benefit_railroad_income.pystates and checks these.NO_RAILROAD_INCOMEwith its reason. A new reader fails this test until its author reads the rule, and the test also fails on an entry that no longer applies. R3 reads names written out in full, so a name built with an f-string or concatenation, or a scalar parameter, passes unseen. So does a module that splits Social Security and railroad benefits between two top-level lists. I confirmed it fails when a list loses the entry, even with a comment left behind, and when a module-level constant lists Social Security alone. Two entries sit outside the benefit programs, both in Washington's senior and disabled property tax exemption. Count railroad benefits in state tax worksheets, income tests and limits as each state's law does #10722 adds the tax-free railroad parts its income list needs, and its disability retirement test reads Social Security disability receipt as a yes or no signal.FEDERAL_GAPS, and the test fails on an entry once its source counts railroad benefits or no state code reads it. A new reader of a source already inFEDERAL_GAPSpasses. A third step would reach further eligibility tests and benefit amounts, such asis_snap_eligibleandaca_ptc, and R5 doesn't follow it. R5 reads a parameter path written out in code, built through names assigned in the same module or function, or named in a string; a path passed as a function argument passes unseen. I confirmed R5 fails when any one of the 17 entries goes missing, when the school meals list gainsrailroad_benefits, and on an entry that no state code reads.R1 and R2 use Hypothesis with five examples per program in CI. YAML cases, each with its rule beside it, pin every program whose rule names railroad retirement, every county program, Louisiana, North Dakota, Oregon, South Dakota and Washington ECEAP, plus New Jersey's premium and age cases.
axiom: TheAxiomFoundation/rulespec-us#2142 queued
🤖 Generated with Claude Code