From e42135acff708d58e9d7c9722d7af85732561cd9 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 20 Oct 2026 18:16:58 -0400 Subject: [PATCH 1/5] Count MI household resources benefits and premiums for the claimant and spouse only MCL 206.508(3) defines the household as a claimant and spouse, and 206.508(4) counts income received by persons of the household. A dependent's own Social Security, SSI or railroad benefit is received by the dependent, even when the claimant is the representative payee, and a premium a dependent paid is not one the claimant or spouse paid (206.510). Child support, TANF and general assistance stay counted for every member, as payments made to the claimant for the household. WIP: tests follow. Co-Authored-By: Claude Opus 5.5 --- ...usehold-resources-claimant-spouse.fixed.md | 1 + .../mi/tax/income/household_resources.yaml | 5 +-- .../household_resources_all_members.yaml | 24 +++++++------- .../mi/tax/income/mi_household_resources.py | 31 ++++++++++++++----- 4 files changed, 39 insertions(+), 22 deletions(-) create mode 100644 changelog.d/mi-household-resources-claimant-spouse.fixed.md diff --git a/changelog.d/mi-household-resources-claimant-spouse.fixed.md b/changelog.d/mi-household-resources-claimant-spouse.fixed.md new file mode 100644 index 00000000000..627b5db5f3c --- /dev/null +++ b/changelog.d/mi-household-resources-claimant-spouse.fixed.md @@ -0,0 +1 @@ +Count Michigan household resources' Social Security, SSI and railroad retirement benefits, and deduct health insurance premiums, only for the claimant and spouse (MCL 206.508(3) and 206.510), so a dependent's own benefits and premiums no longer change the homestead property tax and home heating credits. diff --git a/policyengine_us/parameters/gov/states/mi/tax/income/household_resources.yaml b/policyengine_us/parameters/gov/states/mi/tax/income/household_resources.yaml index 449b7ae9cf2..d6dd15e34c8 100644 --- a/policyengine_us/parameters/gov/states/mi/tax/income/household_resources.yaml +++ b/policyengine_us/parameters/gov/states/mi/tax/income/household_resources.yaml @@ -2,7 +2,7 @@ description: Michigan accounts for the following income sources as the household values: 2021-01-01: # Each source counts for the claimant and spouse only (MCL 206.508(3)), - # except those in household_resources_all_members (lines 21, 22 and 27). + # except those in household_resources_all_members (lines 22 and 27). # MI-1040CR line 14, wages, including strike pay. - irs_employment_income - strike_benefits @@ -32,7 +32,8 @@ values: - alimony_income - gambling_winnings # MI-1040CR line 21, Social Security, SSI and railroad retirement - # benefits, including amounts received for dependents. + # benefits: the claimant's and spouse's own. A dependent's benefit is + # the dependent's, even when the claimant is the representative payee. - social_security - ssi - railroad_benefits diff --git a/policyengine_us/parameters/gov/states/mi/tax/income/household_resources_all_members.yaml b/policyengine_us/parameters/gov/states/mi/tax/income/household_resources_all_members.yaml index c08195a2bcf..851c5a92236 100644 --- a/policyengine_us/parameters/gov/states/mi/tax/income/household_resources_all_members.yaml +++ b/policyengine_us/parameters/gov/states/mi/tax/income/household_resources_all_members.yaml @@ -1,18 +1,18 @@ -description: Michigan counts these household resources sources for every tax unit member, not only the claimant and spouse, as amounts the claimant receives for others in the household. +description: Michigan counts these household resources sources for every tax unit member, not only the claimant and spouse, as payments made to the claimant for the household. values: 2021-01-01: - # MI-1040CR line 21: Social Security, SSI and railroad retirement - # benefits, including "amounts received for minor children or other - # dependent adults who live with you". - - social_security - - ssi - - railroad_benefits + # Social Security, SSI and railroad retirement benefits (MI-1040CR line + # 21) are not listed: they count only for the claimant and spouse. MCL + # 206.508(3) defines the household as "a claimant and spouse", and a + # dependent's own benefit is received by the dependent, even when the + # claimant is the representative payee. # MI-1040CR line 22: "child support and all payments received as a foster - # parent". + # parent", paid to the claimant for the child. - child_support_received # MI-1040CR line 27: "the total payments made to your household by MDHHS # and all other public assistance payments". A Family Independence - # Program grant covers the children in the case. + # Program grant is paid to the claimant and covers the children in the + # case. - tanf - general_assistance metadata: @@ -22,9 +22,9 @@ metadata: reference: - title: MCL 206.508(3) and (4), household and total household resources href: https://www.legislature.mi.gov/Laws/MCL?objectName=mcl-206-508 - - title: Michigan 2025 Individual Income Tax Instructions, MI-1040CR lines 21, 22 and 27 + - title: Michigan 2025 Individual Income Tax Instructions, MI-1040CR lines 22 and 27 href: https://www.michigan.gov/taxes/-/media/Project/Websites/taxes/Forms/IIT/TY2025/MI-1040-Book.pdf#page=32 - - title: Michigan 2024 Home Heating Credit Instructions, MI-1040CR-7 lines 26, 27 and 32 + - title: Michigan 2024 Home Heating Credit Instructions, MI-1040CR-7 lines 27 and 32 href: https://web.archive.org/web/20250202150154/https://www.michigan.gov/taxes/-/media/Project/Websites/taxes/Forms/IIT/TY2024/BOOK_MI-1040CR-7.pdf#page=8 - - title: Michigan 2025 Home Heating Credit Instructions, MI-1040CR-7 lines 24, 25 and 30 + - title: Michigan 2025 Home Heating Credit Instructions, MI-1040CR-7 lines 25 and 30 href: https://web.archive.org/web/20260218211009/https://www.michigan.gov/taxes/-/media/Project/Websites/taxes/Forms/IIT/TY2025/MI-1040CR-7-Book.pdf?rev=e4ba4fedc63942e48442037517312d4a&hash=AF396E577B1932DF55BFD7F22D7EF06A#page=9 diff --git a/policyengine_us/variables/gov/states/mi/tax/income/mi_household_resources.py b/policyengine_us/variables/gov/states/mi/tax/income/mi_household_resources.py index 103dffc9cdc..4b121a7d646 100644 --- a/policyengine_us/variables/gov/states/mi/tax/income/mi_household_resources.py +++ b/policyengine_us/variables/gov/states/mi/tax/income/mi_household_resources.py @@ -69,11 +69,22 @@ def formula(tax_unit, period, parameters): # irs_gross_income. A tax-unit-level source (other_net_gain, # filer_loss_limited_net_capital_gains) already describes the # filer's return. - # The sources in household_resources_all_members are amounts the - # claimant receives for others in the household (lines 21, 22 and - # 27), so they are summed over every member. So is a source defined - # for a larger group than the tax unit, such as tanf for the SPM - # unit: add gives the tax unit its members' shares. + # That includes Social Security, SSI and railroad retirement + # benefits (line 21). The beneficiary receives them: a claimant who + # is a minor child's or dependent adult's representative payee holds + # the benefit for the beneficiary, who is not a person of the + # household. Revenue Administrative Bulletin 2015-18 also counts + # benefits "received by the taxpayer, the taxpayer's spouse or minor + # children", and the line 21 instructions include "amounts received + # for minor children or other dependent adults who live with you"; + # the statute's definition of household governs both. + # The sources in household_resources_all_members are payments made + # to the claimant for the household: child support and foster care + # payments (line 22) and public assistance grants (line 27), whose + # records may sit on the child they are paid for. They are summed + # over every member. So is a source defined for a larger group than + # the tax unit, such as tanf for the SPM unit: add gives the tax unit + # its members' shares. all_members = p.household_resources_all_members business_income = 0 @@ -129,7 +140,11 @@ def formula(tax_unit, period, parameters): # Line 31: "insurance premiums you paid for yourself and your # family". MCL 206.510(1) lets a person deduct "the amount that # person paid in premiums ... for that insurance plan for the - # person's family". A premium on any member's record is read as one - # the claimant or spouse paid for the family's coverage. - health_insurance_premiums = add(tax_unit, period, ["health_insurance_premiums"]) + # person's family". health_insurance_premiums records the premiums + # each person paid, so the claimant's and spouse's amounts, which + # may include family coverage they bought, come off. A premium a + # dependent paid is not one the claimant or spouse paid. + health_insurance_premiums = tax_unit_non_dep_add( + tax_unit, period, ["health_insurance_premiums"] + ) return max_(0, total - adjustments - health_insurance_premiums) From a206eeaaef0e0a824f6972eb3bbd0c5377a96888 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 07:32:53 +0000 Subject: [PATCH 2/5] Test MI household resources against the claimant-and-spouse household YAML: a minor child's or dependent adult's own Social Security, SSI and railroad benefits, and premiums a dependent paid, no longer count; the heating-credit regression that counted a dependent adult's SSI now gives $279 in both pension cases. Property tests: the reference counts line 21 and line 31 for the head and spouse only, a dependent's benefits never change resources, a filer's count in full, and resources never fall as a filer's income (other than Schedule C income) rises. Michigan stays an intended exception in the dependent-retirement invariant because a dependent's pension can lower the household's FIP grant, which still counts on line 27. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LwQq6K4grkKNkfjkW6hbaN --- ...dent_retirement_income_state_invariants.py | 18 +- .../home_heating/mi_home_heating_credit.yaml | 30 +-- .../mi/tax/income/mi_household_resources.yaml | 145 +++++++++++--- .../test_mi_household_resources_exclusions.py | 14 +- .../test_mi_household_resources_members.py | 179 +++++++++++++----- 5 files changed, 290 insertions(+), 96 deletions(-) diff --git a/policyengine_us/tests/core/test_dependent_retirement_income_state_invariants.py b/policyengine_us/tests/core/test_dependent_retirement_income_state_invariants.py index 49783dcfb0f..49595f2d791 100644 --- a/policyengine_us/tests/core/test_dependent_retirement_income_state_invariants.py +++ b/policyengine_us/tests/core/test_dependent_retirement_income_state_invariants.py @@ -30,8 +30,9 @@ units without dependents it equals `add`. 2. Outside STATES_WITH_INTENDED_RETIREMENT_TAX_DECREASES, giving the dependents retirement income never lowers the filer's state income tax. - Michigan is an intended exception: a dependent adult's pension can lower - their SSI and increase the claimant's refundable credit. Outside + Michigan is an intended exception: a dependent's pension can lower the + household's Family Independence Program grant, which counts in household + resources, and so raise the claimant's refundable credit. Outside STATES_COUNTING_DEPENDENT_INCOME it changes neither the state AGI nor the state taxable income. (State income tax itself may still rise: credits keyed to household income, such as Oklahoma's sales tax relief credit, @@ -371,13 +372,12 @@ def test_tax_unit_non_dep_add_edge_cases(): # subtracting income that never entered AGI; property 2 checks only that it # never lowers tax there. STATES_COUNTING_DEPENDENT_INCOME = {"AL", "AR", "IA", "MS", "NJ"} -# Intended exception per ruling d1143 (2026-10-09): follow MI-1040CR lines -# 18 and 21 (2025 MI-1040 booklet, PDF page 28 / printed page 32): -# https://www.michigan.gov/taxes/-/media/Project/Websites/taxes/Forms/IIT/TY2025/MI-1040-Book.pdf#page=28 -# Line 18 counts pensions only for the claimant and spouse; line 21 counts -# SSI received for dependent adults who live with them. A dependent adult's -# pension can reduce SSI, lower household resources and raise refundable -# credits, while the claimant's pension subtractions and tax base stay fixed. +# Michigan: a dependent's own pension and SSI are not household resources +# (MCL 206.508(3) defines the household as "a claimant and spouse"), but the +# Family Independence Program grant paid to the claimant counts in full +# (MI-1040CR line 27). A dependent's pension can lower that grant, lower +# household resources and raise the claimant's refundable credits, while the +# claimant's pension subtractions and tax base stay fixed. STATES_WITH_INTENDED_RETIREMENT_TAX_DECREASES = {"MI"} YEARS = [2025, 2026] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/credits/home_heating/mi_home_heating_credit.yaml b/policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/credits/home_heating/mi_home_heating_credit.yaml index 46943e5822e..ec7b87f4ca3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/credits/home_heating/mi_home_heating_credit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/credits/home_heating/mi_home_heating_credit.yaml @@ -185,11 +185,11 @@ output: mi_home_heating_credit: 0 -# Ruling d1143 (2026-10-09): follow MI-1040CR lines 18 and 21. -# 2025 MI-1040 book, PDF page 28 (printed page 32): -# https://www.michigan.gov/taxes/-/media/Project/Websites/taxes/Forms/IIT/TY2025/MI-1040-Book.pdf#page=28 -# Line 18 excludes a dependent adult's pension; line 21 includes their SSI. -- name: Dependent adult pension lowers Michigan tax through SSI (d1143) +# MCL 206.508(3) defines the household as "a claimant and spouse", so a +# dependent adult's own pension and SSI are both left out of household +# resources. The MI-1040CR line 21 instructions, which count amounts +# received for dependent adults, give way to the statute. +- name: A dependent adult's pension and SSI both stay out of household resources period: 2025 absolute_error_margin: 0.01 input: @@ -263,18 +263,18 @@ # Annual SSI: 12 * $967 = $11,604. Countable annual pension: # $2,400 - 12 * $20 general exclusion = $2,160; $11,604 - $2,160 = $9,444. ssi: [0, 11_604, 0, 9_444] - # Claimant wages + dependent SSI; the dependent's pension is excluded. - mi_household_resources: [21_604, 19_444] + # Claimant wages only; the dependent's SSI and pension are the + # dependent's own. + mi_household_resources: [10_000, 10_000] adjusted_gross_income: [10_000, 10_000] mi_pension_benefit: [0, 0] mi_subtractions: [0, 0] mi_taxable_income: [0, 0] mi_income_tax_before_refundable_credits: [0, 0] - # Two exemptions: $815 - 3.5% * household resources. - mi_standard_home_heating_credit: [58.86, 134.46] - # Apply the 2025 60% funding factor: $58.86 * .60; $134.46 * .60. - mi_home_heating_credit: [35.316, 80.676] - # Only the heating credit changes: tax falls by $45.36, - # equal to $2,160 * 3.5% * 60% = $80.676 - $35.316. - mi_income_tax: [-35.316, -80.676] - state_income_tax: [-35.316, -80.676] + # Two exemptions: $815 - 3.5% * $10,000 = $465. + mi_standard_home_heating_credit: [465, 465] + # Apply the 2025 60% funding factor: $465 * .60 = $279. The pension no + # longer changes the credit through the dependent's SSI. + mi_home_heating_credit: [279, 279] + mi_income_tax: [-279, -279] + state_income_tax: [-279, -279] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/mi_household_resources.yaml b/policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/mi_household_resources.yaml index 63c026b3e91..bbb0a8b826d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/mi_household_resources.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mi/tax/income/mi_household_resources.yaml @@ -791,7 +791,7 @@ # Line 33: 50,500. mi_household_resources: 50_500 -- name: Social Security survivors benefits paid for a child count on line 21 +- name: Social Security survivors benefits paid for a child are the child's, not the claimant's period: 2025 input: people: @@ -812,12 +812,14 @@ output: # Line 14: 30,000. Line 15: 0; the child's 400 of interest is the # child's own income. - # Line 21: "Include death benefits and amounts received for minor - # children or other dependent adults who live with you": 9,000. - # Line 33: 30,000 + 9,000 = 39,000. - mi_household_resources: 39_000 - -- name: SSI and child support received for a child count on lines 21 and 22 + # Line 21: 0. MCL 206.508(3) defines the household as "a claimant and + # spouse"; the child's benefit is received by the child, even with the + # claimant as representative payee. The statute governs RAB 2015-18 and + # the line 21 instructions, which count benefits for minor children. + # Line 33: 30,000. + mi_household_resources: 30_000 + +- name: Child support received for a child counts on line 22 but the child's SSI does not period: 2025 input: people: @@ -836,13 +838,13 @@ members: [person1, person2] state_code: MI output: - # Line 14: 20,000. Line 21: SSI received for a minor child, 6,000. - # Line 22: "child support and all payments received as a foster - # parent", 4,800. - # Line 33: 20,000 + 6,000 + 4,800 = 30,800. - mi_household_resources: 30_800 + # Line 14: 20,000. Line 21: 0; the child's SSI is the child's own + # (MCL 206.508(3)). Line 22: "child support and all payments received + # as a foster parent", paid to the claimant, 4,800. + # Line 33: 20,000 + 4,800 = 24,800. + mi_household_resources: 24_800 -- name: A dependent adult's Social Security counts but the dependent's pension does not +- name: Neither a dependent adult's Social Security nor the dependent's pension counts period: 2025 input: people: @@ -874,10 +876,10 @@ output: # Line 14: 50,000. Line 18: 0; the dependent parent's pension is the # parent's own income. - # Line 21: amounts received for "other dependent adults who live with - # you", 15,000. - # Line 33: 50,000 + 15,000 = 65,000. - mi_household_resources: 65_000 + # Line 21: 0; the dependent parent's Social Security is the parent's + # own (MCL 206.508(3)). + # Line 33: 50,000. + mi_household_resources: 50_000 - name: A dependent's capital loss does not reduce the claimant's line 19 period: 2025 @@ -956,14 +958,14 @@ # Line 33: 10,000 + 6,000 = 16,000. mi_household_resources: 16_000 -- name: Premiums paid for a child's coverage reduce household resources on line 31 +- name: Premiums the claimant paid for family coverage reduce line 31 but a child's own premium does not period: 2025 input: people: person1: age: 40 employment_income_before_lsr: 40_000 - health_insurance_premiums: 2_400 + health_insurance_premiums: 3_600 person2: age: 9 health_insurance_premiums: 1_200 @@ -975,9 +977,9 @@ members: [person1, person2] state_code: MI output: - # Line 31: "insurance premiums you paid for yourself and your family", - # 2,400 + 1,200 = 3,600, reading the child's premium as one the claimant - # paid for the child's coverage. + # Line 31: "insurance premiums you paid for yourself and your family": + # the claimant's 3,600, which covers the child (MCL 206.510(1)). The + # 1,200 on the child's record is a premium the child paid. # Line 33: 40,000 - 3,600 = 36,400. mi_household_resources: 36_400 @@ -1473,3 +1475,102 @@ output: charitable_deduction_for_non_itemizers: 300 mi_household_resources: 40_000 + +- name: A dependent adult's own SSI and personally paid premiums are excluded + period: 2025 + input: + people: + claimant: + age: 40 + is_tax_unit_head: true + is_tax_unit_spouse: false + is_tax_unit_dependent: false + employment_income: 10_000 + dependent: + age: 75 + is_tax_unit_head: false + is_tax_unit_spouse: false + is_tax_unit_dependent: true + ssi: 9_444 + health_insurance_premiums: 1_000 + tax_units: + tax_unit: + members: [claimant, dependent] + spm_units: + spm_unit: + members: [claimant, dependent] + tanf: 0 + households: + household: + members: [claimant, dependent] + state_code: MI + output: + # MCL 206.508(3)-(4) and 206.510(1): the claimant's 10,000 of earnings; + # the dependent's own 9,444 SSI and the 1,000 of premiums the dependent + # paid are not the claimant's. + mi_household_resources: 10_000 + +- name: Claimant-paid family premiums come off once while a dependent adult's SSI is excluded + period: 2025 + input: + people: + claimant: + age: 40 + is_tax_unit_head: true + is_tax_unit_spouse: false + is_tax_unit_dependent: false + employment_income: 10_000 + health_insurance_premiums: 1_000 + dependent: + age: 75 + is_tax_unit_head: false + is_tax_unit_spouse: false + is_tax_unit_dependent: true + ssi: 9_444 + tax_units: + tax_unit: + members: [claimant, dependent] + spm_units: + spm_unit: + members: [claimant, dependent] + tanf: 0 + households: + household: + members: [claimant, dependent] + state_code: MI + output: + # 10,000 earnings - 1,000 claimant-paid family premiums (MCL 206.510(1)) + # = 9,000. The dependent's 9,444 SSI is the dependent's own. + mi_household_resources: 9_000 + +- name: A spouse's own Social Security and SSI count in full + period: 2025 + input: + people: + head: + age: 70 + is_tax_unit_head: true + is_tax_unit_spouse: false + social_security_retirement: 12_000 + spouse: + age: 68 + is_tax_unit_head: false + is_tax_unit_spouse: true + ssi: 3_000 + social_security_retirement: 6_000 + child: + age: 15 + is_tax_unit_dependent: true + social_security_survivors: 5_000 + tax_units: + tax_unit: + members: [head, spouse, child] + filing_status: JOINT + households: + household: + members: [head, spouse, child] + state_code: MI + output: + # Line 21: the claimant's and spouse's own benefits, 12,000 + 6,000 + + # 3,000 = 21,000. The child's 5,000 is the child's own. + mi_household_resources: 21_000 diff --git a/policyengine_us/tests/test_mi_household_resources_exclusions.py b/policyengine_us/tests/test_mi_household_resources_exclusions.py index 5c9796aa37a..8abb755e30e 100644 --- a/policyengine_us/tests/test_mi_household_resources_exclusions.py +++ b/policyengine_us/tests/test_mi_household_resources_exclusions.py @@ -4,7 +4,10 @@ Schedule 1", which include the self-employed health insurance deduction (Schedule 1 line 17). Line 31 subtracts "insurance premiums you paid for yourself and your family", but "Do not include any insurance premiums deducted -on lines 21 or 30" (2025 MI-1040 book, page 33). +on lines 21 or 30" (2025 MI-1040 book, page 33). health_insurance_premiums +records the premiums each person paid, so only the head's and spouse's count +(MCL 206.510(1)); theirs may cover the family, and a dependent's own premium +is not one the claimant or spouse paid. MCL 206.510(1) excludes from income "(a) The first $300.00 of gifts in cash or kind from nongovernmental sources" and "(b) The first $300.00 received from @@ -16,8 +19,9 @@ So for every household: -1. Each premium dollar is subtracted once. Zeroing every member's premiums - raises household resources by between 0 and the household's total +1. Each premium dollar the head or spouse paid is subtracted once, and a + dependent's is not subtracted. Zeroing every member's premiums raises + household resources by between 0 and the head's and spouse's total premiums, and by exactly that total when household resources were positive. 2. Household resources are non-decreasing in the head's gambling winnings. @@ -155,7 +159,7 @@ def assert_premiums_subtracted_once(households): n = len(households) for i, h in enumerate(households): tol = tolerance(h) - premiums = total(members(h), PREMIUMS) + premiums = total(filers(h), PREMIUMS) subtracted = float(result[n + i]) - float(result[i]) assert -tol <= subtracted <= premiums + tol, h if result[i] > tol: @@ -193,7 +197,7 @@ def test_self_employed_premiums_subtracted_once(): """The self-employed health insurance deduction (line 30) and line 31 together subtract each premium once: for a self-employed claimant, a self-employed couple, premiums above the deduction's earnings limit, and - a self-employed dependent whose premium the claimant is read to pay.""" + a self-employed dependent whose own premium is not subtracted.""" households = [ {"head": person(self_employment_income=50_000, **{PREMIUMS: 5_000})}, { diff --git a/policyengine_us/tests/test_mi_household_resources_members.py b/policyengine_us/tests/test_mi_household_resources_members.py index 08eadb4c63a..c612e7de6ff 100644 --- a/policyengine_us/tests/test_mi_household_resources_members.py +++ b/policyengine_us/tests/test_mi_household_resources_members.py @@ -4,41 +4,54 @@ counts "all income received by all persons of a household". The MI-1040CR asks for "all taxable and nontaxable income you and your spouse received" (2025 MI-1040 book, page 31), so a dependent's own income and Schedule 1 -adjustments are on the dependent's return, not the claimant's. The form -counts amounts the claimant receives for others in the household on three -lines (page 32): +adjustments are on the dependent's return, not the claimant's. + +That includes Social Security, SSI and railroad retirement benefits (line +21). A minor child's or dependent adult's own benefit is received by the +beneficiary, even when the claimant is the representative payee, so it is +not household resources. Revenue Administrative Bulletin 2015-18 and the +line 21 instructions count amounts received for minor children or dependent +adults; the statute's definition of household governs both. + +The claimant receives two kinds of amount for others in the household +(page 32), which count wherever they are recorded: -- line 21: Social Security, SSI and railroad retirement benefits, including - "amounts received for minor children or other dependent adults who live - with you"; - line 22: child support and foster parent payments; - line 27: payments to the household by MDHHS and other public assistance. -Line 31 is "insurance premiums you paid for yourself and your family"; a -premium on any member's record is read as one the claimant or spouse paid -for the family's coverage. Line 31 leaves out "any insurance premiums -deducted on lines 21 or 30" (page 33), so the head's and spouse's -self-employed health insurance deduction, which is on line 30, is not -subtracted again. Lines 20 and 24 count gambling winnings and gifts "over -$300" (MCL 206.510(1)(a) and (b)), one amount for the claimant and spouse. +Line 31 is "insurance premiums you paid for yourself and your family" (MCL +206.510(1)). health_insurance_premiums records the premiums each person +paid, so only the head's and spouse's count; theirs may cover the family. +Line 31 leaves out "any insurance premiums deducted on lines 21 or 30" +(page 33), so the head's and spouse's self-employed health insurance +deduction, which is on line 30, is not subtracted again. Lines 20 and 24 +count gambling winnings and gifts "over $300" (MCL 206.510(1)(a) and (b)), +one amount for the claimant and spouse. So for every household: 1. mi_household_resources equals a reference written from the form: the head - and spouse's lines 14 to 20 and 23 to 26 and their line 30 adjustments, - plus every member's lines 21, 22 and 27, less every member's premiums not - deducted on line 30, floored at zero. -2. A dependent's own income and adjustments do not matter: zeroing them - leaves household resources unchanged. + and spouse's lines 14 to 21 and 23 to 26, their line 30 adjustments and + their premiums not deducted on line 30, plus every member's lines 22 and + 27, floored at zero. +2. A dependent's own income, benefits, adjustments and premiums do not + matter: zeroing them leaves household resources unchanged. In + particular a dependent's own Social Security, SSI or railroad benefit + never changes household resources. 3. Amounts received for the household count wherever they are recorded: - moving a dependent's line 21, 22 or 27 amount, or premium, to the head - leaves household resources unchanged. -4. Raising a dependent's line 21, 22 or 27 amount by d raises household + moving a dependent's line 22 or 27 amount to the head leaves household + resources unchanged. +4. Raising a dependent's line 22 or 27 amount by d raises household resources by between 0 and d, and by exactly d when they were positive. 5. Each of the spouse's own sources adds what it adds on the head. 6. The lists are reformable: a source moved into household_resources_all_members counts for every member, and an SPM unit source in household_resources counts in full. +7. The claimant's and spouse's own benefits count in full: raising one by d + raises household resources by exactly d when they were positive, and by + between 0 and d otherwise. +8. Household resources never fall when the head's or spouse's income, + other than self-employment income, rises. Every generated household has a dependent, so properties 2 to 4 always bind, and property 4 always includes a household with positive resources. @@ -84,18 +97,35 @@ "workers_compensation": 26, # Guaranteed income pilot payments: the recipient's own (line 25). "gi_cash_assistance": 25, + # Line 21: the beneficiary's own benefits (MCL 206.508(3)). + "social_security_retirement": 21, + "social_security_survivors": 21, + "ssi": 21, + "railroad_benefits": 21, # Line 30: penalty on early withdrawal of savings (Schedule 1 line 18). "early_withdrawal_penalty": 30, } # Inputs the claimant receives for the household, by MI-1040CR line. HOUSEHOLD_LINES = { - "social_security_retirement": 21, - "social_security_survivors": 21, - "ssi": 21, - "railroad_benefits": 21, "child_support_received": 22, "general_assistance": 27, } +BENEFITS = [ + "social_security_retirement", + "social_security_survivors", + "ssi", + "railroad_benefits", +] +# The claimant's and spouse's own income, for property 8. Not +# self-employment income: line 16 nets it against other business losses, +# while its line 30 self-employment tax deduction is on the gross amount, so +# with an S corporation loss of 404, Schedule C income of 434 adds 30 on +# line 16 and deducts 30.66 on line 30. +INCOME = [ + name + for name in CLAIMANT_LINES + if name not in ("early_withdrawal_penalty", "self_employment_income") +] PREMIUMS = "health_insurance_premiums" # MCL 206.510(1)(a) and (b): the first $300 of gifts and of gambling winnings. EXCLUSION = 300 @@ -210,6 +240,7 @@ def reference(h, person_adjustments): line_16 = max(0, amount(own, ["self_employment_income", "s_corp_income"])) line_17 = max(0, amount(own, ["rental_income"])) line_18 = amount(own, by_line(CLAIMANT_LINES, 18)) + line_21 = amount(own, by_line(CLAIMANT_LINES, 21)) line_19 = max(-CAPITAL_LOSS_LIMIT, amount(own, ["long_term_capital_gains"])) excluded = ["gambling_winnings", "financial_assistance"] lines_20_to_26 = amount( @@ -233,10 +264,11 @@ def reference(h, person_adjustments): } line_30 = sum(filer_adjustments.values()) line_30 += amount(own, ["early_withdrawal_penalty"]) - # Line 31: every member's premiums, less those deducted on line 30. - line_31 = amount(everyone(h), [PREMIUMS]) + # Line 31: the head's and spouse's premiums, less those deducted on + # line 30. + line_31 = amount(own, [PREMIUMS]) line_31 -= filer_adjustments["self_employed_health_insurance_ald_person"] - total = line_14 + line_15 + line_16 + line_17 + line_18 + line_19 + total = line_14 + line_15 + line_16 + line_17 + line_18 + line_19 + line_21 total += lines_20_to_26 + received return max(0, total - line_30 - line_31) @@ -260,7 +292,7 @@ def copy(h): def without_dependents_own_amounts(h): out = copy(h) for d in out["dependents"]: - for name in CLAIMANT_LINES: + for name in [*CLAIMANT_LINES, PREMIUMS]: d[name] = 0 return out @@ -268,7 +300,7 @@ def without_dependents_own_amounts(h): def with_household_amounts_on_head(h): out = copy(h) for d in out["dependents"]: - for name in [*HOUSEHOLD_LINES, PREMIUMS]: + for name in HOUSEHOLD_LINES: out["head"][name] = out["head"].get(name, 0) + d.get(name, 0) d[name] = 0 return out @@ -309,9 +341,9 @@ def base_household(dependent_age=10, spouse=False): def test_each_source_for_a_dependent(): """For a child and for a dependent parent, every source on its own: a - dependent's own income and adjustments leave household resources at the - base, and an amount received for the household adds in full, as it - would for the head.""" + dependent's own income, benefits, adjustments and premiums leave + household resources at the base, and an amount received for the + household adds in full, as it would for the head.""" households, cases = [], [] for age, spouse in itertools.product([10, 75], [False, True]): base = base_household(age, spouse) @@ -324,7 +356,7 @@ def test_each_source_for_a_dependent(): h["dependents"][0][name] = value households.append(h) cases.append((age, spouse, name, value)) - if name in HOUSEHOLD_LINES or name == PREMIUMS: + if name in HOUSEHOLD_LINES: on_head = copy(base) on_head["head"][name] = value households.append(on_head) @@ -347,29 +379,24 @@ def test_each_source_for_a_dependent(): if name is None or name.startswith("head:"): continue base = base_result[(age, spouse)] - if name in CLAIMANT_LINES: - assert result[i] == pytest.approx(base, abs=TOLERANCE), cases[i] - elif name in HOUSEHOLD_LINES: + if name in HOUSEHOLD_LINES: assert result[i] == pytest.approx(base + value, abs=TOLERANCE) assert result[i] == pytest.approx( head_result[(age, spouse, name, value)], abs=TOLERANCE ), cases[i] - else: # Premiums paid for the family. - assert result[i] == pytest.approx(base - value, abs=TOLERANCE) - assert result[i] == pytest.approx( - head_result[(age, spouse, name, value)], abs=TOLERANCE - ), cases[i] + else: # The dependent's own income, benefits and premiums. + assert result[i] == pytest.approx(base, abs=TOLERANCE), cases[i] def test_spouse_counts_like_the_head(): """Both spouses' own amounts count: each source on the spouse adds what - it adds on the head.""" + it adds on the head, and so do their premiums.""" households = [] - for name in CLAIMANT_LINES: + for name in [*CLAIMANT_LINES, PREMIUMS]: if name == "early_withdrawal_penalty": continue on_head = base_household(spouse=True) - on_head["head"][name] += 7_000 + on_head["head"][name] = on_head["head"].get(name, 0) + 7_000 on_spouse = base_household(spouse=True) on_spouse["spouse"][name] = 7_000 households += [on_head, on_spouse] @@ -526,3 +553,65 @@ def test_more_received_for_a_dependent(households, source, extra): households[i], source, ) + + def _raise(households, role, source, extra): + raised = [] + for h in households: + r = copy(h) + if role == "dependent": + target = r["dependents"][0] + elif role == "spouse" and r.get("spouse") is not None: + target = r["spouse"] + else: + target = r["head"] + target[source] = target.get(source, 0) + extra + raised.append(r) + return raised + + @hypothesis.settings( + max_examples=20, deadline=None, derandomize=True, suppress_health_check=SLOW + ) + @hypothesis.given( + st.lists(household(), min_size=1, max_size=10), + st.sampled_from(BENEFITS), + st.integers(min_value=1, max_value=50_000), + ) + def test_benefits_count_for_filers_only(households, source, extra): + """2 and 7. A dependent's own benefit never changes household + resources; the head's or spouse's counts in full.""" + households = households + [base_household(spouse=True)] + n = len(households) + result, _ = calculate( + households + + _raise(households, "dependent", source, extra) + + _raise(households, "head", source, extra) + + _raise(households, "spouse", source, extra) + ) + for i, h in enumerate(households): + # The raised household's scale is at most the base's plus extra. + tol = tolerance(h) + 8 * float(np.spacing(np.float32(extra))) + assert result[n + i] == pytest.approx(result[i], abs=tol), (h, source) + for k in (2, 3): + change = float(result[k * n + i]) - float(result[i]) + assert -tol <= change <= extra + tol, (h, source, k) + if result[i] > tol: + assert change == pytest.approx(extra, abs=tol), (h, source, k) + + @hypothesis.settings( + max_examples=20, deadline=None, derandomize=True, suppress_health_check=SLOW + ) + @hypothesis.given( + st.lists(household(), min_size=1, max_size=10), + st.sampled_from(["head", "spouse"]), + st.sampled_from(INCOME), + st.integers(min_value=1, max_value=50_000), + ) + def test_monotone_in_filer_income(households, role, source, extra): + """8. More of the head's or spouse's own income never lowers + household resources.""" + raised = _raise(households, role, source, extra) + result, _ = calculate(households + raised) + n = len(households) + for i, h in enumerate(raised): + tol = tolerance(h) + assert result[n + i] >= result[i] - tol, (households[i], role, source) From d458ba61e6165a129a3f60ae37095226dcf181e3 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 2 Nov 2026 15:58:09 -0500 Subject: [PATCH 3/5] Record that Michigan household resources now follow the statute The source-conflict backlog entry us-mi:household-resources-dependent-amounts still described the form reading this PR replaces. It now follows the statute from 2021 (the parameters start then), lists this PR, and says that line 31 subtracts only premiums the claimant and spouse paid. A Hypothesis docstring still named line 21, which the test no longer draws. Co-Authored-By: Claude Opus 5.5 --- .../test_mi_household_resources_members.py | 2 +- source_conflicts/candidates.yaml | 22 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/policyengine_us/tests/test_mi_household_resources_members.py b/policyengine_us/tests/test_mi_household_resources_members.py index c612e7de6ff..963ca09c95a 100644 --- a/policyengine_us/tests/test_mi_household_resources_members.py +++ b/policyengine_us/tests/test_mi_household_resources_members.py @@ -531,7 +531,7 @@ def test_properties(households): st.integers(min_value=1, max_value=50_000), ) def test_more_received_for_a_dependent(households, source, extra): - """4. More of a line 21, 22 or 27 amount for a dependent raises + """4. More of a line 22 or 27 amount for a dependent raises household resources by between 0 and the increase, and by exactly the increase when they were positive.""" # A household with positive resources, so the exact-increase branch diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 1cea80fc061..b83fee820a8 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -4408,7 +4408,7 @@ candidates: - id: us-mi:household-resources-dependent-amounts program: income-tax years: - from: 2024 + from: 2021 type: tax question: Do total household resources include the instructions' amounts for dependents and other family members when the statute defines household as claimant and spouse? @@ -4422,22 +4422,24 @@ candidates: readings: statute: Count the claimant and spouse's income. other: Count the specified income and premiums for all members, including amounts received for dependent adults. - example: A dependent adult's $2,400 pension changes SSI from $11,604 to $9,444, household resources from $21,604 - to $19,444, and heating credit from $35.316 to $80.676. + example: A minor child's $9,000 of Social Security survivors benefits, received with the claimant as + representative payee, stays out of household resources; the line 21 instructions would count it. pe_us: - follows: conflicting-source + follows: statute code: - policyengine_us/variables/gov/states/mi/tax/income/mi_household_resources.py + - policyengine_us/parameters/gov/states/mi/tax/income/household_resources.yaml - policyengine_us/parameters/gov/states/mi/tax/income/household_resources_all_members.yaml prs: - https://github.com/PolicyEngine/policyengine-us/pull/9796 + - https://github.com/PolicyEngine/policyengine-us/pull/10325 state: ruled - note: 'Partly changed by #9796: PE-US now counts only the claimant''s and spouse''s own income, as the statute - does, except the sources on MI-1040CR lines 21, 22 and 27 (Social Security, SSI, railroad benefits, child support, - TANF and general assistance), which it counts for every member as amounts received for others, as the form does - (mi_household_resources.py, household_resources_all_members.yaml). Ruled in October 2026 to follow the form; - the statute-first rule still requires deciding whether a dependent''s own benefits on those lines are received - for others.' + note: 'Ruled to follow MCL 206.508(3): Social Security, SSI and railroad benefits (MI-1040CR line 21) count for + the claimant and spouse only, so a dependent''s own benefit stays out even when the claimant receives it as + representative payee. RAB 2015-18 counts benefits received by minor children, and the line 21 instructions count + amounts received for minor children or other dependent adults. Line 31 subtracts the premiums the claimant and + spouse paid, family coverage included, and not premiums a dependent paid. PE-US treats child support (line 22) + and public assistance (line 27) as payments the claimant receives, so they count for every member.' - id: us-mi:household-resources-premium-double-deduction program: homestead-credit years: From 020348401b3a9a61c5041d154ceca07a003181c1 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 2 Nov 2026 16:16:13 -0500 Subject: [PATCH 4/5] Correct two source attributions in the Michigan household tests The test module's docstring said RAB 2015-18 counts amounts for dependent adults; it covers benefits received by minor children, and only the line 21 instructions add other dependent adults. It also attributed line 31's wording to MCL 206.510(1); the words are the 2025 MI-1040 book's (page 32). The backlog note now names PE-US as the one that follows MCL 206.508(3). Co-Authored-By: Claude Opus 5.5 --- .../tests/test_mi_household_resources_members.py | 11 ++++++----- source_conflicts/candidates.yaml | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/policyengine_us/tests/test_mi_household_resources_members.py b/policyengine_us/tests/test_mi_household_resources_members.py index 963ca09c95a..78a78da0c8d 100644 --- a/policyengine_us/tests/test_mi_household_resources_members.py +++ b/policyengine_us/tests/test_mi_household_resources_members.py @@ -9,9 +9,10 @@ That includes Social Security, SSI and railroad retirement benefits (line 21). A minor child's or dependent adult's own benefit is received by the beneficiary, even when the claimant is the representative payee, so it is -not household resources. Revenue Administrative Bulletin 2015-18 and the -line 21 instructions count amounts received for minor children or dependent -adults; the statute's definition of household governs both. +not household resources. Revenue Administrative Bulletin 2015-18 counts +benefits received by minor children, and the line 21 instructions count +amounts received for minor children or other dependent adults; the statute's +definition of household governs both. The claimant receives two kinds of amount for others in the household (page 32), which count wherever they are recorded: @@ -19,8 +20,8 @@ - line 22: child support and foster parent payments; - line 27: payments to the household by MDHHS and other public assistance. -Line 31 is "insurance premiums you paid for yourself and your family" (MCL -206.510(1)). health_insurance_premiums records the premiums each person +Line 31 is "insurance premiums you paid for yourself and your family" (page +32). health_insurance_premiums records the premiums each person paid, so only the head's and spouse's count; theirs may cover the family. Line 31 leaves out "any insurance premiums deducted on lines 21 or 30" (page 33), so the head's and spouse's self-employed health insurance diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index b83fee820a8..909fdd81ec8 100644 --- a/source_conflicts/candidates.yaml +++ b/source_conflicts/candidates.yaml @@ -4434,11 +4434,11 @@ candidates: - https://github.com/PolicyEngine/policyengine-us/pull/9796 - https://github.com/PolicyEngine/policyengine-us/pull/10325 state: ruled - note: 'Ruled to follow MCL 206.508(3): Social Security, SSI and railroad benefits (MI-1040CR line 21) count for + note: 'PE-US follows MCL 206.508(3): Social Security, SSI and railroad benefits (MI-1040CR line 21) count for the claimant and spouse only, so a dependent''s own benefit stays out even when the claimant receives it as representative payee. RAB 2015-18 counts benefits received by minor children, and the line 21 instructions count amounts received for minor children or other dependent adults. Line 31 subtracts the premiums the claimant and - spouse paid, family coverage included, and not premiums a dependent paid. PE-US treats child support (line 22) + spouse paid, including family coverage, and not premiums a dependent paid. PE-US treats child support (line 22) and public assistance (line 27) as payments the claimant receives, so they count for every member.' - id: us-mi:household-resources-premium-double-deduction program: homestead-credit From 18634f3acc51b01ae35933c1c13b446f76bd170c Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 2 Nov 2026 16:21:49 -0500 Subject: [PATCH 5/5] Use active voice in the household resources test docstring Co-Authored-By: Claude Opus 5.5 --- .../test_mi_household_resources_members.py | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/policyengine_us/tests/test_mi_household_resources_members.py b/policyengine_us/tests/test_mi_household_resources_members.py index 78a78da0c8d..a0a1d374bb5 100644 --- a/policyengine_us/tests/test_mi_household_resources_members.py +++ b/policyengine_us/tests/test_mi_household_resources_members.py @@ -4,18 +4,18 @@ counts "all income received by all persons of a household". The MI-1040CR asks for "all taxable and nontaxable income you and your spouse received" (2025 MI-1040 book, page 31), so a dependent's own income and Schedule 1 -adjustments are on the dependent's return, not the claimant's. +adjustments belong on the dependent's return, not the claimant's. That includes Social Security, SSI and railroad retirement benefits (line -21). A minor child's or dependent adult's own benefit is received by the -beneficiary, even when the claimant is the representative payee, so it is -not household resources. Revenue Administrative Bulletin 2015-18 counts +21). The beneficiary receives a minor child's or dependent adult's own +benefit, even when the claimant acts as representative payee, so household +resources leave it out. Revenue Administrative Bulletin 2015-18 counts benefits received by minor children, and the line 21 instructions count amounts received for minor children or other dependent adults; the statute's definition of household governs both. The claimant receives two kinds of amount for others in the household -(page 32), which count wherever they are recorded: +(page 32), which count on any member's record: - line 22: child support and foster parent payments; - line 27: payments to the household by MDHHS and other public assistance. @@ -24,8 +24,8 @@ 32). health_insurance_premiums records the premiums each person paid, so only the head's and spouse's count; theirs may cover the family. Line 31 leaves out "any insurance premiums deducted on lines 21 or 30" -(page 33), so the head's and spouse's self-employed health insurance -deduction, which is on line 30, is not subtracted again. Lines 20 and 24 +(page 33): line 30 takes the head's and spouse's self-employed health +insurance deduction, so line 31 doesn't subtract it again. Lines 20 and 24 count gambling winnings and gifts "over $300" (MCL 206.510(1)(a) and (b)), one amount for the claimant and spouse. @@ -39,9 +39,9 @@ matter: zeroing them leaves household resources unchanged. In particular a dependent's own Social Security, SSI or railroad benefit never changes household resources. -3. Amounts received for the household count wherever they are recorded: - moving a dependent's line 22 or 27 amount to the head leaves household - resources unchanged. +3. Amounts the claimant receives for the household count on any member's + record: moving a dependent's line 22 or 27 amount to the head leaves + household resources unchanged. 4. Raising a dependent's line 22 or 27 amount by d raises household resources by between 0 and d, and by exactly d when they were positive. 5. Each of the spouse's own sources adds what it adds on the head. @@ -119,9 +119,9 @@ ] # The claimant's and spouse's own income, for property 8. Not # self-employment income: line 16 nets it against other business losses, -# while its line 30 self-employment tax deduction is on the gross amount, so -# with an S corporation loss of 404, Schedule C income of 434 adds 30 on -# line 16 and deducts 30.66 on line 30. +# while line 30 takes its self-employment tax deduction on the gross +# amount, so with an S corporation loss of 404, Schedule C income of 434 +# adds 30 on line 16 and deducts 30.66 on line 30. INCOME = [ name for name in CLAIMANT_LINES @@ -443,7 +443,7 @@ def test_reformed_lists(): p = baseline.tax_benefit_system.parameters.gov.states.mi.tax.income sources = list(p.household_resources(f"{YEAR}-01-01")) all_members = list(p.household_resources_all_members(f"{YEAR}-01-01")) - # The dependent's own pilot payment is not household resources... + # Household resources leave out the dependent's own pilot payment... assert baseline.calculate("mi_household_resources", YEAR)[0] == pytest.approx( 40_000, abs=TOLERANCE ) @@ -476,8 +476,8 @@ def test_reformed_lists(): # --------------------------------------------------------------------------- -# Hypothesis properties. Hypothesis is a dev extra: without it these tests -# are not collected and the deterministic tests above still run. +# Hypothesis properties. Hypothesis is a dev extra: without it the module +# defines none of these tests, and the deterministic tests above still run. # --------------------------------------------------------------------------- try: @@ -589,7 +589,7 @@ def test_benefits_count_for_filers_only(households, source, extra): + _raise(households, "spouse", source, extra) ) for i, h in enumerate(households): - # The raised household's scale is at most the base's plus extra. + # The raised household's scale can't exceed the base's plus extra. tol = tolerance(h) + 8 * float(np.spacing(np.float32(extra))) assert result[n + i] == pytest.approx(result[i], abs=tol), (h, source) for k in (2, 3):