Skip to content

The model leaves military retired pay out of 54 benefit income lists, including WIC, HUD, Head Start and TANF #10890

Open

Description

@MaxGhenis

The model takes military retired pay and military survivor annuities in two inputs, military_retirement_pay and military_retirement_pay_survivors, and sums them in military_retirement_income. It builds pension_income from the taxable and tax-exempt pension inputs alone, so pension_income holds no military retired pay. At main, 54 benefit income lists name pension_income (one names taxable_pension_income) and leave out military_retirement_income. In each of those programs the model counts a government employee or private pension and drops the same amount of military retired pay.

Another 75 benefit lists name both, among them SNAP, SSI and most LIHEAP lists. The default dataset fills neither military input, so the model drops nothing from default microsimulation results. It undercounts income in household calculations that enter military retired pay.

Five households

We entered each household below for 2026 twice: once with military retired pay and once with the same amount as a private pension.

Program Household With military retired pay With a private pension
CSFP Ohio couple aged 67 and 65, $30,000 of Social Security and $45,000 of retired pay 138.6% of the poverty guideline; $651 for each spouse 346.6%; $0
WIC Idaho parent aged 42 with $60,000, child aged 2 countable income $3,708; $723.73 of WIC for the child $60,000; $0
HUD Ohio tenant aged 50 with $30,000, in assisted housing annual income $0; total tenant payment $25 a year $30,000; $9,000
Head Start Ohio parent aged 30 with $60,000, child aged 4 gross income $0; child eligible $60,000; not eligible
North Dakota TANF parent aged 40 with $24,000, child aged 8 $739 in January $0

For example, the model reads CSFP income from the school meals list, counts only the couple's Social Security and places them under CSFP's 150% limit. It gives both spouses CSFP in 46 states and DC. In Illinois, Kansas and Massachusetts the model also tests the county, and in Texas it applies the state's own income test.

The WIC family's $3,708 comes from twelve months of Idaho's $309 TANF grant, which the model also pays them. The model builds Idaho's TANF income on the federal TANF unearned list, where it also leaves the pay out. For the HUD tenant, the model cuts the payment to its minimum rent, which it sets at $25 a year, though HUD sets minimum rent by the month in 24 CFR 5.630(a).

What the agencies count

Where the model drops it

The 54 lists

The model stores two dated blocks for California CARE/FERA and for Louisiana child care, and all four leave the pay out.

Federal programs

Program List, at the pension line
WIC usda/wic/income/sources.yaml L16
School meals, and CSFP through school_meal_fpg_ratio (school meals: #10801) usda/school_meals/income/sources.yaml L17
HUD annual income hud/annual_income/sources/unearned.yaml L4
Head Start hhs/head_start/income/sources.yaml L11
TANF unearned income (tanf_gross_unearned_income, read by 37 states' TANF code) hhs/tanf/cash/income/sources/unearned.yaml L13

State and county cash assistance

Program List, at the pension line
Colorado TANF states/co/cdhs/tanf/income/unearned.yaml L10
Colorado Old Age Pension states/co/ssa/oap/income/sources/unearned.yaml L10
DC TANF states/dc/dhs/tanf/income/sources/unearned.yaml L11
Maine TANF states/me/dhhs/tanf/income/sources/unearned.yaml L17
Massachusetts Transitional Cash Assistance Program states/ma/dta/tcap/gross_income/unearned.yaml L9
Minnesota MFIP states/mn/dcyf/mfip/income/sources/unearned.yaml L14
Montana TANF states/mt/dhs/tanf/income/sources/unearned.yaml L7
North Carolina TANF states/nc/ncdhhs/tanf/income/unearned.yaml L11
North Dakota TANF states/nd/dhs/tanf/income/sources/unearned.yaml L14
South Carolina TANF states/sc/tanf/income/unearned/sources.yaml L11
Wyoming POWER states/wy/dfs/power/income/sources/unearned.yaml L14
Marin County General Relief local/ca/marin/general_relief/income_sources.yaml L16
Orange County General Relief local/ca/oc/general_relief/income/sources/unearned.yaml L11
San Bernardino County General Relief local/ca/sbd/general_relief/income/sources/unearned.yaml L20
San Francisco CAAP local/ca/sf/caap/countable_income/sources/unearned.yaml L7
San Mateo County General Assistance local/ca/smc/general_assistance/income/sources.yaml L13
Santa Clara County General Assistance (taxable_pension_income) local/ca/scc/general_assistance/countable_income/unearned_sources.yaml L11

Child care and early childhood

Program List, at the pension line
Alabama CCSP states/al/dhr/ccsp/income/countable_income/sources.yaml L8
Alaska CCAP states/ak/dpa/ccap/income/countable_income/unearned_sources.yaml L17
Arizona CCAP states/az/hhs/ccap/income/countable_income/sources.yaml L13
California child care states/ca/cdss/child_care/income/sources.yaml L21
Connecticut Care 4 Kids states/ct/oec/c4k/income/unearned_sources.yaml L5
Georgia CAPS states/ga/decal/caps/income/countable_income/sources.yaml L14
Illinois CCAP states/il/dhs/ccap/income/countable_income/sources.yaml L11
Illinois ISBE early childhood programs states/il/isbe/income/countable_sources.yaml L11
Iowa CCA states/ia/hhs/cca/income/countable_income/unearned_sources.yaml L6
Louisiana CCAP states/la/ldoe/ccap/income/unearned_sources.yaml L7, L20
Mississippi CCPP states/ms/dhs/ccpp/income/countable_income/unearned_sources.yaml L10
Montana Best Beginnings states/mt/dphhs/ccap/income/countable_income/sources.yaml L16
New Hampshire Child Care Scholarship states/nh/dhhs/ccap/income/countable_income/sources.yaml L11
New Jersey CCAP states/nj/njdhs/ccap/income/countable_income/unearned_sources.yaml L11
North Carolina Subsidized Child Care states/nc/ncdhhs/scca/income/sources.yaml L8
North Dakota CCAP states/nd/dhs/ccap/income/sources.yaml L18
Oklahoma Child Care Subsidy states/ok/dhs/ccs/income/sources.yaml L28
South Carolina Child Care Scholarship states/sc/dss/ccap/income/countable_income/sources.yaml L9
South Dakota CCA states/sd/dss/cca/income/sources.yaml L16
Texas Child Care Services states/tx/twc/ccs/income/sources.yaml L10
Utah CCAP states/ut/dwf/ccap/income/sources/unearned.yaml L34
Virginia CCSP states/va/dss/ccsp/income/countable_income/unearned_sources.yaml L6
Wisconsin Shares states/wi/dcf/shares/income/sources.yaml L35
Wyoming child care states/wy/dfs/ccap/income/countable_income/sources.yaml L20

Energy, health and tax relief

Program List, at the pension line
California CARE and FERA states/ca/cpuc/income_sources.yaml L80, L122
Los Angeles EZ-SAVE local/ca/la/dwp/ez_save/income_sources.yaml L23
Riverside County LIHEAP local/ca/riv/cap/liheap/countable_income/sources.yaml L9
Riverside County SHARE local/ca/riv/cap/share/countable_income/sources.yaml L9
Texas CEAP states/tx/tdhca/ceap/income/sources.yaml L20
Texas Family Planning Program states/tx/fpp/income/sources/unearned.yaml L6
Mississippi Working Disabled Medicaid states/ms/dom/wd/eligibility/income/sources/unearned.yaml L4
Denver property tax relief local/co/denver/dhs/property_tax_relief/income_sources.yaml L10

Outside these benefit lists, the model also leaves the pay out of Michigan's household resources list, which it reads for the home heating credit and the homestead property tax credit. Michigan defines that income in MCL 206.510(1) as "the sum of federal adjusted gross income as defined in the internal revenue code plus all income specifically excluded or exempt".

Related work

Possible fix

Add military_retirement_income beside pension_income in each list, as in the SNAP and SSI lists, after checking each state's rule for an exclusion. If the model folded it into pension_income, it would count the pay twice in market income and in the 75 benefit lists that already name both.

Reproduction

Script and output at 935b24f
from policyengine_us import Simulation

YEAR = 2026
JANUARY = f"{YEAR}-01"
STATES = (
    "AL AK AZ AR CA CO CT DE DC FL GA HI ID IL IN IA KS KY LA ME MD MA MI MN MS MO "
    "MT NE NV NH NJ NM NY NC ND OH OK OR PA RI SC SD TN TX UT VT VA WA WV WI WY"
).split()
SOURCES = ["military_retirement_pay", "taxable_private_pension_income"]


def simulate(households):
    """Each household is (state, {person: inputs}, SPM unit inputs)."""
    s = {
        key: {}
        for key in [
            "people",
            "families",
            "tax_units",
            "spm_units",
            "marital_units",
            "households",
        ]
    }
    for i, (state, people, spm_inputs) in enumerate(households):
        names = [f"{name}_{i}" for name in people]
        for pid, inputs in zip(names, people.values()):
            s["people"][pid] = {k: {YEAR: v} for k, v in inputs.items()}
        adults = [pid for pid in names if s["people"][pid]["age"][YEAR] >= 18]
        s["families"][f"family_{i}"] = {"members": names}
        s["tax_units"][f"tax_unit_{i}"] = {"members": names}
        s["spm_units"][f"spm_unit_{i}"] = {
            "members": names,
            **{k: {YEAR: v} for k, v in spm_inputs.items()},
        }
        s["marital_units"][f"marital_unit_{i}"] = {"members": adults}
        for pid in names:
            if pid not in adults:
                s["marital_units"][f"marital_unit_{pid}"] = {"members": [pid]}
        s["households"][f"household_{i}"] = {
            "members": names,
            "state_code": {YEAR: state},
        }
    return Simulation(situation=s)


# One household per income source: index 0 holds military retired pay and
# index 1 holds the same amount as a private pension.
print("WIC: Idaho parent aged 42 with $60,000 of retired pay, child aged 2")
sim = simulate(
    [("ID", {"parent": {"age": 42, src: 60_000}, "child": {"age": 2}}, {}) for src in SOURCES]
)
income = sim.calculate("wic_countable_income", YEAR)
tanf = sim.calculate("tanf", YEAR)
limit = sim.calculate("wic_income_limit", JANUARY)
meets = sim.calculate("meets_wic_income_test", JANUARY)
categorical = sim.calculate("meets_wic_categorical_eligibility", JANUARY)
wic_january = sim.calculate("wic", JANUARY)
wic_year = sim.calculate("wic", YEAR)
for j, src in enumerate(SOURCES):
    child = 2 * j + 1
    print(
        f"  {src}: countable income {income[j]:,.0f} (of which TANF {tanf[j]:,.0f}), "
        f"limit {limit[j]:,.0f}, "
        f"meets income test {bool(meets[j])}, child categorically eligible "
        f"{bool(categorical[child])}, child WIC {wic_january[child]:,.2f} in January "
        f"and {wic_year[child]:,.2f} in {YEAR}"
    )

print("HUD: Ohio tenant aged 50 with $30,000 of retired pay and $12,000 of rent, in assisted housing")
sim = simulate(
    [
        (
            "OH",
            {"tenant": {"age": 50, src: 30_000, "pre_subsidy_rent": 12_000}},
            {"receives_housing_assistance": True},
        )
        for src in SOURCES
    ]
)
for variable in ["hud_annual_income", "hud_adjusted_income", "hud_ttp"]:
    values = sim.calculate(variable, YEAR)
    print(f"  {variable}: " + ", ".join(f"{src} {v:,.2f}" for src, v in zip(SOURCES, values)))

print("Head Start: Ohio parent aged 30 with $60,000 of retired pay, child aged 4")
sim = simulate(
    [("OH", {"parent": {"age": 30, src: 60_000}, "child": {"age": 4}}, {}) for src in SOURCES]
)
gross = sim.calculate("head_start_gross_income", YEAR)
fpg = sim.calculate("spm_unit_fpg", YEAR)
income_eligible = sim.calculate("is_head_start_income_eligible", YEAR)
eligible = sim.calculate("is_head_start_eligible", YEAR)
for j, src in enumerate(SOURCES):
    child = 2 * j + 1
    print(
        f"  {src}: gross income {gross[j]:,.0f}, poverty guideline {fpg[j]:,.0f}, "
        f"child income eligible {bool(income_eligible[child])}, child eligible {bool(eligible[child])}"
    )

print("North Dakota TANF: parent aged 40 with $24,000 of retired pay, child aged 8")
sim = simulate(
    [("ND", {"parent": {"age": 40, src: 24_000}, "child": {"age": 8}}, {}) for src in SOURCES]
)
unearned = sim.calculate("nd_tanf_gross_unearned_income", JANUARY)
tanf = sim.calculate("nd_tanf", JANUARY)
for j, src in enumerate(SOURCES):
    print(
        f"  {src}: parent's gross unearned income in January {unearned[2 * j]:,.2f}, "
        f"TANF in January {tanf[j]:,.2f}"
    )

print("CSFP: couple aged 67 and 65 with $30,000 of Social Security and $45,000 of retired pay")
for src in SOURCES:
    sim = simulate(
        [
            (
                state,
                {
                    "head": {"age": 67, "social_security_retirement": 30_000, src: 45_000},
                    "spouse": {"age": 65},
                },
                {},
            )
            for state in STATES
        ]
    )
    csfp = sim.calculate("commodity_supplemental_food_program", YEAR)
    ratio = sim.calculate("school_meal_fpg_ratio", YEAR)
    countable = sim.calculate("school_meal_countable_income", YEAR)
    oh = STATES.index("OH")
    both = [state for k, state in enumerate(STATES) if csfp[2 * k] > 0 and csfp[2 * k + 1] > 0]
    print(
        f"  {src}: Ohio countable income {countable[oh]:,.0f}, income-to-poverty ratio "
        f"{ratio[oh]:.3f}, CSFP {csfp[2 * oh]:,.0f} and {csfp[2 * oh + 1]:,.0f}; "
        f"both spouses get CSFP in {len(both)} of {len(STATES)} states; "
        f"neither or one in {sorted(set(STATES) - set(both))}"
    )
WIC: Idaho parent aged 42 with $60,000 of retired pay, child aged 2
  military_retirement_pay: countable income 3,708 (of which TANF 3,708), limit 39,128, meets income test True, child categorically eligible True, child WIC 59.80 in January and 723.73 in 2026
  taxable_private_pension_income: countable income 60,000 (of which TANF 0), limit 39,128, meets income test False, child categorically eligible False, child WIC 0.00 in January and 0.00 in 2026
HUD: Ohio tenant aged 50 with $30,000 of retired pay and $12,000 of rent, in assisted housing
  hud_annual_income: military_retirement_pay 0.00, taxable_private_pension_income 30,000.00
  hud_adjusted_income: military_retirement_pay 0.00, taxable_private_pension_income 30,000.00
  hud_ttp: military_retirement_pay 25.00, taxable_private_pension_income 9,000.00
Head Start: Ohio parent aged 30 with $60,000 of retired pay, child aged 4
  military_retirement_pay: gross income 0, poverty guideline 21,640, child income eligible True, child eligible True
  taxable_private_pension_income: gross income 60,000, poverty guideline 21,640, child income eligible False, child eligible False
North Dakota TANF: parent aged 40 with $24,000 of retired pay, child aged 8
  military_retirement_pay: parent's gross unearned income in January 0.00, TANF in January 739.00
  taxable_private_pension_income: parent's gross unearned income in January 2,000.00, TANF in January 0.00
CSFP: couple aged 67 and 65 with $30,000 of Social Security and $45,000 of retired pay
  military_retirement_pay: Ohio countable income 30,000, income-to-poverty ratio 1.386, CSFP 651 and 651; both spouses get CSFP in 47 of 51 states; neither or one in ['IL', 'KS', 'MA', 'TX']
  taxable_private_pension_income: Ohio countable income 75,000, income-to-poverty ratio 3.466, CSFP 0 and 0; both spouses get CSFP in 0 of 51 states; neither or one in ['AK', 'AL', 'AR', 'AZ', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'GA', 'HI', 'IA', 'ID', 'IL', 'IN', 'KS', 'KY', 'LA', 'MA', 'MD', 'ME', 'MI', 'MN', 'MO', 'MS', 'MT', 'NC', 'ND', 'NE', 'NH', 'NJ', 'NM', 'NV', 'NY', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VA', 'VT', 'WA', 'WI', 'WV', 'WY']

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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