Skip to content

Apply Colorado's AND-CS payment floor and 3.549 income rules to every client - #10161

Merged
MaxGhenis merged 15 commits into
mainfrom
co-and-cs-payment-floor-3549
Nov 8, 2026
Merged

MaxGhenis merged 15 commits into
mainfrom
co-and-cs-payment-floor-3549

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR changes Colorado AND-CS (co_state_supplement) in three ways under 9 CCR 2503-5 (ruleVersionId 12428). It builds on #10145 and #10176 (OAP).

  1. Payment floor. From January 1, 2026, a state supplementary payment raises a grant below the $13 payment floor standard to that floor (3.546(C)(2), (E); 3.549(B), (H)). The floor applies only to a positive grant: under 3.520.781(A), a client whose total countable income, SSI included, "equals or exceeds" the grant standard is not eligible.
  2. 3.549 for every client. On main, 3.549(A) applies only to SSI couples, and everyone else uses federal ssi_countable_income. This PR applies 3.549 to every client:
    • 3.549(A), every client's own income: a married client gets half the $20 disregard, and a client whose only unearned income is SSI gets none. Under (A)(2)(f), the client's own share of the $20 ($10 if married) less the client's gross unearned income, SSI included, reduces earnings when positive.
    • 3.549(C)-(D): AND-CS deems a spouse's income without SSI's deeming threshold or child allocations. Earned: (gross − 65) / 2. Unearned: gross less whatever remains of the couple's combined $20.
    • 3.549(E): AND-CS deems a child's parents' income "using the same calculations as a spouse".
    • 3.549(F), from March 1, 2020: AND-CS deems nothing from a spouse or parent who receives SSI. It also deems nothing from one who receives Old Age Pension or Medicaid and whose own countable income stays within the individual federal benefit rate (judgment call 1 below). Before then, 3.545(F) excluded only the benefit income itself.
  3. One Medicaid variable for both Adult Financial programs. co_adult_financial_medicaid_enrolled replaces OAP's co_oap_medicaid_enrolled. It keeps OAP's reported-coverage route (receives_medicaid). Both deeming exemptions read it, so AND-CS and OAP share one private branch and never open one inside the other.

The payment floor

Source What it says
3.546(E) "Effective January 1, 2026, the payment floor standard for AND-CS is $13."
3.549(B), (H) "If the grant payment is less than the AND-CS payment floor standard ..., a state supplementary payment will be issued to raise the grant payment to meet the payment floor standard."
3.510 "Payment Floor Standard" is "the minimum Adult Financial grant payment that an eligible ... (AND-CS) ... client may receive."
3.520.781(A) "If a client's total countable income equals or exceeds the Adult Financial program grant standard, the client shall not be eligible ..."

History. The floor first appears in the January 1, 2026 emergency rule (ruleVersionId 12318). Before then, 3.546(C) allowed only discretionary MOE lump sums (ruleVersionId 11861). So payment_floor.yaml holds $0 until 2026 and $13 from 2026-01-01.

Who gets it. CDHS's rulemaking packet 2025-00596 (p. 4) gives the AND-CS caseload as about 250 people and the cost of meeting the floor as $285. Paying the floor to every disabled SSI recipient under 60 with a $0 grant would cost thousands of times that, so the 3.520.781(A) reading fits.

3.546's "but are not receiving the full SSI benefit standard". Since 2012 the AND-CS grant standard has equaled the SSI individual rate ($994 in 2026). A single client on the full rate already has total countable income of at least $994, which 3.520.781(A) excludes, so the PR adds no separate gate. A member of an SSI couple ($745.50 each) doesn't receive the full individual standard and stays a client, as in #10145.

3.549 outside SSI couples

Rule Federal ssi_countable_income (before) This PR
(A)(2)(c)(2) SSI is the only unearned income $20 general exclusion moves to earnings no unearned disregard; none reaches earnings
(A)(2)(f) unused disregard always moves to earnings the client's own share of the $20 ($10 if married) less the client's gross unearned income, SSI included, when positive
(A)(2)(c)(1) married whole $20 (individual) $10 each
SSI student earned income exclusion excluded counted: 3.520.786 limits exempt income to the items it lists
(C) spouse's earnings deemed only above the $497 threshold, after child allocations (gross − 65) / 2
(D) spouse's unearned income as above gross − (20 − client's use of the $20)
(E) parents' income to a child after parental and child allocations combined income of the parents the child's ids name (without ids, the tax unit's unlinked parents), spouse calculation, in full to each child client
(F) spouse or parent on SSI; or on OAP or Medicaid with own SSI countable income ≤ $994 — not deemed, from 2020-03-01

Dating (F). The current (F) took effect March 1, 2020 (ruleVersionId 8577). The earlier 3.545(F) (effective March 2, 2014; version in force January 1, 2020) excluded only "the income from those benefits", which the deemed sources here never include. So income/deeming/assistance_exemption_applies.yaml holds false before 2020-03-01. Before March 2020, AND-CS deems each SSI couple member's non-SSI income to the other (Case 31: in 2019 the head gets $152.50 rather than $232.50).

OAP receipt for (F). The PR judges it month by month on the spouse's own income, as co_oap_deeming_exempt does: OAP-eligible, with the OAP standard less own countable income positive.

Medicaid for (F). From 2027, membership in a household that receives SNAP can meet the community engagement requirement (42 CFR 435.554(c)(7)), and SNAP counts both grants as income. co_adult_financial_medicaid_enrolled computes medicaid_enrolled in a private branch where only reported coverage exempts anyone, so the branch settles enrollment while AND-CS still deems every other Medicaid spouse's or parent's income. The result does not depend on calculation order (tested). AND-CS asks for it only for someone within the limit, not exempt otherwise, and sharing a marital unit, tax unit or household with an AND-CS client.

Worked cases (all in YAML)

2026, monthly unless noted.

Case Before (main) This PR Rule
Couple, head pension $487, spouse none (SSI $512 each) head $5 head $13 994 − 512 − 477 = 5 → floor
Couple, head pension $497 (SSI $507 each) head $0 head $0 507 + 487 = 994: ineligible, no floor
Grant inputs: SSI 993.50 total $0.50 $13 floor
2025, SSI 958 $9 $9 no floor before 2026
Single, SSI only, earns $500 countable 207.50 countable 217.50 (A)(1), (A)(2)(c)(2)
Single disabled student earning $500 countable 0 countable 217.50 3.520.786
Client, no income; spouse earns $1,500, on Medicaid (SSI 783.50) $0 $210.50 SSI deems 707.50; (F) deems nothing
Client SSI only; spouse earns $300 countable 0 countable 117.50 (C); SSI's threshold deems 0
Client SSDI $300; spouse pension $400 countable 280 countable 680 (A) 290 + (D) 390
Child; parent earns $2,000 countable 0 countable 967.50 (E)
Married client: $10 interest, $200 earnings; spouse $50 pension — own 67.50, deemed 40 (A)(2)(c)(1), (f), (D)(2): the client's $10 covers the interest; the spouse's pension takes the couple's other $10
2019 SSI couple, spouse pension $100 head $232.50 head $152.50 3.545(C), (F)
Spouse on SSI, own countable income $994.50 — exempt (F): SSI receipt meets the income condition
Spouse on Medicaid without SSI, own countable income $994.50 — not exempt (F) income condition, individual rate
Disabled SSI couple, spouse pension $1,015, head no income (SSI $248 each) head $746 head $746 (F): the SSI spouse deems nothing; 994 − 248

Invariants

policyengine_us/tests/core/test_co_and_cs_invariants.py checks Hypothesis-drawn single and married clients (15 examples of up to 8 households, one simulation each). Each married household appears four ways: spouse on Medicaid, spouse not, more spousal earnings, roles swapped.

  1. Payment. When the standard less total countable income is positive, the supplement equals the larger of that difference and the floor; otherwise it is 0. So it is 0 or between $13 and $994.
  2. Singles. The model never pays a single client in their own household. For a client who receives SSI, 3.549(A) countable income is ≥ SSI's countable income, and the two are equal when the client has no earnings or at least $20 of other unearned income.
  3. Exemption. A spouse's Medicaid enrollment within the SSI limit only lowers countable income and only raises the supplement.
  4. Monotonicity. More earnings for a non-exempt spouse never raise the supplement. For a client without in-kind support who stays a client, they never lower countable income either.
  5. Roles. Swapping tax-unit head and spouse changes nothing.

Tests

  • YAML: co_state_supplement.yaml (35), co_state_supplement_own_countable_income.yaml (8), co_state_supplement_deemed_income.yaml (12), co_state_supplement_countable_income.yaml (4), co_state_supplement_eligible.yaml (11), and the OAP files, which now use the shared Medicaid variable.
  • co_state_supplement_deeming_exempt.yaml (12) builds each case around a real client and spouse, with year-keyed inputs for the 2020 cases, and Case 12 pins the individual-rate limit on the Old Age Pension route.
  • Python: test_co_and_cs_invariants.py (4), test_co_oap_invariants.py (2; in both, the property test reports a skip when the environment lacks hypothesis), test_ssi_state_supplement_couple_invariants.py (6) and test_ssi_state_supplement_medicaid_dependency.py (28).
  • CI group. test_ssi_state_supplement_medicaid_dependency.py runs in heavy-a (Makefile REST_HEAVY_A_TESTS), not Rest/core. The invariants files run in core. Local Linux measurements (one process per file, peak RSS): Medicaid dependency 3.0 GB, 215 s with import; each invariants file about 1.25 GB, 50 s. On Linux CI (run 41721281741, at an earlier head of this PR), heavy-a's 5 files ran 74 tests in 681 s.

Readings to check

  1. Judgment call 1, the SSI limit. 3.549(F) doesn't define "the SSI limit". We read it as the limit SSI applies to each person, as CDHS uses the phrase in 3.570.43. A spouse or parent who receives SSI meets the income condition, and someone on Old Age Pension or Medicaid without SSI meets it when their own countable income doesn't exceed the individual federal benefit rate. For example, a disabled SSI couple in Colorado whose spouse draws a $1,015 monthly pension keeps the head's $746 AND-CS payment in January 2026. If the spouse's own income faced the individual rate, the payment would stop.
  2. Married share of the (A)(2)(f) spillover. It's the client's own share of the $20, $10 when married, as OAP's 3.533(A)(2)(f) reads, so no more than $20 applies to the couple ((A)(2)(c)(1)). Axiom computes it against the full $20.
  3. Parents in (E). This PR combines the parents' income (one $65 and the child's remaining $20) and deems it in full to each child client. SSI divides parental income among eligible children; 3.549 does not say to.
  4. 2014–2020 spillover. 3.545(B)(1) based the spillover on "unearned income from all sources except SSI". It changes countable income only, not payments.

Overlap

Not modeled

Microsimulation impact

We compared main at the merge base 25c4253483 with this head, 96859129b5, on the default dataset for 2026. We estimate that AND-CS (co_state_supplement) pays $0 on both sides, and that SNAP, taxes, benefits and household net income don't change.

  • Clients. In January 2026, five Colorado sample records (47,618 people weighted) meet co_state_supplement_eligible. All five receive SSI, and none has a spouse in the household. On main, SSI plus AND-CS countable income equals the $994 grant standard for each of them, so each grant comes to $0.
  • Earners. Two of the five (20,769 weighted) work, and SSI is their only unearned income. SSI applies its $20 exclusion to their earnings; under 3.549(A)(2)(c)(2), this branch doesn't, so their countable income rises by $10 a month. Their SSI plus income then exceeds the standard by $10, and their grant stays $0.
  • Payment floor. No eligible record has a positive grant on either side, so the $13 floor raises no payment.
  • SSI couples. The sample's two Colorado members of SSI couples carry zero weight, neither one meets co_state_supplement_eligible, and neither one's own countable income exceeds $994. So no weighted record tests the couple cases above.
  • Countable income. co_state_supplement_countable_income falls by $4.30tn because the two sides compute it for different people. On main it carries no defined_for, so the model computes it for people in every state, mostly as SSI countable income. On this branch, its two parts carry defined_for = "co_state_supplement_eligible". Only co_state_supplement reads it, and that variable has the same defined_for on both sides, so no payment changes.
Output main total, 2026 2026 change Records changed (weighted)
co_state_supplement $0 $0 0 (0)
co_state_supplement_countable_income $4,302.75bn -$4,302.55bn 27,911 (67,179,330)
snap $94.77bn $0 0 (0)
income_tax $2,595.13bn $0 0 (0)
state_income_tax $577.97bn $0 0 (0)
household_net_income (households) $17,162.30bn $0 0 (0)
household_benefits $2,060.63bn $0 0 (0)

impact: on the default dataset in 2026, AND-CS pays $0 on both sides, and SNAP, taxes, benefits and household net income don't change. Two sample clients who work (20,769 weighted) count $10 a month more income, and their grant stays $0.

axiom: TheAxiomFoundation/rulespec-us#1716 queued, extended with a comment (payment floor); TheAxiomFoundation/rulespec-us#1717 queued, extended with a comment (parental deeming, married disregard, SSI limit)

🤖 Generated with Claude Code

MaxGhenis and others added 6 commits October 12, 2026 06:07
The Colorado AND-CS, Texas Medicaid-facility and New Mexico adult
residential care supplements gated on is_ssi_eligible_individual, which
is false for the tax-unit-spouse member of an SSI couple. Each state's
rule pays every SSI recipient on their own (9 CCR 2503-5 3.546-3.548;
HHSC MEPD H-1500 and H-6000; 8.106.400.10(C) and 8.106.500.10 NMAC), so
gate on SSI receipt instead, the repo's convention for SSI-recipient
programs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One vectorized simulation of 48 married couples checks that eligibility
is SSI receipt, that the result does not depend on which spouse is the
tax-unit head, that two citizen spouses are treated alike, and that a
spouse failing the SSI citizenship condition is never eligible. main
fails the first three; the is_ssi_eligible_individual |
is_ssi_eligible_spouse alternative fails the fourth.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1 (GPT-6.1 Sol):
- Colorado: 9 CCR 2503-5 3.549(A) counts each AND-CS client's own
  income, with the $20 disregard split between spouses and no deeming
  between SSI-recipient spouses (3.549(F)). The model used
  ssi_countable_income, which halves a joint claim's pooled income.
  New co_state_supplement_countable_income does the per-client count
  where SSI's couple computation applies and keeps the federal amount
  elsewhere.
- Texas: H-6000 keeps a facility resident eligible for SSI when
  countable income "does not exceed" the $30 reduced standard, and
  42 USC 1382(a)(1)(A) agrees, so gate on SSI eligibility within the
  limit (a $0 payment included) plus take-up, or reported receipt.
- One reference per document for the CO rule PDF.

Also reverts the partner fixture edit: partner API contract tests
change only after Ziming Hua approves (CLAUDE.md).

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

3.549(A)(2)(f) applies "the difference between the gross unearned income
and the $20.00 deduction" to earnings only when the client's unearned
income is under $20, and (A)(2)(a) counts unearned income "from all
sources", SSI included. So an AND-CS client, who always receives SSI,
gets no share of the disregard on earnings unless their gross unearned
income is under $20. This matches Axiom's encoding of 3.549
(us-co:regulations/9-ccr-2503-5/3.549). co_state_supplement_countable_income
becomes MONTH so it can read that month's SSI.

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

Review round 2 (GPT-6.1 Sol):
- Texas: testing uncapped_ssi admitted an SSI-abolished resident and a
  resident on the own-household rate whose income equalled it. Test
  H-6000's condition directly: countable income not over the $30
  reduced standard, with SSI not abolished.
- Colorado: a joint couple's in-kind support and maintenance is one
  presumed maximum value (ssi_pmv_amount), which SSI splits between
  the spouses; count half of it for each spouse, not all of it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
9 CCR 2503-5 3.546(E) sets a $13 AND-CS payment floor from January 1,
2026, and 3.549(B), (H) raise a grant below it with a state
supplementary payment. Under 3.520.781(A) a client whose total countable
income equals or exceeds the grant standard is not eligible, so the floor
tops up only positive grants.

co_state_supplement_countable_income now applies 3.549 to every client,
not only SSI couples: own income under 3.549(A), plus income deemed from
a spouse (3.549(C)-(D)) or from a child's parents (3.549(E)), except
from a spouse or parent on SSI, Old Age Pension or Medicaid with income
within the SSI limit (3.549(F), dated March 1, 2020).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_co_and_cs_invariants.py checks, over Hypothesis-drawn single and
married clients in one simulation per example: the payment rule and its
bounds, that 3.549(A) never counts less than SSI for a single client (and
the same where SSI's and Colorado's disregards coincide), that the 3.549(F)
Medicaid exemption only lowers countable income, monotonicity in a
non-exempt spouse's earnings, and invariance to tax-unit roles.

AND-CS now reads medicaid_enrolled_for_ssi_state_supplement for the
3.549(F) exemption, so Colorado joins the SSP/SNAP/Medicaid calculation
order test.

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

Copy link
Copy Markdown
Contributor Author

Stacked follow-up: #10183 (draft) does this PR's 'Colorado ISM for clients in another person's household' follow-up, based on head 96f5c6e2d4. It replaces the ISM block in _and_cs_client_income.py with co_ssa_in_kind_support_and_maintenance. That keeps SSI's PMV halved for couples, and adds SSA's one-third reduction (3.520.79(B)(6) matching), Colorado's own amount for non-SSI clients, and the pre-2014 rule. It updates co_state_supplement.yaml Case 28 ($3,976/yr becomes $240/yr) and appends Cases 31-35. It does not touch test_co_and_cs_invariants.py. I'll rebase #10183 when this branch moves. The ISM amount reading is queued for Max (d1446) and gates #10183's merge, not this PR's.

🤖 Generated with Claude Code

MaxGhenis and others added 3 commits October 12, 2026 20:43
…oat floor

- 3.549(F) Medicaid prong: read co_state_supplement_medicaid_enrolled,
  computed in a private branch with January's AND-CS set to zero. It keeps
  the SNAP route to Medicaid's community engagement exemption (SNAP counts
  AND-CS as income) and gives the same answer whatever is calculated
  first. medicaid_enrolled_for_ssi_state_supplement drops that route and
  answers from the cache when Medicaid was calculated first.
- 3.549(E): deem from the parents the child's parent ids name, whatever
  their age; without ids, the tax unit's unlinked parents other than the
  child. A grandparent named only as the mother's parent no longer counts,
  and a 17-year-old parent now does.
- Before March 2020, 3.545(F) excluded only the benefit income itself, so
  no spouse or parent is exempt from deeming, SSI recipients included.
- The payment floor tests eligibility on the grant in cents: a single
  client whose 3.549(A) income equals SSI's sits exactly at the standard,
  and single precision left a grant of $0.00006 that the floor raised to
  $13 (found by the property test; YAML Case 32).
- Property tests compare countable income only for clients who receive
  SSI, as 3.546 requires; regression test for the review's examples.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
co_state_supplement_medicaid_enrolled now computes medicaid_enrolled in a
branch where it is itself false for everyone, rather than one where
January's AND-CS is zero. AND-CS in the branch deems every Medicaid
spouse's or parent's income, so it is no higher than its final value and
SNAP is no lower: one step from the final fixed point, from the
conservative side. The parent never holds this variable before computing
it, so get_override_branch always shares the parent's cache. This matches
co_oap_medicaid_enrolled in #10176, so the two can merge into one
Adult Financial variable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.520.79(B)(6) charges an AND-CS client the ISM SSA charges, and SSA's
presumed maximum value halves once spousal deeming starts. Spousal
earnings that cross SSI's deeming threshold therefore lower the client's
ISM by about as much as the deemed earnings rise, and countable income can
fall by cents. Found by Hypothesis in the ISM session (#10183); pinned by
test_ism_basis_switch_at_ssi_deeming_threshold.

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

@hua7450 hua7450 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.

Review at aaa00d545d: the policy checks out; the tests and the merge need work

The payment floor ($13 from 2026-01-01, positive grants only), 3.549(A) for every client, (C)–(E) deeming and the 2020-03-01 date for (F) all match 9 CCR 2503-5.

Please fix

  • co_state_supplement_medicaid_enrolled ignores receives_medicaid. 3.549(F) and 3.534(C) both say "receiving ... Medicaid", and #10176's co_oap_medicaid_enrolled counts reported coverage. Keep that route when the two variables merge.
  • co_state_supplement_deeming_exempt.yaml:
    • Cases 1, 2 and 4 pass through Medicaid: the default person is an enrolled adult with no income, so the SSI and OAP routes are untested. Add co_state_supplement_medicaid_enrolled: false, as Case 7 does.
    • Cases 8–10 use 2020-02/2020-03 with scalar inputs for YEAR variables (co_state_supplement_medicaid_enrolled, state_code). Those inputs are stored for a year starting that month and ignored, so Case 9 passes through the default CA household's Medicaid. Use period: 2020 with month-keyed outputs, or key the inputs by year.
  • Merging main (#10145 and #10176 have landed; 7 files conflict, each changed on one side only):
    • Merge the two Medicaid branches into one Adult Financial variable, with the reported-coverage route and OAP's skip guard, so AND-CS and OAP don't open nested branches.
    • Judge OAP receipt by month, as main's OAP does, rather than co_oap(year) > 0.
    • Use one reading in both programs for the (f) spillover (full $20 here, the married half in OAP) and for whether an SSI recipient needs the income test (OAP applies it, AND-CS doesn't).
    • The PR body puts the Medicaid dependency test in Rest/core; the Makefile runs it in heavy-a. Re-measure after the merge.

Optional

  • 2014–2020: 3.545(B)(1) based the spillover on "unearned income from all sources except SSI". It changes countable income only, not payments; worth a line under "Readings to check".
  • References: earned_share.yaml puts a single page in its title; assistance_exemption_applies.yaml dates 3.545(F) January 1, 2020, but the section is marked "Eff. 3/2/14"; payment_floor.yaml could cite packet page 1.
  • Invariant 4: scope only the countable-income assertion; the supplement check still holds.

@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

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Picking this up for the US hub. I'm continuing an earlier session's work on this brief; that session stopped before pushing anything here. I'll post a hand-off comment here when it's ready.


Generated by Claude Code

#10145 (the base) and #10176 (OAP) have landed. The AND-CS files main
holds equal #10145's head 3d1da21, so this branch keeps its own side
there; TX and the couple invariants, which this branch's own commits never
touched, take main's side.

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

- Merge co_oap_medicaid_enrolled and co_state_supplement_medicaid_enrolled
  into co_adult_financial_medicaid_enrolled, keeping OAP's reported-coverage
  route (3.549(F) and 3.534(C) say "receiving ... Medicaid") so AND-CS and
  OAP share one private branch and never nest one inside the other.
- 3.549(F): judge Old Age Pension receipt month by month on the spouse's
  own income, as co_oap_deeming_exempt does; apply the income limit to SSI
  recipients too, as OAP applies its limit; and compute Medicaid only for
  people near an AND-CS client who are not exempt otherwise.
- 3.549(A)(2)(f): the spillover to earnings is from the client's own share
  of the $20 (half when married), as OAP's 3.533(A)(2)(f) reads, so no more
  than $20 applies to the couple. Deemed-income Case 8 changes accordingly.
- Rebuild the deeming-exemption YAML around a real client and spouse, with
  year-keyed inputs for the 2020 cases, plus SSI-above-limit and
  reported-coverage cases.
- Invariant 4 scopes only the countable-income check to clients without ISM.
- Reference titles: one-page title, 3.545(F)'s 2014 date, packet page 1.
- Drop #10145's changelog fragment, which main has released.

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

Copy link
Copy Markdown
Contributor Author

Picking this up for the US hub. I'm continuing earlier sessions' work on this brief; they stopped before pushing anything here. I'll post a hand-off comment here when it's ready.


Generated by Claude Code

@hua7450

hua7450 commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator

Readings at 8707792d09: OAP's on both. I accept the two readings this PR now uses for AND-CS:

  • 3.549(F): an SSI recipient must also pass the income test, as OAP's 3.534(C) applies its limit.
  • 3.549(A)(2)(f): a married client's leftover disregard comes from their own half of the $20, as OAP's 3.533(A)(2)(f) reads.

That settles item 2 under "Readings to check" and the SSI-recipient part of item 1. It doesn't cover the rest of item 1, which is how "the SSI limit" is defined.

I'm marking this PR ready for review so CI can run. This isn't an approval: I read the code at this head but haven't run any tests, and I'll review the results once CI finishes and your hand-off is posted.

@hua7450
hua7450 marked this pull request as ready for review November 3, 2026 21:22
MaxGhenis pushed a commit that referenced this pull request Nov 3, 2026
…heck

- 2002-2006: co_ssa_in_kind_support_and_maintenance had no formula, so
  AND-CS lost the presumed maximum value #10161 counted (a 2004 renter with
  outside shelter support went from $37 to $225). formula_2002 keeps that
  count, halved for a couple, until the pre-2014 component base is audited.
  New co_state_supplement.yaml Case 38 pins $37.
- OAP: co_oap_in_kind_support_and_maintenance reads Colorado's ISM, so OAP
  clients get SSA's one-third reduction matched (3.520.79(B)(6)) and
  Colorado's maximum without SSI (3.520.79(C)(3)). The ISM variable drops
  its Colorado-only restriction: OAP deems a spouse's ISM and the spouse may
  live elsewhere (3.534(C)). OAP own-income Case 10 now counts $351 - $20.
- Invariant 3 takes the floor top-up from the rule, max(0, floor - grant)
  for a positive grant, not from the supplement under test.
- The medical-confinement comment says an SSI recipient in a facility with
  outside shelter support is still charged SSA's ISM.

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

Copy link
Copy Markdown
Contributor Author

Ready for hub review

Head: 8707792d091935e5a7bd5f47f0986d81525aaf56 (base main; hua7450 marked it ready for review at 21:22Z so CI could run).

I continue earlier sessions' work on this brief. They pushed nothing here, so every commit after aaa00d545d is mine. I kept all ten of the PR's earlier commits: hua7450's review confirmed their policy against 9 CCR 2503-5, and I re-derived the worked cases below by hand.

What changed

hua7450's review, item by item

Please fix

  1. Medicaid ignores receives_medicaid. Fixed. co_adult_financial_medicaid_enrolled (policyengine_us/variables/gov/states/co/ssa/co_adult_financial_medicaid_enrolled.py:29-32) ORs reported coverage into the result, both before work requirements apply and after the branch. New YAML Case 11 in co_state_supplement_deeming_exempt.yaml has a spouse with receives_medicaid: true and medicaid_enrolled: false, and that spouse is exempt.
  2. Deeming-exempt YAML. Rebuilt (co_state_supplement_deeming_exempt.yaml). Every case is a client and spouse in CO. Cases 1, 2 and 4 set co_adult_financial_medicaid_enrolled: false, so they test the SSI and OAP routes. Cases 9 and 10 (formerly 8-10) use period: 2020 with year-keyed inputs and month-keyed outputs.
  3. Merge main:
    • One Adult Financial Medicaid variable with reported coverage and OAP's skip guard. Done. It replaces co_oap_medicaid_enrolled and co_state_supplement_medicaid_enrolled, and OAP's files and tests now read it. AND-CS's skip guard is at co_state_supplement_deeming_exempt.py:58-74. The Medicaid-order test asserts no branch named co_adult_financial_medicaid survives either order.
    • OAP receipt by month. Done at co_state_supplement_deeming_exempt.py:48-56: OAP-eligible, and the OAP standard less the person's own OAP countable income (SSI included) is positive. That is the test co_oap_deeming_exempt uses.
    • One reading for the (f) spillover and for the SSI income test. Both now follow OAP. The spillover is from the client's own share of the $20, $10 when married (_and_cs_client_income.py:36-44). The income limit applies to SSI recipients too (co_state_supplement_deeming_exempt.py:29-45, 57). See the judgment calls below.
    • Test group. The body now says test_ssi_state_supplement_medicaid_dependency.py runs in heavy-a (Makefile REST_HEAVY_A_TESTS). Re-measured locally below; Linux CI hasn't run on this draft.

Optional

  • 2014–2020 spillover under 3.545(B)(1): added as reading 4 in the body.
  • References: earned_share.yaml no longer has a page in its title; assistance_exemption_applies.yaml dates 3.545(F) March 2, 2014 ("version in force January 1, 2020"); payment_floor.yaml opens the packet at page 1, titled #page 1,4,9.
  • Invariant 4 (test_co_and_cs_invariants.py:163-168): only the countable-income assertion is limited to clients without in-kind support. The supplement assertion runs for every case, and the property test passes with it.

Also: #10145's changelog fragment came back in the merge after main had released it (1392313e09). I deleted it, so the release won't print it twice.

Hand computations (2026, monthly)

  • Couple, head pension $487: SSI (1,491 − 467) / 2 = 512 each; head's own income 487 − 10 = 477; grant 994 − 512 − 477 = 5, raised to the $13 floor. YAML: $13.
  • Client SSDI $300, spouse pension $400: 300 − 10 = 290 own; 400 − (20 − 10) = 390 deemed; 680. YAML: 680.
  • Deemed-income Case 8, which changed: a married client with $10 interest and $200 earnings uses their $10 share on the interest, so none reaches earnings: (200 − 65) / 2 = 67.50 (was 62.50). The spouse's $50 pension takes the couple's other $10: 40 deemed (was 50).
  • Deeming-exempt Case 7 (new): a spouse on SSI earning $2,074 has countable income (2,074 − 85) / 2 = 994.50 > 994, so is not exempt.

co_state_supplement.yaml values didn't move: all 32 cases pass unchanged.

Tests run (this head, Linux, Python 3.14)

  • YAML, one file per process: co_state_supplement.yaml 32, _countable_income 4, _deemed_income 10, _deeming_exempt 11, _eligible 11, _own_countable_income 7; OAP co_oap.yaml 36, _deemed_income 20, _deeming_exempt 9, _eligible 5, _in_kind_support_and_maintenance 2. All pass.
  • All CO YAML (gov/states/co, test_batched.py --mode per-subdir): 807 passed in 6 batches, one worker (peak RSS 8.0 GB in batch 6). An earlier two-worker run lost batch 6 to SIGKILL while other test processes shared the VM; the rerun alone passed.
  • Python: test_co_and_cs_invariants.py 4/4 with Hypothesis (1.26 GB peak RSS, 53 s with import); test_co_oap_invariants.py 2/2 (1.24 GB, 47 s); test_ssi_state_supplement_couple_invariants.py 6/6 (1.22 GB, 45 s); test_ssi_state_supplement_medicaid_dependency.py 28/28 (2.99 GB, 215 s).
  • Code health: test_source_conflicts 103, test_reference_urls 32, test_no_concatenated_reference_urls 48, test_parameter_yaml_keys 34, test_no_builtin_sum_over_entity_calls, test_no_group_variables_in_person_adds, test_no_in_place_writes_to_cached_arrays. All pass.
  • Partner fixtures, run only: analytics_coverage/edge_cases/state/co/state_supplement.yaml 3/3, .../co/oap.yaml 3/3, my_friend_ben/2025.yaml 1/1. No partner output moves.

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

Mutant Killed by
Spillover against the full $20 again co_state_supplement_deemed_income.yaml (1 failure, Case 8)
SSI receipt skips the income limit co_state_supplement_deeming_exempt.yaml (Case 7)
Medicaid variable drops receives_medicaid co_state_supplement_deeming_exempt.yaml (Case 11)
OAP route removed from the exemption co_state_supplement_deeming_exempt.yaml (Case 4)

CI

Pull request run 41721281741 at 8707792d09: success, every job passing, Household API Partners, all Baseline and Contrib shards, Rest Python shards and Microsimulation included. It started when hua7450 marked the PR ready (21:22Z) and finished at 22:26Z.

Judgment calls

hua7450 accepted calls 1 (the SSI-recipient part) and 2 at this head (comment). How to define "the SSI limit" itself is still open.

  1. (F) income limit for SSI recipients. 3.549(F) reads "receives ... SSI or Medicaid and has income no greater than the SSI limit"; the earlier head treated SSI receipt alone as enough. I apply the limit to every route, as OAP applies 3.534(C)'s, using the person's own monthly SSI countable income against the individual $994 rate. The effect: a member of an SSI couple whose own countable income exceeds $994 now has it deemed to the other spouse. The alternative is the couple limit for couple members, which amounts to SSI receipt alone.
  2. Married (A)(2)(f) spillover. I use OAP's landed reading, the client's own $10 share, so no more than $20 applies to the couple ((A)(2)(c)(1)). Axiom's encoding uses the full $20; if the hub prefers that, OAP needs the same change.
  3. Shared Medicaid variable name. co_adult_financial_medicaid_enrolled replaces two variables, one of which was on main (co_oap_medicaid_enrolled). No partner fixture or other caller outside CO OAP/AND-CS reads either one (grep).
  4. The Medicaid skip guard asks for Medicaid only for people sharing a marital unit, tax unit or household with an AND-CS client, since only a spouse or parent can have income deemed and the deeming variable finds them in those groups.
  5. OAP receipt before 2023. OAP's parameters start in 2023. Core back-fills the 2023 values to March 2020–2022, so OAP receipt for the (F) exemption uses 2023 amounts then, as co_oap itself does.

What I couldn't check

This session's network policy blocks www.sos.state.co.us and web.archive.org, so I couldn't fetch 9 CCR 2503-5. The rule quotes in the body come from the PR's earlier body and hua7450's review, not from my own reading. The hand computations use those quoted rules and SSA's published rates.

Proposed follow-up

  • Unify the Adult Financial (A)(2)(f) reading with Axiom. Once the hub picks the full-$20 or married-half spillover, align rulespec-us's 3.549(A)(2)(f) or PolicyEngine's 3.533/3.549 helpers, which now share the married-half reading.

Generated by Claude Code

@MaxGhenis

MaxGhenis commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor Author

Hub review in progress

Reviewing head 8707792d091935e5a7bd5f47f0986d81525aaf56. Mutants are still running; the final review will follow as a new comment. Findings so far:

Findings

P2-1. The PR removes co_oap_medicaid_enrolled, which shipped in 2.52.0, and the changelog doesn't say so

policyengine_us/variables/gov/states/co/ssa/oap/co_oap_medicaid_enrolled.py (deleted); changelog.d/co-and-cs-payment-floor-3549.fixed.md:1.

#10176 added co_oap_medicaid_enrolled, and it was released in 2.52.0 (2026-10-20, CHANGELOG.md: "Apply Colorado's $189 Old Age Pension payment floor ..."). This PR deletes it and renames it to co_adult_financial_medicaid_enrolled. Nothing in the repo reads the old name any more (grep -rln "co_oap_medicaid_enrolled\|co_state_supplement_medicaid_enrolled" over *.py *.yaml *.md *.ipynb at the head returns nothing). But an API or package user who sets it as an input, as the OAP YAML tests did on main, now gets a SituationParsingError ("You tried to calculate or to set a value for variable ... but it was not found"). I saw that error with the names the other way round: a situation setting co_adult_financial_medicaid_enrolled against main. The fragment is fixed and doesn't mention the removal.

Fix: say so in the fragment. Either keep fixed and append the sentence below, or, since CLAUDE.md gives removed a minor bump, add a second fragment changelog.d/co-and-cs-payment-floor-3549.removed.md with this text:

Remove `co_oap_medicaid_enrolled`; set `co_adult_financial_medicaid_enrolled` instead, which both Colorado Old Age Pension and AND-CS read for their deeming exemptions.

P3-1. The spillover text says "under $20", but the code subtracts SSI from the spillover, and for a married client the gate is $10

policyengine_us/variables/gov/states/co/ssa/state_supplement/_and_cs_client_income.py:36-44; PR body, "3.549 outside SSI couples" table, row "(A)(2)(f) unused disregard".

The body says the client's own share reaches earnings "only when gross unearned income incl. SSI is under $20", and the code comment says the "rest of the disregard" then reduces earned income. The code computes max_(0, disregard - unearned - ssi). So the amount that reaches earnings is the share less all gross unearned income, SSI included, not the share less what the unearned disregard used. For a married client it is positive only when unearned income plus SSI is under $10. Landed OAP (co_oap_own_countable_income.py:45) has the same line, so this is a wording mismatch, not a divergence between the programs. Witness (my probe, PR head, 2026-01, ssi input $5, interest $3/month, earnings $300/month):

P3 married, SSI 5, interest 3, earn 300: co_state_supplement_own_countable_income=[116.5, 0.0]
P3 single,  SSI 5, interest 3, earn 300: co_state_supplement_own_countable_income=[111.5]

The code gives 116.50 = 3 − 3 + (300 − 65 − (10 − 3 − 5)) / 2 and 111.50 = (300 − 65 − (20 − 3 − 5)) / 2. The body's wording would give 114 (rest 7) and 109 (rest 17). No test has SSI between $0 and $20 (every spillover case sets ssi: 0), and mutant M6 below, which implements the body's wording, survives every AND-CS and OAP YAML file. Payments are almost never affected: a client with under $20 of SSI has income close to the standard. Fix the text to match the code, and pin it with a case:

  • body row: "only the client's own share ($20, or $10 if married) less the client's gross unearned income, SSI included, when that is positive"
  • comment, lines 36-41: # 3.549(A)(2)(f): the client's own share of the disregard (half of the $20 when married, as in OAP's 3.533(A)(2)(f)) less gross unearned income, SSI included, reduces earned income when positive. A client whose only unearned income is SSI has no disregard to pass on.
  • a co_state_supplement_own_countable_income.yaml case with ssi: {2026-01: 5}, $36/year of interest and $3,600/year of earnings, expecting 111.5 for a single client.

If the hub reads (A)(2)(f) the body's way, OAP's line 45 needs the same change.

P3-2. No test pins the payment effect of judgment call 1, which is a $745 cliff for an SSI couple

policyengine_us/variables/gov/states/co/ssa/state_supplement/co_state_supplement_deeming_exempt.py:33-45, 57.

co_state_supplement_deeming_exempt.yaml Case 7 checks the exemption flag at $994.50. No co_state_supplement.yaml case shows what that does to the payment. My probe: a disabled SSI couple in CO, 2026-01, the spouse has a pension and the head has no income:

Spouse pension / month main: SSI, AND-CS (head, spouse) PR: SSI, AND-CS (head, spouse)
1,000 255.50 each; 738.50, 0 255.50 each; 738.50, 0
1,014 248.50 each; 745.50, 0 248.50 each; 745.50, 0
1,015 248.00 each; 746.00, 0 248.00 each; 0, 0
1,200 155.50 each; 838.50, 0 155.50 each; 0, 0

At $1,015 the spouse's own countable income is 995 > 994, so the spouse is no longer exempt. The head's countable income becomes 995 (1,015 less the couple's remaining $20), and 248 + 995 ≥ 994 ends the head's grant. A $1 pension rise costs the couple $746 a month. Under the other reading (the couple rate for a couple member, i.e. SSI receipt alone), the head keeps $746–$838.50. This follows from the reading the body states, and hua7450 accepted that the income test applies to SSI recipients. But the amount is what the hub decides when it defines "the SSI limit", so add the 1,014/1,015 pair to co_state_supplement.yaml so that the choice is visible and pinned.

P3-3. No test covers the 3.549(E) under-18 gate

policyengine_us/variables/gov/states/co/ssa/state_supplement/co_state_supplement_deemed_income.py:79.

Mutant M5 drops person("is_child", year) *, which deems parents' income to adult clients aged 18–59. It survives all six AND-CS YAML files and both OAP files I ran. Every parental case has a child aged 1, 10 or 17. Add a co_state_supplement_deemed_income.yaml case: a disabled SSI client aged 18 (or 20) in a household with a parent earning $24,000/year, expecting co_state_supplement_deemed_income: 0. Pair it with a 17-year-old, who gets 967.50.

P3-4. Overlap with open PRs #10146 and #10141

P3-5. The property tests disappear without a skip when hypothesis isn't installed

policyengine_us/tests/core/test_co_and_cs_invariants.py:260-266 (and main's test_co_oap_invariants.py).

After a plain uv sync, pytest reported test_co_and_cs_invariants.py 3 passed and test_co_oap_invariants.py 1 passed, with no skip. Once I installed --extra dev, they were 4 passed and 2 passed. CI installs --extra dev (.github/workflows/python-tests.yaml:34,100,178), so CI runs them. A local run can still look like a full pass without the property test. Replace the try/except ImportError with hypothesis = pytest.importorskip("hypothesis") at module level for the property test, or define a skipped placeholder test in the else branch, so that its absence shows up as a skip.


Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review
VERDICT: APPROVE
8707792
METHODOLOGY_CHOICE: yes

Independent review of head 8707792d09, which is still the PR's head (nothing has moved since the hand-off). I could not fetch 9 CCR 2503-5 (see "What I couldn't check"), so I checked the rule only as the PR, hua7450's review and the code quote it. Within that limit I found no wrong result, no CI failure and no false claim a reader would rely on. The branch merges cleanly with current main (25c4253483). The findings below are one P2 (a released variable is removed and the changelog doesn't say so) and P3 test, doc and coordination items. Judgment call 1 (what "the SSI limit" means) is still open, and the hub should settle it knowing it creates a $745 cliff for SSI couples; witness below.

Findings

P2-1. The PR removes co_oap_medicaid_enrolled, which shipped in 2.52.0, and the changelog doesn't say so

policyengine_us/variables/gov/states/co/ssa/oap/co_oap_medicaid_enrolled.py (deleted); changelog.d/co-and-cs-payment-floor-3549.fixed.md:1.

#10176 added co_oap_medicaid_enrolled, and it was released in 2.52.0 (2026-10-20, CHANGELOG.md: "Apply Colorado's $189 Old Age Pension payment floor ..."). This PR deletes it and renames it to co_adult_financial_medicaid_enrolled. Nothing in the repo reads the old name any more (grep -rln "co_oap_medicaid_enrolled\|co_state_supplement_medicaid_enrolled" over *.py *.yaml *.md *.ipynb at the head returns nothing). But an API or package user who sets it as an input, as the OAP YAML tests did on main, now gets a SituationParsingError ("You tried to calculate or to set a value for variable ... but it was not found"). I saw that error with the names the other way round: a situation setting co_adult_financial_medicaid_enrolled against main. The fragment is fixed and doesn't mention the removal.

Fix: say so in the fragment. Either keep fixed and append the sentence below, or, since CLAUDE.md gives removed a minor bump, add a second fragment changelog.d/co-and-cs-payment-floor-3549.removed.md with this text:

Remove `co_oap_medicaid_enrolled`; set `co_adult_financial_medicaid_enrolled` instead, which both Colorado Old Age Pension and AND-CS read for their deeming exemptions.

P3-1. The spillover text says "under $20", but the code subtracts SSI from the spillover, and for a married client the gate is $10

policyengine_us/variables/gov/states/co/ssa/state_supplement/_and_cs_client_income.py:36-44; PR body, "3.549 outside SSI couples" table, row "(A)(2)(f) unused disregard".

The body says the client's own share reaches earnings "only when gross unearned income incl. SSI is under $20", and the code comment says the "rest of the disregard" then reduces earned income. The code computes max_(0, disregard - unearned - ssi). So the amount that reaches earnings is the share less all gross unearned income, SSI included, not the share less what the unearned disregard used. For a married client it is positive only when unearned income plus SSI is under $10. Landed OAP (co_oap_own_countable_income.py:45) has the same line, so this is a wording mismatch, not a divergence between the programs. Witness (my probe, PR head, 2026-01, ssi input $5, interest $3/month, earnings $300/month):

P3 married, SSI 5, interest 3, earn 300: co_state_supplement_own_countable_income=[116.5, 0.0]
P3 single,  SSI 5, interest 3, earn 300: co_state_supplement_own_countable_income=[111.5]

The code gives 116.50 = 3 − 3 + (300 − 65 − (10 − 3 − 5)) / 2 and 111.50 = (300 − 65 − (20 − 3 − 5)) / 2. The body's wording would give 114 (rest 7) and 109 (rest 17). No test has SSI between $0 and $20 (every spillover case sets ssi: 0), and mutant M6 below, which implements the body's wording, survives all eight YAML files I ran. Payments are almost never affected: a client with under $20 of SSI has income close to the standard. Fix the text to match the code, and pin it with a case:

  • body row: "only the client's own share ($20, or $10 if married) less the client's gross unearned income, SSI included, when that is positive"
  • comment, lines 36-41: # 3.549(A)(2)(f): the client's own share of the disregard (half of the $20 when married, as in OAP's 3.533(A)(2)(f)) less gross unearned income, SSI included, reduces earned income when positive. A client whose only unearned income is SSI has no disregard to pass on.
  • a co_state_supplement_own_countable_income.yaml case with ssi: {2026-01: 5}, $36/year of interest and $3,600/year of earnings, expecting 111.5 for a single client.

If the hub reads (A)(2)(f) the body's way, OAP's line 45 needs the same change.

P3-2. No test pins the payment effect of judgment call 1, which is a $745 cliff for an SSI couple

policyengine_us/variables/gov/states/co/ssa/state_supplement/co_state_supplement_deeming_exempt.py:33-45, 57.

co_state_supplement_deeming_exempt.yaml Case 7 checks the exemption flag at $994.50. No co_state_supplement.yaml case shows what that does to the payment. My probe: a disabled SSI couple in CO, 2026-01, the spouse has a pension and the head has no income:

Spouse pension / month main: SSI, AND-CS (head, spouse) PR: SSI, AND-CS (head, spouse)
1,000 255.50 each; 738.50, 0 255.50 each; 738.50, 0
1,014 248.50 each; 745.50, 0 248.50 each; 745.50, 0
1,015 248.00 each; 746.00, 0 248.00 each; 0, 0
1,200 155.50 each; 838.50, 0 155.50 each; 0, 0

At $1,015 the spouse's own countable income is 995 > 994, so the spouse is no longer exempt. The head's countable income becomes 995 (1,015 less the couple's remaining $20), and 248 + 995 ≥ 994 ends the head's grant. A $1 pension rise costs the couple $746 a month. Under the other reading (the couple rate for a couple member, i.e. SSI receipt alone), the head keeps $746–$838.50. This follows from the reading the body states, and hua7450 accepted that the income test applies to SSI recipients. But the amount is what the hub decides when it defines "the SSI limit", so add the 1,014/1,015 pair to co_state_supplement.yaml so that the choice is visible and pinned.

P3-3. No test covers the 3.549(E) under-18 gate

policyengine_us/variables/gov/states/co/ssa/state_supplement/co_state_supplement_deemed_income.py:79.

Mutant M5 drops person("is_child", year) *, which deems parents' income to adult clients aged 18–59. It survives all six AND-CS YAML files and both OAP files I ran. Every parental case has a child aged 1, 10 or 17. Add a co_state_supplement_deemed_income.yaml case: a disabled SSI client aged 18 (or 20) in a household with a parent earning $24,000/year, expecting co_state_supplement_deemed_income: 0. Pair it with a 17-year-old, who gets 967.50.

P3-4. Overlap with open PRs #10146 and #10141

P3-5. The property tests disappear without a skip when hypothesis isn't installed

policyengine_us/tests/core/test_co_and_cs_invariants.py:260-266 (and main's test_co_oap_invariants.py).

After a plain uv sync, pytest reported test_co_and_cs_invariants.py 3 passed and test_co_oap_invariants.py 1 passed, with no skip. Once I installed --extra dev, they were 4 passed and 2 passed. CI installs --extra dev (.github/workflows/python-tests.yaml:34,100,178), so CI runs them. A local run can still look like a full pass without the property test. Replace the try/except ImportError with hypothesis = pytest.importorskip("hypothesis") at module level for the property test, or define a skipped placeholder test in the else branch, so that its absence shows up as a skip.

Mutants

Each mutant ran in its own copy of the head, against the six AND-CS YAML files plus co_oap_deeming_exempt.yaml and co_oap.yaml, one file per process. The copy was deleted after each run, and git status in the PR worktree is clean.

Mutant Change Result
M1 (hand-off) spillover from the full $20: disregard → p.unearned in _and_cs_client_income.py:44 killed: co_state_supplement_deemed_income.yaml Case 8 (only)
M2 (hand-off) SSI receipt skips the income limit: exempt = receives_ssi | (within_limit & receives_oap) killed: co_state_supplement_deeming_exempt.yaml Case 7 (only)
M3 (hand-off) Medicaid drops receives_medicaid on the pre-2027 path (co_adult_financial_medicaid_enrolled.py:32) killed: co_state_supplement_deeming_exempt.yaml Case 11 (only; neither OAP file I ran covers reported coverage)
M4 (hand-off) OAP route removed from the AND-CS exemption killed: co_state_supplement_deeming_exempt.yaml Case 4 (only)
M5 (mine) 3.549(E) under-18 gate dropped (co_state_supplement_deemed_income.py:79) survives all 8 files (P3-3)
M6 (mine) the body's (A)(2)(f) wording: own share less non-SSI unearned, gated on unearned + SSI < $20 survives all 8 files (P3-1)
M7 (mine) payment floor without the eligibility gate (co_state_supplement.py:36) killed: co_state_supplement.yaml Cases 24, 26, 27, 30, 32
M8 (mine) Medicaid skip guard limited to the marital unit (co_state_supplement_deeming_exempt.py:65-69) killed: co_state_supplement_deemed_income.yaml Case 6

The hand-off's four mutants die where it says.

Checked and sound

  • The author's brief. It asked for: main merged (done at 06d34c12e6, and it still merges cleanly); every review item answered (below); hand-computed YAML with source comments; Hypothesis property tests with stated reasons; a mutant per fix; a rewritten body with the impact: and axiom: lines; a changelog fragment. All of these are present. The fragment misses the removal (P2-1). Two property gaps are the P3-1 and P3-3 cases. The brief's Count Colorado's in-kind support and maintenance for AND-CS clients in another person's household #10183 item is outside this PR.

  • Head and scope. The head is 8707792d09, as the hand-off says. git diff origin/main...pr-10161 is empty for .github/ and policyengine_us/tests/policy/baseline/partners/, and the PR's file list (25 files) has nothing under either.

  • CI. Pull request run 41721281741 at this head: conclusion success, and all 36 jobs concluded success, none cancelled or skipped. Those jobs include Household API Partners, all 11 Baseline shards, 9 Rest Python shards, Microsimulation and 9 Contrib shards. The plan put the heavy-a group (REST_HEAVY_A_TESTS, 5 files) in Rest Python shard 8. Its log shows heavy-a (5 files) with 74 passed in 680.75 s, including all 28 test_ssi_state_supplement_medicaid_dependency.py tests PASSED. The core-1 group ran all four test_co_and_cs_invariants.py tests, test_properties included, and both test_co_oap_invariants.py tests; all passed. The earlier run at that SHA (41719043321) was skipped while the PR was a draft.

  • The defect reproduces at main. The PR's co_state_supplement.yaml, run against main's code, fails 6 of 32 cases: 20, 23 and 25 (floor) and 29, 30 and 31 (deeming). The other 26 pass on both.

  • Hand values, computed before reading the code (2026 SSI $994/$1,491 and 2019 $771/$1,157, confirmed in gov/ssa/ssi/amount/*.yaml):

    • Couple, head pension $487: SSI (1,491 − 467) / 2 = 512 each; own 487 − 10 = 477; 994 − 512 − 477 = 5, raised to 13.
    • Pension $497: SSI 507 each; own 487; 507 + 487 = 994, which is not below the standard, so 0 and no floor.
    • SSDI $300, spouse pension $400: 290 + (400 − 10) = 680.
    • Case 8: the $10 interest uses the client's $10 share; (200 − 65) / 2 = 67.50; spouse 50 − 10 = 40.
    • Case 7: (2,074 − 20 − 65) / 2 = 994.50 > 994, so not exempt.
    • Spouse earning $1,500 on Medicaid: SSI deems (1,500 − 85) / 2 = 707.50 against the couple rate, SSI 783.50; (F) deems nothing; 994 − 783.50 = 210.50.
    • Client SSI only, spouse earning $300: (300 − 65) / 2 = 117.50. Child, parent earning $2,000: (2,000 − 65) / 2 = 967.50.
    • 2019 couple, spouse pension $100: SSI (1,157 − 80) / 2 = 538.50; deemed 100 − 20 = 80; 771 − 538.50 − 80 = 152.50.

    All of these match the YAML and the hand-off.

  • Tests at this head, one file per process. AND-CS YAML: co_state_supplement 32, _countable_income 4, _deemed_income 10, _deeming_exempt 11, _eligible 11, _own_countable_income 7, all passed. OAP YAML: co_oap 36, _deemed_income 20, _deeming_exempt 9, _eligible 5, _in_kind_support_and_maintenance 2, _own_countable_income 15, all passed. Python: test_co_and_cs_invariants.py 4/4 and test_co_oap_invariants.py 2/2 (with hypothesis), test_ssi_state_supplement_couple_invariants.py 6/6, test_ssi_state_supplement_medicaid_dependency.py 28/28 (153 s of tests, 216 s with import).

  • hua7450's review, item by item.

    1. receives_medicaid is ORed in on both paths (co_adult_financial_medicaid_enrolled.py:32,66). Deeming-exempt Case 11 sets receives_medicaid: true and medicaid_enrolled: false, and mutant M3 shows that case is what kills the regression.
    2. Deeming-exempt Cases 1, 2, 4, 7 and 8 set co_adult_financial_medicaid_enrolled: false. Cases 9 and 10 use period: 2020 with year-keyed state_code and Medicaid inputs and month-keyed ssi and outputs.
    3. One Medicaid variable; OAP receipt by month (co_state_supplement_deeming_exempt.py:52-56); OAP's readings for (f) and for the SSI income test; heavy-a in the body.

    The optional items are done too: reading 4 is in the body; the earned_share.yaml title has no page; the assistance_exemption_applies.yaml 3.545(F) title says "effective March 2, 2014"; payment_floor.yaml opens the packet at page 1 and is titled #page 1,4,9; invariant 4 scopes only the countable assertion (test_co_and_cs_invariants.py:164-168). The OAP test and variable edits are pure renames: every changed line swaps co_oap_medicaid_enrolled for co_adult_financial_medicaid_enrolled.

  • No Medicaid loop. co_adult_financial_medicaid_enrolled overrides itself with reported coverage inside its branch (:56-66) and pops the branch in finally. Both deeming exemptions read only it, and only past their skip guards (co_oap_deeming_exempt.py:51-55, co_state_supplement_deeming_exempt.py:64-74). I probed a mixed couple neither test covers: an OAP client aged 66 married to a disabled AND-CS client aged 45, spouse on SNAP workfare, pension $300 or $800, in 2026 and 2030. co_oap, co_state_supplement, snap, medicaid_enrolled and both exemptions were identical in forward and reverse calculation order, no co_adult_financial_medicaid* branch survived, and nothing recursed.

  • Readers. co_state_supplement is read by SNAP unearned income (gov/usda/snap/income/sources/unearned.yaml:27), household_state_benefits (four lists), spm_unit_benefits, programs.yaml and four reforms (Tlaib x3, TX rebate), all as a plain sum. co_state_supplement_countable_income, _own_countable_income, _deemed_income and _deeming_exempt have one reader each, inside AND-CS. co_adult_financial_medicaid_enrolled is read only by the two deeming exemptions. payment_floor is read only by co_state_supplement (OAP reads its own). assistance_exemption_applies is read only by co_state_supplement_deeming_exempt. No reader becomes reachable that wasn't before. The comment that "SNAP counts both grants as income" holds: co_oap and co_state_supplement are both in SNAP's unearned sources.

  • Code claims. Since 2012 the AND-CS grant standard has equalled the SSI individual rate in every year (grant_standard.yaml against individual.yaml, 2012–2026), as co_state_supplement.py:24-28 says. The floor is $0 before 2026 (Case 21) and applies only when the grant is positive (Cases 24, 26 and 32). The (F) exemption is off before 2020-03 (Case 9's month split).

  • Body and hand-off claims. The test counts, the line references (co_adult_financial_medicaid_enrolled.py:29-32, co_state_supplement_deeming_exempt.py:29-45, 48-56, 58-74, _and_cs_client_income.py:36-44) and the CI run all match. Commit 1392313e09, cited for Pay CO, TX and NM SSI supplements to both members of an SSI couple #10145's released fragment, is main's release commit; the PR adds only its own fragment. The impact: and axiom: lines are present as the brief set them.

  • Can it move baseline outputs? Yes. co_state_supplement changes for CO AND-CS clients: up at the 2026 floor and where a Medicaid spouse or parent is now exempt, down where non-SSI spousal or parental income below SSI's deeming threshold is now deemed, for SSI couples before March 2020, and for couple members above $994 of own income (P3-2). Through SNAP, spm_unit_benefits and household net income follow. The hub's population run should report CO AND-CS spending and recipients for 2019, 2020–2025 and 2026, plus CO SNAP, against main, and break 2026 out by SSI couples and floor recipients. The body's cited caseload, about 250, is the scale to compare against.

What I couldn't check

  • 9 CCR 2503-5 itself. This session's network policy refuses www.sos.state.co.us (CONNECT 403; WebFetch doesn't resolve it), and also web.archive.org, ecfr.gov, govinfo.gov, law.cornell.edu, ssa.gov, cdhs.colorado.gov and leg.colorado.gov. So I confirmed no quote of 3.510, 3.520.781(A), 3.520.786, 3.545, 3.546 or 3.549 (A)–(H), nor the 2020 and 2014 dating. That includes the $13 floor, the married $10 share, the (A)(2)(f) wording behind P3-1, the "SSI limit" in (F), "unemancipated child under 18" in (E), and the CDHS packet's caseload and cost. I relied on the code's and hua7450's statements of the rule. The hub, or a session that can reach the Secretary of State's site, should check the (A)(2)(f) and (F) text against P3-1 and P3-2.
  • Population impact and microsimulation (not run, per the brief).
  • The memory figures in the hand-off (3.0 GB, 1.25 GB peak RSS). This VM has no /usr/bin/time, so I measured wall time only.

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

A spouse or parent who receives SSI now meets 3.549(F)'s income condition
by receiving it, since SSI's own test already held their countable income
within the limit SSI applies to them (the couple rate in an eligible
couple), as 3.570.43 uses the phrase. Someone on Old Age Pension or
Medicaid without SSI still faces the individual federal benefit rate on
their own countable income. This removes a $746 cliff where a $1 pension
rise ended an SSI couple head's grant; new co_state_supplement Cases 33-35
pin the payment at $1,014, $1,015 and $1,200 pensions.

Also from review round 1:
- the 3.549(A)(2)(f) comment now describes what the code does (own share
  less gross unearned income, SSI included), pinned by a case with $5 SSI;
- cases for 3.549(E)'s under-18 gate (client 18 vs 17);
- the property tests report a skip when hypothesis isn't installed;
- a removed fragment for co_oap_medicaid_enrolled, which shipped in 2.52.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6GVxJNmuxpvgfooGjd
MaxGhenis pushed a commit that referenced this pull request Nov 4, 2026
Brings in #10161's round 1 fixes. Both branches appended co_state_supplement
cases from Case 33: #10161's three SSI-couple cases keep 33-35, and this
branch's six ISM cases become 36-41.

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

Copy link
Copy Markdown
Contributor Author

Ready for hub review

Head: 3371fc55736bf5c246fbafaa7c98bc1bea116cc0

Round 1 fixes (items 1 to 6). The branch was at the named head 8707792d09 when I started, and no one else pushed while I worked. Two commits: 6ed284fecb, which merges origin/main, and 3371fc5573 with the fixes.

Items

  1. Pick-up and merge. I merged origin/main with a merge commit. Nothing conflicted. Main hasn't touched any Colorado SSA file since the last merge, and Limit SSI spousal-deeming child allocations to the couple's co-resident children #10146 and Apply 416.1163(e)(2) to deemed SSI and identify SSI couples by marriage, not tax roles #10141 are still open.

  2. P2-1, the removed variable. removed is a fragment type in pyproject.toml's towncrier config, so I added changelog.d/co-and-cs-payment-floor-3549.removed.md with the review's sentence.

  3. Judgment call 1, the SSI limit. co_state_supplement_deeming_exempt.py:29-38 has the comment block from the item. :58 is now exempt = receives_ssi | (within_limit & receives_oap). The Medicaid path (needs_medicaid = near_client & within_limit & ~exempt) is unchanged, so Medicaid still decides only for someone within the individual rate who isn't exempt otherwise.

    • co_state_supplement.yaml Cases 33-35: a disabled SSI couple under 60, CO, 2026-01, with the spouse's pension and no income for the head. Each spouse's SSI is (1,491 − (pension − 20)) / 2, and the head's AND-CS is 994 less that SSI, since the SSI spouse deems nothing:
      • $1,014: SSI (1,491 − 994) / 2 = 248.50; head 994 − 248.50 = 745.50.
      • $1,015: SSI (1,491 − 995) / 2 = 248; head 994 − 248 = 746.
      • $1,200: SSI (1,491 − 1,180) / 2 = 155.50; head 994 − 155.50 = 838.50.
      • The spouse gets 0 in all three: own 1,005 (or 1,004 or 1,190) plus SSI exceeds $994. Deemed income is 0 for both.
    • co_state_supplement_deeming_exempt.yaml Case 7 (SSI spouse, own countable income $994.50) now expects [true, true]. I renamed it and rewrote its comment.
    • Judgment call: I didn't add a separate Medicaid-only case at $994.50. Case 6 is exactly that situation: same people, ssi: 0, employment_income: 24_888, co_adult_financial_medicaid_enrolled: true, expecting [true, false]. A copy would duplicate it, so I renamed Case 6 ("a Medicaid spouse without SSI above the SSI limit is not exempt") and pointed its comment at Case 7.
    • Mutant MA, restoring within_limit & (receives_ssi | receives_oap), is killed by co_state_supplement_deeming_exempt.yaml Case 7 and by co_state_supplement.yaml Cases 34 and 35. Case 33 survives it, as expected: at $1,014 the spouse's own income is 994, within the individual rate either way.
  4. P3-1, the (A)(2)(f) spillover. _and_cs_client_income.py:36-39 now carries the review's comment. The code is unchanged, and so is OAP's matching line. co_state_supplement_own_countable_income.yaml Case 8: a single client, ssi of 5 in 2026-01, $36/year of interest, $3,600/year of earnings. The $20 covers the $3 of interest; 20 − 3 − 5 = 12 reaches earnings; (300 − 12 − 65) / 2 = 111.50. The review's M6 (the old body's wording) is now killed by that case only.

  5. P3-3 and P3-5, tests.

    • co_state_supplement_deemed_income.yaml Case 11: a disabled SSI client aged 18 whose parent earns $24,000/year gets 0. Case 12 is the same household with the client aged 17: (2,000 − 65) / 2 = 967.50. The review's M5 (dropping person("is_child", year) *) is now killed by Case 11.
    • test_co_and_cs_invariants.py and test_co_oap_invariants.py: a module-level importorskip would also skip each file's non-property tests, so I kept the import guard and added an else: branch that defines test_properties with @pytest.mark.skip(reason="hypothesis is not installed"). With hypothesis blocked by an import hook, pytest reports 1 skipped for -k test_properties in each file.
  6. The body. I replaced the spillover cell and judgment call 1 with the item's texts, and added an "Overlap" section with the item's bullet. Other sentences the round made false, now fixed:

    • Summary (A) bullet: the spillover sentence.
    • Summary (F) bullet: SSI receipt alone exempts.
    • The (F) table row.
    • The worked-case row "Spouse on SSI, $994.50" now reads exempt. I added the Medicaid-only $994.50 row and the $1,015 couple row (main gives $746 too, per the round 1 review's probe).
    • Test counts.
    • CI note: "Linux CI times aren't measured yet" became heavy-a's 74 tests in 681 s at run 41721281741, as the round 1 review reported. I didn't check that log myself.

    I read the whole body back after the PATCH. It matches what I sent, apart from a trailing newline. The impact: and axiom: lines are unchanged.

Tests at this head, one file per process (uv sync --extra dev)

File Result
co_state_supplement.yaml 35 passed
co_state_supplement_deeming_exempt.yaml 11 passed
co_state_supplement_deemed_income.yaml 12 passed
co_state_supplement_own_countable_income.yaml 8 passed
co_oap_deemed_income.yaml 20 passed
co_oap_in_kind_support_and_maintenance.yaml 2 passed
test_co_and_cs_invariants.py 4 passed
test_co_oap_invariants.py 2 passed

ruff format --check and ruff check are clean on the four changed Python files.

Mutants

Each mutant ran in its own process on the working tree, and I restored the file with git checkout after each one (git status clean).

Mutant Killed by
MA: exempt = within_limit & (receives_ssi | receives_oap) _deeming_exempt Case 7; co_state_supplement Cases 34, 35 (_deemed_income 12/12 pass)
M5: drop person("is_child", year) * _deemed_income Case 11
M6: spillover gated on unearned + SSI < share, less non-SSI unearned only _own_countable_income Case 8

CI

Pull request run 41859948897 at 3371fc5573: conclusion success, all 36 jobs success, none cancelled or skipped. It took about 66 minutes; the last job to finish was Contrib other-shard-3.

Not checked

  • I didn't fetch 9 CCR 2503-5. The (F), 3.570.43 and (A)(2) wording in the code comment and body is the hub's quoted text.
  • No microsimulation or population impact (per the brief).
  • No partner or .github/ file changed.

Proposed follow-up

None beyond the #10146 overlap the body already names.


Generated by Claude Code

@MaxGhenis

MaxGhenis commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor Author

Hub review in progress (superseded)

The final review is at #10161 (comment).


Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Ready for hub review
VERDICT: APPROVE
3371fc5
METHODOLOGY_CHOICE: yes

This is round 2, a delta review of head 3371fc5573 against the round 1 review at 8707792d09. The head hasn't moved since the hand-off. The round adds two commits:

  • 6ed284fecb merges origin/main at 25c4253483, which is still main's tip.
  • 3371fc5573 holds the fixes.

The fixes do what round 1 and items 1 to 6 of the assignment asked. I found no wrong result, no failing test or CI job, and no false claim in the body. One P3 remains: no test pins the individual-rate limit on the Old Age Pension route, so my own mutant MB, which drops that limit, passes every existing case. The PR picks one reading of the undefined "SSI limit" in 9 CCR 2503-5 3.549(F), so METHODOLOGY_CHOICE is yes. The hub settled that reading, and the code applies it as settled.

Findings

P3-1. No test pins the individual-rate limit on the Old Age Pension route

policyengine_us/variables/gov/states/co/ssa/state_supplement/co_state_supplement_deeming_exempt.py:58

The hub's reading: "Someone on Old Age Pension or Medicaid without SSI meets it when their own monthly countable income ... doesn't exceed the individual federal benefit rate". The Medicaid half is pinned by _deeming_exempt Cases 5 and 6, at $994 and $994.50. The OAP half has one case, Case 4: an OAP spouse with no income. The 2026 OAP grant standard is $1,032 (gov/states/co/ssa/oap/grant_standard.yaml), above the $994 individual rate. A married OAP spouse not on SSI, with a pension between $1,015 and $1,041, therefore still receives OAP but fails the income condition.

Failure scenario. Mutant MB, exempt = receives_ssi | receives_oap, exempts that spouse. The mutant passed all 8 files I ran it against, one process per file:

  • co_state_supplement 35/35, _countable_income 4/4, _deemed_income 12/12, _deeming_exempt 11/11, _eligible 11/11, _own_countable_income 8/8;
  • co_oap_deeming_exempt 9/9 and co_oap 36/36.

A future edit could drop the limit unnoticed.

Fix. Add this case to co_state_supplement_deeming_exempt.yaml. I ran it as a standalone file: it passes at the head (1 passed) and fails under MB (1 failed, "Case 12, an Old Age Pension spouse above the individual rate is not exempt."). That failure also shows the spouse does receive OAP in the model. Otherwise the mutant couldn't flip the flag.

- name: Case 12, an Old Age Pension spouse above the individual rate is not exempt.
  # The spouse is 65, on OAP but not SSI or Medicaid, with a $1,030/month
  # pension. OAP: own countable 1,030 - 10 = 1,020, below the $1,032 standard,
  # so OAP is paid. SSI countable income 1,030 - 20 = 1,010 exceeds the $994
  # individual rate, so 3.549(F)'s income condition fails.
  period: 2026-01
  input:
    people:
      head:
        age: 40
        is_ssi_disabled: true
        ssi: 500
      spouse:
        age: 65
        ssi: 0
        pension_income: 12_360
        co_adult_financial_medicaid_enrolled: false
    marital_units:
      marital_unit:
        members: [head, spouse]
    households:
      household:
        members: [head, spouse]
        state_code: CO
  output:
    co_state_supplement_deeming_exempt: [true, false]

Notes for the hub (not defects in this PR)

Mutants

Each mutant ran in its own worktree of the head, one test process per file, against the 6 AND-CS YAML files plus co_oap_deeming_exempt.yaml and co_oap.yaml. My first parallel batch hit the VM's OOM killer (4 kills in dmesg). I reran co_state_supplement.yaml for MB and MC one process at a time. Every worktree was restored afterwards, and git status is clean in all of them and in the main checkout.

Mutant Change Result
MA (hand-off) exempt = within_limit & (receives_ssi | receives_oap) killed by co_state_supplement Cases 34 and 35 and _deeming_exempt Case 7; Case 33 passes, as the hand-off says
M5 (hand-off) drop person("is_child", year) * (co_state_supplement_deemed_income.py:79) killed by _deemed_income Case 11
MB (mine) exempt = receives_ssi | receives_oap survives all 8 files (P3-1); killed by the proposed Case 12
MC (mine) spillover ignores SSI: max_(0, disregard - unearned) (_and_cs_client_income.py:42) killed by _own_countable_income Cases 3 and 8 and _countable_income Case 3

Checked and sound

  • The SSI-limit reading. co_state_supplement_deeming_exempt.py:58 is exempt = receives_ssi | (within_limit & receives_oap). :71 is still needs_medicaid = near_client & within_limit & ~exempt, so Medicaid decides only for someone within the individual rate who isn't exempt otherwise. The comment at :29-38 is the hub's text word for word and matches the code. The flag is all-false before 2020-03 (:23-28), as in round 1. receives_ssi is ssi_paid(ssi) > 0 or the reported receives_ssi input, the same test SNAP, Rhode Island, Oregon and Nebraska use.

  • Hand values, computed from the rule quotes before I read the cases. 2026 SSI rates are $994 individual and $1,491 couple.

    • Cases 33 to 35: SSI is (1,491 − (P − 20)) / 2, which gives 248.50, 248 and 155.50. The head's grant is 994 − SSI: 745.50, 746 and 838.50. The spouse's own income of P − 10 plus SSI exceeds 994 in each case, so the spouse gets 0. This matches the YAML.
    • My probe of the same household at pensions of 1,000, 1,014, 1,015 and 1,200 gives the head 738.50 / 745.50 / 746 / 838.50 at both the head and main, with the flag [True, True] and deemed income 0 at the head. So the body's row "spouse pension $1,015 ... main $746, this PR $746" holds, and the round 1 cliff is gone.
    • _deeming_exempt Case 7: an SSI spouse earning $2,074/month has own countable income of (2,074 − 85) / 2 = 994.50. The spouse receives SSI, so the case expects [true, true].
    • Case 6 is the Medicaid-only spouse at $994.50 that the brief asked for: ssi: 0, employment_income: 24_888, co_adult_financial_medicaid_enrolled: true, expecting [true, false]. Case 5 pins the $994 side of the boundary (24,876 a year, [true, true]). A separate copy would only duplicate Case 6, so the author's call is sound.
    • _own_countable_income Case 8: the $20 covers the $3 of interest, and 20 − 3 − 5 = 12 reaches earnings. Countable income is (300 − 12 − 65) / 2 = 111.50.
    • _deemed_income Cases 11 and 12: the parent earns 24,000 / 12 = 2,000 a month. Deemed income is 0 at age 18 and (2,000 − 65) / 2 = 967.50 at 17. The parent sets takes_up_medicaid_if_eligible: false, so the Medicaid exemption doesn't hide the gate, and M5 confirms that the age gate is what Case 11 tests.
  • The spillover comment (_and_cs_client_income.py:36-39) matches :40-42. The disregard is $20, or $10 when married (:30-31). The amount that reaches earnings is max_(0, disregard - unearned - ssi), where unearned is gross non-SSI unearned income including ISM. An SSI-only client gets 0 (ssi_only). The code didn't change, only the comment.

  • The skip. With hypothesis blocked by a shadow package that raises ImportError, and with its pytest plugin off (-p no:hypothesispytest), test_co_and_cs_invariants.py reports 3 passed, 1 skipped and test_co_oap_invariants.py reports 1 passed, 1 skipped. Both skip with reason "hypothesis is not installed". With hypothesis installed they report 4 passed and 2 passed. Without -p no:hypothesispytest, the installed hypothesis plugin crashes in pytest_terminal_summary. That is a side effect of my blocking method, not something an environment without hypothesis would see. The author's else: placeholder keeps the non-property tests running, which a module-level importorskip would not.

  • The changelog. pyproject.toml declares removed as a [[tool.towncrier.type]]. towncrier build --draft --version 0.0.0 lists the fragment under "### Removed", with the round 1 sentence. The fragment is a top-level file in changelog.d/.

  • The merge. git merge-tree --write-tree 8707792d09 25c4253483 gives tree a826a3973d, the same tree as 6ed284fecb: a clean merge with nothing added by hand. No file the PR touches changed in the merge.

  • Tests at the head, one file per process. AND-CS: co_state_supplement 35, _countable_income 4, _deemed_income 12, _deeming_exempt 11, _eligible 11, _own_countable_income 8. OAP: co_oap 36, _deemed_income 20, _deeming_exempt 9, _eligible 5, _in_kind_support_and_maintenance 2, _own_countable_income 15. All passed, and the counts match the body. ruff format --check and ruff check are clean on the four changed Python files.

  • CI. Pull request run 41859948897 at 3371fc5573: conclusion success, 36 of 36 jobs success, none cancelled or skipped.

    • The job logs show test_co_and_cs_invariants.py::test_properties PASSED in Rest Python shard 2 and test_co_oap_invariants.py::test_properties PASSED in shard 1, not skipped.
    • heavy-a (shard 8; REST_HEAVY_A_TESTS, Makefile lines 57-61, which include test_ssi_state_supplement_medicaid_dependency.py) reports 74 passed ... in 748.13s at this head. The body's 681 s figure is from the round 1 run it names, which is accurate as stated.
  • The body. I checked every sentence this round changed against the code:

    • the summary's (A) and (F) bullets;
    • the spillover cell and the (F) row of the table;
    • the "Medicaid for (F)" sentence;
    • the three worked-case rows: SSI spouse at $994.50 exempt, Medicaid-only at $994.50 not exempt, and the $1,015 couple at $746 both before and after;
    • judgment call 1, which is the item's text word for word;
    • the Overlap bullet, which is also the item's text word for word;
    • the test counts and the skip note.

    All of them hold. The impact: and axiom: lines exist (see the note above on axiom:).

  • Readers. co_state_supplement_deeming_exempt is read only by co_state_supplement_deemed_income.py:36. and_cs_client_income is called only by co_state_supplement_deemed_income.py and co_state_supplement_own_countable_income.py. co_state_supplement feeds SNAP unearned income, household_state_benefits, spm_unit_benefits, programs.yaml and four reforms (Tlaib ×3, TX rebate), all as a plain sum. This round makes no new reader reachable.

  • Baseline outputs. This round can move baseline outputs relative to round 1's head. Compared with main it moves them only where round 1 already did, except for one group. In 2026 and in any year from March 2020, a member of an SSI couple whose own SSI countable income exceeds $994 now has nothing deemed. That raises the other spouse's AND-CS back to main's value: $745.50 to $838.50 in the probe. Beyond round 1's checks, the hub's population run should break out CO AND-CS for SSI couples with one spouse's own countable income above $994, plus CO SNAP through the grant.

  • The brief. Items 1 to 6 are all done: the merge, the removed fragment, the SSI-limit code, comment, cases and mutant, the spillover comment and case, the under-18 cases and the skip, and the body. The hub's suggested separate Medicaid-only $994.50 case is Case 6 renamed, as the hand-off explains. Items 7 to 11 concern Count Colorado's in-kind support and maintenance for AND-CS clients in another person's household #10183 and are outside this PR.

  • Scope. The PR's 25 files include nothing under .github/ or policyengine_us/tests/policy/baseline/partners/.

What I couldn't check

  • 9 CCR 2503-5. This session can't reach www.sos.state.co.us (DNS refused), and the proxy refuses www.coloradosos.gov, web.archive.org, ecfr.gov, govinfo.gov and uscode.house.gov (CONNECT 403). So I confirmed no rule text myself. I relied on the hub's quotes of 3.549(A)(2), 3.549(F), 3.570.43, 3.520.79(B)(6) and 3.520.71(E), from its reading of ruleVersionId 12428.
  • Population impact and microsimulation, per the brief.
  • Peak memory for the Python files. I measured wall time and pass counts only.

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

…xemption

No test covered an OAP spouse not on SSI whose own SSI countable income
exceeds the individual rate while OAP is still paid, so dropping the
limit (exempt = receives_ssi | receives_oap) passed every case. Case 12
covers that spouse and fails under that mutant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6K4hbmpvP2YevFmELw
MaxGhenis pushed a commit that referenced this pull request Nov 5, 2026
MaxGhenis pushed a commit that referenced this pull request Nov 5, 2026
No test set is_homeless, so dropping homeless from _ism_exempt passed
every CO SSA case; Case 19 pins it. The ISM invariants docstring cited
co_state_supplement Case 34, which the merge of #10161 renumbered to 37.

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

Copy link
Copy Markdown
Contributor Author

Ready for hub review

Head: 96859129b5ea19ac4991b220fbb9c6154d1f67f2

This round builds on 3371fc5573, the head the item named. No other commit landed on the branch. I didn't merge origin/main: no check needed it, and nothing conflicted.

Items

Item Resolution
1. P3-1, the Old Age Pension limit co_state_supplement_deeming_exempt.yaml:292, "Case 12, an Old Age Pension spouse above the individual rate fails the exemption's income test." It has the name and comment the item gave and the review's inputs and output ([true, false]), and is appended after Case 11, so no other case moved. Commit 96859129b5.
Body The tests line now reads co_state_supplement_deeming_exempt.yaml (12, … ; Case 12 pins the individual-rate limit on the Old Age Pension route). I read the body back after the PATCH, and it matches what I sent. The axiom: and impact: lines are unchanged and left for the hub.
2. Runs See below.

Tests at the head (one file per process)

File Result
co_state_supplement_deeming_exempt.yaml 12 passed
co_state_supplement_deemed_income.yaml 12 passed
co_state_supplement.yaml 35 passed

No Python file changed, so ruff had nothing to check.

Mutant

Mutant Change Result
MB co_state_supplement_deeming_exempt.py:58, exempt = receives_ssi | (within_limit & receives_oap) becomes exempt = receives_ssi | receives_oap Killed. 1 failed, 11 passed: Case 12, co_state_supplement_deeming_exempt@2026-01: [1. 1.] differs from [1. 0.]. I restored the file, and git status was clean apart from the new case.

Hand computation (2026, from the case's comment and the review)

  • Pension 12,360 / 12 = 1,030 a month.
  • OAP: own countable 1,030 − 10 = 1,020, below the 1,032 grant standard, so OAP is paid.
  • SSI countable income: 1,030 − 20 = 1,010, above the 994 individual rate, so the spouse fails (F)'s income condition.

The mutant's flip to true shows the model treats the spouse as receiving OAP. Otherwise dropping the limit couldn't change the flag.

CI

Pull request run 41943988631 at 96859129b5 had not finished 60 minutes after my 00:47Z push. At 01:53Z, 35 of 36 jobs had concluded success, none had failed or been cancelled, and Contrib tests / Full Suite - Contrib (other-shard-3) (started 01:22Z) was still in progress. Per the brief, I'm handing off with the run URL. The hub should confirm the final conclusion before landing.

The body has no CI status sentence to update. Its only CI mention is the heavy-a timing at the round 1 head (run 41721281741), a measurement labelled with its head, which I left as it was.

Judgment calls

What I couldn't check

  • 9 CCR 2503-5 3.549(F) itself: I didn't fetch the rule. The case comment cites it as the item gave it.
  • Population impact and microsimulation, per the brief.

Generated by Claude Code

@MaxGhenis
MaxGhenis merged commit 082cb2e into main Nov 8, 2026
36 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

US + core hub merge audit, us#10161 at 96859129b5ea19ac4991b220fbb9c6154d1f67f2 (squash): Apply Colorado's AND-CS payment floor and 3.549 income rules to every client.

  • Reviews:
    • Round 1, an independent cloud review, approved 8707792d09 and raised two readings. The PR now treats 3.549(F)'s "SSI limit" as the limit SSI applies to each person, and it starts the (A)(2)(f) spillover from the client's own share of the $20.
    • Round 2 approved 3371fc5573 and proposed a case that pins the individual-rate limit on the Old Age Pension route. 96859129b5 adds that case, Case 12, which kills the mutant the review found.
    • hua7450 commented on October 20 and requested no changes.
  • Main merge and the overlap guard: main has moved 74 commits past the merge base 25c4253483. A local merge of this head with main cd0ab7bb37 matches git merge-tree's tree, and no file in it reads the removed co_oap_medicaid_enrolled. On that merge, one process each:
    • Colorado's ssa YAML tests (169 cases) and LEAP tests (58) pass;
    • so do test_co_and_cs_invariants.py (4), test_co_oap_invariants.py (2), test_ssi_state_supplement_couple_invariants.py (6) and test_ssi_state_supplement_medicaid_dependency.py (28);
    • so do the two code-health guards, test_source_conflicts.py (103) and test_no_group_variables_in_person_adds.py (10).
  • Gates checked live at merge:
    • gh pr checks exits 0;
    • the latest Pull request run at the head concluded success (41943988631, 36 of 36 jobs);
    • MERGEABLE;
    • not a draft;
    • no reviewer's latest review requests changes;
    • the semantic-overlap guard, with the combination verified at main cd0ab7bb37;
    • the merge pins the head.
  • Impact (default dataset, 2026, the head against main at the merge base 25c4253483): we estimate that AND-CS pays $0 on both sides, and that SNAP, taxes, benefits and household net income don't change. On main, all five eligible sample clients (47,618 weighted) have SSI plus countable income at the $994 standard. Two who work count $10 a month more under 3.549(A)(2)(c)(2), so their grant stays $0. The sample's two SSI couple members carry zero weight. The body's impact section has the table.
  • Follow-ups: Count Colorado's in-kind support and maintenance for AND-CS clients in another person's household #10183 builds on this branch and retargets to main once this lands. Limit SSI spousal-deeming child allocations to the couple's co-resident children #10146 and Apply 416.1163(e)(2) to deemed SSI and identify SSI couples by marriage, not tax roles #10141 overlap this PR's files, as the body's Overlap section describes.
  • Axiom: TheAxiomFoundation/rulespec-us#1716 and #1717 queued, each extended with a comment.

🤖 Generated with Claude Code

@MaxGhenis
MaxGhenis deleted the co-and-cs-payment-floor-3549 branch November 8, 2026 07:47
MaxGhenis added a commit that referenced this pull request Nov 8, 2026
#10161 landed on main as squash commit 082cb2e. This merge uses
#10161's final head, 9685912, as the base, so the tree equals main
plus this branch's own changes since that head.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis pushed a commit that referenced this pull request Nov 9, 2026
Main's Colorado AND-CS rules (#10161) found a client's spouse through
the marital unit. In a situation that omits marital units, that unit
holds every member, so a married client got the full $20 disregard
and a third adult's income was deemed as a spouse's.

The $20 disregard split (3.549(A)(2)(c)(1)) now reads
state_is_married, and spouse deeming (3.549(C)-(D)) reads
state_couple_total, as Old Age Pension does. Both keep a declared
spouse who lives apart and count only SSI's identified spouse in a
default unit. Case 42 covers a couple beside a claimed third adult.

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.

3 participants