Skip to content

Restore the part-year facility-stay test cases now that SSI follows each month's facility status - #10856

Merged
hua7450 merged 2 commits into
PolicyEngine:mainfrom
hua7450:msp-post-merge-followups
Nov 13, 2026
Merged

hua7450 merged 2 commits into
PolicyEngine:mainfrom
hua7450:msp-post-merge-followups

Conversation

@hua7450

@hua7450 hua7450 commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Follows up #10633, #10640 and #10820 (the fix for #10818). No formula, parameter or variable changes.

What and why

#10633 ended the facility stay in msp_fpg.yaml Case 4 before December and added a NOTE to _msp_spouse_income.py, because SSI then combined a couple's income by December's facility status for the whole year (#10818). Its description said both would go back once #10820 was on main. #10820 merged as 38a392741c, so this PR lets the stay run through December and deletes the NOTE.

For the same reason, #10640 dropped the ssi_countable_income assertion from Case 45 of is_medically_needy_for_medicaid.yaml (New York, a stay from January to June) and said to restore it as 20,880 each. The reviewer's round-3 review of #10640 (G12) corrected that figure: 20,880 is the figure with no stay. This PR restores the assertion with the value the model gives, [14,320, 27,320], which matches the reviewer's arithmetic.

It also takes four optional suggestions from the reviewer's approving round-3 reviews of #10633 and #10820. The carried-over suggestions from those reviews are not in this PR.

Changes

  1. msp_fpg.yaml Case 4. person2's stay now runs from July through December: the two 2026-12: false inputs are gone, and the comment about the old SSI behavior is replaced by June's SSI arithmetic. Expected values are unchanged. In June both spouses are at home, so SSI combines their income (20 CFR 416.1802(b)(1)): $1,000 + $1,500 - $20 = $2,480, above the $1,491 couple rate, so neither spouse is eligible for SSI. Each spouse's income is then above the $497 rate difference and is deemed: $2,480, above the QI-1 couple limit of 1.35 x $21,640 / 12 = $2,434.50, so two-person guideline $1,803.33 and no tier. From July person2 is in the facility (416.414(b)(3)) and each spouse is tested alone: person1 $980, one-person $1,330, QMB; person2 $1,480 and not on Medicare.
  2. _msp_spouse_income.py. Deletes the four-line NOTE that said SSI attributes a couple's income by the year's last month. Comment only.
  3. Source-conflict candidate us-tx:msp-spouse-deeming-allowance (still state: open; no ruling, no marker):
    • years.from moves from 2026 to 2025. Revision 25-2 of Texas MEPD Handbook Appendix XXIX (effective June 1, 2025; "information is effective March 1, 2025") has the same steps with 2025 amounts: "Community MEPD $483, CAS $483, QMB $458, SLMB $550, QI-1 $619", against SSI's $1,450 - $967 = $483. The archived revision is added as a second manual source, and the question gives both years' amounts.
    • 42 U.S.C. 1396a(r)(2)(A) is added as a source and quoted in the statute reading: the methodology for people "under section 1396d(p) of this title may be less restrictive, and shall be no more restrictive, than the methodology" of SSI.
  4. Part-year cases for the two annual readers (md_paa_countable_income.yaml Case 4; the facility case at the end of medicaid_optional_senior_or_disabled_countable_income.yaml). person1 also has ssi_earned_income: 12_000, so each case now pins the earned-income line of its reader as well as the unearned one. Expected values go from [11,760, 5,760] to [17,370, 5,760]:
    • person1: ($1,000 - $20) + ($1,000 - $65) / 2 = $980 + $467.50 = $1,447.50 a month, x 12 = $17,370. person2 is unchanged at ($500 - $20) x 12 = $5,760. Both spouses are aged, so neither is an ineligible spouse and nothing is deemed.
    • If either reader's earned line read the monthly ssi_marital_earned_income instead, January to June would give person2 the couple's $1,000 a month of earnings, $6,000 for the year, and person2 would get $5,760 + ($500 - $65) / 2 x 12 = $8,370 (traced from the code, not run).
  5. is_medically_needy_for_medicaid.yaml Case 45 (from Apply each state's rule for a Medicaid applicant whose spouse is not aged, blind or disabled #10640; round-3 G12). The case asserts ssi_countable_income: [14_320, 27_320] again, and the comment above it now gives that arithmetic instead of saying to restore 20,880 later. ssi_countable_income follows each month's status:
    • January to June, person1 is in the facility, so each spouse counts their own income less $20 (20 CFR 416.414(b)(3)): ($8,000 / 12 - $20) x 6 = $3,880 and ($34,000 / 12 - $20) x 6 = $16,880.
    • July to December, both are home, so each counts half of the couple's $42,000 / 12 - $20 = $3,480 (20 CFR 416.1802(b)(1)): $1,740 x 6 = $10,440.
    • Totals: $14,320 and $27,320. The medically needy test still uses the couple standard by December's status, and the couple's $41,640 (not $41,760, as the comment said before) is above 12 x $2,489 = $29,868, so no other output changes.
  6. Test names. In ssi_marital_earned_income.yaml and ssi_marital_unearned_income.yaml, "... before one spouse enters a medical facility" becomes "... before one spouse's first full month in a medical facility": the month of entry is still combined, and the separate computation starts with the first month the spouse is in the facility "as of the beginning of the month and stay[s] the entire month" (20 CFR 416.414(a)(1); POMS SI 02005.050 D.1). Inputs and expected values are unchanged.
  7. Changelog fragment changelog.d/msp-post-merge-followups.changed.md.

Expected values changed

File Case Output Before After
md_paa_countable_income.yaml Case 4 md_paa_countable_income [11,760, 5,760] [17,370, 5,760]
medicaid_optional_senior_or_disabled_countable_income.yaml "A spouse's facility stay from July counts by December's status for the whole year, as an annual approximation." medicaid_optional_senior_or_disabled_countable_income [11,760, 5,760] [17,370, 5,760]
is_medically_needy_for_medicaid.yaml Case 45 ssi_countable_income not asserted [14,320, 27,320]

No other expected value changes. msp_fpg.yaml Case 4 keeps all six of its expected values with the longer stay, and Case 45 keeps its other five outputs.

Test plan

  • YAML tests whose expected values come from an external source: the changed and restored values follow 20 CFR 416.1112, 416.1124, 416.1163, 416.414(b)(3) and 416.1802(b)(1); each case's comment gives the arithmetic.
  • Source conflicts: no new reading. The Texas candidate stays open and gains a year and a source; no register entry or marker is due.
  • The six changed YAML test files pass locally on the merge with main at 47c4e8720b (3c109bf46b): 125 cases (msp_fpg.yaml 4, md_paa_countable_income.yaml 4, medicaid_optional_senior_or_disabled_countable_income.yaml 52, ssi_marital_earned_income.yaml 5, ssi_marital_unearned_income.yaml 5, is_medically_needy_for_medicaid.yaml 55), one process, policyengine-core from the lockfile. That merge resolved one conflict in medicaid_optional_senior_or_disabled_countable_income.yaml, keeping this PR's part-year case and the two California cases Deduct a California couple's dependents' premiums whatever their marital unit #10855 added after it. Before the merge, on main at 28009dbefa, the same files passed 123 cases. No other test file was run; CI covers the rest.
  • test_source_conflicts.py was not run locally. The edited candidates.yaml parses, its 438 ids are unique, and the new sources have valid kinds and https links (read). CI runs the guard.
  • ruff format --check and ruff check (0.15.5) pass on _msp_spouse_income.py.
  • Changelog fragment in changelog.d/.

Not in this PR

axiom: TheAxiomFoundation/rulespec-us#2010 (Medicare Savings Program spouse rules, extended), TheAxiomFoundation/rulespec-us#2012 (Medicaid applicant with a spouse who is not aged, blind or disabled, extended) and TheAxiomFoundation/rulespec-us#2191 (SSI couple income around a facility stay, extended), queued

🤖 Generated with Claude Code

…ach month's facility status

PR 10820 (38a3927) makes SSI combine a couple's income by each
month's facility status, so the workarounds added while SSI used
December's status can go:

- msp_fpg.yaml Case 4: the stay runs from July through December again;
  expected values are unchanged. Delete the NOTE in
  _msp_spouse_income.py.
- is_medically_needy_for_medicaid.yaml Case 45 (from PR 10640): assert
  ssi_countable_income again, as [14_320, 27_320], the reviewer's
  corrected figure (round-3 G12); 20,880 each was the figure with no
  stay.

Also take the reviewer's optional round-3 suggestions on PRs 10633 and
10820:

- Candidate us-tx:msp-spouse-deeming-allowance starts in 2025, from
  Revision 25-2 of Texas MEPD Appendix XXIX, and cites 42 U.S.C.
  1396a(r)(2)(A).
- The Maryland PAA and Medicaid optional pathway part-year cases give
  person1 12,000 of earned income, pinning each reader's earned line:
  [17_370, 5_760].
- Two SSI test names date the change from the first full month in a
  facility.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	policyengine_us/tests/policy/baseline/gov/hhs/medicaid/income/medicaid_optional_senior_or_disabled_countable_income.yaml
@DTrim99

DTrim99 commented Nov 13, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Restore the part-year facility-stay test cases now that SSI follows each month's facility status

Summary

This is a test-and-comment follow-up to #10633, #10640 and #10820 (the fix for #10818), at head 3c109bf46b. The head is the author's commit 25ef4e6ab4 plus a merge of main at 47c4e8720b. That merge changes none of the PR's lines: the +/- lines of 25ef4e6ab4 against its parent match the head's diff against main exactly.

What the PR does:

  • msp_fpg.yaml Case 4: the facility stay runs through December again.
  • is_medically_needy_for_medicaid.yaml Case 45: the ssi_countable_income assertion comes back with the corrected values [14,320, 27,320], not the 20,880 that Apply each state's rule for a Medicaid applicant whose spouse is not aged, blind or disabled #10640 had said to restore.
  • _msp_spouse_income.py: the stale NOTE is deleted.
  • Two annual-reader cases (Maryland PAA, Medicaid optional senior or disabled): person1 now has earned income, so each case pins the earned line.
  • Two SSI test names now date the change from the first full month in a facility.
  • Texas source-conflict candidate: extended back to 2025, with one more statute source.

I checked every changed or restored expectation by hand against main's formulas, month by month where the case asserts months. They all agree. By my reading of the formulas as they stood before #10820, both restored cases (msp_fpg Case 4 June and Case 45) would have failed there, so they now pin the monthly behaviour. CI ran every changed YAML file green at this head, along with the source-conflict guard.

I found nothing critical and nothing that needs to change before merge. There are two optional suggestions.

Critical (must fix)

None.

Should address

None.

Suggestions

  1. msp_fpg.yaml Case 4 name (line 56): the name still reads "the guideline and income test change in the month a spouse enters a facility". The PR renames the two ssi_marital_* cases for exactly this reason. In the model, July is the first month person2 is in the facility "as of the beginning of the month and stay[s] the entire month" (20 CFR 416.414(a)(1), eCFR), and the month of entry itself is still combined. For consistency, consider "... change in a spouse's first full month in a facility".

  2. source_conflicts/candidates.yaml, us-tx:msp-spouse-deeming-allowance: years.from is now 2025, and the question gives both years' amounts. The note still says PE-US "uses SSI's $497 in every state" and lists only the 2026 Texas limit gaps. Optional housekeeping:

    No guard depends on either change. CI's test_candidate_fields and test_candidates_are_public pass.

Verified correct

All monthly figures below come from my hand traces of the formulas on main at the merge base 47c4e8720b. CI results are labelled as such.

Test inputs carry forward. policyengine_us/system.py sets auto_carry_over_input_variables = True. Core carries the latest earlier input forward and never backward. So in Case 4, ssi_lives_in_medical_treatment_facility: {2026-07: true} is false from January to June and true from July to December. Dropping the two 2026-12: false inputs therefore really does extend the stay through December.

1. msp_fpg.yaml Case 4 (TX, 2026)

  • Inputs:
    • person1: 68, on Medicare, unearned income $1,000 a month.
    • person2: 62, disabled, not on Medicare, $1,500 a month; facility with Medicaid paying from July.
  • Rates: individual FBR $994, couple FBR $1,491, so the rate difference is $497 a month (12 x 497 = 5,964 a year). FPG is $15,960 for one person and $21,640 for two.
  • June, at this head.
    • SSI couple income: ssi_couple_computation_applies is true (joint claim, neither in a facility). So ssi_marital_unearned_income is 1,000 + 1,500 = 2,500 each, and ssi_countable_income is (2,500 - 20) / 2 = 1,240 each.
    • SSI eligibility: ssi_amount_if_eligible is 1,491 / 2 = 745.50. uncapped_ssi is 745.50 - 1,240 = -494.50 for each spouse, so neither counts as SSI-eligible in msp_spouse_income, and each one's annual income is deemed to the other.
    • Couple test (msp_tests_as_couple):
      • The spouse's 18,000 is above 5,964, and split_by_facility is false.
      • Deemed countable: 12,000 + 18,000 - 240 = 29,760. Own countable: 11,760.
      • 29,760 x 15,960 = 474,969,600, which is above 11,760 x 21,640 = 254,486,400, so the deemed test is stricter and the couple test is true.
      • For person2: 474,969,600 is above 17,760 x 21,640 = 384,326,400, so also true.
    • Results:
      • msp_fpg = 21,640 / 12 = 1,803.33 for both.
      • msp_countable_income = 29,760 / 12 = 2,480 for both.
      • QI ceiling: 1.35 x 1,803.33 = 2,434.50, and 2,480 is above it, so person1 is NONE. person2 is not on Medicare, so NONE.
  • July, at this head. person2 is in a Medicaid facility, so the couple computation is false and split_by_facility is true.
    • Neither spouse tests as a couple, so msp_fpg = 15,960 / 12 = 1,330.
    • msp_countable_income = 11,760 / 12 = 980 and 17,760 / 12 = 1,480.
    • 980 is at or below 1,330, so person1 is QMB. person2 is NONE.
  • June, before Combine an SSI couple's income by each month's facility status #10820 (pinning check).
    • ssi_marital_unearned_income was YEAR-defined and read December's status. With the stay through December, December is separate, so each spouse keeps their own income. ssi_countable_income for June reads it as a twelfth: 1,000 and 1,500.
    • June's couple computation still halves: (1,000 - 20) / 2 = 490 and (1,500 - 20) / 2 = 740.
    • uncapped_ssi: 745.50 - 490 = 255.50 and 745.50 - 740 = 5.50. Both are above zero, so nothing is deemed.
    • Result: msp_fpg 1,330, countable 980 and 1,480, person1 QMB. All three June assertions would have failed there, by my reading.
  • July does not depend on Combine an SSI couple's income by each month's facility status #10820.
  • The stay that ended before December (the version on main) passes either way. Only the stay through December pins the monthly variables.

2. is_medically_needy_for_medicaid.yaml Case 45 (NY, 2026)

  • Inputs:
    • person1: 72, Social Security $8,000 (666.67 a month), in a facility from January to June.
    • person2: 70, $34,000 (2,833.33 a month).
  • Both spouses are aged, so neither is an ineligible spouse and no SSI deeming applies.
  • ssi_countable_income by month:
    • January to June: separate. 666.67 - 20 = 646.67 and 2,833.33 - 20 = 2,813.33. Times 6: 3,880 and 16,880.
    • July to December: couple. (3,500 - 20) / 2 = 1,740 each. Times 6: 10,440.
    • Annual totals: 14,320 and 27,320.
  • Medically needy test:
    • The test reads the annual ssi_countable_income. NY does not budget couples together (budgets_couple_together is false), and the couple is not split in December, so medicaid_medically_needy_income_from_spouse is 0.
    • The couple total is 41,640, above the limit 12 x 2,489 = 29,868, so both are not eligible. That leaves the other five outputs unchanged, and the comment's "together 41,640" is right.
    • Tested alone, 12 x 1,836 = 22,032. The 1,836 and 2,489 match 138% of FPG rounded up per month: 15,960 x 1.38 / 12 = 1,835.40 and 21,640 x 1.38 / 12 = 2,488.60.
  • Before Combine an SSI couple's income by each month's facility status #10820: December is a couple month, so the YEAR-defined marital income combined to 42,000 for each spouse.
    • January to June: 3,500 - 20 = 3,480 a month, 20,880.
    • July to December: 10,440.
    • Total: 31,320 each. That matches the old comment's figure, and by my reading [14,320, 27,320] would have failed there.

3. md_paa_countable_income.yaml Case 4 and the facility case in medicaid_optional_senior_or_disabled_countable_income.yaml (2025)

  • How the annual formulas read the year: _ssi_couple_income(person, year, ...) reads ssi_couple_computation_applies for the year, which gives December's status (separate here). So each spouse uses their own annual income.

  • person1: unearned 1,000 - 20 = 980, plus earned (1,000 - 65) / 2 = 467.50, gives 1,447.50 a month and 17,370 a year.

  • person2: (500 - 20) x 12 = 5,760.

  • NC uses the default SSI exclusions: disregard $20, additional disregard 0, no premium deduction. Nothing is deemed between two aged spouses.

  • Mutations, each by my reading:

    • Earned line reads the summed monthly ssi_marital_earned_income: person2 gets 6 x 1,000 = 6,000, so 5,760 + (6,000 - 780) / 2 = 8,370. That would fail the case.
    • Unearned line reads the summed monthly variable instead: person1 15,000 - 240 + 5,610 = 20,370, person2 12,000 - 240 = 11,760.

    Before this PR person1 had no earnings, so a mutation on the earned line went undetected. The new input closes that gap.

  • These two cases test the annual helper, not the monthly variables. Before Combine an SSI couple's income by each month's facility status #10820 they would still have given 17,370 and 5,760, which is expected. The ssi_couple_computation_applies assertions for June and July are unchanged.

4. Removing the NOTE in _msp_spouse_income.py is accurate.

5. No formula changed. Every non-test file in the diff:

  • _msp_spouse_income.py: four comment lines deleted, no code.
  • source_conflicts/candidates.yaml: registry data only, for the Texas candidate.
  • changelog.d/msp-post-merge-followups.changed.md: new fragment. The changed type fits.

6. Test renames. The ssi_marital_earned_income.yaml and ssi_marital_unearned_income.yaml renames match 20 CFR 416.414(a)(1): "throughout a month we mean that you are in the medical treatment facility as of the beginning of the month and stay the entire month". Inputs and expected values are unchanged.

7. Texas candidate sources.

  • MEPD Revision 25-2, page 488 is Appendix XXIX, "Revision 25-2; Effective June 1, 2025 / Note: The following information is effective March 1, 2025". It reads "Program-Specific Living Allowance Allocation: Community MEPD $483, CAS $483, QMB $458, SLMB $550, QI-1 $619, QDWI $916". The candidate quotes this correctly up to QI-1.
  • $1,450 - $967 = $483 is SSI's 2025 rate difference.
  • 42 U.S.C. 1396a(r)(2)(A) reads: "... or under section 1396d(p) of this title may be less restrictive, and shall be no more restrictive, than the methodology— (i) in the case of groups consisting of aged, blind, or disabled individuals, under the supplemental security income program". The #r_2 anchor exists on the Cornell page.
  • The candidate stays state: open with no marker, so no register entry is due.

8. Other checks.

  • Tests stay in their variable-named files.
  • No partner-test files are touched.
  • No state-gated key variables are added (NH Add New Hampshire state supplementation for 2026 #10156 pattern).
  • The new comments have no conflict-sounding wording, and _msp_spouse_income.py is not in KNOWN_UNMARKED.

Axiom line assessment

queued, naming TheAxiomFoundation/rulespec-us#2010, #2012 and #2191 (all "extended"). All three are OPEN, labelled pe-parity, and were last updated 2026-11-13 00:55 UTC, after the author's commit 25ef4e6ab4 of 2026-11-12. Each one's header names this PR at 25ef4e6ab4, and the content matches:

  • Windows CPS test error #2010: case 18 now has the stay from July through December. It gives June $2,480, two-person, no tier, and July $980, one-person, QMB, matching msp_fpg Case 4. Interpretation 12 records the NOTE's deletion. Interpretation 13 adds the 2025 Texas amounts and 42 USC 1396a(r)(2)(A).
  • Minnesota Child and Dependent Care Credit #2012: case 15 gives ssi_countable_income $14,320 and $27,320 with the same month-by-month arithmetic, the couple's $41,640 against $29,868, and notes that this PR restores the assertion.
  • MS Dependents exemption #2191: interpretation 3 adds the earned income and the $17,370 / $5,760 figures for the two annual readers. The first-full-month wording matches the renames.

The current head 3c109bf46b only adds a merge of main that leaves the PR's lines unchanged, so the issues match the head's behaviour. Refreshing the SHA they cite is optional. Their structure (objective, why queued, verbatim law, cases, interpretations) is unchanged from the versions accepted on #10633, #10640 and #10820. The line is valid.

CI status

Re-checked near the end of the review: 28 pass, 10 pending, 0 failing.

  • Pending: the nine Contrib shards and Microsimulation. The PR changes no formula, so I don't expect them to depend on it.

  • YAML files (from the job logs):

    File Cases Job
    msp_fpg.yaml 4 Baseline contrib-hhs
    is_medically_needy_for_medicaid.yaml 55 Baseline contrib-hhs
    medicaid_optional_senior_or_disabled_countable_income.yaml 52 Baseline contrib-hhs
    ssi_marital_earned_income.yaml 5 Baseline ssa-usda
    ssi_marital_unearned_income.yaml 5 Baseline ssa-usda
    md_paa_countable_income.yaml 4 Baseline states-shard-2

    All of these cases pass at this head.

  • Source-conflict guard: test_source_conflicts.py passed in Python shard 6 at this head (950 passed). That includes test_candidate_fields, test_candidates_are_public and test_conflict_sounding_comments_do_not_grow.

  • PR validation (lock, guard tests, ruff, changelog) passed.

Branch status

0 commits behind main (47c4e8720b), 2 ahead. git merge-tree --write-tree PolicyEngine/main 3c109bf46b is clean and returns the head's own tree (9620f1e1d5), so the merged tree is the tested tree. The author's merge resolved one conflict in medicaid_optional_senior_or_disabled_countable_income.yaml. It kept both this PR's part-year case and the two California cases from #10855, and CI ran all 52 cases of that file green.

Verdict: APPROVE

@DTrim99 DTrim99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. The restored cases check by hand now that SSI follows each month's facility status: msp_fpg.yaml Case 4's stay runs through December again (June: two-person guideline, $2,480, no tier; July: one-person, $980 and $1,480), Case 45 asserts ssi_countable_income of [14,320, 27,320] month by month, and the Maryland PAA and Medicaid-optional cases now pin the earned line too. By my reading, each would fail on main before #10820. The removed NOTE in _msp_spouse_income.py is accurate to remove, no formula changed, and the three Axiom issues match. Two optional suggestions: rename Case 4 to "first full month", matching the SSI renames, and update the Texas candidate's "$497" note. CI was green on every changed file at 3c109bf46b, with the contributed-reform and microsimulation jobs still running.

@hua7450
hua7450 merged commit b0bf4ed into PolicyEngine:main Nov 13, 2026
38 checks passed
MaxGhenis added a commit that referenced this pull request Nov 13, 2026
Keep both sides' cases in md_paa_countable_income.yaml: Case 4 from #10820
and #10856, and this branch's four monthly in-kind support cases.

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