Skip to content

Wire military retirement pay and survivors into federal and state tax (#10181) - #10182

Open
jindal-git wants to merge 5 commits into
PolicyEngine:mainfrom
jindal-git:wire-military-retirement-pay
Open

jindal-git wants to merge 5 commits into
PolicyEngine:mainfrom
jindal-git:wire-military-retirement-pay

Conversation

@jindal-git

Copy link
Copy Markdown
Contributor

Closes #10181.

Summary

This PR wires military_retirement_pay and military_retirement_pay_survivors into federal gross income (irs_gross_income), adjusted_gross_income, market_income, SNAP unearned income, and SSI unearned income. It also harmonizes state-level military retirement subtractions and senior pension exclusions so that both retiree pay and military survivor benefits are recognized according to state law.

Why separate variables are kept

  • military_retirement_pay and military_retirement_pay_survivors remain separate variables. In states like North Carolina (G.S. § 105-153.5(b)(5a)) and South Carolina (S.C. Code § 12-6-1170/1171), eligibility and worksheets differ between retiree pay and survivor benefits (a civilian surviving spouse has years_in_military = 0, but qualifies based on deceased spouse's service).
  • Neither variable is merged into taxable_pension_income or taxable_public_pension_income, because 20+ state programs (e.g. Arkansas Form AR1000F line 17 vs 18, Michigan interest/dividends deduction, Nevada CCDP, Oregon LIHEAP, CCAP in multiple states) already list both pension_income and military_retirement_pay side-by-side. Adding military retirement into taxable_pension_income would cause double-counting in those states.

Changes

  1. Federal Gross Income & AGI:

    • Added military_retirement_pay and military_retirement_pay_survivors to policyengine_us/parameters/gov/irs/gross_income/sources.yaml under IRC § 61(a)(11).
    • Added both components to COMPONENTS in policyengine_us/variables/household/income/person/general/market_income.py.
    • Added both components to unearned income sources for SNAP (parameters/gov/usda/snap/income/sources/unearned.yaml) and SSI (parameters/gov/ssa/ssi/income/sources/unearned.yaml).
  2. State Subtraction & Exemption Harmonization:

    • Harmonized state subtraction variables and parameters to include military_retirement_pay_survivors alongside military_retirement_pay:
      • Arkansas: parameters/gov/states/ar/tax/income/gross_income/sources/individual.yaml, joint.yaml, and ar_military_retirement_income_person.py
      • Arizona: variables/gov/states/az/tax/income/subtractions/az_military_retirement_subtraction.py
      • Colorado: parameters/gov/states/co/tax/income/subtractions/pension/income_sources.yaml
      • Connecticut: parameters/gov/states/ct/tax/income/subtractions/subtractions.yaml
      • Georgia: parameters/gov/states/ga/tax/income/agi/exclusions/retirement/sources.yaml
      • Idaho: parameters/gov/states/id/tax/income/deductions/retirement_benefits/income_sources.yaml
      • Iowa: parameters/gov/states/ia/tax/income/taxable_income/subtractions.yaml
      • Louisiana: parameters/gov/states/la/tax/income/exempt_income/sources.yaml
      • Michigan: parameters/gov/states/mi/tax/income/subtractions.yaml
      • Nebraska: ne_military_retirement_subtraction.py (and fixed typo ne_military_retirement_substraction.py -> ne_military_retirement_subtraction.py)
      • New Mexico: nm_armed_forces_retirement_pay_exemption_person.py
      • North Dakota: parameters/gov/states/nd/tax/income/taxable_income/subtractions/sources.yaml
      • Oklahoma: ok_military_retirement_exclusion.py
      • Rhode Island: parameters/gov/states/ri/tax/income/agi/subtractions/subtractions.yaml
      • Utah: ut_military_retirement_credit_eligible.py and ut_military_retirement_credit_potential.py
      • Virginia: va_military_benefit_subtraction_person.py
      • Vermont: vt_military_retirement_pay_exclusion.py, vt_military_retirement_cap_based_exemption.py, vt_military_retirement_income_based_exemption.py, and vt_retirement_income_exemption_eligible.py
      • West Virginia: parameters/gov/states/wv/tax/income/subtractions/subtractions.yaml and senior_citizen_disability_deduction/modification_sources.yaml
  3. Tests:

    • Added new federal YAML tests in tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/military_retirement_pay.yaml verifying irs_gross_income, adjusted_gross_income, market_income, snap_unearned_income, ssi_unearned_income, and dependent exclusion.
    • Added California test in tests/policy/baseline/gov/states/ca/tax/income/ca_taxable_income.yaml confirming state taxation through federal AGI.
    • Updated existing baseline tests in NC (nc_military_retirement_deduction.yaml) and VT (vt_retirement_income_exemption.yaml) that previously supplied workaround taxable_public_pension_income or higher wages to compensate for lack of federal AGI wiring.
    • Core invariant tests in test_dependent_retirement_income_state_invariants.py passed across 2025 and 2026.
    • All state test suites passed.
    • Zero edits to partner test files under tests/policy/baseline/partners/**.

axiom: needed

@hua7450
hua7450 self-requested a review October 13, 2026 20:25

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

Thanks for taking this on. Putting military_retirement_pay and military_retirement_pay_survivors into federal gross income is right. Military retired pay is taxed as a pension (Pub 525 (2024)), and survivor annuities "must be included in your gross income" (Pub 575 (2024)). The SNAP and SSI placements are right too.

The difficulty is what this does downstream. Before this PR, the pay never reached federal AGI, so every state that starts from federal AGI or taxable income left it untaxed. That happened to be correct wherever the state exempts military retirement, so those states never needed a modeled exclusion. Now the pay reaches their base, and only the states that already had a military subtraction were updated. The survivor additions in AR, AZ, CT, LA, MI (line 11), ND, NM, OK, UT, VA and WV do match state law.

Must fix

1. household_net_income counts the tax on the pay but not the pay

household_market_income sums gov/household/market_income_sources.yaml:3-29, which has neither military input. The PR added them only to the person-level market_income.py:30-31. So household_net_income now subtracts the federal tax and the lost SNAP but never adds the income, while spm_unit_net_income does count it.

Example: a single 60-year-old in TX, 2024, with $30,000 of military_retirement_pay. Federal tax goes from $0 to $1,616, and SNAP goes from $3,495 to $0, but household market income stays $0. household_net_income falls by $5,111 when it should rise by $24,889.

Fix: add both inputs to market_income_sources.yaml, and assert household_net_income in the new federal test.

2. States that exempt military retirement pay now tax it

In each of these states, the pay now enters the state base through federal AGI or gross income and nothing removes it. Unless noted, the examples are a 2025 single filer aged 65 whose only income is $30,000 of the stated input; "law" is the result under that state's rules.

State Law Model now → law Fix
NY Tax Law § 612(c)(3)(ii); IT-201 line 26 "(including the military)" $1,045 → $0 Add both inputs to ny/tax/income/agi/subtractions/sources.yaml
IL 35 ILCS 5/203(a)(2)(F); Pub 120 "military plans" $1,294.43 → $0 Add both to il/tax/income/base/subtractions.yaml
MA c. 62 § 2(a)(2)(E): uniformed-services retired pay and SBP $1,245 → $0 Subtract both in ma_gross_income.py next to public_pension
PA PA-40 instructions: "Military pension benefits" not taxable; SBP to a beneficiary $921 → $0 Add both to pa/.../nontaxable_income_sources.yaml; add survivors to the forgiveness eligibility income
KY KRS 141.019; Schedule P excludes up to $31,110 $1,029.20 → $0 Include both in the pension amount at ky_pension_income_exclusion.py:16
KS K.S.A. 79-32,117(c)(vii) $852.02 → $0 Add both in ks_agi_subtractions.py:29-41; update the proxy comment
IN IC 6-3-2-4, deductible in full, incl. surviving spouse (IB 27) $825 plus county tax → $0 Add a deduction for both inputs; mind double claims via in_other_deductions
HI HRS § 235-7(a)(2)-(3); N-11 line 13 about $815 before credits → $0 Add both to both blocks of hi/tax/income/subtractions/subtractions.yaml
WI Wis. Stat. § 71.05(1)(am); Schedule SB line 12 names SBP $604.62 → $0 Add both to both blocks of wi/tax/income/subtractions/sources.yaml
MO RSMo 143.121.3(12) (MO-A line 10); SBP qualifies for the public pension exemption $392.46 → $0 Add the pay to agi_subtractions.yaml; add survivors to the Section A public pension amount
OH R.C. 5747.01(A)(23): uniformed-services retired pay and SBP $314.63 → $0 Give oh_uniformed_services_retirement_income_deduction a formula (head/spouse), still overridable
ME 36 M.R.S. § 5122(2)(M-2): includes "the surviving spouse"; instructions "including survivor benefits" survivors: $455.30 → $0 Read both inputs at me_pension_income_deduction.py:40
DC D.C. Code § 47-1803.02(a)(2)(N)(ii): survivor benefits at 62+ (D-40 line 12) survivors: $580 → $0 Add a survivors-at-62+ subtraction to dc/tax/income/subtractions/sources.yaml
DE 30 Del. C. § 1106(b)(3)b: up to $12,500 of U.S. pensions at 60+, incl. a deceased taxpayer's $742 → $125 Add both inputs to the 60+ income basket; treat survivors under 60 as a pension
MD § 10-209(d)(1) and Worksheet 13A: pay above the § 10-207(q) cap counts toward the 65+ pension exclusion $50,000 of pay: $694.11 → $0 Pass the excess above the military cap into md_pension_subtraction_amount
CA R&TC §§ 17132.9–17132.10: up to $20,000 each of retired pay and SBP, 2025–2029, federal AGI ≤ $125,000 single / $250,000 joint wages $60,000 plus $20,000 pay: about $1,555 too much Model the exclusion with its AGI limits; add a 2025 test (the new CA test is 2024 only)
MN 290.091 subd. 2(a)(iv) removes the subd. 21 military subtraction from AMT income $100,000 of pay: AMT $1,921.05 → $0 Add mn_military_pension_subtraction to AMT_SUBTRACTIONS
OR ORS 316.157(2)(e)(C): military pay is pension income for the retirement income credit $15,000 of pay: $396.14 before refundable credits → $0 Include both inputs in line 1 of or_retirement_credit.py (taxing the pay itself is right)
NJ NJ-1040 lines 37a–37c test NJ gross income, which excludes military pensions wages $185,000, pay $30,000 and a $10,000 529 deposit: deduction lost, about $637 Test nj_agi instead of federal AGI in nj_529_deduction.py:21-22; can be a follow-up

Montana (MCA 15-30-2120(3)(n)) and North Carolina (the years_in_military default) are under "Should fix".

3. Survivor changes that don't match state law, and Iowa 2023

  • CO: co_pension_subtraction_indv.py:32,40 gives filers under 55 only pension_survivors. Book 104 line 4 lets a secondary beneficiary under 55 subtract up to $20,000 (Book 104 (2025)).
    • Example: wages $40,000 plus $18,000 of SBP at age 45 now owes $792 more.
    • Fix: use pension_survivors + military_retirement_pay_survivors in that branch.
  • ID (2025+): survivors were added only to the 2021–2024 list, and id_military_retirement_deduction.py:20 reads only the retiree's pay. Idaho Code 63-3022A(1)(b) covers "the unremarried widow or widower".
    • Example: $20,000 of SBP gives $1,060 too much tax.
    • Fix: add survivors to id_military_retirement_deduction.
  • VT (2022–2024): survivors now feed the $10,000 cap path and the eligibility gate in every year. 32 V.S.A. 5830e(d) covered only "U.S. military retirement income" until Act 71 (S.51) added survivor benefit income from 2025.
    • Example: TY2024, $10,000 of SBP is exempted, so tax is about $335 too low.
    • Fix: gate survivors on income_based_structure.in_effect.
  • NE (2021): ne_military_retirement_subtraction.py:26-41 adds survivors with no year gate. Form 1040N-MIL says the pre-2022 election excludes "annuity payments to a spouse, former spouse, or child".
    • Example: TY2021, $20,000 of SBP gives an $8,000 subtraction instead of $0.
    • Fix: add a dated survivor-eligibility parameter, true from 2022.
  • IA (2023): the 2021-01-01 block of ia/tax/income/taxable_income/subtractions.yaml has neither input. Iowa Code 422.7(20)-(21) exempted both since 2014; only the form line moved in 2024.
    • Example: TY2023, age 50, $30,000 of pay now owes $713.23 instead of $0.
    • Fix: add both inputs to that block, and correct the "added in 2024" comment.

4. Georgia excludes the same military dollars twice

ga/tax/income/agi/exclusions/retirement/sources.yaml:31-32 adds the full military pay to the retirement-exclusion income. ga_military_retirement_exclusion_person already excludes up to $35,000 of it for filers under 62.

Ga. Comp. R. & Regs. r. 560-7-4-.02(3) says "Only retirement income that is included in Georgia taxable income shall be included when computing the retirement income exclusion".

Example: 2025, disabled single filer aged 50, $60,000 of wages and $40,000 of pay.

  • Exclusions are $70,000 instead of $45,000.
  • Tax before credits is $934.20 instead of $2,231.70.

Fix: count only the pay left after ga_military_retirement_exclusion_person, plus survivor pay.

Should fix

  • Input definitions overlap.
    • military_retirement_pay.py:10 says "including survivor benefits", yet a separate survivors input exists.
    • The survivors label says surviving spouses, but the new test gives it to an 18-year-old dependent.
    • Neither says whether it is the taxable 1099-R amount, net of the SBP cost reduction, CRSC and the § 104 disability portion.
    • Where SBP is entered changes state results. For example, Maine deducts SBP entered as retired pay but not as survivors.
    • Suggest: define retired pay as the retiree's own taxable pay, and survivors as SBP/RCSBP annuities to any annuitant. Point CRSC and VA DIC to veterans_benefits.
  • MI: the PR puts survivors on Schedule 1 line 11, but the worksheets that reduce limits by line 11 still read only military_retirement_pay. These are mi_standard_deduction_tier_two.py:35, ..._tier_three.py:34, the tier one, expanded and tier three retirement worksheets, and mi_interest_dividends_capital_gains_deduction.py:37.
    • Example: TY2025, born 1950, $20,000 of SBP and $20,000 of interest. The model gives $0 tax; the law gives $603.50.
  • RI (TY2021–2022): the (c)(9) pension modification sources leave out military pay, which RI Pub 2024-01 says qualifies. The (c)(11) military line starts in 2023.
    • Fix: add both inputs to the (c)(9) sources for 2021–2022 only.
  • MT (2024+): MCA 15-30-2120(3)(n) subtracts the lesser of Montana earned income and 50% of military pay, plus up to 50% of SBP, for qualifying residents. It isn't modeled.
    • Example: with $20,000 of Montana wages, the model gives $967.73 instead of $262.73.
    • Fix: model it with an explicit residency assumption, or document it as a limitation.
  • NC: the deduction logic matches G.S. 105-153.5(b)(5a). But years_in_military and the survivor flag default to 0 and false, so pay entered alone is now taxed: $733.13 instead of $0.
    • Suggest: document on the military inputs that NC needs the service record.
  • Tests:
    • The new federal file doesn't use the Case N, description. / person1 conventions, and it uses absolute_error_margin: 1.
    • Cases 1–2 mention taxable income but don't assert it.
    • No case asserts household_net_income.
    • Please add a survivors case for each changed state.

Minor

  • Pensions are § 61(a)(10) since P.L. 115-97, not (a)(11) (new test header). The Pub 525 and Pub 575 pages above would be good references for sources.yaml.
  • The new CA case uses 5,363, the 2023 deduction; the 2024 value is 5,540.
  • The changelog fragment describes only the federal wiring. It omits the state survivor additions, the CO and GA source changes and the NE file rename.

@jindal-git

Copy link
Copy Markdown
Contributor Author

Thank you @hua7450 for the thorough and detailed review! We have addressed all points raised across federal wiring, state calculations, survivor benefits gating, and test conventions in the latest commit:

1. State Law & Exclusions Missing

  • Indiana (IN): Implemented in_military_retirement_deduction.py and parameters base.yaml / excess_rate.yaml under IC 6-3-2-4 (,250 + 75% excess for 2021; 100% deduction for 2022+); wired into in/tax/income/deductions/deductions.yaml; added unit tests in in_military_retirement_deduction.yaml. Cleaned up docstring in in_other_deductions.py.
  • California (CA): Implemented ca_military_retirement_exclusion.py with parameters cap.yaml ($20,000 per recipient) and agi_limit.yaml ($125k single / $250k joint) for TY 2025–2029 under R&TC §§ 17132.9–17132.10; wired into ca/tax/income/agi/subtractions.yaml. Fixed 2024 CA standard deduction to $5,540 and added 2025 test case in ca_taxable_income.yaml.
  • Hawaii (HI): Added military_retirement_pay and military_retirement_pay_survivors to hi/tax/income/subtractions/subtractions.yaml (Haw. Rev. Stat. § 235-7(a)(3)); added test cases in hi_subtractions.yaml.
  • Wisconsin (WI): Added both inputs to wi/tax/income/subtractions/sources.yaml (Wis. Stat. § 71.05(1)(am), Schedule SB line 12); added test in wi_military_retirement_subtraction.yaml.
  • Missouri (MO): Added military_retirement_pay to mo/tax/income/subtractions/agi_subtractions.yaml (RSMo 143.121.3(12) / MO-A line 10) for direct deduction, and added military_retirement_pay_survivors to public pension in mo_pension_and_ss_or_ssd_deduction_section_a.py; added test in mo_pension_and_ss_or_ssd_deduction_section_a.yaml.
  • Ohio (OH): Implemented formula in oh_uniformed_services_retirement_income_deduction.py summing head and spouse's military retirement and survivor pay (R.C. 5747.01(A)(23)); added tests in oh_uniformed_services_retirement_income_deduction.yaml.
  • Maine (ME): Updated me_pension_income_deduction.py to include survivor pay alongside military retirement pay under 36 M.R.S. § 5122(2)(M-2); verified in me_pension_income_deduction.yaml.
  • District of Columbia (DC): Implemented dc_survivor_benefits_subtraction.py with parameter min_age.yaml (62) for D-40 line 12 under D.C. Code § 47-1803.02(a)(2)(N)(ii); added tests in dc_survivor_benefits_subtraction.yaml.
  • Delaware (DE): Added both inputs to de/tax/income/subtractions/exclusions/pension/income_sources.yaml (60+ pension exclusion) and in de_pension_exclusion.py included both in eligible_pension_income so under-60 survivors receive the $2,000 cap under 30 Del. C. § 1106(b)(3)b; added tests in de_pension_exclusion.yaml.

2. Worksheets & Edge Cases

  • Maryland (MD): In md_pension_subtraction_amount.py, routed military retirement income in excess of the § 10-207(q) military cap into peninc for the general pension subtraction under Md. Code Tax-General § 10-209(d)(1) and Worksheet 13A.
  • Minnesota (MN): Added mn_military_pension_subtraction to AMT_SUBTRACTIONS in mn_amt_taxable_income.py (Minn. Stat. § 290.091 subd. 2(a)(iv)).
  • Oregon (OR): Included military_retirement_pay and military_retirement_pay_survivors in or_retirement_credit.py Line 1 retirement income (ORS 316.157(2)(e)(C)).

3. Survivor Benefits (SBP/RCSBP) Gating & Timing

  • Colorado (CO): In co_pension_subtraction_indv.py, included military_retirement_pay_survivors with pension_survivors under C.R.S. § 39-22-104(4)(f).
  • Idaho (ID): In id_military_retirement_deduction.py, included survivor pay under Idaho Code § 63-3022A(1)(b).
  • Vermont (VT): Gated survivor benefits in vt_retirement_income_exemption_eligible.py and vt_military_retirement_cap_based_exemption.py to 2025+ under 32 V.S.A. § 5830e(d) (Act 71 / S.51), while maintaining the retiree exemption for earlier years.
  • Nebraska (NE): Created parameter survivors_eligible.yaml (true from 2022) and gated ne_military_retirement_subtraction.py per Form 1040N-MIL.
  • Iowa (IA): Added both inputs to the 2021-01-01 block of ia/tax/income/taxable_income/subtractions.yaml under Iowa Code § 422.7(20)-(21).
  • New York (NY), Illinois (IL), Massachusetts (MA), Pennsylvania (PA), Kentucky (KY), and Kansas (KS): Verified / updated statutory exclusions for both military retirement pay and survivor pay.

4. Georgia Double-Exclusion Fix

  • Removed military_retirement_pay from ga/tax/income/agi/exclusions/retirement/sources.yaml and updated ga_retirement_income_exclusion_retirement_income.py to include only pay remaining after the under-62 exclusion (ga_military_retirement_exclusion_person) plus survivor pay, preventing double-counting per Ga. Comp. R. & Regs. r. 560-7-4-.02(3).

5. Definitions, Worksheets & Tests

  • Input Definitions & Docstrings: Clarified in military_retirement_pay.py and military_retirement_pay_survivors.py that these represent taxable amounts under IRC § 61(a)(10) and 10 U.S.C. §§ 1447–1455 net of SBP cost reductions, pointing CRSC/VA DIC to veterans_benefits, and noted NC service tenure requirements.
  • Michigan (MI): Updated all 6 worksheets reducing limits by Schedule 1 line 11 to include both military retirement and survivor pay.
  • Rhode Island (RI): Added both inputs to (c)(9) pension modification sources for 2021–2022 (pre-2023 separate exemption).
  • Tests: Reformatted military_retirement_pay.yaml to standard Case N, description. and person1 conventions, asserted exact values for taxable_income and household_net_income, removed error margins, and added survivor test cases across affected states.
  • Changelog: Updated changelog.d/wire-military-retirement-pay.fixed.md with all federal and state changes.

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

Thanks for working through the whole list. Almost all of the first review is fixed at 10199be03c: 25 of the 26 must-fix items, plus the MI, RI and test-convention items. I traced each fix from the input to the final state tax:

  • Federal and household: household net income; the MN AMT.
  • Exclusions and subtractions: CA (single filers), HI, IL, IN, KS, NY, MA, MO, PA, WI, KY, OH, DC, DE, MD (65+), ME.
  • Credits: the OR credit.
  • Survivors: CO, ID, IA 2023, VT and NE.
  • Georgia: the double exclusion.

The head and spouse gating in 10199be03c also matches state law. A few of the fixes have side effects, and New Jersey is still open.

Must fix

1. California: the exclusion is capped per spouse instead of per return

ca_military_retirement_exclusion.py:27-32 caps each spouse's pay at $20,000 and then adds them, so a joint return can exclude $40,000 of retired pay, and another $40,000 of SBP. FTB says the exclusion is "not to exceed $20,000 for each type of payments … The exclusion is capped at $20,000 for a surviving spouse, spouses filing a joint return, and any other individual". Sources: the 2025 Schedule CA (540) instructions, line 5a/5b, and FTB Pub 1032 (2025).

Example: 2025, joint return, both spouses 62, each with $60,000 of military_retirement_pay. The model excludes $40,000 and gives $1,471.38 of tax before credits. Excluding $20,000 gives $2,385.06, so California tax is $913.68 too low.

Fix: cap each payment type on the tax unit's total, and update the "per category per person" description in cap.yaml.

2. Pennsylvania: tax-forgiveness eligibility income now counts military pension

pa/tax/income/forgiveness/eligibility_income_sources.yaml:11-12 adds military_retirement_pay. Schedule SP says "Do not include the following types of nontaxable income in Line 10 … Military pension benefits" (2025 PA-40 instructions). Survivor annuities (Code 7, line 4) are correctly included.

Example: 2025, single, age 65, $30,000 of pension and $5,000 of wages. Eligibility income should be $5,000, which gives full forgiveness and $0 tax. The model counts $35,000, gives no forgiveness, and charges $153.50.

Fix: remove military_retirement_pay from that list.

3. Massachusetts: the Senior Circuit Breaker now leaves out military pay

Excluding the pay from ma_gross_income (the earlier fix) also drops it from ma_scb_total_income. § 6(k)(1) adds pensions back: total income is AGI "increased by, to the extent they are excluded or subtracted from adjusted gross income … retirement, pension, or annuities".

Example: 2025, single, age 65, renter paying $12,000, with $30,000 of pay. The credit is $2,820 instead of $70.

Fix: add both inputs to ma/.../senior_circuit_breaker/income/disallowed_deductions.yaml.

4. Georgia 2021: a military exclusion that didn't exist yet reduces the retirement exclusion

ga_retirement_income_exclusion_retirement_income.py:28-30 now subtracts ga_military_retirement_exclusion_person before computing retirement income. The military exclusion parameters (military_retirement/base.yaml, additional/amount.yaml) start in 2022 with no earlier value, so 2021 picks up the 2022 amount. Georgia's 2021 subtraction list doesn't include that exclusion.

Example: TY2021, disabled filer aged 50, $30,000 of pay. The retirement exclusion becomes $12,500 instead of $30,000, and Georgia tax is $414 instead of $0.

Fix: add 2021-01-01: 0 to both parameters.

5. Maryland: wrong cap age for disabled filers aged 55–64

md_pension_subtraction_amount.py:17-18,30-35 computes the excess over the military cap using the pension exclusion's age of 65. The military subtraction itself (md_military_retirement_subtraction.py:34-40) switches caps at 55. So for a disabled filer aged 55–64, the excess is measured against $12,500 after $20,000 was already subtracted. § 10-209(d)(1) bars counting military income "included in the subtraction under § 10–207(q)".

Example: 2024, single, age 60, disabled, $40,000 of pay and $30,000 of wages. Military-related subtractions total $47,500 against $40,000 of pay. That is $7,500 too much, or $10,000 in 2021–2022.

Fix: compute each person's capped military subtraction once, and subtract that amount here.

6. New Jersey 529 deduction (still open from the first review)

nj_529_deduction.py:21-22 still tests federal adjusted_gross_income against the $200,000 limit. The NJ-1040 instructions use NJ gross income, "If your gross income was $200,000 or less" (2025 NJ-1040 instructions). NJ gross income excludes "United States military pensions and survivor's benefit payments" (same booklet, page 10).

Example: 2025, single NJ resident, $185,000 of wages, $30,000 of pay and $10,000 of investment_in_529_plan_indv. The model denies the deduction, so NJ tax is $637 too high.

Fix: test nj_agi, which is NJ-1040 line 29, instead of federal AGI.

Should fix

  • Tests for this round's fixes. These paths have no test setting the input each fix touches:

    • GA, IL, KS, KY, MA, MD, MN AMT, MO line 10, NY, OR and PA;
    • CO under 55, ID 2025+ survivors and IA 2021–23;
    • the seven MI worksheets, NE 2021, RI 2021–22 and VT 2022–24.

    Several of the problems above would have shown up as test failures. Please add one case per changed formula or list, plus NE 2021/2022 and VT 2024/2025 boundary cases.

  • CA exclusion tests. The only test is one single filer at $60,000 AGI. Please add:

    • the AGI cliff, using "does not exceed": $125,000 excludes and $125,001 doesn't;
    • a joint return at $250,000;
    • a dependent recipient;
    • a 2030 case;
    • the joint case from item 1.
  • The federal test locks in a food-package benefit the filer isn't eligible for. Case 1's household_net_income: 28_915 includes $531 of CSFP. That's because gov/usda/school_meals/income/sources.yaml omits military pay, while 7 CFR 247.9(d)(1) uses gross income. The correct value is 28,384.

    • Please either assert the components instead of the net figure, or use an age under 60 as Case 3 does.
    • The school-meal income list can be a separate PR.
  • The same "head plus spouse military pay" sum is repeated. This round adds 17 inline sums (DE, ID, IN, KS, KY, MA, MD, ME, OH, OR and the seven MI worksheets) and 10 parameter lists. A single person-level adds variable combining the two inputs would let these name one variable. States that treat survivors differently would keep reading the separate inputs: CA (a separate cap per type), CO under 55, NE, VT, GA, DC, NC and MO.

  • Parameter metadata.

    • These files have no label:
      • ca/.../military_retirement/cap.yaml and agi_limit.yaml;
      • dc/.../survivor_benefits/min_age.yaml;
      • in/.../military_retirement/base.yaml and excess_rate.yaml.
    • Values need underscores (125_000), and 1.0 should be 1.
    • The CA files cite §§ 17132.9 and 17132.10, but link only 17132.9.
  • NE survivors_eligible.yaml. Its reference titled "2021 Form 1040N-MIL" links to the 2021 booklet page, which says nothing about survivors. Please cite Form 1040N-MIL for the false value and Information Guide 8-364 for the 2022 value.

  • Input definitions, partly done. The "including survivor benefits" overlap is removed from the docstrings. Still needed:

    • Say that both inputs are the taxable amount, meaning after the SBP premium reduction, excluding CRSC and the § 104 disability portion (Pub 525 (2024)).
    • Point CRSC and VA DIC to veterans_benefits.
    • Relabel the survivors input: it still says "paid to surviving spouses", but Case 4 is an 18-year-old annuitant.
    • Two NC files still say military_retirement_pay can hold survivor benefits "as its documentation permits": nc_military_retirement_deduction.py:41-43 and nc_military_retirement_survivor_eligible.py:22-23.
  • Montana (MCA 15-30-2120(3)(n)) and the NC service-record default are still open from the first review. Documenting them as known limitations is fine.

Minor

  • The changelog's state list leaves out WI, which has non-test changes.
  • in_military_retirement_deduction.py:33 repeats the head_or_spouse gate.
  • ne_military_retirement_subtraction.py:27-30 can multiply by p.survivors_eligible.
  • The 2021 and 2024 IA subtraction lists are now identical, so the 2024 block can go.
  • The NY sources file dropped the note that taxable_public_pension_income is a proxy.
  • The DE "capped at 2,000" test uses $1,500, so it never reaches the cap.
  • Several test files end with extra blank lines.

…PolicyEngine#10181)

- Add military_retirement_pay and military_retirement_pay_survivors to federal irs_gross_income sources
- Add military_retirement_pay and military_retirement_pay_survivors to market_income, SNAP unearned income, and SSI unearned income
- Harmonize state military retirement subtractions and senior pension exclusions to include military_retirement_pay_survivors (AZ, AR, CO, CT, GA, IA, ID, LA, MI, ND, NE, NM, OK, RI, UT, VA, VT, WV)
- Fix typo in ne_military_retirement_subtraction filename
- Add YAML test for federal gross income, AGI, market income, and SNAP/SSI unearned income
- Add CA taxable income test verifying military retirement pay inclusion
- Update NC and VT baseline tests to reflect wiring into AGI
- Add changelog fragment
@jindal-git
jindal-git force-pushed the wire-military-retirement-pay branch from 10199be to 6e7667f Compare October 15, 2026 19:40
@jindal-git

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough second review @hua7450! We have addressed all the feedback and cleanly rebased on origin/main (9560e7f183, picking up the test infrastructure improvements in #10231 and #10201).

Must-Fix

  1. California joint cap:
    • Updated ca_military_retirement_exclusion.py to evaluate the $20,000 cap separately per type (retiree pay vs. survivor benefits) across the return under R&TC §§ 17132.9(c) and 17132.10(c).
    • Added labels, underscores (125_000, 250_000), and the R&TC § 17132.10 statutory link in cap.yaml and agi_limit.yaml.
  2. Pennsylvania tax forgiveness:
    • Removed military_retirement_pay from pa/.../forgiveness/eligibility_income_sources.yaml while retaining survivor benefits per PA-40 SP.
    • Added pa_eligibility_income.yaml test verifying military pension exclusion and survivor benefit inclusion.
  3. Massachusetts Senior Circuit Breaker:
    • Added both inputs to ma/.../senior_circuit_breaker/income/disallowed_deductions.yaml.
    • Added tests in ma_gross_income.yaml and ma_scb_total_income.yaml testing exclusion under § 2(a)(2)(E) and re-addition under § 6(k)(1).
  4. Georgia pre-2022 exclusion:
    • Added 2021-01-01: 0 to ga/.../military_retirement/base.yaml and additional/amount.yaml (HB 1064 effective 2022-01-01).
    • Added 2021 and 2024 test cases to ga_retirement_income_exclusion_retirement_income.yaml.
  5. Maryland § 10-209(d)(1) excess:
    • Created person-level md_military_retirement_subtraction_amount.py which switches caps at age 55 under § 10-207(q).
    • Updated both md_military_retirement_subtraction.py and md_pension_subtraction_amount.py to reference it once, preventing double-subtraction for disabled filers aged 55–64. Added test case in md_pension_subtraction_amount.yaml.
  6. New Jersey 529 deduction:
    • Updated nj_529_deduction.py to test nj_agi (NJ-1040 line 29) against the $200,000 limit rather than federal AGI. Added test case in nj_529_deduction.yaml.

Shared Person-Level Adds Variable

  • Created military_retirement_income.py (adds = ["military_retirement_pay", "military_retirement_pay_survivors"]).
  • Replaced 17 repeated inline sums (DE, ID, KS, KY, MA, MD, ME, OH, OR, market_income, and all 7 MI worksheets) and 10 parameter lists (market_income_sources, HI, IL, IA, NY, PA forgiveness & nontaxable, RI, WI, DE, MA) with military_retirement_income.

Should-Fix & Minor Improvements

  • CA Tests: Added test cases in ca_taxable_income.yaml for $125,000 vs. $125,001 AGI cliff, joint return at $250,000, dependent recipient, 2030 sunset, and joint return with retiree pay and SBP benefits.
  • Federal Test: Updated Case 1 & 2 in military_retirement_pay.yaml with household_net_income: 28_384 and age: 55 to avoid CSFP miseligibility.
  • State Test Cases Added:
    • GA (2021 & 2024), IL, KS, KY, MA, MD, MN AMT, MO line 10, NY, OR, PA (pa_eligibility_income.yaml).
    • CO (under-55 survivors), ID (2025+ survivors), IA (2023 subtraction), NE (2021 vs 2022 survivor boundaries), RI (2022 retirement income subtraction), VT (2024 vs 2025 survivor boundary).
    • All 7 MI worksheets now have test cases exercising survivor benefits reducing deductions/caps.
  • Metadata & References:
    • Added labels and underscores to parameter YAML files in CA, DC, IN.
    • Corrected references in ne/.../survivors_eligible.yaml to cite Form 1040N-MIL and Information Guide 8-364.
    • Documented SBP premium reduction, CRSC/VA DIC exclusion (IRC § 104 / Pub 525), relabeled survivors to annuitants, and noted Montana MCA 15-30-2120(3)(n) and NC service record default as known limitations.
    • Removed survivor-holding references in NC files.
    • Fixed duplicate head_or_spouse gate in in_military_retirement_deduction.py, simplified NE survivor multiplier, removed duplicate 2024 IA block, restored NY proxy note, updated DE cap test to $3,000, trimmed trailing blank lines across YAML test files, and added WI to changelog.

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.

Wire military retirement pay and survivor benefits into federal pension income and AGI

2 participants