Skip to content

Cap Minnesota's K-12 subtraction per child by grade and add MSA living-alone pathways - #10586

Merged
MaxGhenis merged 11 commits into
mainfrom
statute-bugs-mn-k12-msa
Nov 3, 2026
Merged

MaxGhenis merged 11 commits into
mainfrom
statute-bugs-mn-k12-msa

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Two verified model bugs from the statute-first backlog. The statute governs and forms fill gaps (Max, 2026-10-19). The statute settles the caps and the pathways. It doesn't say when a child's grade counts, so the Minnesota Department of Revenue's guidance fills that gap (see Notes).

us-mn-k12-subtraction-grade-caps (2021+)

Source. Minn. Stat. 290.0132 subd. 4 (the governing subdivision; main cited subd. 9, which concerns delayed depreciation) and the 2025 Schedule M1M instructions, line 13 (PDF page 5). Both cap the subtraction separately for each qualifying child: $1,625 in kindergarten to grade 6, $2,500 in grades 7 to 12.

What changed. mn_k12_education_subtraction was min(k12_tuition_and_fees, children × $2,500). It's now the sum over qualifying children (modelled as K-12 dependents, the proxy mn_k12_qualifying_children uses) of min(max(own expenses, 0), cap for their grade). Two new annual person variables:

  • mn_k12_education_subtraction_qualifying_expenses_person: the child's otherwise-qualifying subtraction expenses, after excluding expenses used for the K-12 education credit;
  • mn_k12_education_subtraction_higher_cap_eligible: whether the child's grade at the end of the tax year is 7 to 12. It has an age default (see Notes) and stays settable as an override.

The $1,625 and $2,500 values are unchanged; their references now cite subd. 4 and the M1M page.

Witness. 2025, an 11-year-old with $2,000 and a 15-year-old in grades 7–12 with $1,000: 1,625 + 1,000 = $2,625. Main gave min(3,000, 5,000) = $3,000. A single K-6 child with $2,000: $1,625 (main $2,000).

us-mn-msa-living-alone-pathways (2011+)

Source. Minn. Stat. 256D.44 subd. 2 assigns the subd. 3(a) or (b) living-alone standard to people eligible for a medical assistance HCBS waiver and to people with the local agency's placement determination under 256I.04 subd. 1a. DHS Combined Manual 0020.21 agrees, and says residence in a Housing Support setting isn't required (PDF page 3). Its married-couple list (PDF page 5) gives the upgrade only to a couple on SSI federal living arrangement A or ineligible for SSI through excess income; subd. 2 has no such limit, so the code follows subd. 2. The 2026 standards are on PDF page 4.

What changed. Two monthly person inputs, default false: mn_msa_hcbs_waiver_eligible (waiver eligibility, not enrollment) and mn_msa_housing_support_plan_approved (the subd. 1a determination, not Housing Support receipt or residence alone). mn_msa_payment_category ORs them with mn_msa_housing_assistance_eligible to upgrade "living with others" to "living alone". Either spouse's pathway upgrades a couple. Medicaid-facility handling is unchanged. No monetary parameters change.

Witness. January 2026, an individual living with others who is eligible for an HCBS waiver: assistance standard $1,055 (main: $755.33). A couple living with others where one spouse is waiver-eligible: COUPLE_LIVING_ALONE for both. The pathways apply from the modelled 2011 start.

Notes

  • Tax-unit total. When no child has a per-child record, k12_tuition_and_fees meets the sum of the children's caps, so a household that holds only that input keeps a subtraction. That path can't stop one child's unused cap from reaching another child's expenses. Once any qualifying child has a positive per-child record, the formula ignores the total for every child, so the records must then cover every child; the per-child input's documentation says so.
  • Limit: expenses used twice. The K-12 credit also reads k12_tuition_and_fees, and subd. 4(a)(3) subtracts "any amount used to claim the credit". On main the two also read the same total, so this PR doesn't change that gap. The per-child input's documentation excludes those expenses.
  • Grade default. Subd. 4(b) sets the caps by grade without saying when; the Minnesota Department of Revenue's K-12 page uses the grade at the end of the tax year. The model has no grade input, so without one mn_k12_education_subtraction_higher_cap_eligible imputes grade from age on is_in_k12_school's convention (ages 5 to 17 are in school, so grade = age − 5): a qualifying child aged 12 or older gets $2,500 and a younger one $1,625. For a caller who sets only the tax-unit total k12_tuition_and_fees, each child under 12 now adds $1,625 to the limit where main added $2,500, which subd. 4(b) requires for kindergarten to grade 6; each child 12 or older still adds $2,500.
  • source_conflicts/candidates.yaml records the two readings this PR takes: us-mn:k12-subtraction-grade-cap-default and us-mn:msa-couple-arrangement-b-pathways. The register entries and markers follow after this merges. The K-12 file's old "In practice ..." comment is gone, so this PR removes its KNOWN_UNMARKED entry from policyengine_us/tests/code_health/test_source_conflicts.py.

impact: none at baseline. populace_us_2024.h5 at populace-us-2024-spm-20260909 stores no k12_tuition_and_fees or per-child K-12 expense column in any entity table, and both new MSA inputs default to false.

axiom: TheAxiomFoundation/rulespec-us#1987 queued

🤖 Generated with Claude Code

…ways

Minn. Stat. 290.0132 subd. 4 caps the K-12 education subtraction
separately for each qualifying child: $1,625 in kindergarten to grade 6
and $2,500 in grades 7 to 12. Main applied $2,500 to every child against
a pooled tax-unit total. Two new person inputs record each child's
qualifying expenses (net of those used for the credit) and whether the
child attended grades 7 to 12; parameter references move from subd. 9
to subd. 4.

Minn. Stat. 256D.44 subd. 2 also gives the MSA living-alone standard to
people eligible for a medical assistance HCBS waiver and to those with
the local agency's 256I.04 subd. 1a placement determination; main
modelled only the housing-allowance pathway. Two monthly inputs join it
in the payment-category upgrade, for either spouse of a couple.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6K4grkKNkfjkW6hbaN
@MaxGhenis

MaxGhenis commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor Author

Ready for hub review

Head: 1bc01e6420af1a526d86a9ffb86418f6b517a124

Per-item status

  • us-mn-k12-subtraction-grade-caps: fixed.
    • Per-child cap by grade: mn_k12_education_subtraction.py:16-36.
    • New inputs: mn_k12_education_subtraction_qualifying_expenses_person.py, mn_k12_education_subtraction_higher_cap_eligible.py.
    • References moved to subd. 4 and M1M page 5: k12_education/cap/lower.yaml, higher.yaml.
  • us-mn-msa-living-alone-pathways: fixed.
    • The OR of the three pathways: mn_msa_payment_category.py:36-40.
    • New inputs: mn_msa_hcbs_waiver_eligible.py, mn_msa_housing_support_plan_approved.py.
    • The stale TODO in mn_msa_housing_assistance_eligible.py now points to the new inputs.

Ownership checks: neither branch existed, and searches for open PRs found none on the same change. #10146 (SSI deeming) and #10374 (Medicaid medically needy) came up but touch other files.

Tests (failing first, then passing; one file per process)

  • mn_k12_education_subtraction.yaml: 6 failed before the fix, 6 passed after. It replaces the 4 old cases, which pooled k12_tuition_and_fees against mn_k12_qualifying_children × $2,500.
  • mn_msa_payment_category.yaml: 5 failed before, 10 passed after. mn_msa_assistance_standard.yaml: 1 failed before, 16 passed after.
  • Other MSA files: net income 8, resource 11, gross income 8, eligible person 11, living arrangement 6, integration 12, representative payee fee 2, special needs 6, guardian fee 9, housing assistance 3, person 16, premium input contract 5, housing assistance eligible 2; all passed.
  • mn_k12_education_credit.yaml 8 passed. Other MN subtraction files: 529 6, active duty 3, military pension 6; all passed.
  • tests/code_health/test_source_conflicts.py 103 passed.

Hand computations

  • K-12, 2025: an 11-year-old with $2,000 and a 15-year-old in grades 7–12 with $1,000 → min(2,000, 1,625) + min(1,000, 2,500) = 2,625 (main 3,000). A K-6 child with $2,000 → 1,625 (main 2,000). Negative expenses: max(−500, 0) + min(3,000, 2,500) = 2,500.
  • MSA, January 2026: waiver-eligible individual living with others → $1,055 (main $755.33).

Mutants (each in its own process, code restored after)

  • K1, higher cap for every child: 2 failed. Killed.
  • K2, pooled expenses against pooled per-child caps: 2 failed. Killed.
  • M1, HCBS input dropped from the OR: 2 failed. Killed.
  • M2, placement input dropped from the OR: 2 failed. Killed.

CI

Draft, not run.

Judgment calls

  • The backlog spec for the K-12 item is cut off in the brief ("The department [...]"). I implemented the visible rule only. Whatever followed is unread and may matter.
  • The subtraction no longer reads the tax-unit k12_tuition_and_fees input, as the spec's per-child design implies. API callers and data that set only that input now get $0 subtraction; main gave up to $2,500 per K-12 dependent. The credit still reads it. The hub may want a fallback.
  • mn_k12_education_subtraction_higher_cap_eligible defaults to false, so the lower cap applies unless the input is set.
  • The new inputs carry no defined_for, since they are plain inputs. The subtraction formula applies only to K-12 dependents.
  • Unverified (VM couldn't reach revisor.mn.gov or dhs.state.mn.us): the statute and manual content is as the backlog spec states it. I quoted nothing from them.
  • The MSA spec's own text is also cut off ("individual with [...]"). Only the $1,055 individual-alone figure was used, and existing tests already carry it.

Proposed follow-up

  • MN K-12: one expense record shared by the credit and the subtraction — model per-child expenses once and assign each dollar to either the credit or the subtraction (subd. 4 excludes expenses used for the credit). That would let k12_tuition_and_fees feed both without double use.

Generated by Claude Code

MaxGhenis and others added 2 commits November 2, 2026 03:24
A household that records only k12_tuition_and_fees got no subtraction after
the per-child change. That total now meets the sum of the children's caps
when no per-child expense exists. Per-child records still govern.

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

codecov Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codecov Report

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

Additional details and impacted files
@@            Coverage Diff            @@
##              main    #10586   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            1         7    +6     
  Lines           15        88   +73     
=========================================
+ Hits            15        88   +73     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

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

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

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

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review
VERDICT: REQUEST_CHANGES
f40af2d
METHODOLOGY_CHOICE: no

Independent review, round 1. The PR head is still f40af2d960, so nothing moved since the brief. CI at this head is green: workflow run 41413205660 ran every job to success, with none cancelled or skipped. That covers the baseline shards, contrib shards, Python shards, Microsimulation, Household API Partners and PR validation.

Sources. This VM couldn't reach revisor.mn.gov, revenue.state.mn.us, dhs.state.mn.us, govinfo.gov or law.justia.com: the proxy refused every connection. I read no statute, form or manual text in this session. Every legal statement below rests on the code, the parameter files, or the hub's note that 290.0132 subd. 4, 290.0674 subd. 1a and 256D.44 subds. 2 and 3 match the backlog spec. I quote no law.

Findings

P1. With no grade record, every child gets the lower $1,625 cap, so callers who set only k12_tuition_and_fees lose subtraction they had on main

policyengine_us/variables/gov/states/mn/tax/income/subtractions/mn_k12_education_subtraction_higher_cap_eligible.py:4-16 (a bare input, default false), read at mn_k12_education_subtraction.py:31-35.

Failure scenario. k12_tuition_and_fees is the only K-12 input on main, so every existing API or household-calculator caller sets that and nothing else. For them, every child now meets the K-6 cap, even a 15- or 16-year-old who is almost certainly in grades 7 to 12. A single parent with one 15-year-old and $2,500 of expenses got $2,500 on main and gets $1,625 here. For a high-school child the statute's cap is the higher one, so the PR moves this caller away from the law, not toward it.

Ran uv run python wit.py in a main worktree and a PR worktree. The script builds a tax unit with a parent aged 40, the listed children and k12_tuition_and_fees, and calculates mn_k12_education_subtraction and mn_k12_education_credit:

children (ages)   total    main subtraction   PR subtraction   credit (both)
(9, 15)           5,000    5,000              3,250            3,000
(9, 15)          10,000    5,000              3,250            3,000
(15,)             2,500    2,500              1,625            1,500
(9, 15, 16)       7,500    7,500              4,875            4,500
(15,) in 2021     2,500    2,500              1,625            1,500

None of the 10 tests catches this. Both fallback tests set mn_k12_education_subtraction_higher_cap_eligible: true on the older child, so the no-flag case ((9, 15) → $3,250) goes untested.

Age default. The model already imputes K-12 attendance from age in is_in_k12_school (ages 5 to 17, so age 5 is kindergarten). On that same convention a child is in grade 7 at age 12, and age 13 or older at year-end means grade 7 or above for at least the fall term. I found no reachable statute, instruction or manual text that maps age to grade, or that settles a child who moves from grade 6 to 7 mid-year. The only support is the model's own imputation. So this is the hub's call. My recommendation is to make the flag a formula default rather than leave it false, since a false default is wrong for most of the children it reaches:

class mn_k12_education_subtraction_higher_cap_eligible(Variable):
    value_type = bool
    entity = Person
    label = "Attended grades 7 to 12 for the Minnesota K-12 Education Subtraction"
    documentation = (
        "Whether this qualifying child attended grades 7 to 12 during the "
        "tax year, so the higher per-child cap applies. Without an input, "
        "children aged 13 or older are assumed to be in grades 7 to 12, on "
        "the same age-for-grade imputation as is_in_k12_school (age 5 is "
        "kindergarten)."
    )
    definition_period = YEAR
    reference = (...)  # unchanged

    def formula(person, period, parameters):
        # Imputation, not policy: not parameterized, like is_in_k12_school.
        return person("age", period) >= 13

If the hub prefers to keep the input, then at least make the no-grade fallback keep main's behaviour. That means applying p.cap.higher per child in the pooled branch when no child carries a per-child record, and saying so in the body. Either way, add a fallback test with no grade flag. With the age default it would be ages 9 and 15, total $5,000 → min(5,000, 1,625 + 2,500) = 4,125.

The body's line "the lower cap applies until a caller sets it" is accurate, but it doesn't say that this is a cut from main for every caller who sets the total only. The impact: line should name that.

P2. Nothing tests the dependent half of "qualifying child"

mn_k12_education_subtraction.py:22-24 (is_in_k12_school & is_tax_unit_dependent).

Mutant K3 (mine) drops & is_tax_unit_dependent. It survives the whole test file: uv run python -m policyengine_core.scripts.policyengine_command test .../mn_k12_education_subtraction.yaml -c policyengine_us → 10 passed. The non-child test case uses a 4-year-old with is_in_k12_school: false, so it only exercises the K-12 half. Add this case. It passes at the head (1 passed) and kills K3 (1 failed):

- name: A K-12 student who is not a dependent is not a qualifying child
  period: 2025
  input:
    people:
      parent:
        age: 40
      child:
        age: 16
        is_in_k12_school: true
        is_tax_unit_dependent: false
        mn_k12_education_subtraction_qualifying_expenses_person: 1_000
        mn_k12_education_subtraction_higher_cap_eligible: true
    tax_units:
      tax_unit:
        members: [parent, child]
        k12_tuition_and_fees: 1_000
    households:
      household:
        members: [parent, child]
        state_code: MN
  output:
    mn_k12_education_subtraction: 0

P3. The test comment cites subd. 3(a) for $1,055, but $1,055 is DHS's 2026 published standard

policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_assistance_standard.yaml, the last case. The comment reads # Minn. Stat. 256D.44 subd. 2 and 3(a): $1,055.

The $1,055 isn't computed from subd. 3(a). It is the 2026-01-01 INDIVIDUAL_LIVING_ALONE value in parameters/gov/states/mn/dhs/msa/assistance_standard/amount.yaml, a combined federal-and-state standard referenced to DHS Combined Manual 0020.21 (01/2026). The same file's 2026 values are 755.33 living with others, 1,582 couple alone and 1,058 couple with others. The brief reports that subd. 3(a) states $519. I couldn't fetch subd. 3 to confirm that or to trace how $519 grows to $1,055 under subd. 1's adjustment. Either way, the comment implies subd. 3(a) states $1,055, and a reader checking the statute won't find it there. Replace it with:

    # Subd. 2 places the person in the subd. 3(a) individual living-alone
    # standard; CM 0020.21 (01/2026) publishes it as $1,055, not the
    # $755.33 living-with-others standard.

P3. A per-child record on one child drops the rest of the tax-unit total without comment

mn_k12_education_subtraction.py:44-45. has_child_records is true as soon as any qualifying child carries a positive record. After that the tax-unit total is ignored, including for children who have no record. For example, a $1,000 record on one child plus k12_tuition_and_fees: 5_000 gives $1,000. The test "Per-child records govern over a tax-unit total" asserts exactly this. It is defensible, but the variable's documentation should say that per-child records, once any exist, must cover every child.

has_child_records doesn't misfire on the cases the brief names. A negative record is clipped to 0 before the sum, so it doesn't switch off the fallback. A record on a parent, or on a child who isn't K-12, is zeroed by where(qualifying, ...), so it also leaves the fallback in force. The test "Expenses for a person who is not a qualifying child are not subtracted" covers the second.

Checked and sound

  • Defect at main. Reproduced. On main the subtraction is min(total, children × 2,500). Two children with $2,000 and $1,000 (K-6 and 7-12) give 3,000 on main and 2,625 at the head, from the test file's own case. Main also gives a K-6 child $2,000 where the per-child cap gives $1,625.

  • Rule, by hand. With per-child records, sum over qualifying children of min(max(expense, 0), cap) with caps 1,625 and 2,500. Cases: 2,000 → 2,000; 5,000 → 2,500; K-6 2,000 → 1,625; 1,625 + 1,000 = 2,625; 0 + 2,500 = 2,500. Fallback: min(5,000, 4,125) = 4,125 and min(3,000, 4,125) = 3,000. All match the tests, and all 10 pass.

  • Qualifying child versus main's count. The new formula's set is exactly mn_k12_qualifying_children's set (is_in_k12_school & is_tax_unit_dependent, in credits/k12_education/mn_k12_qualifying_children.py), so the credit and the subtraction still agree on who counts. I couldn't read 290.0674 subd. 1a, so I can't say whether "dependent" matches its definition. One witness is identical on both branches: an 18-year-old in grade 12 gets $0 on main and at the head, because is_in_k12_school imputes only ages 5 to 17. That is a follow-up, not this PR's defect.

  • Double use, subd. 4(a)(3). On main, mn_k12_education_credit.py:21 and the old subtraction both read k12_tuition_and_fees with no offset, so the same dollars fed both; the body's "identical on main" is correct. At the head the fallback reads the same total the same way, so that gap is unchanged. The per-child path reads only the new person input, which is documented as net of credit expenses, so it can't double-use unless a caller enters the same dollars in both inputs. That is no worse than main. The credit tests pass: credits/k12_education, 13 passed.

  • KNOWN_UNMARKED. Main's entry counted the line "In practice, different limits apply for K-6 vs 7-12", which matched CONFLICT_COMMENT_RE's \bin\ practice\b. That line described a modelling shortcut, not a disagreement between law and form. source_conflicts/candidates.yaml on main has no entry for 290.0132 or this file. So the entry named no real conflict, and removing it is correct. pytest tests/code_health/test_source_conflicts.py → 103 passed at the head.

  • MSA formula. I read the whole of mn_msa_payment_category. The order is unchanged from main: the pathway is computed, a couple's pathway comes from marital_unit.any, select upgrades only the two living-with-others values (any other value passes through), and the Medicaid-facility override is applied last. So the personal-needs path can't receive the living-alone standard (Case 9 asserts this). The model has no separate licensed-residential-facility category, so there is no such path for the upgrade to reach wrongly, though I couldn't read whether subd. 2 excludes those settings. Witnesses at the head:

    • HCBS individual living with others → INDIVIDUAL_LIVING_ALONE, $1,055 (main: $755.33 with no pathway, and the input doesn't exist there).
    • Couple where only one spouse is waiver-eligible → COUPLE_LIVING_ALONE for both (Case 8).
    • Couple where the spouse in a Medicaid facility is the one carrying the pathway → [MEDICAID_FACILITY $132, COUPLE_LIVING_ALONE $1,582]. The community spouse is upgraded by the facility spouse's pathway. Main does the same with mn_msa_housing_assistance_eligible, so this is a follow-up: say whether a facility spouse's eligibility should lift the community spouse.
  • Third pathway. mn_msa_housing_assistance_eligible's own TODO already ties it to the § 256D.44 subd. 5(g) test, so treating it as subd. 2's shelter-needy ground fits the code. I couldn't read subd. 5(g). The variable's remaining comment is accurate: it names the two new inputs and where they're read.

  • Years. Both cap files start at 2021-01-01 with 1,625 and 2,500, and the formula now cites subd. 4 (main cited subd. 9). The MSA inputs have no start date, so they apply from the parameter's 2011 start (Case 10). I couldn't check whether the K-12 caps changed before 2021.

  • Tests run, one file per process at the head. mn_k12_education_subtraction.yaml 10 passed; mn_msa_payment_category.yaml 10 passed; mn_msa_assistance_standard.yaml 16 passed.

  • Mutants, each in its own process, with the code restored afterwards (git status clean, HEAD f40af2d9):

    Mutant Change Result Killed by
    K1 higher cap for every child 3 failed "A child in kindergarten to grade 6…", "Each child is capped separately…", "A tax-unit total over the sum of the caps…"
    K2 pooled expenses against pooled caps 2 failed "Each child is capped separately…", "Negative expenses…"
    K3 (mine) drop is_tax_unit_dependent survives nothing; see P2
    K4 (mine) has_child_records always true 2 failed the two tax-unit-total cases
    M1 HCBS dropped from the OR 2 failed in category, 1 in standard Cases 6 and 8; "Case HCBS"
    M2 placement dropped 2 failed Cases 7 and 10
    M3 (mine) couple uses own pathway only 2 failed includes Case 8
  • Readers.

    • mn_k12_education_subtraction: the subtractions/sources.yaml lists (2021 and 2023), then mn_subtractions → mn_taxable_income.
    • mn_msa_payment_category: mn_msa_assistance_standard, mn_msa_eligible_person (NONE test, unaffected), mn_msa_net_income_eligible, mn_msa_person, mn_msa_special_needs_total (facility test, unaffected), then mn_msa.
    • k12_tuition_and_fees: mn_k12_education_credit, mn_k12_education_subtraction and il_k12_education_expense_credit_potential. The IL file and its inputs aren't in the diff, so Illinois doesn't move.
  • Population impact. Impact pair: mn_k12_education_subtraction, mn_subtractions, mn_taxable_income, mn_income_tax and state_income_tax; and mn_msa_payment_category, mn_msa_assistance_standard and mn_msa. The MSA side can't move at baseline: both new inputs default to false. The K-12 side moves wherever the dataset holds a nonzero k12_tuition_and_fees, because the cap per child falls from $2,500 to $1,625 under the false default (P1). If the data leave that input at zero, nothing moves.

  • Scope. The 14 files touch nothing under .github/ or tests/policy/baseline/partners/. Open-PR searches for mn_k12_education_subtraction, mn_msa_payment_category, k12_tuition_and_fees and mn_msa_housing_assistance_eligible return only Cap Minnesota's K-12 subtraction per child by grade and add MSA living-alone pathways #10586.

  • Body lines. impact: and axiom: are both present. The hand-off's test counts (6 K-12 cases) and "API callers … now get $0" predate the hub's fallback commits, and the head carries 10 cases and the fallback. The PR body reflects the head.

What I couldn't check

  • Every statute and manual text: Minn. Stat. 290.0132 subd. 4, 290.0674 subd. 1a, 256D.44 subds. 2, 3 and 5(g), 256I.04 subd. 1a, CM 0020.21 (including "actual residence isn't needed"), and the 2025 M1M instructions. The proxy refused all of these hosts.
  • Whether the caps changed before 2021, and the $519-to-$1,055 relationship in subd. 3(a).
  • Whether population data hold any k12_tuition_and_fees. The impact run needs the hub's data.

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Picking this up for the US hub. I'll post a hand-off comment here when it's ready.


Generated by Claude Code

Minn. Stat. 290.0132 subd. 4(b) caps the subtraction at $1,625 per child in
kindergarten to grade 6 and $2,500 in grades 7 to 12; the Department of
Revenue sets the cap by the grade at the end of the tax year. With the grade
flag as a bare input, every child defaulted to the lower cap. Default it from
age on is_in_k12_school's convention (grade = age - 5), so children aged 12
or older get the higher cap; the flag stays settable as an override.

Also test the dependent half of "qualifying child" and the age-12 boundary,
note in the per-child input that records must then cover every child, and
attribute the $1,055 MSA standard to CM 0020.21 rather than the statute.

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

Copy link
Copy Markdown
Contributor Author

Ready for hub review

Head: fc2c13a1af7c24d142f7505a2b10416b9a220a61

Merge. Started at f40af2d960b53f3541ff6dd68fd1e97cf2badfba, as named. Merged origin/main (4cf0a98e47) with merge commit f18cad8dcb. No conflicts. The fix commit is fc2c13a1af.

Finding 1 (grade default). mn_k12_education_subtraction_higher_cap_eligible.py:8-24: added the formula age >= 12 and the documentation from the ruling. The label and references are unchanged, and the variable is still settable as an override. I read is_in_k12_school.py before citing it: it treats ages 5 to 17 as in school, and its comment says this is "an imputation rather than a policy rule". New cases in mn_k12_education_subtraction.yaml (after the existing ten):

  • Tax-unit total with no grade input (ages 9 and 15, k12_tuition_and_fees 5,000): min(5,000, 1,625 + 2,500) = 4,125.
  • Age 12 boundary (per-child records of 2,000 for ages 11 and 12, no grade input): 1,625 + min(2,000, 2,500) = 3,625.
  • Override (age 15, flag false, record 2,000): min(2,000, 1,625) = 1,625.

Existing cases whose value changed: none. Every existing case with a child aged 12 or older already sets the flag to true (ages 14, 15, 15, 13, 15, 15). Every child without the flag is aged 4, 7, 9 or 11, so the default gives false, the same as before. All ten existing expectations are unchanged and still pass.

Finding 2. Added the case "A K-12 student who is not a dependent is not a qualifying child" (expected 0) as given.

Finding 3. mn_msa_assistance_standard.yaml, last case: replaced the comment with the given text. I confirmed that amount.yaml has INDIVIDUAL_LIVING_ALONE 2026-01-01: 1_055 and cites CM 0020.21 (01/2026).

Finding 4. mn_k12_education_subtraction_qualifying_expenses_person.py documentation now says that once any qualifying child has a positive record, the subtraction uses only the records and ignores k12_tuition_and_fees, so the records must cover every child. The behaviour is unchanged. The test "Per-child records govern over a tax-unit total" still passes.

Body. "Limit: grade" is replaced by "Grade default", which gives the age rule, its basis (subd. 4(b) plus the DoR K-12 page's end-of-year grade) and the $1,625-under-12 consequence for total-only callers. Other changes:

  • The grade-input bullet under "What changed" now says "grade at the end of the tax year", with an age default.
  • The tax-unit-total note now covers the record-coverage point from finding 4.
  • The impact line is set as instructed.
  • The axiom: line and the closing line are kept.

The readback is identical to my file. REST PATCH replaced the closing line with a different footer, so I wrote the body through the GitHub MCP tool instead, and that kept the line.

Tests at head (one file per process):

File Result
mn_k12_education_subtraction.yaml 14 passed
mn_k12_education_credit.yaml 8 passed
mn_k12_qualifying_children.yaml 5 passed
mn_msa_payment_category.yaml 10 passed
mn_msa_assistance_standard.yaml 16 passed
test_source_conflicts.py 103 passed

make format / ruff: clean. Format also rewrote docs/usage/social-security-pia-ratio.md, a file from main that is out of scope, so I reverted that change and did not commit it.

Mutants (each in its own process, against the committed head, code restored after each):

  • (a) age >= 13 → 1 failed: "Age 12 is the first age imputed to grades 7 to 12".
  • (b) all-false (implemented as age < -1) → 2 failed: "A tax-unit total with no grade input caps by imputed grade" and "Age 12 is the first age imputed to grades 7 to 12".
  • (c) K3, dropping & is_tax_unit_dependent → 1 failed: "A K-12 student who is not a dependent is not a qualifying child".

CI. Pull request run 41522942388 was still in progress 60 minutes after the push: 32 jobs succeeded, none failed, and two were still running (Contrib other-shard-1 and other-shard-3). The run has no final conclusion yet.

Judgment calls.

  • I ran the mutants only after committing. My first restore used git checkout before the commit, which reverted the uncommitted formula, so I discarded that round and reran all three against the commit.
  • For mutant (b) I used a comparison that is always false rather than a literal False, so the return stays an array.
  • No microsimulation was run. The impact line is the hub's dataset check.

No follow-up issues proposed.


Generated by Claude Code

MaxGhenis and others added 6 commits November 2, 2026 19:12
The revenue department's guidance gives the higher cap to a child who finished grade 12 and started college during the year, and the qualifying-child test is a proxy for the 32(c)(3) definition. The documentation, comments and a test name now say so. No behaviour changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The statute is silent on when a child's grade counts, and the department's page and the M1M line differ. The manual's couple lists limit an upgrade that 256D.44 subd. 2 doesn't. Each is a reading this PR takes, so each goes in as a candidate, with the register entry and the marker after this merges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis merged commit 20e552e into main Nov 3, 2026
37 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

US + core hub merge audit, us#10586 at d17a62b009b4b0e2ff3bf51afd5352a3e9fa59c9 (squash): Cap Minnesota's K-12 subtraction per child by grade and add MSA living-alone pathways.

  • Review: independent cloud review (Opus 5.5) at round 1, findings fixed by a cloud fix round, delta review APPROVE at fc2c13a. The hub's two later commits change documentation, comments, a test name and two candidates only; the hub read 256D.44 subd. 2, Combined Manual 0020.21 and the department's K-12 page and M1M line itself.
  • Branch update: GitHub's branch updates merged main 6fa4eaf6d3, then 0a87d1f6b0, then a527e22b1e, then 4b37c729da, into the reviewed head 78054e024e; after each update, every file's changes match the reviewed head's.
  • Gates checked live at merge:
    • gh pr checks exits 0;
    • the latest Pull request run at the head concluded success;
    • MERGEABLE;
    • not a draft;
    • no reviewer's latest review requests changes;
    • the semantic-overlap guard;
    • head pinned.
  • Impact: none at baseline: populace_us_2024.h5 at populace-us-2024-spm-20260909 stores no k12_tuition_and_fees or per-child K-12 expense column in any entity table (read directly from the file), and both new MSA inputs default to false.
  • Axiom: [pe-parity] Minnesota: per-child K-12 subtraction caps and the 256D.44 subd. 2 living-alone grounds (PE-US #10586) TheAxiomFoundation/rulespec-us#1987 queued

@MaxGhenis
MaxGhenis deleted the statute-bugs-mn-k12-msa branch November 3, 2026 08:15
MaxGhenis added a commit that referenced this pull request Nov 3, 2026
On main, #10586 replaced housing_assistance_eligible in mn_msa_payment_category with living_alone_pathway: the housing allowance, an HCBS waiver or a 256I.04 placement. Keep main's pathway, comment and references, and apply this branch's spouse sum, _ssi_couple_total, to the pathway in place of marital_unit.any.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants