Skip to content

Subtract Mississippi's HSA deduction once, from the account holder - #9865

Merged
MaxGhenis merged 3 commits into
mainfrom
fix-ms-hsa-adjustment-double-count
Oct 7, 2026
Merged

MaxGhenis merged 3 commits into
mainfrom
fix-ms-hsa-adjustment-double-count

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Mississippi subtracted a tax unit's health savings account deduction from every member's income. ms_agi_adjustments is a Person variable whose adds list held the TaxUnit variable health_savings_account_ald, and policyengine-core maps a group value onto a person target by copying it to each member (Simulation.map_result). A couple therefore subtracted the deduction twice, and each dependent with income once more (their Mississippi net income goes to the head's AGI). Reported in #9801's hand-off as a pre-existing follow-up.

The law

  • Whose deduction. Miss. Code Ann. § 71-9-11(3) excludes the principal contributed to and the interest earned on a health savings account "from the taxable gross income of the account holder under Section 27-7-15" (H.B. 1213 (2005) § 2). The account holder is the individual "for whose benefit" the account is established (§ 71-9-3(b)).
  • Where it goes. Form 80-105 reports adjustments in Column A (Taxpayer) and Column B (Spouse), with an HSA deduction line (2022 form, line 59). The 2025 instructions say a combined return puts each spouse's income in their own column and separates incomes "throughout the return" (pp. 5–6), and the HSA line takes "the amount deposited into a health savings account" (p. 13).
  • Dependents. A dependent has no HSA deduction on this return, and none of their own under 26 USC 223(b)(6).

The change

  • ms_health_savings_account_adjustment (new, Person) attributes the tax unit's health_savings_account_ald to the head and spouse with Keep dependents' above-the-line deductions off the filer's AGI #9801's person_share_of_tax_unit_amount. Each gets their own health_savings_account_ald_person, scaled so the shares sum to the tax unit's deduction. A dependent's share is zero, even if the dependent has their own amount: a dependent who holds an account reports it on their own return.
  • Default without per-person amounts. The head takes the deduction, as for the other tax-unit amounts that helper reconciles. The dataset has no per-person HSA amounts, so every couple in the microsimulation uses this default. Limitation: a head whose Mississippi income is below the deduction loses the excess to ms_agi's zero floor. A YAML case pins this; a per-person amount on the spouse avoids it. Without the account holder's identity, a 50/50 split (the federal per-person AGI convention) is no better grounded in law.
  • health_savings_account_ald_person (new Person input) is each account holder's own deduction. It only splits the deduction: health_savings_account_ald stays the tax-unit input the dataset supplies. Giving that variable a formula would stop core from uprating the 2024 dataset value, because core runs a formula before it uprates.
  • The Mississippi adjustments list uses ms_health_savings_account_adjustment in place of health_savings_account_ald.

Tests

  • YAML. ms_health_savings_account_adjustment.yaml has 9 cases:
    • single;
    • joint without per-person amounts;
    • the spouse's account;
    • two account holders;
    • per-person amounts that differ from the tax-unit total;
    • a dependent with wages and their own account;
    • a married person filing a separate federal return;
    • separate-return columns, with tax computed by hand;
    • the head-default limitation.
  • Property test. tests/core/test_ms_health_savings_account_adjustment_invariants.py runs three Hypothesis batches of 10–40 Mississippi tax units, plus a seeded population of 200. Units are single, married filing separately, head of household, or joint with and without dependents. Dependents may have their own HSA amounts.
  • Fails on main, passes here. On main (bab1a47c60), the joint case gives ms_agi_adjustments [3,000, 3,000] where [3,000, 0] is expected; the dependent case gives [3,000, 3,000, 3,000]. A main-compatible probe of the property test found the deduction counted 2 to 4 times in 120 of 200 seeded units, and total Mississippi AGI reduced by more than the deduction in 89 units (by up to $17,890). On this branch: 0 and 0. All 457 Mississippi YAML cases and test_ald_determinism.py (9/9) pass.
  • Cost. The property test takes 26 s and 1.0 GB peak locally (macOS). It runs in the sequential rest-core Python group (make test-other-python-rest-core), with no new jobs or runners. GitHub Actions has had every recent PR-workflow run queued, so there is no fresh Linux timing or memory report for that group to compare against.

Invariants (for every input)

  1. Conservation. The members' ms_health_savings_account_adjustment sum to the tax unit's health_savings_account_ald, and that deduction appears exactly once in the members' ms_agi_adjustments.
  2. Bounds. No share is negative or above the tax unit's deduction, and a dependent's is zero.
  3. Attribution. When the head's and spouse's own amounts sum to the deduction, each gets their own; without any, the head gets all of it.
  4. Monotonicity. The deduction lowers the members' total Mississippi AGI by at least zero and at most the deduction.

Impact

Real microsimulations on the default dataset (populace_us_2024.h5@populace-us-2024-spm-20260909), one run per checkout and year under the shared heavy lock (lockrun.sh, run.py, compare.py in ~/reviews/pe-us-merge-backlog-2026-10-02/impact/), compared record by record; enum arrays are not compared. Outputs: ~/reviews/pe-us-ms-hsa-qbid-2026-10-06/microsim/. Base: main bab1a47c60; branch head d5e8301b9c.

2025 2026
Mississippi adjustments (ms_agi_adjustments, persons) −$352.2M (31 records, 36,875 people, all down) −$371.4M (31 records, 37,139 people)
Mississippi AGI (ms_agi) +$89.3M (8 records, 14,845 people, all up) +$94.2M
Mississippi income tax +$3.87M (6 records, 9,219 tax units, all up; largest +$506) +$3.71M (9,285 units; largest +$495)
Federal income tax 0 0
health_savings_account_ald unchanged unchanged

The removed adjustments are the extra copies of the deduction on spouses and dependents. Most of those people had too little Mississippi income for the copy to matter, because ms_agi floors at zero, so AGI rises by much less than the adjustments fall. No household's Mississippi tax falls.

Axiom

axiom: TheAxiomFoundation/rulespec-us#1509 queued

Mississippi's HSA exclusion is not encoded, and Miss. Code Title 71 ch. 9 is not in the pinned corpus. Ingesting it is the encoder blocker; signed encoder runs also need Max's approval.

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 6, 2026 07:33
ms_agi_adjustments added the tax-unit health_savings_account_ald to a
person-level sum, so policyengine-core projected it onto every member:
a couple subtracted it twice, and each dependent with income once more.

Mississippi excludes HSA contributions from the account holder's gross
income (Miss. Code Ann. 71-9-11(3)) and Form 80-105 reports each
spouse's adjustments in their own column. The new
ms_health_savings_account_adjustment gives the head and spouse their own
health_savings_account_ald_person amounts, reconciled to the tax unit's
deduction with person_share_of_tax_unit_amount; without them the head
takes it. Dependents take none (26 USC 223(b)(6)).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Roles are inputs so a drawn dependent stays one, and the test runs three
Hypothesis batches and one seeded population (47 s, 1.0 GB locally).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Give the dependent case its own HSA amount and draw dependents' own
  amounts in the property test, so the dependent zeroing is exercised.
- Pin the head default's limitation: a head with less Mississippi income
  than the deduction loses the excess to the AGI floor.
- Drop the property test's re-implementation of the helper; keep the
  conservation, bounds, attribution and AGI-reduction properties.
- Lead the dependent rationale with the return, cite 223(b)(6) second.
- Correct the adjustments-list line comment (line 59) and a test name.

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

Copy link
Copy Markdown
Contributor Author

Hand-off to the US + core hub. Head d5e8301b9c. Only CI remains; it is queued on GitHub's side.

Review (Opus 5.5, subfleet run --task review --tier standard -m opus), in ~/reviews/pe-us-ms-hsa-qbid-2026-10-06/review/:

Round Head Verdict Report
r1 a0b445c APPROVE, with P2/P3 notes review-ms-hsa-r1.md
r2 (delta) d5e8301 APPROVE review-ms-hsa-r2.md
  • The r1 findings were fixed in d5e8301b9c.
  • r1's P2 asked to keep the head default and document its limitation. That is done in the PR body, with a YAML case pinning it.
  • The r2 P3s are a PR-body count (fixed) and two test nits (left as they are): max_examples and an unused dependent keyword.
  • Neither reviewer had a shell, so their checks were by reading. My runs are below.

Passed locally.

  • The new YAML file (9/9).
  • All 457 Mississippi YAML cases, at the first commit.
  • test_ald_determinism.py (9/9).
  • The new property test (26 s, 1.0 GB).
  • On main, the new cases fail and a probe of the property test shows the double count. Evidence is in ~/reviews/pe-us-ms-hsa-qbid-2026-10-06/before-after/.

Microsim (default dataset, lockrun.sh): Mississippi income tax rises $3.87M in TY2025 and $3.71M in TY2026; federal income tax is unchanged. Details are in the PR body; outputs are in .../microsim/.

Axiom: TheAxiomFoundation/rulespec-us#1509, queued (pe-parity). The blocker is that Miss. Code Title 71 ch. 9 is not in the pinned corpus.

No Max decision needed. This is a bug fix that moves aggregates.

Dependencies: none. It touches only Mississippi files and the new health_savings_account_ald_person input. The open branch ms-joint-combine-negative-column (another session) also touches Mississippi; whichever lands second should rebase.

Follow-ups (not in this PR):

@MaxGhenis
MaxGhenis merged commit b7aaf01 into main Oct 7, 2026
35 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

US + core hub merge audit, us#9865 at d5e8301b9ce34ff38a87fe8002bc0900e7d04ac3 (squash)

  • Reviews: independent Opus 5.5 (Subfleet): r1 APPROVE with P2/P3 notes at a0b445c, then delta r2 APPROVE at this head. r1's P2 (keep the head default) is documented and pinned by a YAML case.
  • Hand-off: from local_211e84d0. This is a bug fix that moves aggregates, so no Max decision is needed.
  • Gates checked live at merge:
    • gh pr checks exits 0 (35 pass);
    • MERGEABLE, and merges clean with current main;
    • not a draft;
    • no CHANGES_REQUESTED review;
    • head pinned.
  • Impact: a real microsim on the default dataset. Mississippi income tax rises $3.87M in TY2025 and $3.71M in TY2026, because the HSA deduction is no longer subtracted twice. Federal income tax is unchanged.
  • Follow-ups: Iowa and Mississippi move a dependent's net income onto the head's state return #9887 (Mississippi and Iowa dependent-income transfer); the person-level adds audit chip.
  • --admin: used only because a required approving review is the sole block.

@MaxGhenis
MaxGhenis deleted the fix-ms-hsa-adjustment-double-count branch October 7, 2026 13:10
MaxGhenis added a commit that referenced this pull request Oct 7, 2026
#9865 (HSA deduction from the account holder) and #9885 (combine a negative
Mississippi joint column with the other column) each passed alone; together
the head's AGI column is -2,000 rather than floored at 0, and the joint tax
combines it, so the whole deduction is used. Main has failed this case since
#9865 landed.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 10, 2026
… gets the whole group amount) (#9897)

* Guard against person variables that add group variables

policyengine-core evaluates adds/subtracts with calculate(..., map_to=<the
variable's entity>), and map_result projects a group value onto every member
with no split. A person variable that lists a tax unit or SPM unit variable
therefore gives each member the whole group amount, and a group total counts
it once per member (MT casualty loss #9888, MS HSA #9865, WV senior #9856,
and OH, IL, CA Riverside and LA cases found the same day).

The new code-health test scans the shared baseline system, resolving
parameter-path lists across their whole history. Three boolean enrollment
flags are allowed; the 10 current cases are known bugs that may only be
removed. A premise test pins the projection on core's template country.

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

* Refresh group projection registry and scope boolean exemptions to reviewed edges

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant