Skip to content

Subtract Michigan premiums once and exclude the first $300 of gambling winnings and gifts (MI-1040CR lines 20, 24, 30 and 31) - #9840

Open
MaxGhenis wants to merge 31 commits into
mainfrom
mi-household-resources-premiums-gambling
Open

MaxGhenis wants to merge 31 commits into
mainfrom
mi-household-resources-premiums-gambling

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Two fixes to Michigan total household resources (mi_household_resources), the income measure for the homestead property tax credit and the home heating credit.

  1. Premiums were subtracted twice for a self-employed claimant. Line 30 subtracts the U.S. Schedule 1 adjustments, which include the self-employed health insurance deduction. Line 31 then subtracted every member's premiums again. The MI-1040CR says line 31 leaves out "any insurance premiums deducted on lines 21 or 30". Example: a self-employed claimant with $50,000 of Schedule C income and $5,000 of premiums lost $10,000 of household resources instead of $5,000. The model gave 36,467.61; the form gives 41,467.61.
  2. The $300 exclusions in MCL 206.510(1)(a) and (b) were missing. Gambling winnings counted in full, where the form counts winnings "over $300" (line 20). Gifts from relatives and friends (financial_assistance) were not counted at all, where the form counts "the value over $300 in gifts" (line 24).

Merge after #9796 (household = claimant and spouse), which itself follows #9790, #9788 and #9801. This branch merges #9796's head 8d494dedec. Until those PRs merge, the diff here includes their commits. This PR's own change is git diff 8d494dedec 7fa23e51f6.

The exclusions apply once to the claimant's and spouse's total, as each form line is one amount for them.

Coordination with #9795. #9795 replaces line 30's list with household_resources_adjustments. Whichever lands second should keep #9795's list as the deductions variable here. Line 31 keeps the premiums deducted on line 30 only while self_employed_health_insurance_ald is in that list, and #9795's list includes it.

The law and the forms

MCL 206.510(1) (https://www.legislature.mi.gov/Laws/MCL?objectName=mcl-206-510):

"Income" means the sum of federal adjusted gross income as defined in the internal revenue code plus all income specifically excluded or exempt from the computations of the federal adjusted gross income. Also, a person who is enrolled in an accident or health insurance plan may deduct from income the amount that person paid in premiums in the tax year for that insurance plan for the person's family. Income does not include any of the following:
(a) The first $300.00 of gifts in cash or kind from nongovernmental sources.
(b) The first $300.00 received from awards, prizes, lottery, bingo, or other gambling winnings.
...
(h) Amounts deducted from monthly social security or railroad retirement benefits for medicare premiums.

The $300 amounts are fixed in the statute and not indexed. The section was last amended effective January 1, 2012 (2011 PA 38 and 172).

2025 MI-1040 book (https://www.michigan.gov/taxes/-/media/Project/Websites/taxes/Forms/IIT/TY2025/MI-1040-Book.pdf). The 2022, 2023 and 2024 books have the same text for each line below, on page 32 or 33:

  • Page 27, what total household resources do not include: "The first $300 from gambling, bingo, lottery, awards, or prizes", "The first $300 in gifts of cash or merchandise received, or expenses paid on your behalf (rent, taxes, utilities, food, medical care, etc.) by parents, relatives, or friends", and "Amounts deducted from Social Security or Railroad Retirement benefits for Medicare premiums".
  • Page 32:
    • Line 20: "Other taxable income includes: awards, prizes, lottery, bingo, and other gambling winnings over $300".
    • Line 21: "Medicare premiums reported on your Social Security or Railroad Retirement statement should be deducted."
    • Line 24: "Enter the value over $300 in gifts of cash or merchandise received, or expenses paid on your behalf (rent, taxes, utilities, food, medical care, etc.) by parents, relatives, or friends."
    • Line 30: "Enter total adjustments from your U.S. Form 1040, Schedule 1." The list includes the "Self-employed health insurance deduction".
  • Page 33, line 31: "Do not include any insurance premiums deducted on lines 21 or 30".

The statute doesn't say whether premiums already deducted in federal AGI can be deducted again. Treasury's line 31 instruction says they can't, and this PR follows the form.

Line mapping

I mapped each model input to its MI-1040CR line before changing anything:

model input before after why
gambling_winnings line 20, in full line 20, over $300 MCL 206.510(1)(b)
miscellaneous_income line 24 (the comment said "gifts") line 20, in full It is in federal gross income (gov.irs.gross_income.sources; 26 CFR 1.61-14), so it is taxable "other income", not a gift (IRC 102 excludes gifts). The $300 in (b) covers only awards, prizes, lottery, bingo and gambling, so it doesn't apply.
financial_assistance ("Cash financial assistance from friends or relatives outside the household") not counted line 24, over $300 These are gifts in cash from nongovernmental sources (MCL 206.510(1)(a)). Gifts are excluded from federal AGI, and total household resources include excluded income.
self_employed_health_insurance_ald (line 30) and health_insurance_premiums (line 31) both subtracted in full line 31 leaves out the head's and spouse's line 30 premiums page 33
Medicare premiums withheld from benefits (line 21) gross social_security on line 21, premiums on line 31 unchanged The form nets them on line 21 and leaves them off line 31. The model keeps gross benefits on line 21 and the premiums on line 31, so they still come off once. A YAML case pins this.

The fix

  • mi_household_resources groups gambling winnings and gifts, like the business and rental groups on lines 16 and 17, and adds each group's amount over its exclusion.
  • New parameters gov.states.mi.tax.income.household_resources_gambling_exclusion and household_resources_gift_exclusion ($300 each, from 2021) cite the statute and the form lines.
  • household_resources.yaml adds financial_assistance (line 24) and moves miscellaneous_income to line 20.
  • Line 31 subtracts every member's premiums, less the self-employed health insurance deduction that line 30 subtracted for the head and spouse, read through the same tax_unit_non_dep_add call. If a reform removes that deduction from the federal list, line 31 keeps the premiums.

Invariants

These hold for every household:

  1. Each premium dollar is subtracted once. Zeroing every member's premiums raises household resources by between 0 and the total premiums, and by exactly that total when household resources were positive.
  2. Gambling winnings. Household resources are non-decreasing in winnings. They don't change while the claimant's and spouse's winnings total at most $300. Above that, when household resources are positive, they rise by the change in winnings over $300.
  3. Gifts. The same as 2.
  4. Line 30 or line 31 doesn't matter. A reform that drops the self-employed health insurance deduction from gov.irs.ald.deductions moves those premiums from line 30 to line 31 and leaves household resources unchanged. Before the fix, it changed them by $5,000 in the example.
  5. Count only the claimant and spouse in Michigan household resources (MI-1040CR lines 14-27, 30 and 31) #9796's form reference (in test_mi_household_resources_members.py) still holds with the new line 20, 24 and 31 rules. is_self_employed is now drawn, so line 30's premium deduction is exercised.

Tests

  • 14 new YAML cases in mi_household_resources.yaml:
    • the $50,000/$5,000 self-employed example;
    • premiums above the deduction's earnings limit;
    • a joint return;
    • Medicare premiums withheld from Social Security;
    • gambling winnings and gifts below, at and above $300, and for a couple;
    • both exclusions together;
    • miscellaneous_income counted in full.
  • New policyengine_us/tests/test_mi_household_resources_exclusions.py: deterministic tests plus Hypothesis properties for invariants 1 to 3 and a reform test for invariant 4 (Hypothesis is a dev extra).
  • test_mi_household_resources_members.py (from Count only the claimant and spouse in Michigan household resources (MI-1040CR lines 14-27, 30 and 31) #9796): the form reference uses the new rules, and financial_assistance (line 24) is among the drawn inputs.

Before the fix, run on #9796's head:

  • YAML: 10 of the 14 new cases fail (the 3 premium cases, 4 gambling, 2 gifts, 1 combined). The 4 that pass are the Medicare case, gifts below and at $300 (gifts were not counted at all), and miscellaneous_income.
  • New property file: all 7 tests fail. Hypothesis shrinks the failures to Schedule C income of $101 with $100 of premiums, which loses $101 of household resources, and to $1 of gambling winnings, which adds $1.
  • The updated members test fails twice (test_spouse_counts_like_the_head, test_properties).

After the fix:

  • YAML: all 53 cases in mi_household_resources.yaml and all 643 in gov/states/mi pass (head 7fa23e51f6).
  • Python: the new property file (8) and the members and losses files (10) pass. tests/code_health (138) passed on c57e5b6216; nothing it checks has changed since.
  • test_exclusions_read_the_parameters raises both exclusions to 500 by reform. With a hard-coded 300 in the formula it fails, as I checked by mutation.
  • ruff format --check and ruff check are clean.

CI cost (local, macOS). test_mi_household_resources_exclusions.py takes 42.5 s wall including import (25.8 s in pytest) at a 2.31 GB peak RSS. It is a top-level tests/ file, so it runs in the Rest suite's remaining group. It covers what YAML can't: for-all-households properties (premiums subtracted once, monotonicity and flatness up to $300) and a reform of gov.irs.ald.deductions.

  • A separate stress run passed with 400 Hypothesis examples for each new property and 150 for the members properties.

Impact

Real microsimulations on the default dataset (populace_us_2024.h5@populace-us-2024-spm-20260909): #9796's head b10ac14936 against this branch at c57e5b6216. The later commits change only tests, comments and #9796's documentation, not a formula. The runs are record by record, with ~/reviews/pe-us-merge-backlog-2026-10-02/impact/lockrun.sh and compare.py, one run at a time under the shared heavy lock.

variable 2024 change 2026 change records changed (2024 / 2026)
mi_household_resources +$308.95M +$316.92M 26 up (82,992 weighted) / 26 up (84,361)
mi_homestead_property_tax_credit ~$0 ~$0 1 down, weight below 1
mi_home_heating_credit −$2.72M −$3.03M 7 down (23,651 / 24,041)
mi_standard_home_heating_credit −$5.22M −$5.05M 7 down
mi_alternate_home_heating_credit 0 0 0
mi_refundable_credits −$2.72M −$3.03M 8 down
mi_income_tax +$2.72M +$3.03M 8 up
household_net_income −$2.72M −$3.03M 8 down (23,651 / 24,042)

The largest change in household resources is $9,600 in 2024 and $10,199 in 2026: a premium that was subtracted twice.

Why the homestead credit doesn't move. Only 4 of the 26 changed records get a homestead credit at all (31,427 weighted tax units in 2024). Three of those are at the 2024 credit cap ($1,800; $1,900 from 2025), and none of the three crosses a phase-out step, so higher household resources don't reduce them. The fourth has weight 0.07: its credit falls from $357.59 to $253.91.

Follow-ups from review r1, not in this PR:

  • Line 31 reads only the direct health_insurance_premiums input. In the default dataset most premiums sit in the split premium variables, so line 31 may miss Medicare and other premiums in the microsimulation.
  • Line 31 doesn't net out the premium tax credit (2025 book, page 33).

Both are in a separate audit task. Two input gaps are documented in the parameters: awards and prizes have no input of their own (entered as miscellaneous_income, they count in full), and line 24's gifts in kind have no input (financial_assistance is cash only).

All of the change comes from the premium fix. The dataset has no gambling_winnings or financial_assistance column, so both are zero in the microsimulation. miscellaneous_income is counted the same way before and after.

axiom: TheAxiomFoundation/rulespec-us#1498 queued (MCL 206.510(1) has no rulespec-us module; the corpus row us-mi/statute/206.510 exists; the signed encoder run needs approval)

🤖 Generated with Claude Code

MaxGhenis and others added 24 commits October 4, 2026 15:13
A filer with capital losses or other capital gains enters capital gain
distributions on Schedule D line 13 (2025 Instructions for Schedule D), so
they net against the losses before the 26 U.S.C. 1211(b) limit on line 21.
The model added distributions (non_sch_d_capital_gains) to gross income and
deducted min(3,000, losses) separately: a 5,000 long-term loss with 3,000 of
distributions gave 0 in AGI instead of -2,000.

- capital_losses_allowed_against_gains (new): losses allowed up to the
  gains in gross income, distributions included (1211(b), first part).
- limited_capital_loss: the net loss up to the limit (1211(b)(1)-(2),
  Schedule D line 21). loss_ald deducts both. This also nets spouses'
  gains and losses on a joint return.
- loss_limited_net_capital_gains (+ person version): Form 1040 line 7a,
  max(-limit, LT + ST + distributions). Net investment income no longer
  adds the distributions separately (Form 8960 line 5a).
- has_qdiv_or_ltcg: qualified dividends, or Schedule D lines 15 and 16
  both above zero (Form 1040 instructions, line 16).
- dependent_taxable_ss_magi: the same netting on the dependent's return.
- dc_self_employment_loss_addition: subtracts both capital parts of
  loss_ald.

Tests: YAML cases with form line comments; grid, Hypothesis property and
monotonicity tests.

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

# Conflicts:
#	policyengine_us/parameters/gov/irs/investment/income/sources.yaml
filer_loss_limited_net_capital_gains (from #9784) now nets the head and
spouse's capital gain distributions with their Schedule D gains and losses
before the 1211(b) limit, and net investment income no longer adds the
distributions separately. The invariant test's reference computation
follows: distributions move from the person-level Form 8960 amounts to
the Schedule D inputs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
capital_losses_allowed_against_gains counts only the capital gains that
gov.irs.gross_income.sources includes, and dependent_taxable_ss_magi nets
distributions only when both sources are listed. Cover both branches with
reforms that drop non_sch_d_capital_gains or capital_gains.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the independent review of #9788:
- mi_household_resources subtracted all above-the-line deductions,
  including the capital loss already netted in the capital gains line
  (MI-1040CR line 30 is U.S. Schedule 1 adjustments only). It now leaves
  out capital_losses_allowed_against_gains and limited_capital_loss. The
  two existing loss-limit cases double counted the loss: 44,000 -> 47,000
  and 47,000 -> 48,500.
- has_qdiv_or_ltcg figures Schedule D lines 15 and 16 over the head and
  spouse, so a dependent's loss cannot switch off the filer's worksheet.
- Distributions are floored at zero per person in every line 7a variable
  (box 2a is not negative), as irs_gross_income does.
- Capital losses are deductible only while capital_gains is a gross income
  source, matching dependent_taxable_ss_magi under such a reform.
- Test that the two loss-limit parameters agree; rename the #9784
  invariant test that no longer compares with the pre-change formula.
- loss_ald label: "Business and capital loss ALD".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI caught two tests written against the old capital loss formula:
- test_dependent_losses_agi_invariants (#9647) compared limited_capital_loss
  with min(cap, sum of losses), which does not net one spouse's gains
  against the other's losses. Its reference now splits 1211(b) the same
  way: losses allowed up to the gains, plus the excess up to the cap.
  Renamed ..._match_all_member_formula.
- md_capital_gains_surtax "partial offset" set capital_losses (a formula
  variable, max(0, -capital_gains)) to 50,000 next to 150,000 of net gains,
  a state no inputs can produce, and its comment applied the $3,000 cap to
  losses within gains. It now inputs the short-term loss directly
  (30,000 gains less 50,000 losses = -20,000): Schedule D line 16 and Form
  502CG line 1 are 100,000, surtax 2,000 (same on main).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MCL 206.508(4) adds back "any net business loss after netting all business
income and loss" and "any net rental or royalty loss". The MI-1040CR nets
line 16 (Schedule C, Form 4797 Part II, Schedule E Parts II and III,
Schedule F) and line 17 (Schedule E Parts I and V) and floors each total at
zero. Line 30 is the U.S. Schedule 1 adjustments, so loss_ald, which holds
business, rental and capital losses, is no longer subtracted there.

Estate and trust income and Form 4797 ordinary gains now count on line 16.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MCL 206.508(3): "'Household' means a claimant and spouse." Netting every
tax unit member's sources let a dependent's business or rental loss offset
the claimant's income (a 15-year-old's Schedule C loss of 20,000 took the
claimant's household resources from 70,000 to 50,000). Lines 16 and 17 now
sum only non-dependents, as loss_ald and irs_gross_income do.

Tests: three dependent YAML cases and a deterministic dependent property
test. The loss_ald reform check now runs once, on the grid, instead of on
every Hypothesis example; test_properties drops from 931 s in CI to about
8 s. The deterministic tests no longer need hypothesis. Small inputs are
drawn at $100 or more, the tolerance docstring is corrected, and comments
list Schedule E Part IV (REMIC) on line 17.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MCL 206.508(3) defines the household as "a claimant and spouse", and the
MI-1040CR asks for the income "you and your spouse received". Every
household resources source except lines 16 and 17 was summed over all tax
unit members, so a dependent's wages, interest, pensions and capital gains
raised the claimant's household resources, and a dependent's Schedule 1
adjustments (such as the deduction for half of self-employment tax)
lowered them.

- Sources are summed over the head and spouse with tax_unit_non_dep_add.
- Line 21 (Social Security, SSI and railroad retirement, including amounts
  received for minor children or dependent adults), line 22 (child
  support) and line 27 (public assistance paid to the household) still
  count for every member, as the form says.
- Line 19 reads filer_loss_limited_net_capital_gains, the head and
  spouse's Schedule D.
- Line 30 sums the head and spouse's Schedule 1 adjustments, with the
  self-employment adjustments read per person.
- Line 31 premiums paid for the family are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With no income, the model computes a Michigan FIP grant (tanf) for the
test household, which counts on line 27 but was missing from the test's
reference. Each SPM unit now gets a tanf input, drawn at random in the
Hypothesis test and counted in full on line 27 of the reference. The
Hypothesis tests also run more examples (50 and 30).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
irs_gross_income leaves tax unit dependents' income off the filer's
return, but self_employment_tax_ald, self_employed_health_insurance_ald
and self_employed_pension_contribution_ald summed every member's
person-level amount, and above_the_line_deductions summed every member's
IRA contributions, early withdrawal penalty, educator expenses, adoption
assistance and education bond interest. A dependent's Schedule SE and
Schedule 1 deductions belong on the dependent's own return.

- The three self-employment aggregates sum their _person variables over
  non-dependents; alimony_expense_ald masks dependents.
- above_the_line_deductions sums gov.irs.ald.deductions with
  tax_unit_non_dep_add.
- Readers that sum the ALD list themselves do the same: taxable_ss_magi,
  taxable_uc_agi, student_loan_interest_ald_magi,
  adjusted_gross_income_person and ma_part_b_agi.
- mo_adjusted_gross_income takes personal ALDs over non-dependents, so its
  remaining-ALD allocation never goes negative.
- medicaid_adjusted_gross_income_person attributes a dependent's own
  person-level deductions to the dependent instead of the head.
- ma_gross_income_loss_adjustment leaves out dependents' losses, as the
  federal gross income it adjusts does.

The _person variables keep each person's own amount, which a dependent's
own return (dependent_taxable_ss_magi) uses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-resources-claimant-spouse

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e member lists

Review r1:
- Line 30 reads the tax-unit adjustments as they are, so supplied inputs
  and reforms of self_employment_tax_ald and the other aggregates are
  respected. #9801 (merged in) makes those aggregates and
  alimony_expense_ald leave dependents out.
- The every-member sources (lines 21, 22 and 27) move to a parameter,
  gov.states.mi.tax.income.household_resources_all_members, and a source
  defined for a group larger than the tax unit (an SPM unit amount) is
  aggregated as a household amount, so a reform cannot hit an entity error.
- gi_cash_assistance counts only for the claimant and spouse: nothing shows a
  pilot payment is public assistance paid to the claimant's household.
- Tests: dependent alimony and guaranteed income YAML cases; property tests
  always have a dependent and a positive-resources household; a reform test.

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

# Conflicts:
#	policyengine_us/tests/core/test_dependent_losses_agi_invariants.py
#	policyengine_us/variables/gov/states/mi/tax/income/mi_household_resources.py
… and move the distributions comment

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to mi-household-resources-business-losses

# Conflicts:
#	policyengine_us/variables/gov/states/mi/tax/income/mi_household_resources.py
…change in the changelog

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s-losses' into mi-household-resources-claimant-spouse

# Conflicts:
#	policyengine_us/variables/gov/states/mi/tax/income/mi_household_resources.py
…aggregate-input cases

Review r1 finding 1: filer_loss_limited_net_capital_gains summed the head's
and spouse's components, so a tax unit net_capital_gains input was ignored
(wages 10,000 plus a 5,000 aggregate gain gave 10,000, not 15,000). It now
takes net_capital_gains less the dependents' own gains and losses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s and gifts

MI-1040CR line 31 leaves out premiums deducted on line 30, which holds the
self-employed health insurance deduction. MCL 206.510(1)(a) and (b) exclude
the first $300 of gifts and of gambling winnings (lines 24 and 20).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 5 commits October 6, 2026 02:10
…nd SE health insurance cases

Review r2 follow-ups: a supplied net_capital_gains reaches net investment
income (YAML case), a supplied self-employed health insurance deduction comes
off Michigan line 30 (YAML case), and the variable documents how a supplied
total combines with dependents' person-level gains.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-spouse' into mi-household-resources-premiums-gambling

# Conflicts:
#	policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/mi_household_resources.yaml
… in kind

Review r1 nits 3-5: a reform raising both exclusions to 500 changes household
resources (a hard-coded 300 fails it), the gambling exclusion parameter notes
that awards entered as miscellaneous_income count in full, and line 24 notes
that financial_assistance is cash only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ces-claimant-spouse

# Conflicts:
#	changelog.d/fix-dependent-ald-filer-agi.fixed.md
#	policyengine_us/tests/core/test_ald_determinism.py
#	policyengine_us/tests/core/test_dependent_above_the_line_deductions_invariants.py
#	policyengine_us/tests/policy/baseline/gov/hhs/medicaid/income/medicaid_adjusted_gross_income_person.yaml
#	policyengine_us/tests/policy/baseline/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/dependent_above_the_line_deductions.yaml
#	policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/mi_household_resources.yaml
#	policyengine_us/variables/gov/hhs/medicaid/income/medicaid_adjusted_gross_income_person.py
#	policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/above_the_line_deductions.py
#	policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/alimony_expense_ald.py
#	policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/above_the_line_deductions/student_loan_interest/student_loan_interest_ald_magi.py
#	policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/adjusted_gross_income_person.py
#	policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/filer_loss_limited_net_capital_gains.py
#	policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/social_security/taxable_ss_magi.py
#	policyengine_us/variables/gov/irs/income/taxable_income/adjusted_gross_income/irs_gross_income/unemployment_insurance/taxable_uc_agi.py
#	policyengine_us/variables/gov/states/ma/tax/income/adjusted_gross_income/ma_part_b_agi.py
#	policyengine_us/variables/gov/states/mi/tax/income/mi_household_resources.py
…ive Schedule C and F income

With #9801 on main: line 30 sums gov.irs.ald.filer_amounts_recorded_on_dependents
over every member, as above_the_line_deductions does, and the losses test now
draws positive dependent Schedule C and F income, whose self-employment tax
deduction is on the dependent's own return.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-spouse' into mi-household-resources-premiums-gambling

# Conflicts:
#	policyengine_us/variables/gov/states/mi/tax/income/mi_household_resources.py
MaxGhenis added a commit that referenced this pull request Oct 6, 2026
Line 16 of the filers' Schedule D now starts from the tax unit
net_capital_gains and takes out dependents' person-level gains and
losses, as #9796 does for Form 1040 line 7a. The Schedule D Tax
Worksheet read net_capital_gains on main, so a tax unit amount supplied
there keeps reaching worksheet line 7.

filer_loss_limited_net_capital_gains goes back to main's formula, so
this PR no longer edits the file #9796 and #9840 change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 9, 2026
* Use the filers' Schedule D for the tax on net capital gain

Net capital gain (26 U.S.C. 1222(11), 1(h)(11)), the Schedule D Tax
Worksheet and the 28% rate gain summed long- and short-term gains,
capital gain distributions, qualified dividends, collectibles gain and
Form 4952 elections over every tax unit member. Adjusted gross income
leaves out tax unit dependents, whose items are on their own returns
(2025 Form 8814, line 4), so a dependent's gain or dividends let the
filer's ordinary income be taxed at capital gain rates. The rate side
also added a negative capital gain distributions input, which AGI
floors at zero (Form 1099-DIV box 2a).

A new helper, filer_schedule_d_lines, gives the head and spouse's
Schedule D lines 7, 15 and 16 with distributions floored per person. It
now feeds filer_loss_limited_net_capital_gains (Form 1040 line 7a),
has_qdiv_or_ltcg, net_capital_gain and the worksheet's Form 4952 lines,
so the AGI side and the rate side read the same lines. Qualified
dividends, the Form 4952 election and the 28% rate gain inputs are
summed over the head and spouse with tax_unit_non_dep_add.

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

* Trim the Schedule D property tests' Hypothesis examples

Keeps the remaining pytest group's added time small: the file now takes
about 50 s of CPU locally (6 tests, 1.4 GB peak footprint).

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

* Keep a supplied net_capital_gains in Schedule D line 16

Line 16 of the filers' Schedule D now starts from the tax unit
net_capital_gains and takes out dependents' person-level gains and
losses, as #9796 does for Form 1040 line 7a. The Schedule D Tax
Worksheet read net_capital_gains on main, so a tax unit amount supplied
there keeps reaching worksheet line 7.

filer_loss_limited_net_capital_gains goes back to main's formula, so
this PR no longer edits the file #9796 and #9840 change.

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

* Use the filers' amounts in Vermont's and Hawaii's capital gain lines

Review r1 found that Vermont's flat capital gains exclusion took every
member's qualified dividends out of the now filer-only
adjusted_net_capital_gain. A dependent's 3,000 of dividends cut a 4,000
exclusion to 1,000 (Vermont tax 936.33 to 1,036.82). The dividends are
now the head and spouse's, as in the federal amount.

Hawaii's Tax on Capital Gains Worksheet took the smaller of the filers'
net capital gain (line 7) and every member's long-term gains (line 4),
so a dependent's loss shrank the head's line 8. Line 4 is now the head
and spouse's too.

The property tests also give dependents section 1202 gain, a long-term
loss carryover and Schedule D line 18 small business stock gain, and
no longer claim the grid runs without Hypothesis.

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

* Test that a supplied net_capital_gains reaches Schedule D line 16

Review r2 asked for a case covering 2b7bf4f: distributions of 1,000
and a tax unit net_capital_gains input of -5,000 make line 16 a loss of
4,000, so has_qdiv_or_ltcg is false and worksheet line 9 is 0. Main
turned the flag on there. The helper's line 16 comment now says it is
figured from net_capital_gains.

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

* Clarify Schedule D worksheet scope and aggregate input limitation

* Match the changelog and helper docstring to the PR's scope

The 28% Rate Gain Worksheet was already filer-only on main (#9988), so the
fragment no longer claims this PR changes it, and it now names Vermont's
dividend subtraction. The helper docstring sentence was missing an "and".

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@DTrim99

DTrim99 commented Oct 12, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Subtract Michigan premiums once and exclude the first $300 of gambling winnings and gifts (MI-1040CR lines 20, 24, 30 and 31)

PR #9840 (author: MaxGhenis, head 3e7a8bf0ae, 30 commits ahead of main). The PR's own work is three commits: d94846ecda, c57e5b6216 and 7fa23e51f6. The other 17 non-merge commits come from #9796, #9790, #9788 and #9801, which have all merged since. This review covers the PR's own diff against #9796's branch tip 546c6011d4, and checks how that diff sits on current main.

Summary

The PR makes two fixes to mi_household_resources, the income measure for the homestead property tax credit and the home heating credit:

  1. Line 31 no longer subtracts premiums that line 30 already subtracted. Line 30 carries the U.S. Schedule 1 adjustments, which include the self-employed health insurance deduction. Line 31 now subtracts every member's premiums less that deduction. The netting applies only while the deduction is on the line-30 list.
  2. The $300 exclusions in MCL 206.510(1)(a) and (b) are applied.
    • Gambling winnings count only above $300 on line 20.
    • financial_assistance (cash gifts from relatives or friends) now counts above $300 on line 24. Before, it was not counted at all.
    • Each exclusion applies once to the claimant's and spouse's combined total.
    • miscellaneous_income moves from line 24 to line 20 and still counts in full, so its value doesn't change.

The law is applied correctly, and I found no wrong result for a household in any year the PR covers.

  • All 53 cases in mi_household_resources.yaml pass on the extracted head tree, as do the 6 deterministic tests in the new property file.
  • I hand-checked 10 expectations and reproduced the headline examples in 2023 and 2025.
  • CI is green (35/35).

These fixes are still needed on current main: a probe of main still subtracts the $50,000/$5,000 claimant's premiums twice (36,467.61) and counts $250 of winnings in full. #9796 and #9795 do not duplicate either fix.

There is one should-address item (S1). The branch now conflicts with main in six files. One conflict needs a judgment call: the merged formula must keep #9795's line-30 list, and the netting check must use that list. Separately, the merge silently re-adds #9796's changelog fragment, which main has already consumed. I applied the resolution I recommend to main in a scratch tree, and every test passes.

Critical (must fix)

None.

Should address

S1. The branch conflicts with main in six files. Line 30 must keep #9795's list, and the merge re-adds #9796's consumed changelog fragment.

Suggestions

  1. Derandomize the two Hypothesis properties.

  2. A supplied self-employed health insurance deduction can net out another member's premiums.

    • Where: mi_household_resources.py:148-155.
    • What happens: line 31 nets the tax unit's deduction against every member's premiums.
      • When the deduction is computed, it can't exceed the self-employed filer's own premiums. self_employed_health_insurance_premiums adds health_insurance_premiums (and is defined for is_self_employed), and the deduction is min_(earnings, premiums).
      • When it is supplied as an input, it can absorb a spouse's unrelated premiums. Supplying it is a supported path: the existing case "A supplied self-employed health insurance deduction comes off line 30" uses it.
    • Head probe (2025):
      • Inputs: head wages $40,000 and a supplied deduction of $5,000; spouse wages $30,000 and premiums of $2,000.
      • Result: 65,000. The spouse's $2,000 is netted away.
      • If the $5,000 was the head's own plan, which was not entered as health_insurance_premiums, the form gives 63,000: line 31 keeps the spouse's $2,000.
    • Fix (either):
      • Cap the netting at the filers' self-employed premiums: min_(tax_unit("self_employed_health_insurance_ald", period), tax_unit_non_dep_add(tax_unit, period, ["self_employed_health_insurance_premiums"])).
        • This gives 63,000 here and keeps the existing supplied case at 9,000.
        • It is identical whenever the deduction is computed.
        • Its own failure mode: someone who supplies the deduction and enters those premiums but leaves is_self_employed false would have them subtracted twice.
      • Or keep the code and state the assumption in the comment: line 31 treats the line-30 premiums as part of health_insurance_premiums.
  3. The comments state PolicyEngine's federal limit, not the form's.

    • Where:

      • The comment in mi_household_resources.yaml:870: "limited to the 3,000 net earnings = 3,000".
      • The assertion at test_mi_household_resources_exclusions.py:269, [5_000, 3_000].
    • What's wrong: both pin the federal formula in self_employed_health_insurance_ald_person.py, which is the minimum of premiums and net self-employment income. Federal law limits the deduction to earned income under section 401(c), which is net of the deductible half of self-employment tax (26 U.S.C. 162(l)(2)(A)).

      • Form 7206 (2025), PDF p.1, line 7 says "Multiply Schedule 1 (Form 1040), line 15, deductible part of self-employment tax, by the percentage on line 6", and line 8 says "Subtract line 7 from line 4".
      • The limit is therefore 3,000 − 211.94 = 2,788.06.
    • The expected value is still right. Following the form:

      • line 30 = 211.94 + 2,788.06 = 3,000.00;
      • line 31 = 5,000 − 2,788.06 = 2,211.94;
      • line 33 = 43,000 − 3,000.00 − 2,211.94 = 37,788.06, the same as the PR.

      The PR's own design guarantees this: every premium dollar comes off once.

    • Fix: reword the comment to say these are PolicyEngine's federal amounts (a pre-existing simplification), and that line 33 is the same under Form 7206. The same note applies to row 2 of rulespec-us#1498 (see the axiom section).

  4. Read the tax-unit deduction directly.

    • Where: mi_household_resources.py:148-153.
    • What happens: the code calls tax_unit_non_dep_add on one TaxUnit-level variable. For a tax-unit variable, that function returns tax_unit(variable, period) (tools/general.py:38-39).
    • Fix: tax_unit("self_employed_health_insurance_ald", period) says the same thing more plainly.
  5. Optional earlier-year case.

    • Why: every new case uses 2025. The parameters start 2021-01-01 and cite the 2022 to 2024 books, which have the same line 20, 24 and 31 text. The section was last amended effective January 1, 2012.
    • Head probes: they give identical results in 2023 and 2025 (winnings $400 → 20,100; the $50,000/$5,000 case → 41,467.61).
    • Fix: add one 2022 or 2023 case to pin the earlier years.
  6. Optional reference consolidation at rebase.

    • What: each new parameter cites the 2025 book twice (#page=32 and #page=27). main's CLAUDE.md (Document the reference page-citation convention #10009) now says "URLs that differ only by #page= are one source".
    • Fix: one entry with href #page=27 and a quoted title ending #page 27,32 would follow it. The variable's five 2025-book hrefs predate this PR, and the same applies to them.

Verified correct

  • The $300 exclusions match the statute and the form.
    • MCL 206.510(1): "Income does not include any of the following: (a) The first $300.00 of gifts in cash or kind from nongovernmental sources. (b) The first $300.00 received from awards, prizes, lottery, bingo, or other gambling winnings." The section was last amended by 2011 PA 38 and 172, effective January 1, 2012.
    • Line 20: "awards, prizes, lottery, bingo, and other gambling winnings over $300".
    • Line 24: "Enter the value over $300 in gifts of cash or merchandise received, or expenses paid on your behalf ... by parents, relatives, or friends".
    • Both line texts are identical on PDF p.32 of the 2022, 2023, 2024 and 2025 books.
    • The 2025 list of what total household resources "do NOT include" (PDF p.27) has "The first $300 from gambling, bingo, lottery, awards, or prizes" and "The first $300 in gifts of cash or merchandise".
    • The home heating credit uses the same "total household resources" (MCL 206.527a).
  • Each exclusion applies once per claim, and the boundaries are exact. Lines 20 and 24 are each one amount for the claimant and spouse.
  • Premiums come off once.
    • Line 31's "Do not include any insurance premiums deducted on lines 21 or 30" appears on PDF p.33 of all four books.
    • Line 30's list includes the "Self-employed health insurance deduction" (2025 p.32; 2022 to 2024 p.33).
    • Head probes:
      • The self-employed claimant gets 41,467.61 (main: 36,467.61).
      • The joint return gets 69,467.61.
      • A claimant flagged self-employed with a $5,000 Schedule C loss has no deduction, so all $4,000 of premiums stay on line 31 (26,000).
      • An unflagged $50,000 Schedule C also gives 41,467.61: the premiums simply move to line 31.
    • The else 0 branch is tested by the reform that drops the federal deduction. The line-31 floor is tested by the existing supplied-deduction case: 9,000, which would be 11,000 without the floor.
  • Medicare premiums. The form nets them on line 21 ("Medicare premiums reported on your Social Security or Railroad Retirement statement should be deducted") and leaves them off line 31. MCL 206.510(1)(h) excludes them from income. The model keeps gross benefits on line 21 and the premiums on line 31. The result is the same: 20,000 − 2,220 = 17,780.
  • Line mapping.
    • miscellaneous_income is in gov.irs.gross_income.sources (sources.yaml:35), so it is taxable "other income" on line 20, in full. It is not a gift, and its value doesn't change.
    • financial_assistance ("Cash financial assistance from friends or relatives outside the household") is a cash gift from a nongovernmental source, which line 24 counts.
  • Tests and arithmetic. 53/53 YAML cases pass at head, and 6/6 deterministic Python tests pass locally. Hypothesis is not installed locally; CI's Rest suite ran the two properties. Hand-checked:
    • $50,000 Schedule C: 50,000 × 0.9235 × 0.153 / 2 = 3,532.39, so 50,000 − 3,532.39 − 5,000 = 41,467.61.
    • Wages $40,000 plus $3,000 Schedule C: 3,000 × 0.9235 × 0.153 / 2 = 211.94, so 43,000 − 211.94 − 3,000 − 2,000 = 37,788.06.
    • Joint return: 80,000 − 8,532.39 − (7,000 − 5,000) = 69,467.61.
    • Medicare case: 17,780.
    • Winnings 1,000 → 20,700. A couple's 200 + 200 → 20,100.
    • Gifts 250 + 250 → 20,200.
    • Winnings 500 and gifts 500 → 20,400.
    • The parameter-reform test: 400/600 at $300 → 20,400; at $500 → 20,100.
    • The dependent test: 20,000 and 20,400.
  • Parameters. Descriptions follow the house template ("Michigan excludes this amount of ..."), with currency-USD, year, labels and statute titles. Every #page anchor shows the cited text. Test periods are plain (2025).
  • Callers. Nine consumer variables read mi_household_resources (five homestead, four home heating), and its interface is unchanged. The two new parameters are read only here. Adding financial_assistance to the Michigan list changes no other program.
  • Changelog. changelog.d/mi-household-resources-premiums-gambling.fixed.md is top-level, matches the branch name, and fixed is the right type.

Out of scope (pre-existing, not counted)

  • Federal gross income omits gambling winnings (Federal gross income omits gambling winnings but still deducts wagering losses; OBBBA 90% wagering loss limit (2026+) not modeled #9637, open). In a head probe, $400 of winnings gives federal AGI of 0. Line 20 reads gambling_winnings directly, so Michigan is unaffected.
  • Line 31's other rules. Line 31 says "You must reduce an insurance premium by the federal premium tax credit" and excludes "amounts paid by an employer with pre-tax payroll contributions" (2025 p.33). It also reads only the direct health_insurance_premiums input. The PR body lists these as follow-ups.
  • Dependent filers' support on line 24. Line 24 also "includes the amount of financial support you received if you are claimed as a dependent on someone else's return". There is no input for this.

Axiom line assessment

axiom: TheAxiomFoundation/rulespec-us#1498 queued is valid.

CI status

All 35 checks pass at 3e7a8bf0ae (gh pr checks 9840, run of 2026-10-06), including Lint, Check changelog fragment, Full Suite - Rest (Python + variables), Microsimulation and Household API Partners. That run predates #9795 and #9796 landing on main. CI has not run on a merge with current main.

Branch status

  • Position: 30 commits ahead of main and 198 behind (main at 2e9eea7e6e; merge base d3978dfc31).
  • GitHub: reports CONFLICTING (merge state DIRTY).
  • git merge-tree --write-tree PolicyEngine/main 3e7a8bf0ae exits 1 with six conflicts:
    • household_resources.yaml (content);
    • household_resources_all_members.yaml (add/add);
    • mi_household_resources.yaml tests (content);
    • test_mi_household_resources_members.py (add/add);
    • filer_loss_limited_net_capital_gains.py (content);
    • mi_household_resources.py (content).
  • Silent re-add: the merge also re-adds changelog.d/mi-household-resources-claimant-spouse.fixed.md with no conflict.
  • Resolution: see S1. With the resolution described there, the merged tree passes all affected Michigan tests.

Verdict: REQUEST_CHANGES

@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 policy is right. The $300 exclusions match MCL 206.510(1)(a)/(b) (once per claim, strictly over $300, one each for gifts and winnings, dependents left out), and premiums now come off once per line 31's instruction. The tests pass and rulespec-us#1498 is dispatch-ready. One should item (see the comment above): the branch conflicts with main in 6 files. Take main's side for the four #9796 conflicts. In the line-30/31 formula, build deductions from main's household_resources_adjustments ∩ ald.deductions (#9795) and test the self-employed health insurance deduction against that list; the head side reverts #9795 and main's side raises a NameError. Also delete the re-added #9796 changelog fragment.

@codecov

codecov Bot commented Oct 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (909176a) to head (b95613e).
⚠️ Report is 493 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #9840   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         1    -3     
  Lines           76        44   -32     
  Branches         2         6    +4     
=========================================
- Hits            76        44   -32     
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.

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