Skip to content

Count military retirement in KS, MS, NC, NJ and NY LIHEAP income - #10409

Open
PavelMakarchuk wants to merge 2 commits into
mainfrom
liheap-military-retirement-ks-ms-nc-nj-ny
Open

PavelMakarchuk wants to merge 2 commits into
mainfrom
liheap-military-retirement-ks-ms-nc-nj-ny

Conversation

@PavelMakarchuk

@PavelMakarchuk PavelMakarchuk commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Five LIHEAP unearned income lists name no military retirement input at all, so a 70-year-old whose only income is $24,000 of military retirement pay, or a military Survivor Benefit Plan (SBP) annuity, has $0 of countable income. Each list counts pension_income, but that adds only taxable_pension_income and tax_exempt_pension_income; military retirement pay is the separate input military_retirement_pay, and an SBP annuity is military_retirement_pay_survivors. military_retirement_income adds both.

This PR adds military_retirement_income to the five lists, with a comment that cites each program's rule:

  • ks/dcf/liheap/income/sources/unearned.yaml
  • ms/mdhs/liheap/unearned_income_sources.yaml
  • nc/ncdhhs/lieap/unearned_income_sources.yaml
  • nj/dca/liheap/income/sources/unearned.yaml
  • ny/otda/heap/income/sources/unearned.yaml

This is item G3 from DTrim99's review of #10317. #10317 switched the lists that named military_retirement_pay and added test_military_retirement_readers.py; that guard cannot catch a list that names neither input. The gap predates #10182. survivor_benefits does not include military_retirement_pay_survivors, so nothing is counted twice.

Rule check for each list

All five FY2026 state plans check "Retirement / pension benefits" in item 1.9 (PDF page 6). Each manual counts pensions or annuities, and no exclusion covers military retired pay or an SBP annuity.

Program Rule
KS LIEAP KEESM 13360 counts "most other income"; 13361 says "Only the following incomes are exempt", and its list has no military retirement or survivor annuity item (it exempts combat pay and named VA payments only).
MS LIHEAP Manual Rule 6.11 C(8) counts "Retirement benefits" (PDF p. 29); F defines unearned income as "all income that is not earned" and lists "Private pensions and annuities" and "civil service annuities ... retirement benefits" (F(2)-(3), PDF p. 31). The D exemptions (PDF pp. 29-30) do not cover them.
NC LIEAP EP-300.09 A (p. 10) takes the income types from FNS 300. The FNS 300.02 chart counts as unearned "Retirement Benefits" from plans set up by "the government or other institutions" (p. 18), "Pensions" (p. 16) and "Annuities" (p. 3). The "Military Pay" row (p. 13) covers active-duty pay items only.
NJ LIHEAP Handbook 2.3.D (FY2026 and FY2027, PDF p. 8) and N.J.A.C. 5:49-2.3(d) count "benefits and pensions, annuities". Handbook 2.3.E.10 (PDF p. 9) excludes "Veteran's benefits"; the plan words that excluded item as "Veterans Administration (VA) benefits" (1.9, PDF p. 7). The Department of Defense, not the VA, pays military retired pay and SBP annuities, so the exclusion does not reach them.
NY HEAP HEAP Manual Chapter 8 D.12(a)(13) counts "Pensions" and (14) "Payments from insurance and annuities" (PDF p. 38); (38) counts all other income not excluded (p. 39). The D.13 exclusions (pp. 39-40) do not cover them.

The NJ row is the one reading a reviewer may want to check: it treats the handbook's veterans' benefits exclusion as limited to VA benefits, as the state plan words it.

Tests

One new case per state, each with two one-person households aged 70: $24,000 military retirement pay and a $9,600 SBP annuity ($800 a month).

File Case Expected
ks/dcf/liheap/income/ks_liheap_countable_income.yaml 12 24,000 and 9,600
ms/mdhs/liheap/ms_liheap_income.yaml 10 24,000 and 9,600
nc/ncdhhs/lieap/nc_lieap_income.yaml 14 gross 24,000 and 9,600; after the $85 a month medical deduction for age 60+, 22,980 and 8,580
nj/dca/liheap/income/nj_liheap_countable_income_person.yaml 9 24,000 and 9,600 (household total too)
ny/otda/heap/income/ny_heap_countable_income.yaml 8 24,000 and 9,600
  • All five new cases fail with the lists on main (5 failed, 48 passed in the five files).
  • With the change: 334 passed in the five LIHEAP folders (KS 133, MS 45, NC 52, NJ 47, NY 57).
  • test_military_retirement_readers.py and test_source_conflicts.py: 107 passed. test_aggregate_list_integrity.py, test_parameter_yaml_keys.py, test_reference_urls.py and test_no_group_variables_in_person_adds.py: 98 passed.
  • No partner contract test reads these programs with military retirement inputs.

Not changed here

  • The KS and MS lists also have no survivor_benefits, although KEESM 13360 and MS Rule 6.11 F count non-Social-Security survivor payments. That is a separate input and a separate gap.

Axiom

axiom: TheAxiomFoundation/rulespec-us#1469, #1467, #1466, #1481 and #1480 queued

These are the queued pe-parity issues for KS, MS, NC, NJ and NY LIHEAP; rulespec-us has no module for any of them yet. Each issue now has a note that adds military retirement income to the request, with the verbatim rule text, the output change, these companion cases and a review_finding addendum: KS, MS, NC, NJ, NY. For NC, rulespec-us already encodes the FNS 300.02 Annuities, Pensions and Retirement Benefits rows (fns-300-sources-of-income/page-3, page-16, page-18).

🤖 Generated with Claude Code

PavelMakarchuk and others added 2 commits October 23, 2026 12:52
The five LIHEAP unearned income lists named neither military retirement
input, so a household whose only income was military retirement pay or a
Survivor Benefit Plan annuity had $0 of countable income. Each program's
rule counts retirement and pension benefits (state plan item 1.9) and its
manual counts pensions and annuities with no exclusion for these payments,
so add military_retirement_income to each list and test both inputs.

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

DTrim99 commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Count military retirement in KS, MS, NC, NJ and NY LIHEAP income

PR #10409 (author: PavelMakarchuk), head ebccea124b. This is a first review. The PR fixes the gap that our #10317 review found (suggestion G3): five merged LIHEAP unearned income lists named no military retirement input, so military retired pay or a Survivor Benefit Plan (SBP) annuity counted $0. It adds military_retirement_income to each list with a comment that cites the state rule, adds one two-household test case per state, and adds a fixed changelog fragment. The PR has no comments or reviews yet, and it touches no partner test file.

Path prefixes:

  • P/ = policyengine_us/parameters/gov/states/
  • T/ = policyengine_us/tests/policy/baseline/gov/states/

Summary

What is right:

There are no critical and no should-address findings. There are four optional suggestions:

  • G1: two remaining LIHEAP-type lists, plus a wider follow-up.
  • G2: the deferred survivor_benefits gap in KS and MS.
  • G3: firmer support for the NJ reading.
  • G4: tidying the rulespec-us comments.

Status.

Critical (must fix)

None.

Should address

None.

Suggestions

G1. Two LIHEAP-type lists outside this PR still name no military retirement input.

  • Where:
    • Texas CEAP, the state's LIHEAP program: P/tx/tdhca/ceap/income/sources.yaml lists pension_income and retirement_distributions but no military input.
    • Riverside County CAP LIHEAP: policyengine_us/parameters/gov/local/ca/riv/cap/liheap/countable_income/sources.yaml lists pension_income only.
  • Effect. The same as G3 in Count military SBP annuities in state benefit income lists #10317: a household whose only income is military retired pay or an SBP annuity has $0 of countable income in these programs. I did not check either program's rule.
  • Wider pattern. On the merged tree, 52 non-tax benefit lists name pension_income but no military retirement input. Examples are HUD annual income, the federal TANF default list, school meals, WIC, Head Start, and many state CCAP and TANF lists. Some omissions may be deliberate.
  • Why only a suggestion. It is outside this PR's stated scope (the five lists from G3), and Count military SBP annuities in state benefit income lists #10317's guard can't catch a list that names neither input.
  • Fix. A follow-up issue listing these files. A guard that requires military_retirement_income wherever pension_income appears would be noisy until those lists are reviewed.

G2. KS and MS still don't count survivor_benefits (the PR body's documented deferral).

  • The rules.
    • KEESM 13360 counts "most other income", and 13361 has no exemption for non-Social-Security survivor payments.
    • MS Rule 6.11 F(2) counts "Private pensions and annuities" (PDF p. 31).
  • The gap. An employer pension survivor annuity entered in survivor_benefits counts $0 in KS and MS LIHEAP. NC, NJ and NY list it.
  • Fix. The body's "Not changed here" section names this gap. Consider linking a tracking issue so it isn't lost.

G3. The NJ reading has firmer support than the PR cites.

  • The regulation. N.J.A.C. 5:49-2.3(e) (LII copy) lists nine kinds of income not considered, and none mentions veterans. Its (d) counts "benefits and pensions, annuities". The veterans' benefits exclusion exists only in the handbook (2.3.E.10).
  • Federal usage.
    • Title 38 of the U.S. Code, "Veterans' Benefits", covers what the VA administers.
    • Military retired pay is paid under 10 U.S.C. chapter 71, and SBP annuities under 10 U.S.C. chapter 73, subchapter II.
  • Fix (optional). Add one clause to the NJ list comment and the rulespec-us Missing MD Two-Income Married Couple Subtraction Worksheet logic #1481 interpretation note. The current comment is already accurate.

G4. Tidy the five rulespec-us companion comments.

Verified correct

State rules (each counts military retired pay and SBP annuities, with no exclusion):

State Counts No exclusion Plan 1.9 "Retirement / pension benefits"
KS LIEAP KEESM 13360: "Countable income includes ... interest earnings and most other income." 13361: "Only the following incomes are exempt". Its military and veterans items are combat pay, Agent Orange, Filipino Veterans Equity, VA UME and spina bifida payments. The October 2024 edition reads the same. Checked: FY2026 p. 6 and FY2025 p. 6 (the list starts 2024-10-01).
MS LIHEAP Rule 6.11 C(8) "Retirement benefits" (PDF p. 29). F(2) "Private pensions and annuities" and F(3) "civil service annuities ... retirement benefits" (PDF p. 31). D(1)-(11) (PDF pp. 29-30). D(7) covers only benefits "that must be excluded by federal law", and no federal law excludes these payments. Checked, p. 6.
NC LIEAP EP-300.09 A (p. 10) takes the income types from FNS 300. The FNS 300.02 chart rows "Retirement Benefits" (plans set up by "the government or other institutions", p. 18), "Pensions" (p. 16) and "Annuities" (p. 3) are all Y / U. The "Military Pay" row (Y / E, pp. 13-14) lists only active-duty items (base pay, allowances, bonuses, combat pay, sea duty and so on), so retired pay isn't treated as earned income. Checked, p. 6.
NJ LIHEAP Handbook 2.3.D, FY2026 (PDF p. 8) and FY2027 (p. 8): "benefits and pensions, annuities". N.J.A.C. 5:49-2.3(d) uses the same words. 2.3.E.10 (p. 9): "Veteran's benefits shall also be excluded". The FY2026 and FY2027 plans leave "Veterans Administration (VA) benefits" unchecked (p. 7), and the regulation has no veterans' exclusion (G3). Checked on p. 6 of the FY2026 and FY2027 plans.
NY HEAP Manual Chapter 8 D.12(a)(13) "Pensions" and (14) "Payments from insurance and annuities" (PDF p. 38), and (38) "All other income not specifically excluded" (p. 39). (11) even counts "Veteran's benefits". D.13(a)(1)-(41) (pp. 39-40). Its only veterans' items are (27) aid and attendance and (29) spina bifida payments. Checked, p. 6.

The PR body's rule table matches these sources, including every page number. I read the NY HEAP Manual (7/1/2021 edition) from the 2026-02-14 Wayback capture, because OTDA's site refuses automated retrieval.

Code (at the head, unchanged on the merged tree):

  • The five lists:
    • P/ks/dcf/liheap/income/sources/unearned.yaml (from 2024-10-01);
    • P/ms/mdhs/liheap/unearned_income_sources.yaml;
    • P/nc/ncdhhs/lieap/unearned_income_sources.yaml;
    • P/nj/dca/liheap/income/sources/unearned.yaml;
    • P/ny/otda/heap/income/sources/unearned.yaml (each from 2025-10-01).
  • How each list is read. Each now has one uncommented - military_retirement_income entry.
    • KS: summed at the SPM unit through adds.
    • MS: max_(add(...), 0) per person.
    • NC: max_(add(...), 0) in nc_lieap_gross_income_person.
    • NJ and NY: per-source max_(..., 0) loops.
    • The variable is Person-level, as the KS SPM-unit adds needs.
  • The comments are accurate.
    • KS: plan 1.9 and KEESM 13361.
    • MS: Rule 6.11 C(8) and F(2)-(3).
    • NC: FNS chart pages 18, 16 and 3.
    • NJ: 2.3.D, 2.3.E.10 and plan 1.9 p. 7.
    • NY: D.12(a)(13)-(14) and D.13.
    • References. The existing reference blocks already cite every page the new comments rely on, so no metadata change is needed.
  • Changelog. changelog.d/liheap-military-retirement-ks-ms-nc-nj-ny.fixed.md is top-level and correctly typed.

Hand-checked expectations (all 18, period 2026, two one-person households aged 70):

Case Output HH1 (24,000 retired pay) HH2 (9,600 SBP) Trace
KS 12 ks_liheap_countable_unearned_income 24,000 9,600 military_retirement_income is the only nonzero source (ssi and ks_tanf are set to 0).
KS 12 ks_liheap_countable_income 24,000 9,600 0 earned + unearned.
MS 10 ms_liheap_income 24,000 9,600 No earnings; unearned max_(24,000, 0); the unit total is floored at 0.
NC 14 nc_lieap_earned_income 0 0 No earned or rental sources.
NC 14 nc_lieap_gross_income_person 24,000 9,600 0 + unearned.
NC 14 nc_lieap_income 22,980 8,580 Share is 1; the work deduction is min_(table, 0) = 0. The medical deduction is 85 × 12 = 1,020 at age 60 or older (EP-300.09 B.4.a, p. 13: "a standard medical deduction of $85, regardless of whether they have an expense"). No other deductions; tanf and childcare_expenses are 0.
NJ 9 nj_liheap_countable_income_person 24,000 9,600 Social Security is 0, so max_(0 − Part B, 0) = 0; unearned 24,000 / 9,600; a qualified member, so no disregard.
NJ 9 nj_liheap_countable_income 24,000 9,600 floor(2,000 + 0.5) × 12 and floor(800 + 0.5) × 12; tanf is 0.
NY 8 ny_heap_countable_income 24,000 9,600 Not excluded (no SSI, not foster); benefits max_(0 − Part B, 0) = 0; floor(2,000) × 12 and floor(800) × 12 (D.14(c), "rounded down to the nearest dollar", p. 43).

Batch checks:

Axiom line assessment

axiom: TheAxiomFoundation/rulespec-us#1469, #1467, #1466, #1481 and #1480 queued. This is valid.

  • Issue state. All five issues are OPEN, labelled enhancement and pe-parity, and last updated 2026-10-24.
  • Dispatch-ready bodies. Each body has module paths, corpus citations, source text, required outputs and companion tests.
  • The companion comments. Pavel posted one on each issue at 2026-10-23 19:39 UTC, a minute after the head commit (19:38 UTC). Each has:
    • the verbatim law;
    • the output and input changes;
    • a two-row companion table that matches the YAML case exactly (KS Case 12, MS 10, NC 14, NJ 9, NY 8);
    • a corpus note and a review_finding addendum.
  • NC. The comment points to the existing rulespec-us modules us-nc/policies/dhhs/fns/fns-300-sources-of-income/page-3, page-16 and page-18, which exist.
  • NJ. The comment flags the 2.3.E.10 reading as an interpretation for source review (see G3).
  • Minor. The "(draft, not merged yet)" wording and the missing head SHA are covered in G4.

CI status

Branch status

Verdict: APPROVE

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

The rules hold for all five states. Each FY2026 plan's item 1.9 counts retirement and pension benefits, and the KEESM, MS Rule 6.11, NC FNS 300.02, NY D.12 and NJ 2.3.D texts count military retirement (NJ's veterans' exclusion is VA-only). military_retirement_income covers retired pay plus SBP with no double count, all 18 expectations hand-check, the five rulespec issues have matching companion rows, and the guards pass on the merged tree. Four suggestions, including TX CEAP and Riverside, which still name no military input. Full report in the comment above.

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