Skip to content

Fix Vermont Act 71 retirement exemption stacking - #9196

Open
saisharan0103 wants to merge 1 commit into
PolicyEngine:mainfrom
saisharan0103:mergepath/issue-9146-vt-2025-act-71-lets-the
Open

Fix Vermont Act 71 retirement exemption stacking#9196
saisharan0103 wants to merge 1 commit into
PolicyEngine:mainfrom
saisharan0103:mergepath/issue-9146-vt-2025-act-71-lets-the

Conversation

@saisharan0103

Copy link
Copy Markdown
Contributor

Issue #9146

Vermont Act No. 71 changed 32 V.S.A. § 5830e(e) so the military retirement and survivor benefit exclusion under subsection (d) may be taken in addition to one elected exclusion under subsections (a)-(c). The existing Vermont retirement income exemption formulas still treated post-2025 exclusions as a single max_() choice among Social Security, military retirement, and CSRS/other retirement amounts, then applied the phase-out band selected from that raw winner.

This updates the 2025+ behavior, keyed by p.military_retirement.income_based_structure.in_effect, to calculate the military income-based exemption separately and add it to the best post-phase-out exclusion among Social Security and CSRS/other contributory retirement. Earlier years keep the existing single-election behavior through the same parameter branch.

Eligibility is also updated so the non-military AGI gate applies only to the elected § 5830e(a)-(c) component, while military income can independently keep the variable defined. Nearby Act No. 71 citation comments are corrected.

Modified files:

  • policyengine_us/variables/gov/states/vt/tax/income/adjusted_gross_income/subtractions/retirement_income_exemption/vt_retirement_income_exemption.py
  • policyengine_us/variables/gov/states/vt/tax/income/adjusted_gross_income/subtractions/retirement_income_exemption/vt_retirement_income_exemption_eligible.py
  • policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/agi/subtractions/vt_retirement_income_exemption.yaml
  • policyengine_us/tests/policy/baseline/gov/states/vt/tax/income/agi/subtractions/vt_retirement_income_exemption_eligible.yaml

Diff size: +184 / -27.

…tirement exclusion stack with the §5830e(a)-(c) election; model still forces a single max_() choice

Closes PolicyEngine#9146
@codecov

codecov Bot commented Aug 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (838be3f) to head (6fd1ef4).
⚠️ Report is 14 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #9196   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            2         2           
  Lines           31        89   +58     
=========================================
+ Hits            31        89   +58     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@MaxGhenis

Copy link
Copy Markdown
Contributor

Cross-family dual review (Claude Fable 5 + GPT-5.6-sol, independent). The core direction is right and verified: for Act 71 years the formula now returns the self-phased military exclusion plus the best post-phase-out election among the modeled (a)/(b) options — exactly the correction #9146 asked for — and the changed arithmetic reproduces by hand (e.g. military $30,000 + SS $1,000 × 0.50 at AGI $60,000 = $30,500; live sims confirm no pre-2025 behavior change). Blockers before this can close #9146:

  1. Subsection (c) is still unmodeled. The election in the statute spans (a) Social Security, (b) CSRS, and (c) other-contributory retirement systems; vt_csrs_retirement_pay_exclusion sums only csrs_retirement_pay (documented as federal CSRS only), and no Vermont variable reads any other contributory-pension input. A (c) pension can't qualify or stack. Implement, or rescope with a follow-up issue.
  2. Tests mostly don't pin the corrections. The military+SS stacking case is a real regression test, but the high-AGI cases pass under the old code too, and the "larger post-phase-out" case phases both options by the same 0.50 factor so raw-vs-phased election is indistinguishable. Please add a military+CSRS stacking case and an election case where raw and post-phase-out orderings differ.
  3. Survivor-benefit convention (issue item 2) is unaddressed. The exclusion reads only military_retirement_pay; a household populated via military_retirement_pay_survivors (used by MD/MN/SC) gets no (d) exclusion. Document or wire the intended convention.
  4. Citation cleanup incomplete. csrs/reduction/start.yaml and end.yaml still say "Act No. 51 (2025)" (it's Act 71; Act 51 is S.59), one test comment still says "pre-Act 51", and both changed variable files have a missing comma in the reference tuple, concatenating the statute and IN-112 URLs into one invalid string.

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