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 6f7d5353bb5..6e76d5e2253 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 @@ -36,7 +36,8 @@ values: - gambling_winnings - miscellaneous_income # 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/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..a0a1d374bb5 100644 --- a/policyengine_us/tests/test_mi_household_resources_members.py +++ b/policyengine_us/tests/test_mi_household_resources_members.py @@ -4,41 +4,55 @@ 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 belong on the dependent's return, not the claimant's. + +That includes Social Security, SSI and railroad retirement benefits (line +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 on any member's record: -- 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" (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): 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. 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. -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 + 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 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. 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 +98,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 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 + 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 +241,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 +265,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 +293,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 +301,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 +342,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 +357,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 +380,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] @@ -415,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 ) @@ -448,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: @@ -504,7 +532,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 @@ -526,3 +554,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 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): + 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) 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 d4301481468..c045589e87a 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 @@ -74,11 +74,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 @@ -143,9 +154,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. - 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. + premiums = tax_unit_non_dep_add(tax_unit, period, ["health_insurance_premiums"]) # "Do not include any insurance premiums deducted on lines 21 or 30" # (2025 MI-1040 book, page 33). Line 30 includes the self-employed # health insurance deduction (Schedule 1 line 17), so those premiums diff --git a/source_conflicts/candidates.yaml b/source_conflicts/candidates.yaml index 2ad017d3121..82732313d7a 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: '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, 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 years: