Skip to content

Add Iowa state supplementation for 2026 - #8017

Merged
hua7450 merged 49 commits into
PolicyEngine:mainfrom
hua7450:ia-ssp
Oct 29, 2026
Merged

hua7450 merged 49 commits into
PolicyEngine:mainfrom
hua7450:ia-ssp

Conversation

@hua7450

@hua7450 hua7450 commented Apr 16, 2026 •

Copy link
Copy Markdown
Collaborator

What and why

Iowa's State Supplementary Assistance was missing from PolicyEngine-US. Add ia_ssa for 2026 under Iowa Code 249.3, 441 IAC 51.7, 52.1 and chapter 177, POMS SI 01415.058 F and the Iowa HHS Employees' Manual 6-B (revised May 22, 2026). It covers the blind, dependent-person, family-life home, residential care, in-home health-related care and Medicare-and-Medicaid (SMME) supplements.

Refs #7733.

  • Who administers and funds it (6-B p.6; Iowa Code 249.2): Iowa funds every supplement and reimburses SSA for the ones SSA pays.

    • SSA pays the blind supplement, and with Iowa certifying eligibility, the dependent-person and family-life home supplements. ia_ssa_federal computes these rows with the shared state supplement helper, then applies SSA's rounding and $1 minimum after splitting a couple's amount between its recipients.
    • Iowa pays residential care, in-home health-related care, SMME and the $20 family-life home top-up. These amounts aren't rounded.
  • 2026 levels:

    Supplement Paid by 2026 amount Source
    Blind SSA $22 a month for each blind recipient 441 IAC 52.1(4); 6-B p.20; POMS F.2 code A
    Dependent person SSA $518, once per recipient or couple. The total income limits are $1,512, $1,534 for a blind client, $2,009 for a couple, $2,031 for a blind client with an aged or disabled spouse, and $2,053 for two blind spouses 6-B pp.24, 26; POMS code C
    Family-life home SSA, plus $20 from Iowa Standard $1,156, which is the $994 SSI rate plus $162. SSA pays up to $142 (the $162 less SSI's $20 exclusion), or $801 for a couple. Iowa adds $20 when SSI is the recipient's only income 6-B pp.30, 34-35; POMS code D
    Residential care Iowa The $38.47 maximum daily rate, or a lower facility rate when one is entered, times covered days, less income above the $130 personal needs allowance (plus the SSI rate in a month of entry from home) 6-B pp.61-64, 72; 441 IAC 51.4(3), 52.1(3)
    In-home health-related care Iowa The approved cost, up to $480.55 per recipient, less income above the $994 home maintenance allowance ($1,491 with a spouse) and each SSI-ineligible child's $497 allowance, net of the child's income 6-B pp.41-44; 441 IAC 177.2(1)"f", 177.8(2)
    SMME Iowa $1 a month 441 IAC 52.1(7); 6-B p.78
  • Payment:

    • SSA-paid rows: the supplement less countable income above the federal benefit rate (FBR). A blind person also gets $22 alongside residential care or in-home care. 6-B pp.20 and 42 leave the $22 out of care participation, and POMS F.1 code A covers a blind recipient outside SSA's other Iowa variations. 441 IAC 52.1(4) reads otherwise (source conflicts below).
    • Residential care and in-home care: "client participation" uses SSI countable income without the $20 exclusion, plus the SSI payment (6-B pp.42, 59). Interest and dividends are excluded (20 CFR 416.1124(c)(22); Manual 8-E pp.23, 36). It's applied to the cost of care.
      • In-home care costing more than $480.55 makes the person ineligible (6-B p.41).
      • A first in-home month that is less than a full month has no participation and pays for the days of service (441 IAC 177.8(2)"b").
      • Residential care pays the covered days entered for a partial month (441 IAC 52.1(3)"b").
      • In the month a resident enters from home, income up to the SSI rate for one person, or for a couple when a spouse lived at home, isn't applied to the cost of care (441 IAC 52.1(3)"a"(6); 6-B pp.63-64). ia_ssa_care_initial_partial_month marks that month.
      • A resident and an eligible spouse are budgeted as a couple only in the month of entry, and only when either spouse received SSI or both enter that month (6-B pp.60-61; 441 IAC 51.4(3)). ia_ssa_rcf_couple_budget marks that month. From the next month, a married resident's care income is own income plus the SSI individual amount computed from it, as SSA then pays each spouse as an individual (6-B pp.61, 68-71), and the resident's resources are tested alone (6-B p.12).
    • Family-life home: SSA's amount, plus the $20 top-up when SSI is the only income (6-B p.35). Interest and dividends don't count as other income (20 CFR 416.1124(c)(22)). The couple's top-up is shared.
    • SMME: $1 when the coverage input is set, countable income is at least 120% of the poverty guideline, no SSA-paid supplement is paid, and SSI pays nothing (Iowa Code 249.3(4)(c), (g); 441 IAC 51.7(3), (6); 6-B pp.74, 76-77). An eligible couple's incomes are combined. The guideline is for two people when SMME income includes a spouse's income (a couple computation, SSI spousal deeming, or a spouse's income counted for an applicant working above the SGA level, as described next), and otherwise for one, since 8-E p.12 processes an applicant "as a one-person household" when SSI deems nothing. Iowa adopts each year's guideline on April 1 (441 IAC 75.1), so January-March use the prior year's. A disabled person working above the SGA level, whom SSI doesn't count, is budgeted on own income under SSI's income rules: the student earned income exclusion, in-kind support and maintenance, and the general and earned income exclusions. A spouse's income above $497, after allocations for ineligible children, is deemed to that person as 8-E pp.12-13 do, and the two-person guideline then applies. 8-E p.12 defines an ineligible spouse as one "not eligible for SSI or non-MAGI-related Medicaid, or State Supplementary Assistance". A spouse SSI treats as aged, blind or disabled isn't one, and neither is a disabled spouse working above the SGA level who has SMME coverage, which means full Medicaid under a group that does not rely on State Supplementary Assistance (6-B p.76), such as MEPD (8-F p.114) or 1619(b) (8-F p.88); SMME is itself State Supplementary Assistance. Such a spouse's income, after the spouse's own student earned income exclusion, is combined with no $497 test and no child allocations. The aged, blind or disabled spouse of an applicant working above the SGA level gets the same combined income and the two-person guideline in place of SSI's deeming from the worker, and that spouse's SSI payment isn't added. A spouse whom SSI still pays after deeming from the worker gets no SMME (Iowa Code 249.3(4)(c); Case 110). Nothing is deemed or combined when either spouse lives in a medical treatment facility, whoever pays, because that spouse isn't a household member (20 CFR 416.1167(a)(1)).
  • Who qualifies:

    Requirement Source How modeled
    Aged, blind or disabled under SSI definitions; for SMME, aged or disabled 6-B p.10; Iowa Code 249.3(4)(a) is_ssi_aged_blind_disabled in ia_ssa_nonfinancial_eligible, or is_ssi_aged or meets_ssi_disability_criteria for SMME, since SMME disability ignores substantial gainful activity (Iowa Code 249.3(4)(a)(2); 441 IAC 51.7(2); 6-B p.10)
    Receives SSI, or would except for excess income Iowa Code 249.3(2)(b), (3)(b); 6-B pp.6, 8 The categorical, resource and citizenship tests follow SSI. Payments use Iowa's budgets, so people over the SSI income limit can be paid
    Must apply for SSI "if they might be eligible" 6-B p.10 takes_up_ssi_if_eligible or uncapped_ssi <= 0. An applicant whose income would qualify for SSI must take it up; an applicant over income needn't
    U.S. citizen or qualified noncitizen 6-B pp.10-12 immigration_status or is_ssi_qualified_noncitizen
    Not an inmate 6-B p.8 ("all SSI eligibility criteria except for the income limit") is_incarcerated bars
    Resources of $2,000, or $3,000 for a couple living together, counting the spouse. A residential care resident is tested alone after the month of entry. A child adds parental resources above $2,000 for one parent or $3,000 for two; for an SSI recipient, Iowa accepts SSA's determination 6-B pp.9, 12, 60; 20 CFR 416.1202 The federal limits and ssi_countable_resources, plus ia_ssa_resources_deemed_from_parents. That variable uses main's _ssi_parental_resource_pool, so a co-resident stepparent's resources are deemed, and deems only to a child SSA would deem to (is_ssi_resource_deeming_child). ia_ssa_has_spouse identifies the spouse
    Certified dependent-person household, family-life home, residential care facility, in-home care plan or SMME coverage 6-B pp.24, 34, 41, 59, 76 ia_ssa_category input
    Lives in Iowa 6-B p.10; 441 IAC 51.6 defined_for = StateCode.IA
  • Children in in-home care (6-B pp.46-49; 441 IAC 177.2(1)"g"): the manual says "do not rely on SSI deeming calculations for children". ia_ssa_income_deemed_from_parents therefore deems parental income by the Iowa method:

    • Earnings only: less $65 and twice the parents' SSI allowance.
    • Earned and unearned: $65 and one-half of the remaining earnings, then the allowance.
    • Unearned only: less the allowance.
    • In every case, the result is also reduced by $497, less the sibling's own income, for each ineligible sibling.
    • The deemors are the co-resident parents and their spouses. A parent who receives SSI isn't one.
    • One-third of child support from an absent parent is excluded (6-B p.49).
  • Couples:

    • Blind spouses get $22 each.
    • The dependent-person supplement is paid once per couple, $259 each. Certifying either spouse applies the couple level.
    • A family-life home couple gets $801 plus a shared $20, $410.50 each.
    • In-home care counts the spouse's income, gives the $1,491 couple allowance "even if only one spouse receives in-home health-related care", and allows one $65 and one-half exclusion per household.
    • SMME compares an eligible couple's combined income, income that includes deemed spouse income, or the combined income of an applicant working above the SGA level and a spouse who isn't an ineligible spouse, with the two-person poverty guideline, and other income with the one-person guideline. Before April it uses the prior year's guideline.
    • Residential care couples are budgeted together only in the month of entry, as described under Payment.
    • Spouses are identified with SSI's spouse test (ia_ssa_has_spouse). Without explicit marital units, a parent isn't paired with an adult child the parent claims, and a default unit of three or more people budgets each member alone (Case 101).
  • COLA: 441 IAC 52.1 adjusts the assistance standards each January 1 for SSA's COLA but publishes no method.

    • The family-life home standard and couple amount follow the FBR: $1,191 and $818 in 2027.
    • So do the in-home home maintenance allowances.
    • The $130 personal needs allowance rises by the SSI COLA under Iowa Code 249.9A(1), to $135 in 2027. Rounding to the nearest dollar is inferred from General Letters 6-B-45 to 6-B-47 ($123, $126 and $130).
    • The $38.47 daily maximum is set through appropriations (Iowa Code 249.12(3)), so 2027 carries it as a frozen projection. The $518 dependent-person amount also stays at its 2026 value (parameter NOTEs). 2023-2025 use the published levels: $474, $490 and $503 dependent amounts, $35.89, $36.82 and $37.60 per diems, and $120, $123 and $126 allowances (the 2023 standards and General Letters 6-B-45 and 6-B-46).
    • The $22, $480.55 and $1 amounts are set in rule text.
  • Inputs: all are Person and monthly, and all default to 0, false or REGULAR.

    • ia_ssa_category records the certified arrangement. NONE excludes the person, including from the blind supplement.
    • ia_ssa_dependent_countable_income, ia_ssa_ihhrc_monthly_cost and ia_ssa_rcf_daily_rate carry forward until changed. ia_ssa_rcf_daily_rate is only for a facility rate below the maximum; 0 pays the maximum.
    • ia_ssa_smme_coverage_eligible is full Medicaid without a spenddown or premium, plus Medicare Part B. For a disabled person working above the SGA level, it also means the person isn't an ineligible spouse (8-E p.12), so it changes the other spouse's SMME budget.
    • ia_ssa_care_partial_month_days (0 is a full month), ia_ssa_care_initial_partial_month (a first in-home month, or the month of entry to residential care from home) and ia_ssa_care_additional_deductions are one-month entries. They have zero formulas, so an entry stays in its month.
    • Impairment-related work expenses for residential care are entered in ia_ssa_care_additional_deductions at one-half for a resident without SSI, because that input is subtracted after the one-half earnings exclusion (441 IAC 52.1(3)"a"(1)). An SSI recipient enters none, because SSA's payment already offsets them (6-B p.59). A deduction a couple shares is entered on one spouse.
    • Entering partial days for one resident leaves another resident's full month unchanged (Cases 32 and 33).
  • Source conflicts: where the sources disagree, the model follows the manual, except for the residential care entry month, where it follows the rule. For SMME income, SMME for a blind person under 65 and the residential care rate, it follows the Iowa Code, and for a married student's earned income exclusion in SMME income it follows 42 U.S.C. 1382a(b)(1) and 20 CFR 416.1112(c)(3), under PolicyEngine-US's statute-first rule (CONTRIBUTING.md, "Source conflicts", merged with Tie source-conflict markers to the register shared with Axiom #10287). All four are listed in source_conflicts/candidates.yaml (us-ia:smme-income-at-least-120-percent, us-ia:smme-blind-under-65, us-ia:rcf-maximum-per-diem-rate, us-ia:smme-student-exclusion-married) until they are registered. For a dependent's income of exactly $518 and the in-home dependent allowance, the rule agrees with the reading taken. The in-home cost ceiling is no longer a conflict. The rulespec-us issue's conflicts comment quotes each side.

    • The blind dependent-person couple: the manual's $2,031 (a $540 supplement) is used, not POMS's $2,053 for Aged/Blind (code NOTE).
    • The in-home cost ceiling (resolved): the manual makes care costing more than $480.55 ineligible, and 441 IAC 177.9(4) agrees: it ends in-home care when "the cost of care exceeds the maximum" (its cross-reference to 177.9(3) should read 177.8(3)). The IAC 2/5/25 edition has the same rule at 177.11(4), so this holds before and after ARC 0460D (effective October 1, 2026).
    • All-earned parental income: the manual deducts $65; 177.2(1)"g"(1) doesn't.
    • SMME income: 441 IAC 51.7(6) and the manual require income that "exceeds" 120% of the poverty guideline, where Iowa Code 249.3(4)(g) says "at least". The model follows the statute: Case 44 (exactly 120%) pays 1, and Case 45 (one cent below) pays 0 (code NOTE).
    • A dependent's income of exactly $518: 6-B p.24 excludes only income "more than $518", while p.25 and 441 IAC 51.5(1) require "less than".
    • The residential care rate: 441 IAC 52.1(3) says payment "will be based on the maximum per diem rate" from July 1, 2017, and 51.4(3) tests income against "31 times the maximum per diem rate". Iowa Code 249.12(3) reimburses privately operated facilities "based on the maximum per diem rates established by the general assembly". 6-B p.72 still describes "two options": a facility rate up to $38.47, or a flat $17.86. The model follows the statute and the rule, and pays the $38.47 maximum unless a lower facility rate is entered (code NOTE).
    • The blind $22 with a care supplement: 441 IAC 52.1(4) sets $22 for "a blind recipient not receiving another type of state supplementary assistance". 6-B p.20 treats the blind supplement as received "simultaneously" with the residential care supplement, p.42 leaves it out of in-home participation, and POMS F.1 code A excludes only SSA's own Iowa variations. The model follows the manual and POMS (code NOTE).
    • The residential care entry month: 441 IAC 52.1(3)"a"(6) and 6-B pp.63-64 deduct the SSI rate for one person, or for a couple when a spouse lived at home. Later on p.64, the manual lets clients "keep enough of the first month's income to meet maintenance or living expenses from the previous living arrangement", up to the SSI standard. The model deducts the fixed SSI rate (code NOTE).
    • SMME for a blind person under 65: Iowa Code 249.3(4)(a) names a person "Sixty-five years of age or older" or "Disabled as defined by 42 U.S.C. §1382c(a)(3)". 441 IAC 51.7(2) requires "all eligibility requirements for supplemental security income benefits other than limits on substantial gainful activity and income", and 6-B pp.10 and 76 include blindness. The model follows the statute, so Case 72, a blind 50-year-old who isn't disabled, pays 0, and Case 76, a blind 50-year-old who is disabled, pays 1 (code NOTE).
    • The in-home sibling allowance in child deeming: 441 IAC 177.2(1)"g"(1)2 allows "The amount of the basic SSI standard for a dependent for each ineligible child in the home". 6-B pp.47-49 allow a "maximum of $497 per child" and say "Subtract any income of the dependent from the maximum deduction". The model follows the manual (code NOTE).
    • The in-home dependent allowance: the 6-B p.42 bullet gives the couple allowance "if there is a spouse living with the client or a dependent living with an eligible person". 441 IAC 177.2(1)"f"(3) applies "Any income of the dependent ... to the dependent's needs before making this disregard", and p.43 says "Subtract a dependent's income". The model follows the rule and p.43 (code NOTE).
    • A married student's earned income exclusion in SMME income: 42 U.S.C. 1382a(b)(1) excludes a student's earnings "if such individual is under the age of 22 and is ... a student regularly attending a school, college, or university", and 20 CFR 416.1112(c)(3) also has no marital or head-of-household test. 8-E p.19 says the student "must meet all of the following criteria", including "Not married" and "Not the head of the household". The model follows the statute and the regulation for the applicant and for a spouse whose income is combined. In Case 106, $810.83 of a disabled student spouse's $1,200 of monthly wages is excluded, and the couple's combined SMME income of $1,790.58 is below the two-person $2,164, so the applicant gets $0; without the exclusion, $2,196 would pay $1 (code NOTE).

The supplement is added to household_state_benefits (all four year blocks, under a new # Iowa benefits comment) and to spm_unit_benefits. SNAP and HUD count it through ia_ssa_countable_for_snap and ia_ssa_countable_for_hud, which leave out the in-home care payment:

  • Iowa's SNAP manual 7-E says "Exclude State Supplementary Assistance payments made for in-home health-related care as a reimbursement" (7 CFR 273.9(c)(5)).
  • HUD excludes it under 24 CFR 5.609(b)(6) and (b)(19).
  • The blind, dependent-person and family-life home amounts paid alongside it stay countable.

Iowa LIHEAP counts the whole ia_ssa as unearned and fixed income (LIHEAP FY26 manual Appendix C p.114), including the in-home care payment.

Files:

policyengine_us/parameters/gov/states/ia/hhs/ssa/              blind_amount, dependent_amount, excluded_unearned_sources, family_life_supplement,
                                                               fpg_year_start_month, ihhrc_cost_limit, rcf_daily_limit, rcf_personal_needs, smme_amount,
                                                               smme_minimum_fpg_rate
policyengine_us/variables/gov/states/ia/hhs/ssa/               ia_ssa, ia_ssa_eligible, ia_ssa_nonfinancial_eligible, ia_ssa_federal,
                                                               ia_ssa_care_countable_income, ia_ssa_rcf_couple_budget, ia_ssa_has_spouse,
                                                               ia_ssa_income_deemed_from_parents,
                                                               ia_ssa_resources_deemed_from_parents, ia_ssa_ihhrc_participation,
                                                               ia_ssa_ihhrc_amount, ia_ssa_smme_countable_income, ia_ssa_smme_spousal_deeming_applies,
                                                               ia_ssa_countable_for_snap, ia_ssa_countable_for_hud, and the eight inputs above;
                                                               the SMME spouse helper module _ia_ssa_smme_spouse_income
policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/   ia_ssa, integration, ia_ssa_resources_deemed_from_parents,
                                                               ia_ssa_nonfinancial_eligible, ia_ssa_income_deemed_from_parents

Shared files:

  • household_state_benefits.yaml gains one Iowa entry per year block.
  • SNAP and HUD income/sources/unearned.yaml and spm_unit_benefits.py each gain one Iowa entry.
  • Iowa LIHEAP income/sources/unearned.yaml and fixed.yaml each gain ia_ssa, the two LIHEAP income variables' descriptions name it, and the Iowa LIHEAP integration.yaml gains Case 9.
  • The programs.yaml Iowa entry changes from in_progress to partial.
  • source_conflicts/candidates.yaml gains four statute-conflict entries: the two SMME entries, the residential care per diem (2023-2026) and a married student's earned income exclusion in SMME income.
  • Federal parameter: gov/ssa/ssi/income/exclusions/child_support_share.yaml, the one-third exclusion of 20 CFR 416.1124(c)(11), came to main with Add Oklahoma state supplementation for 2026 #10165. This PR leaves it as on main.
  • Parental resource and income deeming import main's _ssi_parental_resource_pool, and ia_ssa_has_spouse imports SSI's _ssi_spouse_index. The shared state supplement helper and minimum_payment.yaml are unchanged.

References

Additional section and page citations are included alongside the parameters and formulas.

Coverage limits

The registry marks Iowa as partial, verified for 2026. The levels were checked against the May 22, 2026 manual pages, 441 IAC 52.1 and POMS SI 01415.058 F.2 in October 2026.

Not modeled:

  • the mandatory minimum-income-level supplement for December 1973 recipients and their essential persons (441 IAC 52.1(6); Iowa Code 249.3(1)), and conditional benefits;
  • continued dependent-person and family-life home payments for up to three months of temporary institutionalization (6-B p.11). A resident of a medical treatment facility gets no SSA-paid supplement;
  • for an SMME applicant working above the SGA level (code NOTEs):
    • income deemed from a parent;
    • either spouse's intent to return from a medical facility, and a stay for part of a month. The facility input is read as the whole month, while 8-E p.11 deems for a month in which the applicant lived "for any part of a month in the same household" with the spouse;
    • a spouse in residential care after the month of entry, who is still treated as a household member;
    • when the couple's income is combined, the spouse's in-kind support and maintenance and the couple's presumed maximum value;
    • a spouse's eligibility for SSI, non-MAGI-related Medicaid or State Supplementary Assistance beyond SSI's aged, blind or disabled status and the SMME coverage input. An aged, blind or disabled spouse who qualifies for none of them is combined rather than deemed, and a disabled spouse working above the SGA level who has another non-MAGI-related Medicaid group, such as MEPD, but no SMME coverage is deemed rather than combined;
  • first-month spouse deeming in residential care, Medicaid-category deductions for SMME and state-only sibling eligibility (variable documentation);
  • the unmet medical needs of parents and ineligible children in in-home child deeming (code NOTE). The recipient's own deductions can be entered through ia_ssa_care_additional_deductions.
  • the dependent's own resources (441 IAC 51.5(2)), which the DEPENDENT_PERSON certification covers;
  • the joint budget of a couple in the residential care entry month (6-B p.70, Mr. W). The model splits an eligible couple's care income and the couple rate equally between the spouses; a dependent's allowance can be entered through ia_ssa_care_additional_deductions;
  • a spouse who enters residential care after the other spouse's month of entry. That spouse deducts the SSI couple rate in the entry month, and gets the couple budget when either spouse received SSI, while the spouse already in the facility stays on the individual budget. 441 IAC 51.4(3) and 6-B p.61 address spouses who enter together, and 52.1(3)"a"(6) gives the couple rate for a spouse living in the home, so the sources don't settle this case;
  • after the month of entry, the spouse at home is still tested with the resident's resources, because federal SSI keeps the couple (code NOTE);
  • an RCF child under 16, who needs written approval (6-B p.55), and the reserve bed-day limits of 30 visitation days a year and 20 hospital days a month (441 IAC 52.1(3)"e"-"f"). The covered-days input takes the authorized days;
  • the dependent-person rule that income based on need gets no $20 disregard (6-B p.26);
  • SMME couple resources by Medicaid group. The model uses SSI's spouse rule.

When one of two co-resident parents receives SSI, the in-home child deeming keeps the two-parent allowance. The Iowa sources don't address this case; SSI's parental allocation counts only ineligible parents. The model applies SSI's $65 and one-half exclusions to an in-home care child's own earnings; whether 441 IAC 177 allows them wasn't verified.

Microsimulation and model limits:

The dependent amount, the residential care per diem and the personal needs allowance carry 2023-2025 values from the 2023 standards and General Letters 6-B-45 and 6-B-46 (Cases 86 and 93). Other earlier-year values use parameter backfilling and are unverified historical estimates; no historical coverage is claimed.

Related:

Interactions with open federal PRs

  • Fix SSI interest and dividend exclusions #10382 makes SSI exclude interest and dividends. When it merges, delete excluded_unearned_sources.yaml and its two uses, in ia_ssa_care_countable_income.py and ia_ssa.py, or Iowa excludes them twice. Case 109 catches this: a residential care resident with $1,100 of Social Security and $50 of dividends gets $222.57, and a double exclusion gives $272.57.
  • Apply 416.1163(e)(2) to deemed SSI and identify SSI couples by marriage, not tax roles #10141 caps SSI with spousal deeming at the amount without deeming (20 CFR 416.1163(e)(2)), which lowers the June SSI in Case 73 from 6-B p.67's $843.50 to $814. Case 73 no longer pins that amount: it asserts is_ssi_spousal_deeming_applies, and its ia_ssa values are the same under either amount.
  • Limit SSI spousal-deeming child allocations to the couple's co-resident children #10146 adds monthly SSI variables and limits child allocations to the couple's co-resident children. Iowa's reads of annual SSI variables should then move to them: is_ssi_spousal_deeming_applies in ia_ssa.py, ssi_countable_income in ia_ssa_smme_countable_income.py and ia_ssa_federal.py, and the tax-unit sums of ssi_ineligible_child_allocation in _ia_ssa_smme_spouse_income.py and ia_ssa_ihhrc_participation.py, which would use the couple-scoped allocations.

Test plan

  • 139 Iowa supplement YAML cases (110 in ia_ssa.yaml, 12 in integration.yaml, 7 in ia_ssa_resources_deemed_from_parents.yaml, 6 in ia_ssa_nonfinancial_eligible.yaml, 4 in ia_ssa_income_deemed_from_parents.yaml) pass locally in one policyengine-core run on this branch merged with main at 8ea4342 (2da0ed3). They cover:
    • each supplement and its boundaries:
      • dependent income at the $518 limit, and group income one cent below, at and over the standard;
      • the family-life home top-up with SSI only, with interest only, with $10 of other income and with earnings, plus SSA's amount without federal SSI;
      • residential care in 31- and 28-day months, the rate cap, the maximum rate when no facility rate is entered, a lower facility rate, participation equal to the month's cost, deductions, impairment-related work expenses for a resident without SSI, the month of entry from home (alone or with a spouse), negative self-employment income, and interest and dividends, which care income excludes (Cases 74 and 109);
      • in-home care at and one cent above $480.55, the manual's Ms. A and Mr. B examples, its working-spouse household with two children (the $497 child allowance) and the first partial month;
      • SMME at, and one cent below, 120% of the poverty guideline in April and, with the prior year's guideline, in January, and the prior year's guideline still in March (Case 89), and couples whose combined income is well above, $2 above (with one spouse covered) or $2 below the two-person guideline, and a blind applicant under 65 who isn't disabled and one who is, a disabled applicant working above the SGA level (Case 77), with the student earned income exclusion (Case 87) and outside shelter support (Case 88), and the one-person guideline for a spouse in a medical facility and a spouse whose $497 pension SSI doesn't deem, against the two-person guideline for a $498 pension that it does (Cases 81, 83 and 84), and spouse income deemed to an SGA worker above and below the two-person guideline, with a $497 pension control (Cases 82 and 90-92), a child's allocation taken from the spouse's pension first (Case 94), a deemed $497.01 pension (Case 95), a spouse in a medical facility (Case 96) and an aged spouse whose income is combined (Case 97);
      • for an SMME applicant working above the SGA level: an aged spouse with a child, combined with no child allocation, who gets the same combined income (Case 98); the applicant in a privately paid medical facility (Case 99); an aged spouse who is also an SMME applicant, and two applicants working above the SGA level, each budgeted as an eligible couple with no child allocations (Cases 102 and 103); the aged spouse's $279 SSI payment left out of the combined income (Case 104); the two-person guideline for an aged spouse to whom SSI deems nothing, with wages of $1,900 (Case 105); a disabled student spouse's earned income exclusion (Case 106); and an undocumented, disabled spouse working above the SGA level without SMME coverage, who is an ineligible spouse, so child allocations come off that spouse's wages before deeming, to the applicant (Case 107) or, through SSI, to an aged applicant (Case 108);
      • an applicant SSI counts as disabled, for whom SSI's own deeming sets the two-person guideline (Case 100);
      • an aged spouse whom SSI pays $29 after deeming from an applicant working above the SGA level, who gets no SMME although the combined income reaches the two-person guideline (Case 110). The SMME boundary cases (22-24, 44, 45, 78, 79 and 89) give the person Social Security, so SSI pays nothing;
    • the blind supplement alongside care, its absence in a medical facility, SSA's rounding up to the cent and $1 minimum, and SMME not stacking with it;
    • resources, including the $3,000 couple limit for an in-home recipient with an ineligible spouse, parental deeming with a co-resident stepparent, the manual's Child A example, a blind SSI child exempt from parental deeming, and the sibling allocation;
    • the manual's four parental income deeming examples and its child support example;
    • the age 65 boundary, incarceration, immigration status, no category, another state, declining SSI, and over-income applicants who need not take up SSI;
    • partial days entered for one resident (an in-home first month and a residential care discharge month), and one-month entries that don't carry into the next month;
    • couples: blind, dependent-person (including one spouse certified), the mixed blind dependent-person couple, family-life home, and in-home care with an ineligible spouse and one earnings exclusion;
    • residential care couples in and after the month of entry: the manual's Mr. K, Mr. B and Mr. A examples, spouses sharing a room, spouses entering together, a resident's resources tested alone, and resources pooled in the month of entry (Case 85);
    • situations without marital units: an in-home care parent with a claimed adult child, parental resources deemed to an in-home care child, and an SMME applicant among three adults, budgeted alone (Case 101);
    • 2027 SSI rates with the FBR-linked family-life home standard and couple amount, and the personal needs allowance raised by the COLA, and 2024 and 2025 residential care at General Letters 6-B-45's and 6-B-46's levels (Cases 93 and 86);
    • the annual SNAP, HUD, household_state_benefits and spm_unit_benefits totals, with the in-home payment left out of SNAP and HUD income.
  • Consolidation: 12 cases were removed because each repeated a kept case's branch and outcome. By their numbers at the previous head (3b9e925), with the kept case: 2 (integration Case 8), 3 (67), 4 (4), 11 (64), 14 (14 and 33), 21 (32 and 16), 25 (35), 26 (32 and 34), 27 (integration Case 9), 30 (ia_ssa_nonfinancial_eligible.yaml Case 6), 32 (44) and 36 (26). Two cases now pin the operators. Case 45 has SMME income of 1,595.99, one cent below 120%, and pays 0, so with Case 44 (exactly 1,596, which pays 1) it brackets the statute's "at least". Case 71 has group income of exactly $1,512 (Social Security of $17,904 a year and $40 of dependent income), so it pays 0 under "less than" and would pay 40 under "not more than".
  • Mutation check: removing any of the new spouse terms fails at least one new case. The terms are the two-person guideline for the aged, blind or disabled spouse of an applicant working above the SGA level, the spouse's student earned income exclusion, the SMME coverage test in each of the two spouse-status helpers, that spouse's combined-income override, and the gate that skips child allocations for a spouse who isn't an ineligible spouse. Adding the spouse's SSI payment to the combined income also fails a new case (Case 104). Removing the SSI condition fails Case 110, and removing ia_ssa from either Iowa LIHEAP list fails LIHEAP integration Case 9.
  • Local probes:
    • In one simulation with Iowa, Massachusetts, North Carolina and Virginia residents, only the Iowa residents get ia_ssa, and each household_net_income matches its single-state control.
    • An input entered for one person leaves the other person at their control value.
  • 165 Iowa LIHEAP YAML cases pass locally on the same tree, including the new integration Case 9.
  • test_source_conflicts.py and the program registry tests pass locally on the merged tree (891 passed, 10 skipped).
  • ruff format, ruff check and git diff --check.
  • The code-health tests for parameters, references, YAML and source conflicts pass locally on the merged tree (403 passed, 1 skipped), except two test_selective_test_batches cases that need the coverage module the local environment lacks; test_no_group_variables_in_person_adds.py needs hypothesis and wasn't run. They involve no Iowa file, and CI has the modules.
  • Changelog fragment in changelog.d/.
  • CI passes.

axiom: Iowa Code 249.3, 249.9A(1), 249.12(3); 441 IAC 51.4(3), 51.5(1)-(2), 51.7(2), 51.7(6), 52.1(1)-(4), 52.1(7), 75.1, 177.2(1)"f"-"g", 177.8(2), 177.9(4), and 177.4(1), 177.10(2) (IAC 2/5/25); 20 CFR 416.1112(c)(3), 416.1124(c)(22), 416.1163, 416.1167; Iowa HHS Employees' Manual 6-B, 7-E, 8-E, 8-F; POMS SI 01415.058 F TheAxiomFoundation/rulespec-us#1837 queued; Iowa LIHEAP FY26 manual Appendix C p.114 (State Supplementary Assistance as income) TheAxiomFoundation/rulespec-us#1834 queued

hua7450 added 2 commits April 16, 2026 12:59
Adds Iowa SSA (Iowa Code Ch 249; IAC 441 Chs 50-52, 54, 177) covering:
- Blind supplement (flat $22/month)
- Dependent Person (DP) supplement (5 household configurations)
- Family-Life Home (FLH) supplement (max $142/month)
- In-Home Health-Related Care (IHHRC) supplement (cost-based, max $480.55/$961.10)
- Residential Care Facility (RCF) supplement (cost-related per diem)
- Supplement for Medicare and Medicaid Eligibles (SMME) (flat $1/month)

Closes PolicyEngine#7733
@codecov

codecov Bot commented Apr 16, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.16%. Comparing base (cc5bd64) to head (4a12735).
⚠️ Report is 3278 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff             @@
##             main    #8017       +/-   ##
===========================================
+ Coverage   71.72%   98.16%   +26.44%     
===========================================
  Files        4658       16     -4642     
  Lines       67710      327    -67383     
  Branches      341        2      -339     
===========================================
- Hits        48563      321    -48242     
+ Misses      19140        6    -19134     
+ Partials        7        0        -7     
Flag Coverage Δ
unittests 98.16% <100.00%> (+26.44%) ⬆️

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

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

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

hua7450 and others added 14 commits April 17, 2026 16:32
- Verified $3,031 DP BLIND_WITH_AGED configuration against Iowa HHS; replaced typo comment with verification note
- Fixed 4 broken PDF page anchors (blind.yaml, SMME + DP docstrings)
- Added formulas to ia_ssa_has_full_medicaid / ia_ssa_has_medicare_part_b delegating to federal medicaid_enrolled / medicare_enrolled, making SMME reachable in microsim
- Added IAC 441-177.4(1)(c) own-home eligibility check to IHHRC category
- Extracted ia_ssa_ihhrc_both_need_care variable; removed hard-coded 2 duplicated in two files
- Reworked 5 non-functional ineligible tests to exercise ia_ssa_resources_eligible via ssi_countable_resources
- Added ia_ssa_resources_eligible.yaml with boundary coverage (single/couple x below/at/above)
- Added couple IHHRC test cases (at cap, above cap, one-spouse fallback)
- Expanded category priority from 4 to 11 cases (IHHRC/DP/BLIND/SMME pairings)
- Locked in blind combinability: blind RCF resident -> $0 blind supplement
- Documented IAC 441-52.1(4) mutual exclusivity in ia_ssa_blind_supplement docstring
- Consolidated test files to one-per-variable: merged integration_* and test_2025_to_2026_transition cases into variable-specific files with ssi + ia_ssa outputs side-by-side

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prior formulas used `max(0, -uncapped_ssi) + ssi` as a proxy for total
monthly income. That expression equals `|FBR − countable_income|`, not
actual income, which caused material errors:

- RCF eligibility and client participation understated income for anyone
  with outside income below the FBR, overpaying the supplement by hundreds
  and classifying high-income residents as eligible.
- IHHRC cap (IAC 441—177.4(1)(f)) was compared against excess-over-FBR
  instead of monthly countable income, letting recipients with countable
  income far above the $480.55 cap qualify whenever they were below the FBR.
- DP and FLH phase-out (federally-administered per POMS SI 01415.050.F) did
  not use the federal SSP formula, paying the full cap in income bands where
  the supplement should phase down dollar-for-dollar.

Fixes:
- RCF and IHHRC (state-administered) use monthly SSI countable income +
  federal SSI payment as total income, matching IAC 441—52.1 rules.
- DP and FLH (federally-administered) use
  `max(0, total_standard − max(countable, FBR))`, matching POMS SSP rules.
- Delete unused flh.personal_needs_allowance parameter (dead code — FLH
  assistance standard is a lumped sum that already includes the allowance).
- Add regression tests for each bug.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…into ia-ssp

# Conflicts:
#	policyengine_us/parameters/gov/household/household_state_benefits.yaml
#	policyengine_us/variables/household/income/spm_unit/spm_unit_benefits.py
- Add IAC 441—51.7(6) 120% FPL income floor for SMME eligibility
- Restructure smme.yaml to smme/ folder (amount.yaml + minimum_income_fpl_multiplier.yaml)
- Remove documentation= field from 3 variables (not PolicyEngine convention)
- Fix days_multiplier.yaml description wording
- Update programs.yaml: Iowa SSA status in_progress -> complete, add variable=ia_ssa
- Rewrite tests with realistic income inputs (age, social_security_retirement) instead of bypass inputs (is_ssi_eligible, meets_ssi_resource_test, is_ssi_aged_blind_disabled); verify full federal-state chain
- Add boundary and negative cases (SMME 120% FPL boundary, IHHRC countable income cap, FLH phase-down)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
IHHRC (IAC 441—177.10(3) and 441—177.4(1)(f)):
- Maximum benefit payable is $480.55 per person, always — not $961.10
  per person when both need care. The $961.10 is the combined couple
  INCOME cap in 441—177.4(1)(f), not a payment cap.
- Income eligibility now compares combined marital-unit countable
  income against $961.10 when both spouses need care, and individual
  countable income against $480.55 otherwise.
- Updated parameter descriptions and tests; dropped the now-irrelevant
  441—52.1(5) reference on max_cost_couple (that subsection defers to
  Chapter 177, which sets the per-person payment cap at $480.55).

Blind (IAC 441—52.1(4)):
- Applied federally-administered SSP V-shape formula (like DP/FLH):
  max(0, FBR + state_standard - max(countable, FBR)). A blind recipient
  with countable income above $989 now correctly phases to $0 instead
  of receiving a flat $22 regardless of income.

Medicare Part B (IAC 441—51.7(4)):
- Documented that PolicyEngine's medicare_enrolled does not distinguish
  Part A from Part B. SMME statutorily requires Part B; using
  medicare_enrolled as the closest proxy, acknowledging Part A-only
  enrollees are not filtered out.

RCF eligibility PNA check reviewed and confirmed correct per statute:
441—51.4(3) compares "income according to 441—paragraph 52.1(3)(a)"
which already incorporates the PNA as disregard (2) before the
31 × max_per_diem threshold test. No change needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Blind (IAC 441—52.1(4)):
- Added income gate to BLIND category assignment that matches the
  federally-administered V-shape ceiling (FBR + state standard = $989).
  A blind person whose countable income exceeds $989 now falls through
  to the next applicable category (e.g., SMME if income is also above
  120% FPL) rather than being labeled BLIND with a $0 supplement.

Medicare Part B (IAC 441—51.7(4)):
- Converted ia_ssa_has_medicare_part_b to a pure input variable with
  default False. Previously the formula defaulted to medicare_enrolled
  (Part A and/or B), which pulled Part A-only enrollees into SMME.
  SMME is a $1/month program for a narrow dual-eligible population; a
  False default with explicit opt-in matches both the statutory
  requirement ("currently eligible for Medicare Part B") and the real
  caseload better than an overbroad proxy.

RCF eligibility PNA check re-verified: IAC 441—51.4(3) references "the
income according to 441—paragraph 52.1(3)(a)," and 52.1(3)(a) defines
"Income applied to meet the cost of care" as (countable + SSI benefit)
minus five disregards including the PNA (disregard 2). The current
code applies the PNA as the statute directs. No change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
IAC 441—51.4(3) compares "the income according to 441—paragraph
52.1(3)(a)" against 31 × max_per_diem. Section 52.1(3)(a) describes
two concepts: the gross income input (SSI countable + SSI benefit)
and the post-disregard "Income applied to meet the cost of care"
(client participation). The statute is textually ambiguous as to
which "the income" refers to, but:

- 31 × max_per_diem is approximately the monthly cost of RCF care at
  the maximum per-diem rate. Comparing gross monthly income against
  that cost is the meaningful substantive test — it excludes people
  who could afford care on their own income.

- Standard benefit-program convention uses gross income for
  eligibility tests, with disregards (including personal needs
  allowances) applied in the benefit amount calculation.

- Under the post-disregard reading, the test barely screens anyone
  out: income must exceed ~$1,292 (threshold + PNA + other
  disregards) to be ineligible at the 2025 per-diem rate, so the
  eligibility gate had almost no substantive effect.

Switched ia_ssa_category.py to compare total_rcf_income (pre-PNA)
against 31 × max_per_diem. The PNA remains in ia_ssa_rcf_supplement
where it belongs: reducing client participation in the payment
calculation.

Cross-verified against SSA POMS SI 01415.050.F: RCF is state-
administered by Iowa HHS, so this is a state policy interpretation,
not a federal SSP formula question.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prior "2017-07-01" effective date was incorrect — those values were
copied from Iowa HHS's current web page (which shows 2025 values) and
backdated to 2017 without historical verification. Replaced with
properly sourced historical tiers:

- **2011-01-01**: SSA State Assistance Programs for SSI Recipients —
  Iowa (January 2011), Table 1. Provides frozen values ($22 blind, $142
  FLH aged max supplement, $480.55 / $961.10 IHHRC) and 2011 baselines
  for COLA-adjusted parameters.

- **2017-01-01**: Iowa Administrative Code 01-04-2017 supplement.
  Provides 441—52.1 dollar amounts (FLH $897, DP $1,114/$1,482/$1,136/
  $1,504/$1,526, RCF per diem $30.11, PNA $100) and 441—51.4(1)
  dependent-relative income limit $379.

- **2018-01-01**: Iowa Administrative Code 03-28-2018 rule update for
  441—52.1. Provides 2018 COLA values (FLH $912, DP $1,137/$1,512/
  $1,159/$1,534/$1,556, RCF per diem $30.60, PNA $99).

- **2025-01-01**: Iowa HHS General Letter 6-B-46 (effective January 1,
  2025). Corresponds to the values previously misdated 2017-07-01.
  Preserves test expectations at 2025-01 period.

- **2026-01-01**: Iowa HHS current State Supplementary Assistance
  Standards web page (unchanged).

SMME parameters (amount $1, 120% FPL multiplier) start at 2017-01-01 —
the program existed since October 1, 2003 but the SSA 2011 report does
not publish the $1 amount directly, so we cite only what we can verify.

DP dependent_income_limit and max_per_person_cap start at 2017-01-01
because the SSA 2011 report does not publish these specific Iowa-only
concepts; the 2017 IAC supplement is the earliest direct source.

All 73 Iowa SSA tests continue to pass at 2025-01 and 2026-01 periods.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- RCF income gate now compares post-PNA client participation against
  31 x max_per_diem per IAC 441-51.3(3) cross-ref to 52.1(3)"a"
- IHHRC income gate applies the SSI FBR disregard and checks combined
  marital-unit countable against the applicable cap symmetrically
- IHHRC payment subtracts client participation per IAC 441-177.10(2)(a),
  split evenly across marital-unit members
- DP dependent-income-eligible check moved into ia_ssa_category so a
  person with a disqualifying dependent falls through to BLIND / SMME
  instead of receiving a zero DP supplement
- Resource test sums marital-unit resources for joint SSI claims
- ia_ssa_has_full_medicaid converted to an explicit input with
  default_value=False, matching ia_ssa_has_medicare_part_b, so Medicaid
  pathways outside "full Medicaid" (spenddown, MEPD premium) do not
  trigger SMME
- Fix citation typos: SMME minimum_income_fpl_multiplier cites
  441-51.6(6); RCF days_multiplier cites 441-51.3(3) with unit /1 and
  period eternity
- Strengthen 2026 DP BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT
  comment documenting the +53.5% jump vs 2.85% COLA anomaly
- Add 2017 DP and 2018 RCF historical test cases; add DP fallthrough
  category test; update IHHRC and resources tests for new rules; remove
  obsolete sources/working_references.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…into ia-ssp

# Conflicts:
#	policyengine_us/parameters/gov/household/household_state_benefits.yaml
Replace the six supplement variables (ia_ssa_blind_supplement,
ia_ssa_dp_supplement, ia_ssa_flh_supplement, ia_ssa_ihhrc_supplement,
ia_ssa_rcf_supplement, ia_ssa_smme_supplement) with a single
payment formula in ia_ssa that selects over ia_ssa_living_arrangement.

Rename ia_ssa_category -> ia_ssa_living_arrangement (enum and variable)
to match the reality of what the enum represents.

Helper variables that represent genuine inputs (residency flags,
cost-of-care, DP configuration, Medicaid/Part B flags, SMME eligibility,
both-need-care) remain unchanged.

Tests reorganized:
- ia_ssa_living_arrangement.yaml holds routing/priority tests
- ia_ssa.yaml consolidates the six per-category payment tests with
  outputs renamed to ia_ssa; one BLIND-in-RCF case updated to assert
  the routed RCF payment rather than the zero blind value.

All 77 Iowa SSA YAML tests pass; microsim unaffected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Parameter normalization:
- Rename dp/assistance_standard.yaml -> dp/state_supplement.yaml
- Rename flh/assistance_standard.yaml -> flh/state_supplement.yaml
- Values are now the state portion above FBR (consistent with blind.yaml),
  so all three federally-administered arrangements use one formula shape:
  max(0, (FBR + state_supplement) - max(countable, FBR)).

P2 #1 — FLH Department top-up for SSI-only recipients:
  The Iowa FLH state supplement ($162 from 2017 onward) exceeds the
  federally-administered max_supplement cap ($142) by exactly $20, the SSI
  general-income disregard. Per IAC 441-52.1(1), when the recipient has
  no other income (so SSA's $20 disregard is unused), Iowa HHS issues an
  additional Department payment equal to (state_supplement - max_supplement)
  to close the gap and bring total income to the full standard. In 2011
  the state supplement equals the cap so no top-up is owed; from 2017
  onward the top-up is $20.

P2 #2 — IHHRC client participation charged to sole recipient:
  When only one spouse needs IHHRC, charge the entire combined client
  participation to that spouse instead of splitting it evenly across the
  marital unit. The split remains correct for both-need-care couples
  where both members compute the supplement independently.

Tests:
- FLH Cases 1 and 4 (zero-income) now expect $162 (was $142)
- New IHHRC Case 12 exercises the sole-recipient participation rule:
  couple with $800/mo SS each, one needs care -> supplement $270 instead
  of $335 under the old 50/50 split.

77 + 1 = 78 Iowa SSA tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hua7450
hua7450 marked this pull request as ready for review April 23, 2026 04:45
Address three P2 review items:

1. 2026 DP BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT: Iowa HHS's
   published $3,031 breaks the "-$22 when only one spouse is blind"
   footnote rule that's held for 2011/2017/2018/2025 and inflates the
   phase-down ceiling so high-income 2026 cases still receive DP when
   they should phase to zero. Encoded as the COLA-consistent total
   $2,031 (state portion $1,037). YAML comment documents the suspected
   Iowa HHS publication error and the basis for the override.

2. DP max_per_person_cap and dependent_income_limit now carry
   2018-01-01: $387, matching the base state_supplement 2018 tier.
   Prior gap left 2018-2024 DP payments and eligibility understated
   against the 2017 $379 values.

3. FLH blind recipients receive the $22 blind increment on top of the
   federally-administered $142 cap (POMS OS code I: state portion
   $164 for blind FLH residents). The blind increment replaces — not
   adds to — the SSI-only Department top-up; $22 > $20 always. New
   FLH test case 7 locks in the $164 figure for a blind FLH resident.

79 Iowa SSA tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

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

Iowa State Supplementary Payment (SSP) — PR #8017 Review

Source Documents


Critical (Must Fix)

  1. DP supplement formula uses individual FBR for couple configurations and applies an unjustified per-person cap

    • Location: policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa.py:39-43; parameters/.../dp/state_supplement.yaml; parameters/.../dp/max_per_person_cap.yaml.
    • The formula is dp_raw = max_(0, (individual_fbr + dp_state_supplement) - countable_or_fbr); dp_amt = min_(dp_raw, p.dp.max_per_person_cap). countable_or_fbr is clamped to individual_fbr ($967) even when the configuration represents an eligible couple — federal SSI for an eligible couple fills to the couple FBR ($1,450), not the individual FBR. The state_supplement YAML is back-calculated against individual_fbr for every configuration, producing wildly inflated raw values that the author then bounds with max_per_person_cap = $503.
    • The $503 cap has no regulatory basis as a payment ceiling — it is the dependent relative's income eligibility limit (per IAC 441-51.5(1) / GL 6-B-46 cover page), repurposed here. max_per_person_cap.yaml and dependent_income_limit.yaml are byte-identical across all four years (379, 387, 503, 518), confirming the conflation.
    • Code-path verifier confirmed: for BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT 2025 with zero countable income, code returns $503; regulation requires $547 (= $1,997 standard − $1,450 couple FBR). $44/month error, locked in by test ia_ssa.yaml Case 3.
    • Other affected 2025 configurations: BLIND_WITH_DEPENDENT (true $525, code $503); BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT (true $525, code $503).
    • PDF citation: Iowa HHS GL 6-B-46 ("Making the Dependent Person Payment", manual lines 1714–1720): "Only the income of the eligible person or eligible couple is subtracted from the applicable assistance standard." 2025 standards listed at GL pp. 22 (image p. 28).
    • Fix: Parameterize the assistance standard directly per configuration and select individual vs. couple FBR based on whether the configuration includes an eligible spouse, then supplement = max(0, standard − max(countable, applicable_fbr)). Remove max_per_person_cap.
  2. $20 SSI general disregard incorrectly included in RCF/FLH/IHHRC client participation

    • Location: ia_ssa.py:22-26, 56-70, 71-80, 90-100; ia_ssa_living_arrangement.py:28-33, 39-66.
    • All three programs derive countable_monthly = ssi_countable_income / 12, but ssi_countable_income already applies the federal $20 general income exclusion (gov.ssa.ssi.income.exclusions.general) inside _apply_ssi_exclusions.py. The Iowa rules enumerate disregards exhaustively and omit the $20 exclusion:
      • RCF — IAC 441-52.1(3)(a) / GL 6-B-46 p. 58: "NOTE: Do not allow the SSI $20 income disregard."
      • FLH — GL 6-B-46 p. 30: "EXCEPTION: Do not allow the $20 income disregard."
      • IHHRC — IAC 441-177.4(1)(f) / GL 6-B-46 p. 36: "EXCEPTION: Do not allow the $20 disregard."
    • Code-path verifier confirmed: test ia_ssa.yaml RCF Case 6 (SS $1,000/mo) expects $311.60; correct value is $291.60. $20/month understatement of client participation = $20/month overstatement of supplement for any recipient with non-SSI unearned income ≥ $20/mo. The same error contaminates the income-eligibility gates (rcf_income_eligible, ihhrc_income_eligible, blind_income_eligible) within $20 of the cap.
    • Fix: Introduce an Iowa-specific ia_ssa_countable_income_no_disregard helper that adds back min(unearned_monthly, $20), and use it in RCF/FLH/IHHRC payment formulas and in the corresponding routing-layer gates.
  3. Iowa SSA resource-limit dispatcher under-includes ineligible dependent spouses

    • Location: policyengine_us/variables/gov/states/ia/hhs/ssa/ia_ssa_resources_eligible.py:12-24.
    • Code uses joint = ssi_claim_is_joint to flip both the resource pool (individual vs. marital sum) and the cap ($2,000 vs. $3,000). ssi_claim_is_joint returns True only when both spouses are SSI-categorically-eligible heads/spouses. IAC 441-51.5(2) extends the $3,000 cap whenever the recipient has "a dependent spouse," and 51.5(4) defines that to include an "ineligible spouse … who is financially dependent upon the recipient." Also affects the third sentence of 51.5(2): "recipient, spouse, and dependent child or parent: $3,000."
    • Concrete failure: aged SSI recipient married to a 50-year-old non-disabled spouse with no income → ssi_claim_is_joint = False → tested individually against $2,000 instead of marital-unit against $3,000.
    • Fix: Replace the dispatcher with an Iowa-specific ia_ssa_has_dependent_spouse (or extend an ia_ssa_dp_* variable that already enumerates dependents) and sum resources across all 51.5-covered dependent relatives.
  4. Wrong IAC subsection citations (5 locations) — all 4 verifier claims confirmed

    # File Wrong Correct
    1 parameters/.../ssa/smme/minimum_income_fpl_multiplier.yaml (both refs) 441—51.6(6) 441—51.7(6)
    2 parameters/.../ssa/dp/dependent_income_limit.yaml 441—51.4(1) 441—51.5(1)
    3 parameters/.../ssa/dp/max_per_person_cap.yaml 441—51.4(1) 441—51.5(1)
    4 parameters/.../ssa/rcf/days_multiplier.yaml (both refs) 441—51.3(3) 441—51.4(3)
    5 variables/.../ssa/ia_ssa_living_arrangement.py line 39 comment IAC 441—51.3(3) IAC 441—51.4(3)
    • 441-51.3 ("Supplementation") and 441-51.6 ("Residence") have no numbered subsections, so the cited references literally do not exist. The correct subsections (51.7(6) for the 120% FPL rule, 51.5(1) for dependent-relative income, 51.4(3) for RCF income eligibility) all match the parameter content verbatim.
  5. RCF and IHHRC client-participation formulas omit required regulatory deductions

    • Location: ia_ssa.py:71-100.
    • RCF (IAC 441-52.1(3)(a) / GL 6-B-46 p. 57): Required deduction order is (1) impairment-related work expenses, (2) $65 + ½ remaining earned income, (3) $126 PNA, (4) diversion to spouse at home, (5) diversion to dependent child, (6) unmet medical needs of resident, (7) unmet medical needs of spouse/dependent, (8) first-month previous-living expenses. Code applies only #3.
    • IHHRC (IAC 441-177.4(1)(f) / GL 6-B-46 p. 38): Required deductions are basic SSI standard, $65+½ earned income, dependent SSI standard plus unmet medical needs, ineligible-spouse medical needs, applicant medical needs. Code applies only the basic SSI standard. Entire 177.4(1)(g) child-deeming branch (parental income deemed to a child needing IHHRC, with 1/3 child-support disregard etc.) is unmodeled.
    • PR description acknowledges the "5-step disregard cascade not modeled," but at minimum the $65+½ earned income disregard (a federal SSI primitive already in PE) and the $483-per-dependent diversions are computable and materially affect working/dependent households.
    • Minimum recommended fix: Apply $65+½ earned-income disregard and the dependent diversions for RCF and IHHRC; document the omitted deductions explicitly in variable docstrings.

Should Address

  1. FLH state_supplement historical (pre-2025) values disagree with SSA published baselines — flh/state_supplement.yaml encodes $142 (2011), $162 (2017), $162 (2018), but the SSA 2011 Iowa baseline (PDF 4 lines 99–115) shows the Iowa FLH state supplement was $344 (aged/disabled individual) / $366 (blind individual) in January 2011. The encoded $142 appears to be the SSA-administered cap, not the historical state supplement. (Regulatory S1.)

  2. SMME income test uses SPM-unit FPG instead of individual/couple FPG — smme/ia_ssa_smme_eligible.py:27-29: fpg_monthly = person.spm_unit("spm_unit_fpg", period.this_year) / MONTHS_IN_YEAR. IAC 441-51.7(6) tests the recipient's income against 120% FPL for one (or two if joint claim). A single SSI-eligible aged person living with two adult children (SPM unit of 3) faces a 120% threshold of ~$2,665/mo instead of the correct ~$1,565/mo and would fail the test even though they should pass. Use personal_fpg for individual claims and 2-person FPG for joint claims. (Regulatory S2.)

  3. DP max_per_person_cap parameter is duplicative and undocumented — Identical values to dependent_income_limit across all years. Conflates two regulatory concepts. Remove and replace with per-configuration state supplement encoding (related to Critical #1). (Regulatory S3.)

  4. DP/Blind/FLH input variables lack formula derivations and microsim defaults — ia_ssa_dp_has_eligible_dependent, ia_ssa_dp_dependent_countable_income, ia_ssa_dp_configuration, ia_ssa_resides_in_family_life_home, ia_ssa_resides_in_residential_care_facility, ia_ssa_needs_in_home_health_related_care, ia_ssa_ihhrc_cost_of_care, ia_ssa_rcf_cost_per_diem are pure user-input variables. In a microsim run on enhanced CPS none will be populated, so DP/FLH/RCF/IHHRC will never fire. Acceptable as a manual-input pathway, but add at least minimal default formulas (e.g., default ia_ssa_has_medicare_part_b to is_medicare_eligible) where a federal PE variable already encodes the concept. (Regulatory S5/S6, Suggestion G1.)

  5. 5 input variables omit default_value — ia_ssa_dp_dependent_countable_income, ia_ssa_dp_has_eligible_dependent, ia_ssa_resides_in_family_life_home, ia_ssa_ihhrc_cost_of_care, ia_ssa_needs_in_home_health_related_care, ia_ssa_rcf_cost_per_diem, ia_ssa_resides_in_residential_care_facility. The PR sets default_value = False on ia_ssa_has_full_medicaid and ia_ssa_has_medicare_part_b but is inconsistent for the rest. (Code S2.)

  6. FBR acronym in parameter descriptions — dp/state_supplement.yaml and flh/state_supplement.yaml use "(FBR)" in the description field, violating the parameter-patterns "no acronyms" rule. (Code S4.)

  7. Period-bridging convention undocumented — ia_ssa.py:29, ia_ssa_living_arrangement.py:37, ia_ssa_smme_eligible.py:16 access YEAR-period inputs (ssi_claim_is_joint, is_ssi_aged_blind_disabled) with period.this_year from MONTH formulas. Technically correct but consider a single explanatory comment near the top of ia_ssa.py. (Code S1.)

  8. #page= anchor mismatch in IHHRC max_cost_single.yaml — Reference for 441-177.10(3) uses #page=4 but the rule is on file page 5. (Reference S1.)

  9. Iowa Code 249.9A reference missing #page= anchor — rcf/personal_needs_allowance.yaml. (Reference S2.)

  10. Iowa HHS GL 6-B-46 download URL has no page anchor — Multiple files cite hhs.iowa.gov/media/15607/download bare. Add #page=1 for explicitness or cite the manual chapter URL. (Reference S3.)

  11. Bare HHS landing page reference for 2026 values is insufficient — hhs.iowa.gov/assistance-programs/state-supplementary-assistance is dynamic. Add a Wayback snapshot URL or a (retrieved YYYY-MM-DD) note. (Reference S4.)

  12. Income-eligibility gates inherit the $20-disregard error — ia_ssa_living_arrangement.py:39-66: RCF income gate (< $1,165.60), IHHRC gates (<= $480.55 / <= $961.10), and Blind income gate (< $989) all use the contaminated countable_monthly, so cases at or within $20 of the boundary may be mis-classified. (Regulatory S7 — addressed by Critical #2 fix.)

  13. No 2011 historical-tier test anywhere — Parameters define 2011-01-01 values (blind, RCF PNA $93, max_per_diem $28.14, dp.state_supplement, flh.max_supplement, etc.) but no test uses period: 2011-01. The 2011→2017 transitions are unverified. (Test C1.)

  14. Missing payment test for BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT — Only 4 of 5 non-NONE DP configurations are exercised; this config is the one with the disputed 2026 value, so a payment test pinning 2025 and 2026 is essential. (Test C2.)

  15. V-shape boundary at countable == FBR not directly tested — None of the BLIND/DP/FLH cases use a social_security_retirement value engineered to put ssi_countable_income exactly at individual_fbr. (Test C3.)

  16. RCF post-PNA client-participation boundary not tested — Existing cases sit far above or far below the $1,165.60 threshold; no case engineered to land just below, exactly at, or one cent above. (Test C4.)

  17. IHHRC combined countable equal to caps not tested — ihhrc_countable_after_disregard <= ihhrc_cap uses <=. No case sits exactly at $480.55 single or $961.10 couple. (Test C5.)

  18. Missing pair-wise priority routing tests — RCF > IHHRC, RCF > FLH, RCF > DP, RCF > SMME, FLH > DP, FLH > SMME are not directly tested. Cheap to add and protect against select(...) reordering bugs. (Test S9.)

  19. SMME 120% FPL boundary partially covered, full-Medicaid vs. medically-needy distinction not covered, FLH blind add-on at 2026 not tested, FLH Department top-up countable_monthly == 0 boundary not tested, ineligible-person variants missing, DP has_eligible_dependent: false with non-NONE configuration not tested. (Test S6, S8, S10, S11, S12, S13.)


Suggestions

  1. 2026 BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT $1,037 is an editorial guess — Iowa HHS publishes $3,031 for 2026; PR encodes $1,037 (state portion) on the theory that $3,031 is a typo. Already disclosed in YAML comment and PR description as intentional. Either confirm with Iowa HHS in writing and add response as comment, or fall back to the published $3,031 with a TODO. Documented as intentional — not blocking. (Regulatory S4 / Code G3 / PDF audit b.1.)

  2. Default ia_ssa_has_medicare_part_b to is_medicare_eligible — Would let SMME fire automatically in microsim. (Code G1.)

  3. Extract DRY intermediate variables — countable_monthly, ssi_monthly, basic_ssi_disregard, combined_countable are re-derived in both ia_ssa.py and ia_ssa_living_arrangement.py. Consider shared ia_ssa_countable_income_monthly etc. per the variable-patterns "intermediate variables for code reuse" rule. (Code G1.)

  4. Add YAML comments in dependent_income_limit.yaml and max_per_person_cap.yaml clarifying they are intentionally not breakdowns — Prevents a future contributor from "fixing" them. (Code S3.)

  5. RCF cost_per_diem default to p.rcf.max_per_diem when resident is flagged as in RCF — Behavioral improvement so the default supplement is non-zero. (Code G2.)

  6. ia_ssa_resources_eligible description should note monthly recomputation of an annual SSI resource test. (Code G4.)

  7. Consolidate 2017/2018 IAC supplement citations with effective-date parentheticals. (Reference G1.)

  8. Tighten SSA 2011 footnote-a documentation in dp/state_supplement.yaml. (Reference G2.)

  9. Add YAML comment in rcf/days_multiplier.yaml explaining the "31 = largest possible days-in-a-month" derivation. (Reference G3.)

  10. HHS rates page lists "Flat per Diem Rate $17.86" — likely informational only post-2017 transition to cost-related per diem. Confirm with author whether to encode. (PDF payment-standards audit c.1.)

  11. Standardize absolute_error_margin: 0.01 across YAML test cases. (Test S19.)

  12. Test variants: negative income, explicit ssi_claim_is_joint toggling on couples, RCF per-diem exactly at cap, days-multiplier sensitivity, entity-scaffolding cleanup for ia_ssa_dp_configuration.yaml. (Test S14, S15, S16, S17, S20.)


Investigated and Cleared (False Positives)

  • SMME categorical contradiction (PDF eligibility audit Mismatch #1) — Rejected. Federal is_ssi_eligible checks ABD + resources + immigration only; it does NOT encode an income test. The SMME-target population (income > 120% FPL with full Medicaid + Part B + ABD + SSI resource/immigration eligibility) passes is_ssi_eligible and the SMME branch fires correctly. Verified end-to-end with a worked example (aged 70, $1,600/mo income, $1,500 resources → SMME = $1).
  • IHHRC $961.10 income cap "missing" (PDF IHHRC audit framing concern) — Rejected. The cap IS enforced — at ia_ssa_living_arrangement.py:64 (routing layer), where eligibility cutoffs belong in this codebase's pattern. The reviewer searched only ia_ssa.py (payment layer) and stopped one file short. Same routing/payment split is used for RCF and Blind in the same file.

PDF Audit Summary

Category Count
Confirmed correct (parameters reconciled to PDFs) 27 (8 Ch.52 payment standards, 5 IHHRC 2025 + 2011 baseline values, 7 eligibility/routing rules per Ch.51, 5 DP 2025 standards from GL 6-B-46, 2 SMME)
Mismatches confirmed (deliberate) 1 (2026 DP BLIND_WITH_AGED_OR_DISABLED_SPOUSE_AND_DEPENDENT: repo $1,037 vs HHS $3,031, documented as intentional editorial override)
Mismatches rejected 2 (SMME categorical gate, IHHRC $961.10 income cap routing)
Unmodeled items acknowledged in PR 5+ (5-step IHHRC disregard cascade; RCF disregards #1/2/4-8; child IHHRC deeming branch 177.4(1)(g); first-month proration 177.10(2)(b); 15-day temporary absence rules)
New unmodeled items flagged 8 (FIP application requirement 51.2; supplementation income reduction 51.3; physician-cert / facility-licensing inputs 51.4(1)/(2); RCF couple-room initial-month special rule 51.4(3); dependent earnings $65 work expense 51.5(1); full-month absence rule 51.5(3); SMME living-arrangement enumeration 51.7(5); SSN furnishing 51.9; income from room-and-board 51.8)

Validation Summary

Check Result
Regulatory Accuracy 3 critical (DP couple FBR, $20 disregard, RCF/IHHRC missing deductions), 7 should
Reference Quality 4 critical citation errors (3 YAML + 1 covered under critical #4 group), 4 should
Code Patterns 0 critical, 5 should, 4 suggestions
Test Coverage 5 critical gaps, 8 should
PDF Value Audit 0 unintentional mismatches; 1 deliberate (2026 DP override, documented)
CI Status All 24 checks passing

Review Severity: REQUEST_CHANGES

Justification: four confirmed code/regulatory bugs materially affect output dollars in real cases — (1) DP couple-FBR formula bug is a $44/month error encoded into a passing test; (2) $20 SSI disregard misapplication understates RCF/FLH/IHHRC client participation by $20/month for any recipient with non-trivial unearned income; (3) resource-limit dispatcher under-includes ineligible dependent spouses, denying eligibility to households entitled to the $3,000 cap; (4) five regulatory citations point to non-existent or unrelated subsections, undermining auditability. The deliberate 2026 DP override is acceptable as documented, but the structural bugs warrant fixes before merge.


Top Priorities for Author

  1. Fix DP couple-FBR / per-person-cap issue — Parameterize assistance standard per configuration; pick individual vs couple FBR based on whether configuration has an eligible spouse; remove max_per_person_cap.
  2. Strip $20 disregard for RCF/FLH/IHHRC — Add an ia_ssa_countable_income_no_disregard helper that adds back min(unearned_monthly, $20); use in RCF/FLH/IHHRC payment formulas and routing-layer income gates.
  3. Fix resource-limit dispatcher — Replace ssi_claim_is_joint with an Iowa-specific ia_ssa_has_dependent_spouse that covers ineligible-but-financially-dependent spouses per IAC 441-51.5(4).
  4. Correct IAC subsection citations (5 locations) — smme/minimum_income_fpl_multiplier.yaml (51.6(6)→51.7(6)); dp/dependent_income_limit.yaml and dp/max_per_person_cap.yaml (51.4(1)→51.5(1)); rcf/days_multiplier.yaml (51.3(3)→51.4(3)); ia_ssa_living_arrangement.py:39 comment (51.3(3)→51.4(3)).
  5. Add minimum-recommended deductions — $65+½ earned-income disregard and dependent diversions for RCF and IHHRC.

@hua7450
hua7450 marked this pull request as draft April 28, 2026 14:27
hua7450 and others added 9 commits May 4, 2026 15:01
…mit, IAC citations, SMME FPG

- DP: replace state_supplement (back-calculated against individual FBR) with
  per-config assistance_standard from GL 6-B-46 p. 22; pick couple FBR for
  spouse-inclusive configs. Removes the unjustified $503 max_per_person_cap
  that was conflated with the dependent_income_limit. Fixes 2025 BLIND
  configs that were understated by $22-$44/mo.
- RCF/IHHRC: add ia_ssa_countable_income_no_disregard helper to reverse the
  SSI \$20 general exclusion (GL 6-B-46 pp. 36, 54-58 omit it). Accounts for
  SSI couple computation by sharing the add-back across the marital unit.
  FLH/DP/Blind keep ssi_countable_income — they are SSA-administered and the
  \$20 disregard is real money the recipient receives.
- Resource limit: dispatch on marital_unit.nb_persons() > 1 instead of
  ssi_claim_is_joint, so an aged recipient with an ineligible-but-co-resident
  spouse correctly gets the IAC 441-51.5(2) couple \$3,000 limit.
- IAC citations: 51.6(6) -> 51.7(6) for SMME 2026 ref, 51.4(1) -> 51.5(1)
  for DP dependent income limit, 51.3(3) -> 51.4(3) for RCF days_multiplier
  and the matching comment.
- SMME income test: size FPG by 1-person (or 2-person on joint claim) per
  IAC 441-51.7(6) "income of a recipient", not by full SPM unit.
- Tests: refresh DP/RCF/IHHRC expected values for the new formulas; add a
  resources test for ineligible-co-resident-spouse; restructure DP cases 3,
  4, 8 with realistic 3-person setups instead of single person tagged with
  couple-inclusive configurations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…dd-back

- Add 2011 historical values to dp/dependent_income_limit ($344, verified
  from SSA 2011 Iowa Table 1 Code C state portion = $1,018 - $674 FBR),
  smme/amount ($1 token, SMME enacted by 2004 Iowa Acts ch. 1085), and
  smme/minimum_income_fpl_multiplier (1.2, 120% FPL test in Iowa Code
  249.3(4)(g) since 2004). Eliminates ParameterNotFoundError on pre-2017
  RCF/Blind/etc. simulations where these values are read unconditionally.
- Restore the earned-income portion of the SSI $20 general disregard
  add-back per 20 CFR § 416.1112: when unearned < $20, the leftover
  applies inside the earned flat ($65 + leftover) and is then reduced by
  the 50% earned-share rule. The helper now adds back
  applied_to_unearned + applied_to_earned * (1 - earned_share) instead of
  only min(unearned, $20). Verified against GL 6-B-46 p. 55 example
  ($500/mo earned -> RCF countable $977 = SSI standard + $10).
- Tests: add 2011 RCF historical regression and a $500/mo earned-only RCF
  case that matches the manual's $977 countable income walkthrough.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The helper reconstructs where the SSI $20 general exclusion landed, so its
inputs must mirror _apply_ssi_exclusions exactly: marital unearned + parent
deemed + ISM on the unearned side, and marital earned − blind/disabled
working-student exclusion on the earned side. The previous version saw only
ssi_unearned_income / ssi_earned_income, so it under-detected when the $20
landed on ISM or parental-deemed unearned income (e.g., $100/mo ISM with
$500/mo earnings under-counted client participation by $10/mo).

Also drops redundant period.this_year / MONTHS_IN_YEAR conversions on
flow variables — period auto-converts annual flows to monthly inside a
MONTH formula.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove ungrounded $22 blind add-on from FLH supplement (IAC 441-52.1(4)
  excludes the $22 standard for recipients of any other SSP); replace
  fragile float-equality with tolerance-based gap branch.
- Fix three PDF page anchors: ihhrc/max_cost_single 4→5, rcf/days_multiplier
  2→1, and rcf/ia_ssa_resides_in_residential_care_facility.py 2→1.
- Fix dp/dependent_income_limit.yaml 2017 supplement section title from
  441-51.5(1) to 441-51.4(1).
- Refactor: replace 3 input booleans with one ia_ssa_living_arrangement_input
  enum, matching the MA/MI/AK/CT/IN state SSP pattern. Net -2 files.
- Update Case 7 expected value $164 → $162 to reflect the FLH blind add-on
  removal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Formula bugs uncovered while expanding test coverage:

* IHHRC supplement was always zero in production. ia_ssa_ihhrc_cost_of_care
  had no formula, so cost defaulted to zero and ihhrc_amt collapsed to
  max(0, 0 - participation) = 0. Add a formula that imputes max_cost_single
  when ia_ssa_living_arrangement is IHHRC; users can still override with
  actual care-cost data.

* DP supplement double-attributed to spouses. When both spouses encoded the
  same couple-FBR DP configuration, both computed the full per-couple
  supplement and the SPM-unit total doubled. Add a per-marital-unit divisor
  guard that splits the supplement across claimants.

* DP and SMME compared per-spouse income to couple-level thresholds. For
  joint SSI claims, ssi_countable_income returns combined / 2 per spouse,
  but the DP couple-FBR comparison and the SMME 2-person FPL gate were
  written against per-spouse values. Aggregate countable across the
  marital unit before the comparison when the threshold is couple-level.

Reference and registry fixes:

* dp/dependent_income_limit.yaml: cite operative IAC 441-51.5(1) and the
  HHS Manual; remove the misleading 2018 Ch.52 reference.
* flh/max_supplement.yaml: cite HHS Manual GL 6-B-46 page 31 for the $142
  SSA-administered cap.
* programs.yaml: add parameter_prefix to the IA SSA entry.

Code cleanup: drop the redundant period.this_year / MONTHS_IN_YEAR pattern
in favor of period directly. PolicyEngine auto-divides FLOW-type YEAR
variables when accessed at a MONTH period.

New tests (Cases 9-14 in ia_ssa.yaml):

* Case 9 / 14: BLIND_WITH_DEPENDENT 2025 and 2011 (state portion matches
  SSA 2011 Iowa Table 1, Code C blind: $366).
* Case 10: BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT 2025.
* Case 11: regression test for the marital-unit divisor when both spouses
  set the same couple-FBR DP config.
* Case 12: regression test for joint-claim DP phaseout when combined
  income exceeds couple FBR.
* Case 13: AGED_OR_DISABLED_WITH_DEPENDENT 2011 (state portion matches
  SSA 2011 Iowa Table 1, Code C aged: $344).

All 88 IA SSA YAML tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
BLIND: For joint SSI claims with both spouses blind, ssi_countable_income
returns combined / 2 per spouse — so the previous per-spouse comparison
against (individual_fbr + $22) admitted couples whose combined income
exceeded the couple-level ceiling. Aggregate marital countable, compare
against (couple_fbr + 2 × $22), then split equally to avoid SPM-unit
double-counting (mirrors the DP couple-FBR fix).

FLH: Replace the all-or-nothing $20 top-up (triggered whenever
ssi_countable_income == 0) with a gap-based formula. Department fills
the gap from total income to the FLH standard, so a recipient with
$10/mo of other unearned income needs only a $10 top-up (was $20).
Defensive cap at (state_supplement − max_supplement) so artificially
low ssi_monthly cannot explode the supplement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rce limit

BLIND one-blind joint: previous gate `joint_claim & sum(is_blind) == 2`
only applied couple-FBR basis when both spouses were blind. For joint
SSI claims with one blind spouse, ssi_countable_income still returns
combined / 2 per spouse and the federal piece is paid against couple
FBR, so the per-spouse comparison against individual FBR overpaid.
Generalize: any joint claim uses (couple_fbr + N × $22) where N is the
number of blind people in the marital unit; split only when both blind.
Mirror the same logic in the living-arrangement gate.

ia_ssa_eligible: replace federal `is_ssi_eligible` (which applies the
$2,000 individual resource test for non-joint married claimants) with
ABD + immigration + Iowa's own resource test. Iowa's $3,000 marital
limit (IAC 441—51.5(2)) was unreachable for cases like a claimant with
$2,500 marital resources and a non-ABD spouse. IAC 441—51.1 lets Iowa
pay recipients who would qualify for SSI except for excess income, so
the federal resource test should not gate Iowa eligibility.

Adds Cases 15-16 as regression tests for both fixes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- ia_ssa_living_arrangement: gate FLH and DP at the living-arrangement level
  by recipient/marital countable income vs the FLH standard
  (FBR + state_supplement) and the selected DP assistance standard, so
  high-income households fall through to SMME instead of being classified
  into a clamped-to-zero category. Use marital countable income for couple
  DP configurations to match the marital-unit-level standard.
- ia_ssa_living_arrangement and ia_ssa: IHHRC home-maintenance disregard
  selects the couple SSI standard whenever a spouse lives in the home
  (per IAC 441-177.4(1)(f)(1) "as applicable" and Iowa HHS GL 6-B-46),
  not only when both spouses are SSI-categorically eligible. Renamed to
  ihhrc_basic_ssi_disregard to scope it to IHHRC; BLIND keeps joint_claim
  per IAC 441-52.1(4).
- ia_ssa_resources_eligible: replace the IAC 441-51.5(2)-only citation
  with the broader umbrella authority (IAC 441-50.2) plus the federal SSI
  resource rules that govern non-DP arrangements (SSA POMS SI 01110.003,
  SI 01110.530, 20 CFR 416.1202(a)). Substantive policy unchanged: the
  $2k/$3k schedule applies whether the spouse is SSI-eligible or not,
  per federal SSI itself.
@hua7450

hua7450 commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator Author

Thanks, Pavel. All four are applied as you wrote them, in 99f005d, and main is merged in 0ad5fc5.

The optional suggestions (G57-G63 and the carried ones) are not in this round.

126 Iowa supplement cases pass locally (97 in ia_ssa.yaml), and test_source_conflicts.py and the registry tests pass on the merged tree.

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

Program Review (round 7): Add Iowa state supplementation for 2026

IDs: C = critical, SA = should address, G = suggestion. Prior IDs keep their numbers. New findings start at SA35 and G66. There is no new critical item, so C8 is not used.

Source Documents

  • Reviewed head SHA: 0ad5fc5
  • Mode: incremental from 5837b95
  • Commits since round 6: 99f005d "Address Pavel's round-6 review of Iowa SSA" (5 Iowa files, +237 / -9); 0ad5fc5 (merge of main at 6a92d6a; among PR-scope files only programs.yaml and source_conflicts/candidates.yaml changed, with no Iowa line).
  • Scope: _smme_spouse_income.py (new smme_spouse_is_aged_blind_disabled; no child allocations for that spouse); ia_ssa_smme_spousal_deeming_applies.py (apart, eligible_spouse, two hrefs, two NOTEs); comment-only edits in ia_ssa.py and ia_ssa_smme_countable_income.py; Cases 94-97 appended to ia_ssa.yaml (no existing case edited; 126 Iowa cases in total).
  • Sources ("p.NN" = PDF FILE page; 6-B and 8-F FILE = printed + 4; 8-E FILE = printed + 5): 8-E https://hhs.iowa.gov/media/4011/download?inline ("Revised May 22, 2026"), 8-F https://hhs.iowa.gov/media/4012/download?inline and 6-B https://hhs.iowa.gov/media/3987/download?inline= (all downloaded again); eCFR (October 2026) 20 CFR 416.212, 416.414, 416.1112, 416.1142, 416.1149, 416.1160, 416.1161, 416.1163, 416.1167, 416.1801, 416.1802; POMS SI 00501.154, SI 00835.040, SI 02005.050, SI 01310.165; LII 42 U.S.C. 1382a; GitHub #10138, #10141, #10193, #10243 and TheAxiomFoundation/rulespec-us#1837 (read-only).

Branch Status

  • 45 ahead, 34 behind main (0e7ced1); MERGEABLE. CI: 27 pass, 0 fail.
  • Among Iowa files, the 34 newer commits change only Iowa income-tax files (ia_other_additions, ia_other_subtractions). They change no Iowa supplement, SSI, poverty-guideline or MSP file. The federal SSI deeming, status and couple-computation files are the same at the head and on main (0e7ced1 and dbfc017). The staleness did not affect any finding. A rebase is not necessary for review.
  • Local run at 0ad5fc5: 126/126 Iowa YAML cases; 452 code-health and aggregate-list tests (1 skipped); test_source_conflicts.py 103; test_programs_registry.py 767 (10 skipped, none Iowa); ruff format --check and ruff check clean on the 24 Iowa variable files.
  • No partner test file is touched. The changelog fragment is unchanged. Record only: programs.yaml still says verified_years: "2026" for Iowa.

What round 7 fixed

  • SA31, as proposed. The apart term, the 416.1167 href and the NOTE are in the flag (:16, :36-46, :64), and Case 96 pins ~apart. Under 20 CFR 416.1167(a)(1), either spouse who has left the household is not a household member, whoever pays. (a)(2) needs 416.212 eligibility, which an applicant above the SGA level lacks. For a Medicaid-paid stay of an aged spouse, the SGA path and the aged path now agree (Cases 96 and 81).
  • SA32, as proposed. The helper is byte-identical to the proposal, the combined return is at :58-66, and the 8-F href is added. Case 97 pins eligible_spouse. An aged, blind or disabled (ABD) spouse is not an ineligible spouse (8-E p.12; 8-F p.73), so the couple is combined with no $497 test and no allocations. The three round-6 flip rows now give [0, 0], and the control row (wages 1,700, spouse SS 3,000) still gives [1, 0].
  • SA33 and SA34. Cases 94 and 95 are the proposed text and recompute by hand. A zeroed or earned-first allocation fails only Case 94. Dropping the spouse's unearned term fails Cases 95 and 97. A >= in the $497 test fails Case 92, so "over $497" is pinned from both sides.
  • 126/126 Iowa cases pass on the merged tree, and the 452 code-health tests pass.
  • 12 of 12 new or changed cites are correct, each read on the rendered page or in the eCFR text. No printed page number is used.
  • PR body and issue: the axiom: line is present, and G64 is done. rulespec-us#1837 has rows BF-BI, the flag row, "cases A to BI", "15 formulas", "Parameters from 2023-01-01", BD "April 2026" and a corrected Payment row (G65).
  • Also: G59's second bullet, and G52 in part (8-F href).
  • No regression. No test line is removed. Cases 77, 82, 87, 88, 90-93 and the C4, C7, SA23, SA25, SA27 and SA28 cases pass, and no mutant of the new terms changes them.
  • The head is right not to add the ABD spouse's SSI payment (G67).

Both new should-address items are in the SA31 and SA32 code: three new branches have no test (SA35), and the SA32 rule is applied to the applicant but not to the ABD spouse in the same couple (SA36).

Round-6 status

ID Status Evidence at 0ad5fc5
SA31 spouse in a facility RESOLVED apart, href, NOTE as proposed; Case 96 pins it. Facets untested: SA35
SA32 ABD spouse status RESOLVED Helper and return as proposed; Case 97 pins it. Gaps: SA35, SA36
SA33 child allocation RESOLVED Case 94 verbatim; allocation mutants fail only Case 94
SA34 spouse unearned income RESOLVED Case 95 verbatim; the unearned-term mutant fails Cases 95 and 97
G25 case periods PARTIAL (accepted part stands) 2026-01 (Cases 94-95) and 2026-04 (Cases 96-97) fit
G36 STILL OPEN (no reply) The four branches are unchanged
G37 STILL OPEN (deferred) NOTE (now ia_ssa.py:130-137) and Iowa candidates unchanged
G38 STILL OPEN (deferred) ia_ssa_federal.py unchanged
G39 STILL OPEN (deferred) Coverage input documentation unchanged
G40 STILL OPEN (deferred) Files unchanged
G41 STILL OPEN (deferred) integration.yaml unchanged
G42 STILL OPEN (deferred) ia_ssa_ihhrc_participation.py:49-51 unchanged
G44 PARTIAL (deferred) No GL 6-B-47 link; undated code/249.pdf
G45 STILL OPEN (deferred) Countable :19 still "249.3(4)(g)"; :23 unlabeled
G46 STILL OPEN (deferred) Manual sums unchanged; no new instance
G47 STILL OPEN (deferred) No RCF dividends case
G48 PARTIAL (new) Case 96 reaches the one-person 1,596 through the formula; a >= to > mutant at ia_ssa.py:142 fails it. Couple 2,164 and SGA switch open
G49 STILL OPEN (deferred) Only Case 65 asserts ia_ssa_has_spouse ([false, false])
G50 STILL OPEN (deferred) Unchanged
G51 STILL OPEN (deferred) candidates.yaml:1988-1990 still from: 2026
G52 PARTIAL Flag adds 8-F; ia_ssa.py:10-19 and countable :18-24 lack 8-E #page=12
G53 STILL OPEN (deferred) fpg_year_start_month.yaml unchanged
G54 STILL OPEN (deferred) No NOTE at countable :50; SA36 extends it to the spouse
G55 STILL OPEN (deferred) ia_ssa.py:125 still f"{year}-01-01"
G56 STILL OPEN (deferred) No 2025 SMME or DP case
G57 STILL OPEN (federal; record) Docstring does not name (a)-(c); no issue for 416.1161(a)(10)
G58 STILL OPEN (federal; partly tracked) #10138 names (a) only; (b) untracked; new point (c)
G59 PARTIAL Second bullet done; first bullet open and wider (G66)
G60 STILL OPEN (deferred) 2023 sheet titles unchanged
G61 STILL OPEN, wider The new function is also unprefixed; label unchanged
G62 STILL OPEN; wording corrected Both operands' mutants pass 126/126; the guard cannot double count
G63 STILL OPEN (deferred) No 2023 case; no 2024 DP case
G64 RESOLVED SMME bullet, test list, 126 (97) count and not-modeled list updated
G65 RESOLVED All five round-6 points are in rulespec-us#1837

Tally: 34 IDs were open after round 6. Now 6 are resolved, 5 are partial (G25, G44, G48, G52, G59), 23 are still open and 0 are declined. You deferred G57-G63 and the carried suggestions. A deferral is acceptable for suggestions, and none of them blocks.

Critical (Must Fix)

None.

Should Address

SA35. Three new rule branches have no test, and each mutant flips ia_ssa

  • What is wrong: Case 96 covers only a spouse in a Medicaid-paid stay, and Case 97 has no child. So no case reaches these branches:
    • (a) no child allocations for an ABD spouse (_smme_spouse_income.py:22-24);
    • (b) apart is true when the applicant is in a facility (marital_unit.any, flag :44-46);
    • (c) apart is true for a private-pay stay (ssi_lives_in_medical_treatment_facility, not the Medicaid-paid arrangement).
  • Source: 8-E p.12 takes the child allocations only in the steps for deeming from an ineligible spouse, and 416.1163(b) allocates only from an ineligible spouse's income. Under 416.1167(a)(1), "You, your ineligible spouse ..." who leaves the household stays a member only with a return "in the same month or the month immediately following"; the payer does not matter.
  • Evidence (each mutant run on a copy of the branch, in two or three separate runs):
Branch Mutant Iowa suite Proposed case: head, then mutant
(a) Allocations kept for every spouse 126 pass Case 98: SMME 2,186, then 1,689; ia_ssa [1, 0, 0], then [0, 0, 0]
(b) apart tests the spouse only 126 pass Case 99: SMME 1,596, then 2,106; ia_ssa [1, 0], then [0, 0]
(c) apart needs a Medicaid-paid stay (round 6's rejected variant) 126 pass Case 99: the same flip

One improbable mutant (the payer test on the spouse only) still survives. No case is proposed for it.

  • Why should address: Missing edge cases for an already-tested variable, in new code, and each mutant flips eligibility: the same class as SA29 and SA33. Round 6's optional ABD case would catch (a) only in SMME income, not in ia_ssa. G62 is not a precedent, because its guard mutant never changes ia_ssa. Not critical: the code is correct today.
  • Fix (no code change): append after Case 97. Both pass at the head. Case 98 kills (a); Case 99 kills (b), (c) and a >= to > mutant of the SMME guideline test.
- name: Case 98, no child allocation comes off an aged spouse's income when an SMME applicant working above the SGA level is budgeted as a couple.
  period: 2026-04
  absolute_error_margin: 0.01
  input:
    people:
      person1:
        age:
          2026: 50
        meets_ssi_disability_criteria:
          2026: true
        # Wages of $3,277 a month, above the $1,690 SGA level.
        employment_income:
          2026: 39_324
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person2:
        age:
          2026: 70
        # Social Security of $600 a month.
        social_security_retirement:
          2026: 7_200
      person3:
        age:
          2026: 10
    marital_units:
      couple:
        members: [person1, person2]
      child:
        members: [person3]
    tax_units:
      tax_unit:
        members: [person1, person2, person3]
    spm_units:
      spm_unit:
        members: [person1, person2, person3]
    households:
      household:
        members: [person1, person2, person3]
        state_code:
          2026: IA
  output:
    # 8-E p.12: the aged spouse is not an ineligible spouse, so the couple's
    # income is combined with no allocation for the child (20 CFR 416.1163(b)
    # allocates only from an ineligible spouse's income):
    # (600 - 20) + (3,277 - 65) / 2 = 2,186, at least the two-person 2,164.
    # With the 497 allocation it would be (103 - 20) + 1,606 = 1,689.
    # person2's 1,937.50 is SSI's own deeming from person1, with the
    # allocation: (600 - 20) + (3,277 - 497 - 65) / 2. The model uses SSI's
    # income for anyone SSI counts; if person1 is not an ineligible spouse to
    # person2 either (8-E p.12), person2's would also be 2,186.
    ssi_ineligible_child_allocation: [0, 0, 497]
    ia_ssa_smme_spousal_deeming_applies: [true, false, false]
    ia_ssa_smme_countable_income: [2_186, 1_937.5, 0]
    ia_ssa: [1, 0, 0]

- name: Case 99, nothing is deemed to an SMME applicant working above the SGA level who lives in a privately paid medical facility.
  period: 2026-04
  absolute_error_margin: 0.01
  input:
    people:
      person1:
        age:
          2026: 50
        meets_ssi_disability_criteria:
          2026: true
        # Wages of $3,277 a month, above the $1,690 SGA level.
        employment_income:
          2026: 39_324
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
        ssi_lives_in_medical_treatment_facility: true
        ssi_medicaid_pays_majority_of_care: false
      person2:
        age:
          2026: 45
        # A pension of $520 a month.
        pension_income:
          2026: 6_240
    marital_units:
      couple:
        members: [person1, person2]
    tax_units:
      tax_unit:
        members: [person1, person2]
    spm_units:
      spm_unit:
        members: [person1, person2]
    households:
      household:
        members: [person1, person2]
        state_code:
          2026: IA
  output:
    # 20 CFR 416.1167(a)(1); 8-E p.11-12 "same household": the applicant, who
    # is in a medical facility, is not a household member, whoever pays for
    # the stay, so the spouse's 520 pension is not deemed.
    # (3,277 - 20 - 65) / 2 = 1,596, at least the one-person 1,596. With
    # deeming it would be (520 - 20) + (3,277 - 65) / 2 = 2,106, below the
    # two-person 2,164. person2's own income is 520 - 20 = 500.
    ia_ssa_smme_spousal_deeming_applies: [false, false]
    ia_ssa_smme_countable_income: [1_596, 500]
    ia_ssa: [1, 0]

SA36 changes one value in Case 98. Nothing else in Cases 98 and 99 changes.

SA36. The SA32 rule is applied to the applicant only: the ABD spouse still gets SSI's deeming from the worker, with child allocations

  • What is wrong: For anyone SSI counts, SMME income is SSI's own figure. SSI treats the SGA-level worker as an ineligible spouse (416.1160(d)), so it deems the worker's income to the ABD spouse after child allocations. Under 8-E p.12 the worker is not an ineligible spouse either. So the head budgets one couple two ways, and with ineligible children the ABD spouse's result flips. The helper also tests only SSI's ABD status, so two SGA-level SMME workers treat each other as ineligible spouses.
  • Where: ia_ssa_smme_countable_income.py:37, 69-70; _smme_spouse_income.py:4-9; ia_ssa.py:114-118.
  • Source: "An ineligible spouse is a spouse who is not eligible for SSI or non-MAGI-related Medicaid, or State Supplementary Assistance" (8-E p.12). The SMME person "must be eligible for and receiving full Iowa Medicaid benefits ... under a Medicaid coverage group that does not rely on eligibility for SSA" and for Medicare Part B (6-B p.76); SMME is itself State Supplementary Assistance. The non-MAGI groups include "State Supplementary Assistance (SSA) recipients" and 1619(b) workers (8-F p.73), and a 1619(b) worker "is considered to be an SSI recipient" (8-F p.88). The MAGI adult group excludes Medicare (8-F p.47), and the example on 8-F p.99 decides spouse status from the spouse's own disability and Medicare status.
  • Evidence (April 2026; person1 aged 50, disabled, above the SGA level; both spouses have SMME category and coverage):
Household (monthly) Head: SMME [p1, p2]; ia_ssa Rule (eligible couple) Aged applicant on main
Wages 2,500; spouse 70, SS 1,400; two children 2,597.50, 2,100.50; [1, 0] 2,597.50 each; [1, 1] 2,597.50 each; [1, 1]
Wages 3,277; spouse 70, SS 1,000; two children 2,586, 2,089; [1, 0] 2,586 each; [1, 1] —
Wages 1,700; spouse 70, SS 1,500; three children 2,297.50, 1,480; [1, 0] 2,297.50 each; [1, 1] 2,297.50 each; [1, 1]
Two disabled workers (wages 2,500 and 2,000); two children 1,710.50 each; [0, 0] 2,207.50 each; [1, 1] —
First row without children 2,597.50 each; [1, 1] match —

The gap needs ineligible children; without them, deeming equals combining. Round 6's optional case expected 1,491 for the spouse. That was the code's output, not a rule value; the rule gives 1,886, with no flip.

  • Why should address: Same class and reasons as SA32. 8-E p.12 names State Supplementary Assistance and non-MAGI Medicaid, and the SMME applicant has both by the program's own terms. The round-4 acceptance of SSI's figure predates SA32, and the head now contradicts itself inside one couple. A NOTE does not fix a contradiction with a clear rule. Not critical: the structure is otherwise right, the effect is $1 a month, and the population is input-gated.

  • Fix (tested on a copy of the branch: ruff clean; the 126 Iowa cases and the new cases pass; Cases 82 and 90-97 and the SGA-path cases do not change; the aged and SGA paths agree on every probe row). Three traps:

    • Mirroring the applicant's income alone misses the two-worker couple.
    • Without the ia_ssa.py size term, a spouse whom SSI deems nothing to (wages 1,700; spouse SS 1,000; three children) is wrongly paid against the one-person 1,596. The rule gives [0, 0].
    • Without the spouse's student exclusion, the mirror drops it. With wages 3,277 and a disabled student spouse aged 20 who earns 1,200, the head gives the applicant 2,196 and [1] but the spouse 1,790.58; with the exclusion, both are 1,790.58 and [0]. The PR follows the current 416.1112(c)(3) (G54(b)), so subtract both spouses' exclusions.

    Replace _smme_spouse_income.py with:

from policyengine_us.model_api import *


def smme_spouse_is_aged_blind_disabled(person, period):
    """Whether the other member of a two-person marital unit is not an
    ineligible spouse under 8-E p.12: a person SSI treats as aged, blind or
    disabled, or an SMME applicant working above the SGA level, who has full
    non-MAGI-related Medicaid (8-F PDF page 73, 1619(b) group). For an
    applicant whom SSI does not count, any such member is the spouse."""
    abd = person("is_ssi_aged_blind_disabled", period.this_year)
    sga_applicant = (
        person("meets_ssi_disability_criteria", period.this_year)
        & ~abd
        & person("ia_ssa_smme_coverage_eligible", period)
    )
    status = abd | sga_applicant
    return person.marital_unit.sum(status) - status > 0


def smme_spouse_is_sga_applicant(person, period):
    """Whether a person SSI treats as aged, blind or disabled is married to
    an SMME applicant working above the SGA level whose SMME income combines
    the couple's income. SSI deems from that applicant, but under 8-E p.12
    the applicant is not an ineligible spouse, so the couple is combined."""
    applicant = person("ia_ssa_smme_spousal_deeming_applies", period) & person(
        "ia_ssa_smme_coverage_eligible", period
    )
    abd = person("is_ssi_aged_blind_disabled", period.this_year)
    return abd & (person.marital_unit.sum(applicant) - applicant > 0)


def smme_spouse_income(person, period):
    """A spouse's SSI earned and unearned income. For an ineligible spouse,
    allocations for ineligible children are deducted, from unearned income
    first (20 CFR 416.1163(b)(3)). A spouse who is not an ineligible spouse
    is combined as for an eligible couple, with no allocations and after the
    spouse's own student earned income exclusion (20 CFR 416.1112(c)(3))."""
    earned = person("ssi_earned_income", period)
    unearned = person("ssi_unearned_income", period)
    exclusion = person("ssi_blind_or_disabled_working_student_exclusion", period)
    spouse_exclusion = (
        person.marital_unit.sum(exclusion) - exclusion
    ) * smme_spouse_is_aged_blind_disabled(person, period)
    spouse_earned = max_(person.marital_unit.sum(earned) - earned - spouse_exclusion, 0)
    spouse_unearned = person.marital_unit.sum(unearned) - unearned
    allocations = add(
        person.tax_unit, period, ["ssi_ineligible_child_allocation"]
    ) * ~smme_spouse_is_aged_blind_disabled(person, period)
    unearned_left = max_(spouse_unearned - allocations, 0)
    earned_left = max_(spouse_earned - max_(allocations - spouse_unearned, 0), 0)
    return earned_left, unearned_left

In ia_ssa_smme_countable_income.py, import smme_spouse_is_sga_applicant, and add after :70 (income = where(counted_by_ssi, income, own_income)):

        # The aged, blind or disabled spouse of that applicant gets the same
        # combined income, not SSI's deeming from the applicant.
        applicant = deemed & person("ia_ssa_smme_coverage_eligible", period)
        combined = person.marital_unit.sum(where(applicant, income, 0))
        income = where(smme_spouse_is_sga_applicant(person, period), combined, income)

In ia_ssa.py, import it too, and add | smme_spouse_is_sga_applicant(person, period) as the last term of spouse_income at :114-118.

Comment updates (text only):

  • Replace the flag comment at :47-53 with: # 8-E p.12: "An ineligible spouse is a spouse who is not eligible for SSI or non-MAGI-related Medicaid, or State Supplementary Assistance." Those groups are for aged, blind or disabled people (8-F PDF pages 73-74), and a worker above the SGA level who keeps Medicaid is in the 1619(b) group, "considered to be an SSI recipient" (8-F PDF page 88). So a spouse SSI treats as aged, blind or disabled, or an SMME applicant working above the SGA level, is not an ineligible spouse: the couple's income is combined with no $497 test, as SSI and msp_countable_income combine an eligible couple's income. This test is broader than is_ssi_ineligible_spouse. In the NOTE at :54-57, add "and the SMME coverage input" after "disabled status". This also settles G68.
  • Add "https://hhs.iowa.gov/media/4012/download?inline#page=88", # 8-F PDF page 88 to the flag's tuple.
  • Add "or, for the aged, blind or disabled spouse of such an applicant, the couple's combined income" to the countable documentation and to the comment at ia_ssa.py:107-113, with the new case numbers.

In Case 98, change [2_186, 1_937.5, 0] to [2_186, 2_186, 0], and replace the comment's last four lines (from "person2's 1,937.50") with # person1 is not an ineligible spouse to person2 either (8-E p.12), so person2 gets the same combined 2,186 (Case 102). Append these after Case 101. Both fail at the head and pass with the fix:

- name: Case 102, an SMME applicant working above the SGA level is not an ineligible spouse, so the aged spouse's SMME income is combined with no child allocations.
  period: 2026-04
  absolute_error_margin: 0.01
  input:
    people:
      person1:
        age:
          2026: 50
        meets_ssi_disability_criteria:
          2026: true
        # Wages of $2,500 a month.
        employment_income:
          2026: 30_000
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person2:
        age:
          2026: 70
        # Social Security of $1,400 a month.
        social_security_retirement:
          2026: 16_800
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person3:
        age:
          2026: 10
      person4:
        age:
          2026: 10
    marital_units:
      couple:
        members: [person1, person2]
      child1:
        members: [person3]
      child2:
        members: [person4]
    tax_units:
      tax_unit:
        members: [person1, person2, person3, person4]
    spm_units:
      spm_unit:
        members: [person1, person2, person3, person4]
    households:
      household:
        members: [person1, person2, person3, person4]
        state_code:
          2026: IA
  output:
    # 8-E p.12: an ineligible spouse is "not eligible for SSI or
    # non-MAGI-related Medicaid, or State Supplementary Assistance". Each
    # spouse is an SMME applicant with full non-MAGI-related Medicaid, so
    # each is budgeted as an eligible couple, with no child allocations:
    # (1,400 - 20) + (2,500 - 65) / 2 = 2,597.50, at least the two-person
    # 2,164. SSI's own deeming from person1 to person2, after two 497
    # allocations, gives (1,400 - 20) + (2,500 - 994 - 65) / 2 = 2,100.50.
    ssi_ineligible_child_allocation: [0, 0, 497, 497]
    ia_ssa_smme_spousal_deeming_applies: [true, false, false, false]
    ia_ssa_smme_countable_income: [2_597.5, 2_597.5, 0, 0]
    ia_ssa: [1, 1, 0, 0]

- name: Case 103, two SMME applicants working above the SGA level are budgeted as an eligible couple with no child allocations.
  period: 2026-04
  absolute_error_margin: 0.01
  input:
    people:
      person1:
        age:
          2026: 50
        meets_ssi_disability_criteria:
          2026: true
        # Wages of $2,500 a month.
        employment_income:
          2026: 30_000
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person2:
        age:
          2026: 45
        meets_ssi_disability_criteria:
          2026: true
        # Wages of $2,000 a month.
        employment_income:
          2026: 24_000
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person3:
        age:
          2026: 10
      person4:
        age:
          2026: 10
    marital_units:
      couple:
        members: [person1, person2]
      child1:
        members: [person3]
      child2:
        members: [person4]
    tax_units:
      tax_unit:
        members: [person1, person2, person3, person4]
    spm_units:
      spm_unit:
        members: [person1, person2, person3, person4]
    households:
      household:
        members: [person1, person2, person3, person4]
        state_code:
          2026: IA
  output:
    # 8-E p.12: neither spouse is an ineligible spouse, because each has
    # full non-MAGI-related Medicaid as an SMME applicant. The couple's
    # income is combined with no child allocations:
    # (2,500 + 2,000 - 20 - 65) / 2 = 2,207.50, at least the two-person
    # 2,164. With 994 of allocations taken from the other spouse's wages,
    # it would be (2,500 + 1,006 - 85) / 2 = 1,710.50.
    ia_ssa_smme_spousal_deeming_applies: [true, true, false, false]
    ia_ssa_smme_countable_income: [2_207.5, 2_207.5, 0, 0]
    ia_ssa: [1, 1, 0, 0]

Optional size-trap case: wages 1,700; spouse aged 70 with SS 12,000 a year; three children; both SMME. Expect SMME income [1,797.5, 1,797.5] and ia_ssa [0, 0].

Case numbers assume that Cases 98-104 are all appended in order. If you skip an optional case (100, 101 or 104), renumber the later ones.

Suggestions

New:

  • G66. The flag's comments, label and documentation still describe only the $497 test (merges G59's first bullet).
    • Replace ia_ssa_smme_spousal_deeming_applies.py:24-32 with: 6-B Income (SMME) p.77 determines income "according to SSI income criteria", and 8-E p.11 determines deemed income "for non-MAGI-related Medicaid and State Supplementary Assistance coverage groups according to SSI policies", except the Medically Needy, in-home health-related care, dependent person and MEPD groups. SSI's deeming variables apply only to people SSI treats as aged, blind or disabled, so this test covers a disabled applicant working above the SGA level (Iowa Code 249.3(4)(a)(2), (c)): it is true when the spouse is aged, blind or disabled (income combined) or the spouse's income after child allocations is more than the couple rate less the individual rate (income deemed), unless either spouse is in a medical facility.
    • Label (:11): "Iowa SMME counts a spouse's income for an applicant working above the SGA level" (this also settles G61's label point). Countable documentation (:17): "...any spouse income deemed, or combined for an aged, blind or disabled spouse, under SSI's rules...".
    • The case lists at ia_ssa.py:112-113 and countable :49 include Cases 92 and 96, where the one-person guideline applies. Optional: "Cases 82, 90, 91, 94, 95 and 97; Cases 92 and 96 use the one-person guideline".
    • Case 96 (ia_ssa.yaml:2908-2912): the spouse is aged, so at home the income would be combined, not deemed. Use "the spouse's 520 pension is neither combined nor deemed (the spouse is aged, so at home the couple's income would be combined: 2,106, below the two-person 2,164)".
    • Optional NOTE after :43: "The facility input is read as residence for the whole month (20 CFR 416.414(a)(1)); 8-E p.11 deems for a month in which the applicant lived 'for any part of a month in the same household' with the spouse."
  • G67. Say why the ABD spouse's SSI payment is not added (NOTE only). The joint path adds each spouse's ssi (countable :37); the SA32 path does not. The head is right; do not add ssi. SA32 budgets an eligible couple, which gets no SSI here. The spouse's SSI exists only because SSA treats the worker as an ineligible spouse and takes child allocations, and even then 416.1161(a)(2) and 416.1142(a)(2) exclude SSI. Probe: wages 4,000, spouse aged 70 with no income, three children aged 10 gives 1,957.50 and [0], as on the aged path; adding the spouse's SSI of 279 would give 2,236.50 and [1]. In a 120-household grid, adding SSI flips 18 households, all with three children, because the sum is 1,491 plus 248.50 per child. The joint path's + ssi is harmless (countable plus SSI is at most 1,491, below 1,596). Add after countable :62: # NOTE: The aged, blind or disabled spouse's SSI payment is not added. SSI does not count its own payment as income, and that payment exists only because SSI treats the applicant as an ineligible spouse and takes child allocations (20 CFR 416.1160(d), 416.1163(b)); the eligible-couple budget (8-E p.12) gives no such payment. Optional Case 104 (the probe household; passes at the head and with SA36): expect ssi [0, 279, 0, 0, 0], flag [true, false, false, false, false] and ia_ssa all 0. A mutant that adds SSI fails it.
  • G68. The SA32 comment ties Iowa's test to a federal variable that an open issue may change. ia_ssa_smme_spousal_deeming_applies.py:50-51 says "as is_ssi_ineligible_spouse does". #10243 item 2 asks that ssi_claim_is_joint, is_ssi_eligible_spouse and is_ssi_ineligible_spouse test SSI eligibility, not ABD status; PR #10141 keeps the ABD test. If #10243 lands, the comment is stale, and the helper (which reads is_ssi_aged_blind_disabled) will not follow, which is right because 8-E p.12 is broader. SA36's comment settles this. Without SA36, add to the NOTE at :54-57: "Iowa's test is broader than SSI eligibility, so it does not follow a change to is_ssi_ineligible_spouse (#10243)."
  • G69. The source lists do not name the new sources (PR body and issue only). Add "8-F; 20 CFR 416.1163, 416.1167" to the axiom: line. The corpus list in rulespec-us#1837 names only 6-B, while rows BF-BI cite 8-E, 8-F, 416.1163 and 416.1167; add those four.

Still open from earlier rounds (as written in rounds 4-6, with the updates noted):

  • G36 Four removable branches. G37 Add the "At the discretion of the department" reading to the candidate and the NOTE at ia_ssa.py:130-137. G38 DP couple level for a spouse in residential care: NOTE or "Not modeled" line. G39 State the 249.3(4)(g) upper bound and the 6-B p.77 premium exclusion in the coverage input. G40 Align or split ia_ssa_care_initial_partial_month. G41 Integration Case 12. G42 IHHRC allowance over the tax unit.
  • G44 Link GL 6-B-47 (https://hhs.iowa.gov/media/18744/download?inline). G45 Relabel countable :19 as 249.3(4)(a)(2); label :23. G46 add() at countable :37, :56-58 and ia_ssa_federal.py:37-39; re-wrap ia_ssa_rcf_couple_budget.py:32. G47 RCF dividends case (care income 1,100, pays 222.57).
  • G48 (PARTIAL) Add the couple at 2,164 through the formula and the SGA switch (wages 20,280 against 20,280.12, SSDI 10,800).
  • G49 ia_ssa_has_spouse: [true, true] in Case 83. G50 IHHRC couple sum, day count, truncation, earnings after entry, later-entering spouse. G51 from: 2023 at candidates.yaml:1988-1990. G52 8-E #page=12 in ia_ssa.py:10-19 and countable :18-24. G53 (a)-(d) as in round 6.
  • G54 (a) Document the cap averaging. (b) The round-6 NOTE at countable :50 (current 416.1112(c)(3) has no marital test; 8-E p.19 says "Not married"); with SA36, say that both spouses' exclusions follow current law.
  • G55 FPG reform timing (ia_ssa.py:125). G56 2025 tests (March 1 and April 0 with SS 18,720; DP 503). G59 (PARTIAL) Optional 249.pdf#page=2 in the flag tuple. G60 Title the 2023 sheet Iowa HHS State Supplementary Assistance Standards (effective January 1, 2023).
  • G61 Rename the module to _ia_ssa_smme_spouse_income.py and prefix both functions; say in the docstrings that callers gate on ia_ssa_has_spouse. With SA36, consider smme_spouse_is_not_ineligible.
  • G62 (corrected wording) Round 6 said that ~is_ssi_aged_blind_disabled "is the guarantee against double counting". That was wrong. The guard limits the flag to applicants whom SSI does not count. It cannot prevent double counting, because countable :69-70 already uses SSI's income for anyone SSI counts; without it, the flag only repeats SSI's own switch to the two-person guideline. A mutant without it changes only the flag in Case 51, in Case 100 and in a 7,776-row household grid. A mutant without ia_ssa_has_spouse (:63) can flip ia_ssa, but only for a household entered with no marital units, which is an input shape, not a family situation. So G62 stays a suggestion. Cases 100 and 101 pin the two operands and pass at the head (a one-line alternative to Case 100: add ia_ssa_smme_spousal_deeming_applies: [false, false, false, false] to Case 51):
- name: Case 100, the SGA-path deeming flag stays false for an SMME applicant whom SSI counts as disabled.
  period: 2026-04
  absolute_error_margin: 0.01
  input:
    people:
      person1:
        age:
          2026: 50
        meets_ssi_disability_criteria:
          2026: true
        # SSDI of $1,800 a month and no wages, so SSI counts the person as
        # disabled.
        social_security_disability:
          2026: 21_600
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person2:
        age:
          2026: 45
        # Wages of $1,000 a month.
        employment_income:
          2026: 12_000
    marital_units:
      couple:
        members: [person1, person2]
    tax_units:
      tax_unit:
        members: [person1, person2]
    spm_units:
      spm_unit:
        members: [person1, person2]
    households:
      household:
        members: [person1, person2]
        state_code:
          2026: IA
  output:
    # SSI deems the spouse's 1,000 > 497 (20 CFR 416.1163), so SSI's own
    # deeming sets the two-person guideline and the SGA-path flag stays false:
    # (1,800 - 20) + (1,000 - 65) / 2 = 2,247.50 > 1,491, so SSI is 0, and
    # 2,247.50 is at least the two-person 2,164. person2's own income is
    # (1,000 - 20 - 65) / 2 = 457.50.
    ia_ssa_smme_spousal_deeming_applies: [false, false]
    ia_ssa_smme_countable_income: [2_247.5, 457.5]
    ia_ssa: [1, 0]

- name: Case 101, without marital units an SMME applicant working above the SGA level in a household of three adults is budgeted alone.
  period: 2026-04
  absolute_error_margin: 0.01
  input:
    people:
      person1:
        age:
          2026: 50
        meets_ssi_disability_criteria:
          2026: true
        # Wages of $3,277 a month, above the $1,690 SGA level.
        employment_income:
          2026: 39_324
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person2:
        age:
          2026: 45
        # A pension of $520 a month.
        pension_income:
          2026: 6_240
      person3:
        age:
          2026: 30
    tax_units:
      tax_unit:
        members: [person1, person2, person3]
    spm_units:
      spm_unit:
        members: [person1, person2, person3]
    households:
      household:
        members: [person1, person2, person3]
        state_code:
          2026: IA
  output:
    # With no marital units, the default unit holds all three people, so
    # ia_ssa_has_spouse is false and each member is budgeted alone:
    # (3,277 - 20 - 65) / 2 = 1,596, at least the one-person 1,596. If
    # person2's 520 pension were deemed it would be 2,106, below the two-person
    # 2,164. person2's own income is 520 - 20 = 500.
    ia_ssa_has_spouse: [false, false, false]
    ia_ssa_smme_spousal_deeming_applies: [false, false, false]
    ia_ssa_smme_countable_income: [1_596, 500, 0]
    ia_ssa: [1, 0, 0]
  • G63 2023 and 2024 cases: 2023-01 RCF, SSI only, 318.59; 2024-01 DP, dependent income 100, 490; 2023-01 DP, 474.

Out of scope / follow-up (federal code on main; record only, not blockers)

  • G57: no open issue covers 416.1161(a)(10). File the round-6 issue (deduct child_support_expense and alimony_expense in ssi_{earned,unearned}_income_deemed_from_ineligible_spouse). Since SA32, (b) and (c) matter only for a spouse who is not ABD.
  • G58 (SSI deeming and a medical-facility stay; the federal files are the same on main):
    • (a) An applicant at the $30 facility rate still gets deemed income (416.1163(f)(5)). #10138 names this only in its "Related" line, and PR #10141 lists it as a follow-up. When it is fixed, Case 96's person2 value changes from 2,106 to 500.
    • (b) A spouse who is not ABD and is in a facility is still deemed on the SSI path. No issue covers it.
    • (c) New: ssi_couple_computation_applies keeps the couple computation, and SSI keeps deeming, when an ABD spouse is in a privately paid facility. Applicant aged 70 with wages 3,277, spouse aged 70 with a 520 pension: the model gives 2,106 and [0, 0]; the rule gives 1,596 and [1, 0]. 416.1801(c) ("Eligible spouse", (3)(iii)) needs the same household except during a 416.1149 temporary absence. A private-pay stay is temporary only under 416.1149(a)(2) (return in the same or next month), because the "regardless of length" rule in (c)(1)(i) is for Medicaid-paid stays. POMS SI 00835.040 C.1.b, SI 00501.154 B, SI 02005.050 D.2 and SI 01310.165 A.1 agree. Cash effect: the facility spouse's SSI is 0 in the model and 494 a month under the rule. #10193 lists separation as out of scope.
    • The two Iowa paths now disagree for a private-pay stay: the SGA path separates (Case 99), and the aged path inherits the Medicaid-only federal test.
    • Proposed issue for (b) and (c): "SSI deeming and the couple computation ignore a spouse who has left the household for a medical facility (20 CFR 416.1167, 416.1149, 416.1801(c))". Include the probe rows, the 494 effect and Iowa Cases 96 and 99. Also consider POMS SI 02005.050 B.3: for a spouse temporarily absent in a Title XIX facility, eligibility uses the couple's combined income and each person's own income only for the payment; the federal variable drops the couple computation for both. This was not assessed for Iowa.
    • In this PR, a NOTE beside ia_ssa.py:114-118 naming (a)-(c) stays optional.
  • #10243 item 2 (eligibility-based couple and ineligible-spouse tests): record only; it is the premise of G68.
  • Federal couple student exclusion: ssi_countable_income takes off only half of a student spouse's exclusion in a couple computation (1,993.29 against 1,790.58 in SA36's student example). The SMME joint path inherits it. A candidate for a federal issue.

Investigated and cleared

  • apart scope: either spouse and any payer is right under 416.1167(a)(1). It correctly overrides eligible_spouse: a Medicaid-paid stay gives 416.414(b)(3)'s separate computation, and a long private-pay stay ends couple status.
  • Both spouses in a facility: 416.414(b)(2) applies only by analogy (the applicant has no SSI), and the household is improbable.
  • sum - own: every call site is gated by ia_ssa_has_spouse, directly or through the flag.
  • Periods and entities: YEAR is_ssi_aged_blind_disabled with this_year; MONTH facility input with period; marital_unit.any in a Person formula is the house pattern.
  • The merge: no Iowa supplement, SSI, MSP or FPG file changed, and the Iowa outputs are unchanged.

PDF Audit Summary

Category Count
Documents 8-E, 8-F, 6-B (re-downloaded); eCFR 416.212, 416.414, 416.1112, 416.1142, 416.1149, 416.1160, 416.1161, 416.1163, 416.1167, 416.1801, 416.1802; four POMS sections; 42 U.S.C. 1382a
New or changed cites 12 checked, 12 correct, 0 wrong (a second read checked 10 of them)
New hrefs 2 of 2 corroborate (eCFR 416.1167; 8-F p.73)
Value mismatches 0
Rule mismatches (code run, pages re-read, confirmed) 1: SA36
Rule branches with no test (mutation-proven, flip ia_ssa) 3: SA35
Inherited federal gaps G57; G58 (a)-(c); couple student exclusion
Rejected Adding the spouse's SSI payment (G67); round 6's optional-case spouse value of 1,491

Validation Summary

Check Result
Regulatory SA31-SA34 resolved and correct; SA36; G58(c); G66, G68
References and pages 12/12 correct; no printed page number; G52, G59 partial; G69
Code patterns ruff clean; periods, entities, vectorization correct; no hard-coded value; G61 wider
Tests Cases 94-97 recompute; 6 of 8 targeted mutants killed; all 5 survivors closed by Cases 98-101; SA35; G48 partial; G62 corrected
Verification SA35's three gaps CONFIRMED (survive 126/126, flip ia_ssa); G48 PARTIAL CONFIRMED; G62 guard cannot double count (7,776-row grid); spouse SSI payment: head correct; SA36 CONFIRMED with four flip shapes, fix tested; G58(c) CONFIRMED (federal); #10138 and #10243 content CONFIRMED
Local runs 126/126 Iowa; 452 code-health (1 skipped); source conflicts 103; registry 767 (10 skipped, none Iowa)
Branch 45 ahead, 34 behind; MERGEABLE; CI 27/0; staleness did not affect findings
Partner tests None touched

Review Severity: REQUEST_CHANGES

Two should-address items are open (SA35, SA36), both in the round-7 code. No critical item is open. SA31-SA34, G64 and G65 are resolved.

Next Steps

  1. SA35: append Cases 98 and 99. No code change is needed.
  2. SA36: apply the helper, ia_ssa_smme_countable_income.py and ia_ssa.py changes with the comment updates; change Case 98's person2 value to 2,186; append Cases 102 and 103.
  3. Run the Iowa suite once with all changes, and update the PR body and rulespec-us#1837 for the new cases.
  4. Optional: G66-G69, the G62 pins (Cases 100 and 101), the rest of G48 and the carried suggestions.
  5. Outside this PR: file the federal issues for G57(a) and G58(b)-(c).
  6. To auto-fix issues: run the fix-pr workflow for this PR.

@DTrim99

DTrim99 commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator

PR Review (round 7): Add Iowa state supplementation for 2026

Summary

PR #8017 (author: hua7450). This round reviews head 0ad5fc5946. We approved round 6 at 5837b95c64. Since then there is one author commit, 99f005d419, "Address Pavel's round-6 review of Iowa SSA" (5 Iowa files, +237 / −9), and one clean merge of main at 6a92d6a983. Our review wasn't re-requested. Pavel posted a round-7 review of this head today (17:42 UTC).

What the commit does. It applies Pavel's round-6 items SA31-SA34 as he proposed them:

  • SA31: nothing is deemed when either spouse is in a medical treatment facility (apart; 20 CFR 416.1167). Case 96 tests this.
  • SA32: a spouse whom SSI treats as aged, blind or disabled (ABD) is not an "ineligible spouse" (8-E p.12). So the couple's income is combined, with no $497 test and no child allocations. Case 97 tests this.
  • SA33 and SA34: Cases 94 and 95 pin the order of the child allocation and the $497.01 side of the threshold. Case 94 also closes our round-6 suggestion 1.

What I found.

  • The new code is right for every household it tests.
    • I checked all 13 new expectations (Cases 94-97) by hand.
    • No existing expectation changed. The new gates can't reach Cases 77, 82 or 87-93.
    • Nothing is counted twice.
    • The NH Add New Hampshire state supplementation for 2026 #10156 key lesson doesn't apply, because the commit adds no variable.
  • Our three round-6 suggestions are all fixed. They were a case with a child, the stale Case 82 clause in the PR body, and the stale details in rulespec-us#1837.
  • Two should-address items remain. Pavel's round-7 review reports both (his SA36 and SA35). I confirmed each one by hand, on my own.
    1. SA32's spouse-status rule only runs one way.
      • The ABD spouse in the same couple still gets SSI's deeming from the applicant, after child allocations.
      • Two disabled workers above the SGA level still deem each other.
      • With ineligible children, the two spouses' SMME results disagree. One household gets [1, 0] where the rule gives [1, 1].
    2. Three new branches have no test. They are: no allocations for an ABD spouse, apart for an applicant in a facility, and apart for a private-pay stay. Each one-line mutant passes all 126 cases and flips ia_ssa.
  • Two suggestions: the label and documentation still describe deeming only, and the source lists in the axiom line and the issue are incomplete.
  • CI and branch. CI is green: 27 of 27 checks pass at this head. The merge with main is clean (39 behind).

Prior findings

Finding Status Evidence
Round 6, Suggestion 1: add a case for the child-allocation step Fixed Case 94 (January 2026) uses Pavel's SA33 version, which is better than the case we proposed. The child's 497 allocation takes the spouse's 200 pension first, then 297 of wages. Our case had a spouse with no unearned income, so it would have missed an earned-first mutant. Case 94 catches it: that mutant gives 2,189 and pays $1, while the case expects 2,099 and $0.
Round 6, Suggestion 2: a stale clause in the PR body's test list Fixed The SMME test bullet now reads "...the one-person guideline for a spouse in a medical facility and a spouse whose $497 pension SSI doesn't deem, against the two-person guideline for a $498 pension that it does (Cases 81, 83 and 84), and spouse income deemed to an SGA worker ... (Cases 82 and 90-92)". It also lists Cases 94-97.
Round 6, Suggestion 3: stale details in rulespec-us#1837 Fixed Step 1 now says "Parameters from 2023-01-01 ... with the 2023-2025 values listed in the summary". The summary says "15 formulas". The Required outputs table has a row for ia_ssa_smme_spousal_deeming_applies. The Payment row now uses the two-person guideline "when SMME income includes a spouse's income ... and otherwise for one, using the prior year's guideline before April". Row BD says "As AQ, April 2026", and row AQ now says "≥ 1,565 (January)".
Round 6, "edge cases I checked and am not raising": which spouses count as ineligible We were wrong; now fixed for the applicant In round 6 we cleared this. We argued that an aged spouse with too much income for SSI is "not eligible for SSI", so deeming is right. That missed a spouse who is eligible for a non-MAGI group without SSI, such as a Medicare Savings Program ("People in Medicare savings programs", 8-F p.74). Pavel's three flip rows were right. The fix and Case 97 are correct. The remaining gap is new finding 1.
Round 3, Critical 1 (SGA path: student exclusion and in-kind support and maintenance) Closed in round 5 Cases 87 and 88 are unchanged. Both have one person, so the new gates don't apply.

Pavel's round-6 items, applied as he proposed them and checked as new code:

Item Status Evidence
SA31: a spouse in a medical facility Fixed; correct ia_ssa_smme_spousal_deeming_applies.py:36-46 and :64, with the 416.1167 link at :16. The rule and its text are under Verified. In Case 96, dropping ~apart would give 2,106 against 2,164, so $0, and the case expects $1.
SA32: an ABD spouse is not an ineligible spouse Fixed for the applicant; correct as far as it goes _smme_spouse_income.py:4-9 and :22-24, and flag :47-65. In Case 97, dropping eligible_spouse would leave 400 ≤ 497, so one person: 1,596 against 1,596 pays $1, and the case expects $0. The other spouse in the same couple isn't covered (new finding 1).
SA33: no test for the child allocation Fixed Case 94. See the hand-check table.
SA34: no test deems the spouse's unearned income Fixed Case 95 deems a $497.01 pension as unearned income. With Case 92 ($497, not deemed), the > test is pinned from both sides.

New findings

Critical (must fix)

None.

Should address

  1. SA32's spouse-status rule runs one way, so one couple is budgeted two ways.

    • What is wrong.

      • Since SA32, the SGA-level applicant uses 8-E's definition: a spouse who is ABD is not an ineligible spouse, so their income is combined with no child allocations.
      • The ABD spouse in the same couple still gets SSI's own figure (ia_ssa_smme_countable_income.py:37, :69-70). SSI treats the applicant as an ineligible spouse, so it deems the applicant's income after child allocations.
      • Under 8-E, though, an SMME applicant who has full non-MAGI Medicaid is not an ineligible spouse either.
      • The status test (_smme_spouse_income.py:4-9) also reads only SSI's ABD status. So two disabled workers above the SGA level still deem each other, after child allocations.
    • Where. ia_ssa_smme_countable_income.py:37, 69-70; _smme_spouse_income.py:4-9; ia_ssa.py:114-118.

    • Sources.

      • 8-E p.12: "An ineligible spouse is a spouse who is not eligible for SSI or non-MAGI-related Medicaid, or State Supplementary Assistance."
      • 8-F p.73 lists among the non-MAGI groups "State Supplementary Assistance (SSA) recipients" and "Blind or disabled people who become ineligible for SSI due to 'substantial gainful activity' (1619b people)". SMME is itself State Supplementary Assistance.
      • SSI's own definition is broader: "Ineligible spouse means someone who lives with you as your husband or wife and is not eligible for SSI benefits" (20 CFR 416.1160(d)).
      • SA32 chose 8-E's narrower definition, but only for the applicant. So the two definitions now meet inside one couple.
    • Traces. All in April 2026. person1 is 50, disabled and above the SGA level. Both spouses have the SMME category and coverage.

      Household (monthly) Head Rule (8-E: neither spouse is ineligible, so income is combined)
      A. Wages 2,500; spouse aged 70 with SS 1,400; two children aged 10 person1: (1,400 − 20) + (2,500 − 65) / 2 = 2,597.50 ≥ 2,164, so $1. person2: SSI deems person1's wages after two 497 allocations, 2,500 − 994 = 1,506 > 497, giving (1,400 − 20) + (1,506 − 65) / 2 = 2,100.50 < 2,164, so $0. [1, 0] 2,597.50 each, [1, 1]
      B. Two disabled workers above the SGA level (wages 2,500 and 2,000); two children Neither is ABD under SSI, so each deems the other after 994 of allocations: (2,500 + 1,006 − 85) / 2 = 1,710.50 each. [0, 0] (4,500 − 85) / 2 = 2,207.50 each, [1, 1]
      A without children 2,597.50 each, [1, 1] Same
      • Without children, deeming and combining give the same result. So the gap needs ineligible children.
      • Before this commit, household A was deemed consistently from both sides ([0, 0]). The split is new.
      • Household B's half is older. The round-6 code gives the same 1,710.50, and we missed it then. SA32's own reasoning now covers it.
    • Why should, not critical.

      • The effect is $1 a month, and only households with the input set are affected.
      • The rule rests on 8-E's definition plus the "SSI policies" eligible-couple budget, while SSI's 416.1160(d) would deem. That is a tension between sources, and the recommendation below is clear.
      • The PR has already chosen 8-E's reading (SA32). The problem is that it applies the reading halfway.
    • Fix. Apply the same status test from both sides:

      • (i) In smme_spouse_is_aged_blind_disabled, count an SGA-level applicant with ia_ssa_smme_coverage_eligible as not an ineligible spouse.
      • (ii) When an ABD person's spouse is an SGA applicant whose flag is true, give the ABD person the applicant's combined income instead of SSI's deemed figure.
      • (iii) In ia_ssa, give that ABD person the two-person guideline.

      Pavel's round-7 SA36 patch does this: a helper rewrite, three lines in ia_ssa_smme_countable_income.py and one term in ia_ssa.py. I read it but did not run it. He reports that it passes the 126 cases with Cases 82 and 90-97 unchanged. Add his Cases 102 and 103. I checked their expectations by hand: [2,597.5, 2,597.5] with ia_ssa [1, 1] (household A), and [2,207.5, 2,207.5] with [1, 1] (household B).

      If the maintainers prefer SSI's definition for the ABD spouse, say so in a NOTE and in the "Not modeled" line, and pin household A. That still budgets one couple two ways, so the code fix is better.

  2. Three new branches have no test, and each mutant flips ia_ssa.

    • (a) No allocations for an ABD spouse (_smme_spouse_income.py:22-24).
      • No case has a child together with an ABD spouse.
      • Household (April 2026): wages 3,277; a spouse aged 70 with SS 600; one child aged 10.
      • Head: (600 − 20) + (3,277 − 65) / 2 = 2,186 ≥ 2,164, so $1.
      • Mutant that keeps the allocation: 600 − 497 = 103, so (103 − 20) + 1,606 = 1,689, so $0.
    • (b) apart when the applicant, not the spouse, is in a facility (ia_ssa_smme_spousal_deeming_applies.py:44-46, marital_unit.any).
      • Case 96 puts only the spouse in the facility.
      • Household (April 2026): the applicant, with wages 3,277, is in a facility; the spouse, aged 45 with a 520 pension, is at home.
      • Head: (3,277 − 85) / 2 = 1,596 ≥ 1,596, so $1.
      • Mutant that tests only the spouse: 520 > 497 is deemed, so (520 − 20) + 1,606 = 2,106 < 2,164, so $0.
    • (c) apart for a private-pay stay.
      • Case 96 sets ssi_medicaid_pays_majority_of_care: true.
      • The code reads ssi_lives_in_medical_treatment_facility whoever pays, which 416.1167(a)(1) supports.
      • A mutant that uses the Medicaid-paid living arrangement instead, as ssi_couple_computation_applies does, passes all 126 cases.
      • Household (b) with a private-pay stay flips it.
    • Sources.
      • 8-E p.12 takes the allocations only "When deeming income from an ineligible spouse" (steps 1-2).
      • 20 CFR 416.1167(a): a temporary absence is when "(1) You, your ineligible spouse, parent, or an ineligible child leaves the household but intends to and does return in the same month or the month immediately following; or (2) You enter a medical treatment facility and are eligible for either benefit payable under § 416.212". An applicant above the SGA level has no 416.212 benefit, so only (1) applies, whoever pays.
    • Why should.
      • These are missing tests for changed logic, and each mutant flips eligibility.
      • In round 6 we rated the untested child-allocation step a suggestion because it mirrored main's tested federal deeming formulas.
      • These three branches are Iowa-only and mirror no tested federal code. The federal couple computation keys on the Medicaid-paid arrangement and on one spouse being in a facility.
    • Fix (no code change). Append Pavel's Cases 98 and 99. I checked them by hand at the head:
      • Case 98 (household (a)): SMME [2,186, 1,937.5, 0], ia_ssa [1, 0, 0]. person2's 1,937.50 is SSI's deeming with the allocation: (600 − 20) + (3,277 − 497 − 65) / 2. It becomes 2,186 under the fix for finding 1.
      • Case 99 (household (b), private pay): SMME [1,596, 500], ia_ssa [1, 0].

Suggestions

  1. The flag's label, header comment and documentation still describe deeming only.
    • Label (ia_ssa_smme_spousal_deeming_applies.py:11): "deems spouse income".
    • Header comment (:24-32): it describes only "a spouse's income after child allocations is deemed when it is more than the couple rate less the individual rate".
    • Countable documentation (ia_ssa_smme_countable_income.py:17): "any spouse income deemed under SSI's rules".
    • Since SA32, the flag is also true when an ABD spouse's income is combined, with no $497 test.
    • Case 96's comment (ia_ssa.yaml:2910) says "with deeming it would be 2,106". That spouse is aged 70, so at home the income would be combined (the same 2,106).
    • Fix:
      • Label: for example, "Iowa SMME counts a spouse's income for an applicant working above the SGA level".
      • Documentation: "... any spouse income deemed, or combined for an aged, blind or disabled spouse, under SSI's rules ...".
      • Header: add that the flag is also true for an ABD spouse, and false when either spouse is in a medical facility.
      • Pavel's G66 has the same text.
  2. The source lists don't name the new sources.
    • The axiom: line names 8-E but not 8-F or 20 CFR 416.1163 and 416.1167, which the new code and rows BF-BI rely on.
    • rulespec-us#1837's corpus table lists only 6-B among the Iowa manuals.
    • Add them in both places. This is Pavel's G69.

Verified

The rule.

  • 8-E PDF p.11 deems when "An eligible person was living for any part of a month in the same household with an ineligible spouse".
  • 8-E PDF p.12 defines the ineligible spouse (quoted above), and steps 1-3 take the child allocations from unearned income first and deem nothing at "$497" or less.
  • 8-F PDF pp.73-74 (I read both pages myself): "People who are aged, blind, or disabled may be eligible for Medicaid ... These are referred to as 'non-MAGI-related' coverage groups", including "SSI recipients", "People in Medicare savings programs" and 1619(b) workers, and "Use the Supplemental Security Income program policies ... for these coverage groups".
  • 416.1167(a)(1) and (2) are as quoted above. The code comment's reading, that an absence is temporary only with a return in the same or the next month, is correct. The NOTE says that intent to return isn't modeled, as in ssi_couple_computation_applies.

The code.

  • apart (:44-46).
    • It reads ssi_lives_in_medical_treatment_facility, a monthly input, for the month.
    • marital_unit.any covers either spouse.
    • It overrides eligible_spouse, which is right: a spouse who isn't a household member is neither deemed nor combined.
  • eligible_spouse (:58, _smme_spouse_income.py:4-9).
    • It computes marital_unit.sum(abd) − abd > 0 on the yearly is_ssi_aged_blind_disabled (read through period.this_year).
    • Every call is gated by ia_ssa_has_spouse, a two-person marital unit that SSI's spouse test pairs. Inside the countable formula, that gate comes through the flag (deemed). So "sum minus own" is the other spouse only.
  • Allocations (:22-24). They are multiplied by ~eligible_spouse, so an ABD spouse's income is combined in full. That matches 8-E, where allocations are part of deeming from an ineligible spouse only.
  • No double counting.
    • For the applicant, ssi_claim_is_joint needs two ABD members, so joint is false. is_ssi_spousal_deeming_applies is defined_for = is_ssi_eligible_individual, so it is false too. The spouse's income enters only through the new flag, and only into own_income.
    • For the ABD spouse, the flag is false, because the applicant term needs ~is_ssi_aged_blind_disabled. That spouse's figure is SSI's own, which is what finding 1 is about. Neither person's income goes into both figures.
  • Earlier cases are unchanged.
    • The commit only appends lines to ia_ssa.yaml (one hunk at the end of the file).
    • Cases 82 and 90-92 have a spouse aged 45 at home and no child, so apart and eligible_spouse are false and the allocations are 0.
    • Cases 77, 87, 88, 89 and 93 have one person, so ia_ssa_has_spouse is false.
    • Case 81's applicant is aged, so the flag is false.
    • CI confirms all of them at this head.
  • NH Add New Hampshire state supplementation for 2026 #10156.
    • The commit adds no variable. The new function returns a bool, used only with ~, |, & and multiplication.
    • apart reads a federal monthly bool.
    • No parameter or breakdown is keyed by anything new, so there is no multi-state lookup risk.
  • Callers. smme_spouse_income is still called only by the flag and by ia_ssa_smme_countable_income. smme_spouse_is_aged_blind_disabled is called only by the flag and by the helper.

Edge cases I checked and am not raising.

  • The ABD spouse's SSI payment is not added on the combined path, although the joint path adds ssi.
    • I agree with the head.
    • An eligible-couple budget gives no SSI payment to add. The spouse's SSI exists only because SSA deems with child allocations.
    • The joint path's + ssi can't change an outcome, because countable income plus SSI is at most 1,491, below 1,596.
    • Pavel's G67 suggests a NOTE, which is optional.
  • The facility input is read as residence for the month. 8-E p.11 deems for a month in which the applicant lived "for any part of a month" with the spouse, so a month of entry would still deem. The input's meaning (416.414) and the NOTE cover this, and it is rare.
  • Federal SSI deeming ignores a facility stay (Case 96's person2 still gets 2,106). This is federal code (Pavel's G58), outside this PR, and the case comment says so.

Hand-checked expectations (all new). The 2026 figures are: SSI 994 / 1,491, SGA 1,690. 120% of the guideline is 1,596 / 2,164 from April (2026 guideline) and 1,565 / 2,115 before April (2025 guideline).

Case Period Hand computation Expected Result
94, ssi_ineligible_child_allocation 2026-01 Child aged 10 with no income: 1,491 − 994 = 497 a month; the adults get 0 [0, 0, 497] Correct
94, flag 2026-01 person1: disabled, 50, wages 20,400 / 12 = 1,700 > 1,690, so not ABD. The spouse, 45, isn't ABD. Allocation: 200 of pension, then 297 of wages, leaving 0 + 2,583 > 497. person2 and person3 aren't applicants [true, false, false] Correct
94, SMME income 2026-01 No unearned income, so the $20 comes off earned income: (1,700 + 2,583 − 20 − 65) / 2 = 2,099. person2's own: (200 − 20) + (2,880 − 65) / 2 = 1,587.50. Child: 0 [2,099, 1,587.5, 0] Correct
94, ia_ssa 2026-01 2,099 < 2,115 (two people before April: 1.2 × 21,150 / 12) [0, 0, 0] Correct
95, flag 2026-01 Pension 5,964.12 / 12 = 497.01 > 497 [true, false] Correct
95, SMME income 2026-01 (900 + 497.01 − 20) + (2,000 − 65) / 2 = 1,377.01 + 967.50 = 2,344.51. person2: 497.01 − 20 = 477.01 [2,344.51, 477.01] Correct
95, ia_ssa 2026-01 2,344.51 ≥ 2,115 [1, 0] Correct
96, flag 2026-04 The spouse is in a facility, so apart makes it false. person2 is aged, so not an applicant [false, false] Correct
96, SMME income 2026-04 person1: (3,277 − 20 − 65) / 2 = 1,596. person2 is on SSI's path, where federal deeming ignores the facility: (520 − 20) + (3,277 − 65) / 2 = 2,106; SSI $0 [1,596, 2,106] Correct
96, ia_ssa 2026-04 One person: 1,596 ≥ 1.2 × 15,960 / 12 = 1,596 [1, 0] Correct
97, flag 2026-04 The spouse is 70, so ABD and an eligible spouse: true although 400 ≤ 497 [true, false] Correct
97, SMME income 2026-04 (400 − 20) + (3,277 − 65) / 2 = 1,986. person2's SSI deeming gives the same 1,986, and SSI is $0 [1,986, 1,986] Correct
97, ia_ssa 2026-04 1,986 < 2,164 (two people) [0, 0] Correct

Other checks.

Axiom line assessment

The line reads TheAxiomFoundation/rulespec-us#1837 queued, and it is valid.

  • The issue is OPEN, labelled pe-parity and dispatch-ready. It was updated at 2026-10-23 23:24 UTC, with the push.
  • It matches the head:
    • 126 cases (97 in ia_ssa.yaml) and "15 formulas".
    • A Required outputs row for the flag, with the facility and ABD-spouse terms.
    • New rows BF (Case 94), BG (95), BH (96) and BI (97). Each matches my hand traces: 2,099 < 2,115; 2,344.51 ≥ 2,115; 1,596 ≥ 1,596; 1,986 < 2,164.
    • The SGA interpretation bullet is rewritten with cases BF-BI.
    • The dispatch range is "A to BI".
  • Sources. The companion values come from 8-E, 8-F and the regulation, not from PolicyEngine output.
  • When the should items are fixed, add rows for the new cases, and update the flag row and the SGA bullet for finding 1. Suggestion 2 covers the source lists.

CI status

gh pr checks 8017, rechecked at 18:50 UTC: 27 pass, 0 fail, 0 pending.

Branch status

Verdict: REQUEST_CHANGES

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

Round 7: Pavel's SA31-SA34 are applied correctly (no deeming when either spouse is in a facility, an ABD spouse combined, child-allocation order pinned), all 13 new expectations hand-check, and our round-6 suggestions are done. Two should-address items, both matching Pavel's newer SA35/SA36: (1) the SA32 rule runs one way only, so an ABD spouse is still deemed from the SGA applicant and one couple is budgeted two ways ([1, 0] where 8-E p.12 gives [1, 1]); (2) three new branches have no test, and each mutant passes all 126 cases while flipping ia_ssa (his Cases 98 and 99 hand-check). Full report in the comment above.

hua7450 and others added 2 commits October 26, 2026 15:06
- SA36: apply 8-E p.12's ineligible-spouse rule from both sides. An SMME
  applicant working above the SGA level is not an ineligible spouse, so the
  aged, blind or disabled spouse gets the couple's combined income with the
  two-person guideline, and two such applicants are combined with no child
  allocations. The spouse's own student exclusion comes off before combining.
- SA35: Cases 98 and 99; Cases 100-108 pin every new term (mutation-checked);
  Case 109 pins the residential care dividend exclusion.
- Rename the helper module and functions with the ia_ssa prefix (G61), and
  update comments, labels, documentation and references (G44, G45, G49,
  G51, G52, G54, G59, G60, G66, G67).
- NOTEs cite the new federal issues 10454, 10455 and 10456; register the
  married student exclusion as a source-conflict candidate.
- Case 73 pins the deeming flag instead of the June SSI amount that PR 10141
  changes.

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

hua7450 commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks, Pavel and David. SA35 and SA36 are applied as you wrote them in a330305, and main is merged in 4aae08a. David's round-7 findings 1 and 2 and both suggestions are the same items (SA36, SA35, G66, G69). I also closed the gaps your method would find in the new SA36 code, and filed the federal issues.

Should address

  • SA35: Cases 98 and 99 are your text, with Case 98's spouse value changed to 2,186 for SA36.
  • SA36:
    • ia_ssa_smme_spouse_income is your helper, and the three-line combined override is in ia_ssa_smme_countable_income. ia_ssa.py has the size term.
    • Your comment text is in place, with the 8-F page 88 citation and the NOTE naming the SMME coverage input.
    • Cases 102 and 103 are your text.
    • Two departures, both from your own suggestions:
      • The module and functions carry the program prefix (G61): _ia_ssa_smme_spouse_income.py, with ia_ssa_smme_spouse_is_not_ineligible, ia_ssa_smme_spouse_is_sga_applicant and ia_ssa_smme_spouse_income.
      • 8-F page 88 is folded into the existing 8-F entry ("8-F PDF pages 73-74, 88"), because the repo allows one reference entry per source.

Tests for the SA36 terms (mutation-checked). Removing each term below fails the listed case:

Term Case
Size term in ia_ssa.py (your optional size-trap case, with wages of 1,900 so the worker isn't $10 above SGA) 105
Spouse's student exclusion (your third trap) 106
Coverage test in the spouse status 107
Coverage test in ia_ssa_smme_spouse_is_sga_applicant 108
Combined override 98, 102, 104, 105
Child-allocation gate 98, 102, 103, 105, 107, 108
Adding the spouse's SSI payment (G67) 104, 105

Cases 107 and 108 give the uncovered worker an undocumented status, so the expected value holds under any reading of MEPD. The NOTE says a disabled worker with another non-MAGI group but no SMME coverage input is deemed.

Suggestions done

Federal issues (G57, G58 and the couple student exclusion)

Still deferred:

  • G37-G42, G46, G50, G53, G55, G56, G63, and the rest of G48.
  • G36: the four branches are in code that no review item has changed, and I'd rather not add cases whose values I'd have to derive without a published example. I'll take them in a follow-up.

138 Iowa supplement cases pass locally (109 in ia_ssa.yaml), and test_source_conflicts.py passes (103).

@DTrim99

DTrim99 commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

PR Review (round 8): Add Iowa state supplementation for 2026

Summary

PR #8017 (author: hua7450). This round reviews head 4aae08acae. We requested changes in round 7 at 0ad5fc5946. Since then there is one author commit, a330305e77, "Address Pavel's and David's round-7 reviews of Iowa SSA" (11 files, 1,185 diff lines), and one clean merge of main at dbfc017665. The author re-requested our review. Pavel hasn't reviewed this head yet.

What the commit does.

What I found.

  • All four round-7 items are fixed.
    • I checked every new or changed expectation by hand: Case 73's new pin, Case 83's new line, and Cases 98-109.
    • The new code is right for every household it tests.
    • I traced each one-line mutant the author lists, and each one fails the case named.
    • The NH Add New Hampshire state supplementation for 2026 #10156 key lesson doesn't apply: the commit adds no variable, and every new term is a bool.
  • One new should-address item comes from main, not from the commit. Iowa LIHEAP merged on main (Add Iowa LIHEAP regular heating assistance #10292) 28 minutes after the author's comment. Its income list counts ssi but not ia_ssa, which doesn't exist on main. The Iowa LIHEAP manual counts State Supplementary Assistance as income. On the merged tree, Iowa LIHEAP would leave out every Iowa supplement. The fix is one line in each of two lists, plus a case.
  • One suggestion: the 1619(b) rationale in the new comments is narrower than the rule the code applies.
  • CI and branch. CI is green: 32 of 32 checks pass at this head. The merge with main is clean (18 behind).

Prior findings

Finding Status Evidence
Round 7, Should 1: SA32's spouse-status rule runs one way, so one couple is budgeted two ways Fixed Applied as Pavel's SA36 patch, with the ia_ssa prefix (G61). ia_ssa_smme_spouse_is_not_ineligible counts meets_ssi_disability_criteria & ~abd & ia_ssa_smme_coverage_eligible as a status, together with ABD (_ia_ssa_smme_spouse_income.py:774-789). Household A is now Case 102: [2,597.5, 2,597.5] and ia_ssa [1, 1]. Household B is now Case 103: [2,207.5, 2,207.5] and [1, 1]. Both match my round-7 hand values. Pavel's three traps are covered: the size term (Case 105), the spouse's student exclusion (Case 106) and the coverage terms (Cases 107 and 108).
Round 7, Should 2: three new branches had no test Fixed (a) Case 98: child plus an ABD spouse. 2,186 ≥ 2,164 pays $1; keeping the allocation gives 1,689 and $0. (b) and (c) Case 99: the applicant is in a privately paid facility. 1,596 ≥ 1,596 pays $1. Testing only the spouse, or requiring a Medicaid-paid stay, deems the 520 pension: 2,106 < 2,164, $0.
Round 7, Suggestion 1: the label, header and documentation described deeming only Fixed The label (ia_ssa_smme_spousal_deeming_applies.py:11) is "Iowa SMME counts a spouse's income for an applicant working above the SGA level". The header (:26-37) covers both combining and deeming, and the facility exception. The countable documentation (:18) adds the combined case and the ABD spouse's figure. The Case 96 comment now says "neither combined nor deemed".
Round 7, Suggestion 2: the source lists didn't name the new sources Fixed The axiom: line now names 20 CFR 416.1163 and 416.1167 and 8-F. In rulespec-us#1837, the corpus table has rows for 8-E and 8-F (8-E pp.11-13, 19, 23, 36; 8-F pp.73-74, 88) and for 20 CFR 416.1112(c)(3), 416.1163 and 416.1167.
Round 6: which spouses count as ineligible Fixed for both spouses Round 7 fixed it for the applicant. This round fixes it for the ABD spouse (Should 1 above).
Round 3, Critical 1: SGA path, student exclusion and in-kind support and maintenance Closed in round 5 Cases 87 and 88 are unchanged. Both have one person, so the new terms can't reach them.

Pavel's round-7 suggestions in this commit (checked, not ours):

  • G44: GL 6-B-47 is linked. Its page 1 reads "The personal needs allowance for residential care facility and family-life home is $130."
  • G47: Case 109.
  • G49: Case 83 asserts ia_ssa_has_spouse [true, true].
  • G51: the candidate now reads from: 2023.
  • G52: an 8-E #page=12 href in ia_ssa.py and the countable formula.
  • G54(b): a NOTE and the new candidate.
  • G59: 249.pdf#page=2 in the flag.
  • G60: the titles of the 2023 sheet.
  • G62: Cases 100 and 101.
  • G66: comments and labels.
  • G67: a NOTE and Case 104.
  • G69: the source lists.
  • Still deferred: G36-G42, G46, G48 (rest), G50, G53, G55, G56 and G63. These are Pavel's suggestions, so they don't block.

New findings

Critical (must fix)

None.

Should address

  1. On the merged tree, Iowa LIHEAP doesn't count the Iowa supplement, which its manual counts as income.
    • What is wrong.
      • Add Iowa LIHEAP regular heating assistance #10292 put Iowa LIHEAP on main at 2026-10-26 19:49 UTC. That was after this PR's last push (19:06 UTC) and after the author's comment (19:21 UTC).
      • Its countable unearned income adds each source in gov/states/ia/hhs/liheap/income/sources/unearned.yaml. The list has ssi but not ia_ssa, because ia_ssa doesn't exist on main.
      • After this PR merges, every Iowa State Supplementary Assistance payment is left out of LIHEAP countable income. That includes the federally administered parts (ia_ssa_federal) and the state-paid parts.
      • Examples: a blind SSI recipient's $22 a month ($264 a year in 2026), or the dependent-person supplement's $518 a month (ia_ssa.yaml Case 4).
    • Where. On main, so they reach this branch with the next merge: policyengine_us/parameters/gov/states/ia/hhs/liheap/income/sources/unearned.yaml and fixed.yaml. The formulas that read them are ia_liheap_countable_unearned_income.py and ia_liheap_fixed_income_only.py.
    • Source.
      • Iowa LIHEAP FY26 Policy and Procedures Manual, Appendix C Income Source Guide, row "Social Security Benefits (SSA, SSI, SSDI)" (PDF p.114).
      • The row is marked "Counted as Income?" Yes, income code C. Its definition column includes "SSA (State Supplementary Assistance) - Fully state-funded" and "SSI (Supplemental Security Income) - Federally-funded".
      • main's Iowa LIHEAP code already cites this page for SSI and Social Security.
    • Precedent. Alabama's and Kentucky's LIHEAP lists include their state supplements: al_ssp in al/adeca/liheap/income/sources/unearned.yaml, and ky_ssp in ky/dcbs/liheap/unearned_income_sources.yaml.
    • Why should.
    • Fix.
      • After merging main, add - ia_ssa to ia/hhs/liheap/income/sources/unearned.yaml.
      • Add it to fixed.yaml as well. ia_liheap_fixed_income_only treats every unearned source that isn't in fixed as other income. So listing it only in unearned would take the fixed-income-only points away from an SSI recipient with Iowa's blind supplement.
      • The p.114 row puts State Supplementary Assistance among the Social Security benefits, and the fixed list already holds social_security and ssi for that row.
      • Add one Iowa LIHEAP case, for example a blind 65-year-old with only SSI in 2026. Countable unearned income would be 994 × 12 + 22 × 12 = 12,192, and ia_liheap_fixed_income_only would stay true.
      • Then rerun the Iowa LIHEAP tests. A blind or care-category member in an existing case would now count the supplement.

Suggestions

  1. The 1619(b) reason in the new comments is narrower than the rule the code applies.
    • Where the reason appears.
      • The flag comment (ia_ssa_smme_spousal_deeming_applies.py:59-63): "a worker above the SGA level who keeps Medicaid is in the 1619(b) group, 'considered to be an SSI recipient' (8-F PDF page 88)".
      • The helper docstring (_ia_ssa_smme_spouse_income.py:775-779): "(8-F PDF page 73, 1619(b) group)".
      • The same reason appears in rulespec-us#1837's flag row and SGA bullet ("whom 8-F p.88 treats as an SSI recipient").
    • Why it is narrower.
      • 8-F p.88 gives that group to "some former SSI recipients who no longer qualify for SSI benefits because their earnings are too high". An SMME applicant who never received SSI isn't in it.
      • The code's conclusion still holds, for a different reason. 8-E p.12 names "State Supplementary Assistance", and SMME is a State Supplementary Assistance category.
      • SMME also requires "full Iowa Medicaid benefits ... under a Medicaid coverage group that does not rely on eligibility for SSA" (6-B p.76).
    • Fix. Rest the sentence on that, for example: "an SMME applicant receives State Supplementary Assistance and full Medicaid (6-B p.76), so is not an ineligible spouse". Keep 1619(b) as one example, and change the rulespec-us#1837 row to match. This is wording only. No behavior or test changes.

Verified

The new rule matches the sources I re-read.

  • 8-E p.12 (revised May 22, 2026; printed page 7): "An ineligible spouse is a spouse who is not eligible for SSI or non-MAGI-related Medicaid, or State Supplementary Assistance."
  • 8-E p.19 lists, for the student exclusion, "Under age 22", "Not married" and "Not the head of the household". The new candidate us-ia:smme-student-exclusion-married and the countable NOTE (:56-61) follow 42 U.S.C. 1382a(b)(1) and 20 CFR 416.1112(c)(3), which have no marital test, under the statute-first rule.
  • 8-F p.88 text is as quoted in Suggestion 1. 6-B p.76 requires full Medicaid for SMME.

The code.

  • ia_ssa_smme_spouse_is_not_ineligible (:774-789). The status is abd | (meets_ssi_disability_criteria & ~abd & coverage). It reads the yearly SSI flags through period.this_year and the monthly coverage input through period. "Sum minus own" is the spouse: every caller is gated by ia_ssa_has_spouse, either directly or through the flag.
  • ia_ssa_smme_spouse_is_sga_applicant (:792-803). It is true only for an ABD person whose spouse has the flag and SMME coverage. For an ABD spouse, the applicant's not_ineligible is always true. So the term reduces to "the applicant is at home, with a paired spouse".
  • The combined override (ia_ssa_smme_countable_income.py:91-98).
    • combined sums income only where applicant is true, and that is the applicant's own_income.
    • Two SGA applicants are never overridden, because the override needs ABD.
    • joint is false for these couples, because it needs two ABD members. So nothing is counted twice.
  • The spouse's income (:806-831).
    • The other spouse's student exclusion is subtracted only when that spouse is not ineligible.
    • Allocations apply only to an ineligible spouse. They come from unearned income first (416.1163(b)(3)).
  • The size term (ia_ssa.py:133) uses the same function as the override, so an ABD spouse's figure and guideline always agree.
  • NH Add New Hampshire state supplementation for 2026 #10156. No new variable. Every new term is a bool used with &, |, ~ or multiplication, and no parameter or breakdown is keyed by anything new.
  • Callers. The three helpers are imported only by ia_ssa.py, ia_ssa_smme_countable_income.py and the flag. The old _smme_spouse_income.py is deleted, and no other file imports it.
  • Earlier cases are unchanged. In Cases 82 and 90-95 the spouse isn't ABD and has no SMME coverage. In Case 96 the flag is false because of apart. In Case 97 the ABD spouse's override gives the same 1,986 as SSI's figure (no children). Cases 77 and 87-89 have one person. CI confirms all of them.

Mutation claims (traced by hand, not run).

  • Without the size term, Case 105's person2 is compared with the one-person 1,596: 1,897.50 pays $1.
  • Without the spouse's student exclusion, Case 106 gives 2,196 and $1.
  • Without coverage in the status, Case 107's person1 combines 2,207.50 and gets $1.
  • Without coverage in the applicant test, Case 108's person2 combines 2,597.50 and gets $1.
  • Without the override, Case 102's person2 gets 2,100.50 and $0.
  • With allocations for every spouse, Case 98's person1 gets 1,689 and $0.
  • Adding the spouse's SSI gives 2,236.50 in Case 104 and 1,911.50 in Case 105.

Each of these contradicts the expected values.

Hand-checked expectations (every new or changed one). The 2026 figures are: SSI 994 / 1,491, child allocation 1,491 − 994 = 497, SGA 1,690, student exclusion 2,410 a month / 9,730 a year. 120% of the guideline is 1,596 / 2,164 from April.

Case Hand computation Expected Result
73 (changed) Yearly: person1 is aged; the spouse's 12,000 > 5,964 a year, so deemed. person2 isn't an eligible individual. ia_ssa June and July are unchanged, because 200 + 843.50 (or 814) − 130 − 1,491 < 0 is_ssi_spousal_deeming_applies [true, false] Correct
83 (added line) A two-person marital unit that SSI's spouse test pairs ia_ssa_has_spouse [true, true] Correct
98 Allocations [0, 0, 497]. person1 is an applicant and the spouse is aged, so flag [T, F, F]. (600 − 20) + (3,277 − 65) / 2 = 2,186, and person2 gets the same through the override. 2,186 ≥ 2,164 SMME [2,186, 2,186, 0]; ia_ssa [1, 0, 0] Correct
99 apart (the applicant is in a facility, private pay), so flag [F, F]. (3,277 − 85) / 2 = 1,596 ≥ 1,596. person2: 520 − 20 = 500 [1,596, 500]; [1, 0] Correct
100 person1 is ABD (SSDI, no wages), so the flag is false. SSI deems 1,000 > 497: 1,780 + 935 / 2 = 2,247.50, SSI 0, ≥ 2,164. person2: (1,000 − 85) / 2 = 457.50 [2,247.5, 457.5]; [1, 0] Correct
101 No marital units, so the default unit has 3 people and ia_ssa_has_spouse is false. 1,596 ≥ 1,596; 500; 0 has_spouse [F, F, F]; flag [F, F, F]; [1,596, 500, 0]; [1, 0, 0] Correct
102 Allocations [0, 0, 497, 497]. 1,380 + 2,435 / 2 = 2,597.50 for both, because person2's override replaces SSI's 2,100.50. Both ≥ 2,164 and both have SMME flag [T, F, F, F]; [2,597.5, 2,597.5, 0, 0]; [1, 1, 0, 0] Correct
103 Each spouse is an SGA applicant with coverage, so both flags are true and there are no allocations: (4,500 − 85) / 2 = 2,207.50 ≥ 2,164 [T, T, F, F]; [2,207.5 × 2, 0, 0]; [1, 1, 0, 0] Correct
104 Allocations 3 × 497. SSI: 4,000 − 1,491 = 2,509 > 497, so 1,491 − (2,509 − 85) / 2 = 279 (under the 994 cap, so #10141 doesn't change it). SMME: (4,000 − 85) / 2 = 1,957.50 < 2,164; person2 gets the same ssi [0, 279, 0, 0, 0]; flag [T, F × 4]; [1,957.5, 1,957.5, 0, 0, 0]; all 0 Correct
105 SSI: 1,900 − 1,491 = 409 ≤ 497, so nothing is deemed (yearly: 22,800 − 17,892 = 4,908 ≤ 5,964). SSI = 994 − 980 = 14. SMME: 980 + 1,835 / 2 = 1,897.50 < 2,164 (two people, through the size term) deeming all F; ssi [0, 14, 0, 0, 0]; flag [T, F × 4]; [1,897.5 × 2, 0, 0, 0]; all 0 Correct
106 person2 is 20, a disabled student below SGA: min(min(2,410, 1,200) × 12, 9,730) / 12 = 810.83. (3,277 + 389.17 − 85) / 2 = 1,790.585. SSI deems 3,277 to person2 and gets the same 1,790.585 > 1,491, so SSI 0. < 2,164 exclusion [0, 810.83]; ssi [0, 0]; flag [T, F]; [1,790.58 × 2]; [0, 0] Correct (within 0.01)
107 person2 has no coverage, so person2 is an ineligible spouse to person1: 2,000 − 994 = 1,006 > 497, deemed: (3,506 − 85) / 2 = 1,710.50. person1 has coverage, so person1 is not ineligible to person2, and person2 combines 2,207.50 (no SMME category) allocations [0, 0, 497, 497]; flag [T, T, F, F]; [1,710.5, 2,207.5, 0, 0]; all 0 Correct
108 person1 has no coverage, so person2 keeps SSI: 2,500 − 994 = 1,506 deemed, 1,380 + 1,441 / 2 = 2,100.50 > 1,491, SSI 0; < 2,164. person1's own figure: 1,380 + 2,435 / 2 = 2,597.50 (no SMME) deeming [F, T, F, F]; ssi 0; flag [T, F, F, F]; [2,597.5, 2,100.5, 0, 0]; all 0 Correct
109 SSI: 1,150 − 20 = 1,130 > 994, so 0. Care income excludes the 50 of dividends: 1,100. 1,192.57 − (1,100 − 130) = 222.57 (January, 31 days) ssi 0; care 1,100; ia_ssa 222.57 Correct

Other checks.

Axiom line assessment

The line reads ... 20 CFR 416.1112(c)(3), 416.1124(c)(22), 416.1163, 416.1167; Iowa HHS Employees' Manual 6-B, 7-E, 8-E, 8-F; POMS SI 01415.058 F TheAxiomFoundation/rulespec-us#1837 queued. It is valid.

  • The issue is OPEN and labelled pe-parity. It was updated at 2026-10-26 19:19 UTC, with the push.
  • It matches the head:
    • 138 cases (109 in ia_ssa.yaml) and "15 formulas".
    • The flag and SMME-income rows describe the two-way status, the coverage terms, the spouse's student exclusion and the ABD spouse's combined figure without SSI.
    • There are new companion rows BJ-BT for Cases 98-100 and 102-109. Each matches my hand traces: 2,186; 1,596; 2,247.50; 2,597.50; 2,207.50; 1,957.50; 1,897.50; 1,790.58; 1,710.50; 2,100.50; 222.57.
    • Case 101 is covered in the "Spouse identification" bullet.
    • The SGA and married-student interpretation bullets are rewritten, and the dispatch range is "A to BT".
  • Sources. The companion values come from 8-E, 8-F, the regulation and the statute, not from PolicyEngine output. Row AF still quotes the manual's $843.50 June SSI, which is correct for a companion test taken from the manual.
  • If Suggestion 1 is taken, reword the flag row and the SGA bullet to match. The should item (Iowa LIHEAP wiring) needs no change to Update New York tax rules for 2022 #1837.

CI status

gh pr checks 8017, rechecked at 2026-10-27 13:44 UTC: 32 pass, 0 fail, 0 pending.

Branch status

Verdict: REQUEST_CHANGES

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

Requesting changes, round 8: 0 critical, 1 should. All round-7 items are fixed. The one open item comes from main: Iowa LIHEAP (#10292) merged after this push. Its income sources need ia_ssa, which this PR adds, plus one case. Full report in the comment above.

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

Program Review (round 8): Add Iowa state supplementation for 2026

PR #8017 (hua7450). Round 8, incremental review of the changes since round 7.

IDs: C = critical, SA = should address, G = suggestion. Prior IDs keep their numbers. New findings start at SA37 and G70. There is no new critical item, so C8 is not used.

Paths: V/ = policyengine_us/variables/gov/states/ia/hhs/ssa/, T = policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml, L/ = policyengine_us/parameters/gov/states/ia/hhs/liheap/income/sources/ (on main), LT = policyengine_us/tests/policy/baseline/gov/states/ia/hhs/liheap/integration.yaml (on main). "Countable" = V/ia_ssa_smme_countable_income.py, "flag" = V/ia_ssa_smme_spousal_deeming_applies.py, "helper" = V/_ia_ssa_smme_spouse_income.py. Line numbers refer to the reviewed head. "p.NN" is the PDF FILE page (8-E FILE = printed + 5; 6-B and 8-F FILE = printed + 4).

Source Documents

  • Reviewed head SHA: 4aae08a
  • Mode: incremental from 0ad5fc5 (round 7, CHANGES_REQUESTED)
  • Commits since round 7: a330305 "Address Pavel's and David's round-7 reviews of Iowa SSA" (11 files, +862 / -80); 4aae08a, a merge of main at dbfc017 that changes no Iowa supplement, SSI deeming, MSP or poverty-guideline file.
  • Scope: the new helper (replaces _smme_spouse_income.py); the combined override in countable; the size term in V/ia_ssa.py; comments, NOTEs and hrefs in the flag, countable, V/ia_ssa.py and V/ia_ssa_federal.py; three parameter titles and the GL 6-B-47 href; Cases 98-109 appended and Cases 73, 83 and 96 edited (138 Iowa cases, 109 in T); source_conflicts/candidates.yaml (from: 2023, new us-ia:smme-student-exclusion-married).
  • Iowa sources: 8-E (https://hhs.iowa.gov/media/4011/download?inline), 8-F (media/4012) and 6-B (media/3987), downloaded again with the same checksums as round 7; GL 6-B-47 (media/18744, p.1); GL 6-B-45 p.24; the 2023 standards sheet (media/9237); Iowa Code ch. 249 pp.2-3 (2023 and 2026); 441 IAC ch. 51 and 52; Iowa LIHEAP FY26 manual (media/17262, pp.81, 97, 103, 114, 116, 118) and the FFY2026 state plan, Section 1.9.
  • Federal sources: eCFR 20 CFR 416.414, 416.1112, 416.1124, 416.1140, 416.1149, 416.1160, 416.1161, 416.1163, 416.1167, 416.1801; LII 42 U.S.C. 1382a with the 2004 amendment note.
  • GitHub (read-only): #10138, #10243, #10454, #10455, #10456; PRs #10141, #10146, #10292; TheAxiomFoundation/rulespec-us#1837.

Branch Status

  • 47 ahead and 32 behind main (4c65c82, 2026-10-27 17:03 UTC). A trial merge is clean: programs.yaml and source_conflicts/candidates.yaml change on both sides and merge automatically. GitHub: MERGEABLE, review decision CHANGES_REQUESTED. CI: 32 pass, 0 fail at 4aae08a.
  • What the newer main commits change:
    • #10292 adds Iowa LIHEAP, which does not count ia_ssa (SA38).
    • #10283 removes gov.ssa.ssi.amount.institutional. No Iowa file reads it.
    • #10453 moves poverty-guideline uprating to gov.hhs.fpg_uprating. The 2026 values do not change. SMME reads the projected 2027 guideline only from April 2027, which no case reaches; from then the one-person threshold rises by about $6 a month.
    • The six newest commits change Illinois EITC, Minnesota AMT, Virginia TANF, Florida TCA and the version. None touches an Iowa supplement, SSI, SSA or LIHEAP file.
  • Local runs: at the head, Iowa SSA 138/138, code health 462 passed (1 skipped), test_source_conflicts.py 103, and ruff format --check and ruff check clean on the 24 Iowa variable files. On the head merged with main (5d093eb): Iowa SSA 138/138 and Iowa LIHEAP 164/164; source-conflict and registry tests 888 passed (10 skipped) on the merge with c2785f6.
  • No partner test file is touched. The changelog fragment and the Iowa programs.yaml entry (verified_years: "2026") are unchanged.
  • Process note (not counted): the axiom: line is present and valid (rulespec-us#1837 is open and labelled pe-parity).

What round 8 fixed

  • SA36, as proposed. The helper bodies, the three-line override (countable :91-98), the size term (V/ia_ssa.py:133) and the comment text are the round-7 text. Your two departures are defensible: the program prefix is G61, and folding 8-F p.88 into one 8-F entry follows the one-href-per-source rule. The rule check holds for every shape tested, including a working SMME spouse whose wages are below the SGA level (2,307.50 for each spouse, [1, 1], the same as on the aged path).
  • SA35. Cases 98 and 99 are the proposed text, with Case 98's person2 value at 2,186 for SA36.
  • Cases 100-109 pin every new term. Your mutation table reproduces exactly: each term fails the cases that you name. Of 31 one-site mutants of the new code, 24 are killed, 4 are equivalent and 3 survive (see G71 and "Investigated and cleared"). The five round-7 survivors that had a proposed case are now killed.
  • Hand values. Every expected value in Cases 98-109 recomputes by hand, and DTrim99 checked them by hand too. Case 106's comment gives 1,790.585 against 1,790.583 in code, inside the 0.01 margin.
  • Case 73. The old June pin (SSI 843.50) protected no Iowa output: June ia_ssa is 615.52 for any June SSI from 0 to 1,421. Case 59 pins the entry-month rule. The new flag pin also holds under PR #10141.
  • Federal issues. #10454, #10455 and #10456 exist, are open and match their NOTEs. The ia_ssa_federal.py move from #10138 to #10243 is right, because PR #10141 keeps the ABD test in ssi_claim_is_joint.
  • References. 35 of 35 new or changed hrefs, titles and cites are correct. No href uses a printed page number.
  • Candidates. G51's from: 2023 is correct. The married-student candidate is a real conflict, follows the statute and cites correctly.
  • No regression. The test diff removes only Case 73's June pin and two comments. No prior expected value changed.

Both new should-address items concern State Supplementary Assistance paid alongside SSI. SA37 comes from the round-7 SA36 patch, which this review proposed: an aged spouse whom SSI pays can now also get the $1 SMME. SA38 comes from main: Iowa LIHEAP does not count ia_ssa.

Round-7 status

ID Status Evidence at 4aae08a; is the deferral defensible?
SA35 RESOLVED Cases 98 and 99. The three round-7 mutants fail them, and each flips ia_ssa
SA36 RESOLVED As proposed, with G61 names. Cases 102-108 pin every term. New edge from the override: SA37
G25 PARTIAL (accepted part stands) New cases use 2026-04 and 2026-01; both fit
G36 DECLINED for now Branches unchanged; three of the four still survive the suite. The reason ("no published example") is weak, because Cases 94-109 are also derived by hand. A deferral of a test suggestion in untouched code is defensible
G37 STILL OPEN (deferred) NOTE V/ia_ssa.py:146-153 and the candidate still omit "At the discretion of the department". Defensible
G38 STILL OPEN (deferred) V/ia_ssa_federal.py changed only in the NOTE cite. Defensible
G39 STILL OPEN (deferred) Coverage input documentation unchanged; the 249.3(4)(g) upper bound is still unstated. Defensible
G40 STILL OPEN (deferred) Files unchanged. Defensible
G41 STILL OPEN (deferred) integration.yaml unchanged. Defensible
G42 STILL OPEN (deferred) V/ia_ssa_ihhrc_participation.py unchanged. Defensible
G44 RESOLVED GL 6-B-47 linked (rcf_personal_needs.yaml:34-35); p.1 states $130, effective January 1, 2026
G45 RESOLVED Countable labels :20, :22, :24. The round-4 remainder (other page lists; unlabeled hrefs at V/ia_ssa_has_spouse.py:14-15) stays optional
G46 STILL OPEN (deferred) Manual sums unchanged; ia_ssa_rcf_couple_budget.py:32 not re-wrapped; no new instance. Defensible (style)
G47 RESOLVED Case 109 (222.57). Removing dividends from excluded_unearned_sources fails only Case 109
G48 PARTIAL No case reaches 2,164 or the SGA switch through the formula. SA37's rewrites of Cases 44, 78 and 89 close the one-person part
G49 RESOLVED Case 83 asserts ia_ssa_has_spouse: [true, true] (T:2461)
G50 STILL OPEN (deferred) Unchanged. Defensible
G51 RESOLVED candidates.yaml:2081. The 2023 sheet lists the $17.86 flat and $35.89 maximum rates; GL 6-B-45 p.24 has both for 2024
G52 RESOLVED 8-E #page=12 at V/ia_ssa.py:22-23 and countable :26-27
G53 STILL OPEN (deferred) fpg_year_start_month.yaml unchanged; RC-0130 still unlinked (T:2264). Defensible
G54 PARTIAL (b) RESOLVED: the NOTE at countable :56-61 covers both spouses, and the candidate is correct. (a) not answered: the cap averaging is undocumented and now also applies to the spouse's exclusion (helper :50). Defensible
G55 STILL OPEN (deferred) V/ia_ssa.py:141 still reads f"{year}-01-01"; gov/hhs/fpg.yaml still exists after #10453. Defensible
G56 STILL OPEN (deferred) Only Case 86 (RCF) is in 2025. Defensible
G57 RESOLVED Helper docstring :43-47 names (a)-(c); #10454 covers (a); open PR #10146 covers (b)-(c)
G58 RESOLVED #10455 covers (a)-(c); NOTE V/ia_ssa.py:121-128; Case 96 cites it
G59 RESOLVED 8-E p.11 scope sentence (flag :26-31); 249.pdf#page=2 in the flag tuple
G60 RESOLVED The three titles match the sheet's heading
G61 RESOLVED Prefixed module and functions; gate sentence in all three docstrings; label
G62 RESOLVED Cases 100 and 101. Dropping the ABD guard fails Cases 100 and 106; dropping ia_ssa_has_spouse fails Case 101
G63 STILL OPEN (deferred) No 2023 case; no 2024 DP case. Defensible
G66 RESOLVED Flag comment :26-37, label :11, countable documentation :18, case lists, Case 96 comment, whole-month NOTE :47-53
G67 RESOLVED NOTE countable :78-82 and Case 104. Adding the spouse's SSI fails Cases 104 and 105
G68 RESOLVED "This test is broader than is_ssi_ineligible_spouse" (flag :66-67)
G69 RESOLVED The axiom: line names 8-F, 416.1163 and 416.1167; the #1837 corpus table lists 8-E, 8-F, 416.1112(c)(3), 416.1163 and 416.1167

Tally: 34 IDs were open after round 7. Now 18 are resolved, 3 are partial (G25, G48, G54), 12 are still open as deferred suggestions and 1 is declined for now (G36). Every open one is a suggestion, and each deferral is defensible.

Critical (Must Fix)

None.

Should Address

SA37. The SA36 override lets an aged spouse whom SSI pays also get the $1 SMME

  • What is wrong: The override gives the ABD spouse of an applicant working above the SGA level the couple's combined income. SSA still treats that applicant as an ineligible spouse, deems after child allocations and can pay the ABD spouse SSI. So that spouse can get both SSI and the $1 SMME. Before SA36 this could not happen: countable income plus SSI is at most 1,491, below 1,596 for one person and 2,164 for two. The round-7 SA36 proposal missed this; the cause is that patch, not your changes to it.
  • Where: countable :94-98 (override) and V/ia_ssa.py:154-161 (the smme term).
  • Source: Iowa Code 249.3(4) requires "all of the following paragraphs", including "c. Would be eligible for supplemental security income benefits but for having excess income or but for being engaged in substantial gainful activity and having excess income" (p.2). A person whom SSA pays is eligible for SSI, so (c) fails. 6-B p.74 states the purpose: "to provide a cash benefit to certain Medicaid recipients who do not qualify for other cash assistance benefits" (6-B p.74). Iowa's eligible-couple budget (8-E p.12) cannot remove an SSI payment that SSA computes under 416.1160 and 416.1163.
  • Evidence (April 2026; person1 aged 50, disabled, SMME with coverage; person2 aged 70, no income, SMME with coverage; children aged 10):
Household person2 ssi Head: SMME [p1, p2]; ia_ssa Rule Round 7 head
Wages 4,500; three children 29 2,207.50 each; [1, 1] [1, 0] [1, 0]
Wages 4,450 / 4,550; three children 54 / 4 [1, 1] [1, 0] [1, 0]
Wages 4,800; four children 127.50 [1, 1] [1, 0] [1, 0]
Wages 4,600; three children (control) 0 [1, 1] [1, 1] [1, 0] (the SA36 gap)
Same as row 1, person1 aged 70 (SSI path) 0 [1, 1] [1, 1] [1, 1]

In row 1, SSA deems 4,500 − 3 × 497 = 3,009, so (3,009 − 85) / 2 = 1,462 and SSI is 1,491 − 1,462 = 29. The override gives (4,500 − 85) / 2 = 2,207.50, at least the two-person 2,164.

  • Reach: three or more ineligible children and a narrow wage band (about 4,413-4,558 a month with three children; 4,413-5,055 with four), plus the SMME inputs on an SSI recipient. $1 a month. Zero in microsimulation: ia_ssa_category defaults to REGULAR and the coverage input to false.
  • Why should address: the SA36 class (a clear rule, a $1 flip, input-gated), and a regression in this round's code. Not critical: the structure is right, and one term closes it. Not a suggestion: 249.3(4)(c) leaves nothing open, and nothing documents the choice.
  • Fix (tested on a copy of the branch). In V/ia_ssa.py, after the NOTE that ends at :153, and in the smme term:
        # Iowa Code 249.3(4)(c) limits SMME to a person who "Would be eligible
        # for supplemental security income benefits but for having excess
        # income or but for being engaged in substantial gainful activity and
        # having excess income", and 6-B p.74 pays it to "certain Medicaid
        # recipients who do not qualify for other cash assistance benefits".
        # So a person SSI pays gets no SMME, including the aged, blind or
        # disabled spouse of an applicant working above the SGA level, whom
        # SSI still pays after deeming from that applicant (Case 110).
        smme = (
            person("ia_ssa_smme_coverage_eligible", period)
            & (
                person("ia_ssa_smme_countable_income", period)
                >= p.smme_minimum_fpg_rate * poverty
            )
            & (federally_paid == 0)
            & (person("ssi_if_takes_up", period) == 0)
        )

In countable, add after the G67 NOTE (:82):

        # A spouse whom SSI pays gets no SMME (Iowa Code 249.3(4)(c); ia_ssa,
        # Case 110).

ssi_if_takes_up tests eligibility, not take-up; a person eligible for SSI who does not take it up already fails ia_ssa_nonfinancial_eligible. There is no new cycle, because ia_ssa already reads ssi. Do not gate the override instead: that changes no ia_ssa value in the suite, but Cases 104 and 105 would show SSI's figure for person2, so the couple would be budgeted two ways again.

The gate also blocks six cases that set SMME income on a person with no income (SSI 994). Cases 44, 78 and 89 then fail. Cases 24, 45 and 79 still pass, but only through the new gate: dropping federally_paid == 0 (killed today by Case 24) and loosening the guideline test by one cent (killed today by Cases 45 and 79) would both survive. Give each case Social Security income so that SSI is 0. Replace these six cases with:

- name: Case 24, SMME cannot stack with blind payment.
  period: 2026-01
  absolute_error_margin: 0.01
  input:
    state_code:
      2026: IA
    age:
      2026: 65
    # Social Security of $1,025 a month.
    social_security_retirement:
      2026: 12_300
    ia_ssa_category: SMME
    ia_ssa_smme_coverage_eligible: true
    ia_ssa_smme_countable_income: 2_000
    is_blind: true
  output:
    # 1,025 - 20 = 1,005 is above 994, so SSI is 0, and SSA pays the blind
    # supplement of 994 + 22 - 1,005 = 11. A federally paid supplement
    # excludes SMME even with SMME income set above the guideline.
    ssi: 0
    ia_ssa_federal: 11
    ia_ssa: 11

- name: Case 44, SMME income at exactly 120 percent of poverty qualifies under Iowa Code 249.3(4)(g).
  period: 2026-04
  absolute_error_margin: 0.01
  input:
    state_code:
      2026: IA
    age:
      2026: 65
    # Social Security of $1,616 a month.
    social_security_retirement:
      2026: 19_392
    ia_ssa_category: SMME
    ia_ssa_smme_coverage_eligible: true
  output:
    # 1,616 - 20 = 1,596 is above 994, so SSI is 0. From April, Iowa uses the
    # 2026 guideline (441 IAC 75.1): 1.2 * 15,960 / 12 = 1,596; the statute
    # requires income "of at least" 120 percent, so 1,596 qualifies.
    ssi: 0
    ia_ssa_smme_countable_income: 1_596
    ia_ssa: 1

- name: Case 45, SMME income one cent below 120 percent of poverty.
  period: 2026-04
  absolute_error_margin: 0.01
  input:
    state_code:
      2026: IA
    age:
      2026: 65
    # Social Security of $1,615.99 a month.
    social_security_retirement:
      2026: 19_391.88
    ia_ssa_category: SMME
    ia_ssa_smme_coverage_eligible: true
  output:
    # 1,615.99 - 20 = 1,595.99 is above 994, so SSI is 0, but below April's
    # 1.2 * 15,960 / 12 = 1,596, so no SMME.
    ssi: 0
    ia_ssa_smme_countable_income: 1_595.99
    ia_ssa: 0

- name: Case 78, in January SMME income at the prior year's 120 percent qualifies.
  period: 2026-01
  absolute_error_margin: 0.01
  input:
    state_code:
      2026: IA
    age:
      2026: 65
    # Social Security of $1,585 a month.
    social_security_retirement:
      2026: 19_020
    ia_ssa_category: SMME
    ia_ssa_smme_coverage_eligible: true
  output:
    # 1,585 - 20 = 1,565 is above 994, so SSI is 0, and equals January's
    # 1.2 * 15,650 / 12 = 1,565.
    ssi: 0
    ia_ssa_smme_countable_income: 1_565
    ia_ssa: 1

- name: Case 79, in January SMME income one cent below the prior year's 120 percent.
  period: 2026-01
  absolute_error_margin: 0.01
  input:
    state_code:
      2026: IA
    age:
      2026: 65
    # Social Security of $1,584.99 a month.
    social_security_retirement:
      2026: 19_019.88
    ia_ssa_category: SMME
    ia_ssa_smme_coverage_eligible: true
  output:
    # 1,584.99 - 20 = 1,564.99 is above 994, so SSI is 0, but below 1,565.
    ssi: 0
    ia_ssa_smme_countable_income: 1_564.99
    ia_ssa: 0

- name: Case 89, in March SMME income at the prior year's 120 percent still qualifies.
  period: 2026-03
  absolute_error_margin: 0.01
  input:
    state_code:
      2026: IA
    age:
      2026: 65
    # Social Security of $1,585 a month.
    social_security_retirement:
      2026: 19_020
    ia_ssa_category: SMME
    ia_ssa_smme_coverage_eligible: true
  output:
    # 1,585 - 20 = 1,565 is above 994, so SSI is 0.
    # 1.2 * 15,650 / 12 = 1,565 until April (441 IAC 75.1; RC-0130 Rev. 04/25).
    ssi: 0
    ia_ssa_smme_countable_income: 1_565
    ia_ssa: 1

Optional, for clarity only (Cases 48 and 49 also pin these terms): Case 22 with social_security_retirement: 24_240 (countable 2,000) and Case 23 with 12_240 (countable 1,000), each with ssi: 0. Append after Case 109:

- name: Case 110, an aged spouse whom SSI pays gets no SMME although the couple's combined income reaches the two-person guideline.
  period: 2026-04
  absolute_error_margin: 0.01
  input:
    people:
      person1:
        age:
          2026: 50
        meets_ssi_disability_criteria:
          2026: true
        # Wages of $4,500 a month, above the $1,690 SGA level.
        employment_income:
          2026: 54_000
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person2:
        age:
          2026: 70
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person3:
        age:
          2026: 10
      person4:
        age:
          2026: 10
      person5:
        age:
          2026: 10
    marital_units:
      couple:
        members: [person1, person2]
      child1:
        members: [person3]
      child2:
        members: [person4]
      child3:
        members: [person5]
    tax_units:
      tax_unit:
        members: [person1, person2, person3, person4, person5]
    spm_units:
      spm_unit:
        members: [person1, person2, person3, person4, person5]
    households:
      household:
        members: [person1, person2, person3, person4, person5]
        state_code:
          2026: IA
  output:
    # SSI treats person1 as an ineligible spouse: 4,500 - 3 * 497 = 3,009 is
    # deemed, (3,009 - 20 - 65) / 2 = 1,462, so person2's SSI is
    # 1,491 - 1,462 = 29. Iowa Code 249.3(4)(c) limits SMME to a person who
    # "Would be eligible for supplemental security income benefits but for
    # having excess income", so person2 gets no SMME although the combined
    # (4,500 - 20 - 65) / 2 = 2,207.50 is at least the two-person 2,164.
    ssi: [0, 29, 0, 0, 0]
    ia_ssa_smme_countable_income: [2_207.5, 2_207.5, 0, 0, 0]
    ia_ssa: [1, 0, 0, 0, 0]

Results: the rewritten cases pass at the head, so they can land first. With the code change, the rewrites and Case 110, the Iowa SSA folder passes 139/139; at the head, Case 110 fails ([1, 1, 0, 0, 0]). The two mutants above are killed again. In the PR body SMME bullet, add "and SSI pays nothing (Iowa Code 249.3(4)(c))" after "no SSA-paid supplement is paid".

SA38. After a merge of main, Iowa LIHEAP does not count ia_ssa

  • What is wrong: #10292 put Iowa LIHEAP on main at 2026-10-26 19:49 UTC, 42 minutes after your push. L/unearned.yaml:21 and L/fixed.yaml:12 list ssi but not ia_ssa, which does not exist on main. After this PR merges, LIHEAP leaves out every Iowa supplement. This is a merge-time item, not an author error. DTrim99 raised the same item in round 8 (Should 1); this review confirms it and adds the variable choice and a case that pins it. No issue or PR tracks it.
  • Source: LIHEAP FY26 manual, Appendix C, row "Social Security Benefits (SSA, SSI, SSDI)" (p.114): counted as income (code C); the definition column reads "SSA (State Supplementary Assistance) - Fully state-funded". The Definitions (p.81) name SSA benefits, SSI and SSDI as fixed income. The p.114 row groups State Supplementary Assistance with SSI and records a payment "to capture source of income for AE fixed income criteria", so both lists need it.
  • Which variable: plain ia_ssa, not ia_ssa_countable_for_snap. The p.114 row makes no exception. The in-home health-related care payment "is made to the adult recipient" (6-B p.50). Appendix C excludes only narrow reimbursements: executor fees (p.97), job costs (p.103), TAA (p.116) and VA mileage (p.118). The state plan's unchecked "Reimbursements" are "for mileage, gas, lodging, meals, etc." The SNAP and HUD exclusions rest on 7 CFR 273.9(c)(5) and 24 CFR 5.609(b), which do not govern LIHEAP.
  • Evidence (the head merged with main; the proposed case below):
Lists contain Proposed case ia_liheap
Nothing (as merged) Fails: countable 11,928 vs 16,992 520
ia_ssa in both Passes 480
ia_ssa in unearned.yaml only Fails: fixed-income-only is false 440
ia_ssa_countable_for_snap in both Fails: 12,192 vs 16,992 520

With the fix, the Iowa LIHEAP folder passes 164/164 (165/165 with the case), Iowa SSA stays 138/138, the parameter and reference code-health tests pass, and there is no dependency cycle. A blind-only case (DTrim99's household, 12,192) passes with either variable, so it does not pin the choice.

  • Why should address: missing aggregate wiring on the merged tree, as DTrim99 rated it (precedents #10300 and #9558). It is in scope, because this PR adds ia_ssa and already wires it into SNAP, HUD, spm_unit_benefits and household_state_benefits. Not critical: two separately correct changes interact, Iowa LIHEAP is not a program this PR encodes, and most amounts are small. Blind SSI recipients are reached in microsimulation (+$264 a year).
  • Fix: merge main. In L/unearned.yaml, replace :20-21 with:
    # ssi and ia_ssa are monthly variables; the formula sums the twelve months.
    - ssi
    # Appendix C, Social Security Benefits (SSA, SSI, SSDI) (page 114), also
    # counts "SSA (State Supplementary Assistance) - Fully state-funded".
    # ia_ssa includes the in-home health-related care payment, which is made
    # to the recipient (6-B PDF page 50). SNAP and HUD exclude that payment as
    # a reimbursement, but Appendix C has no such exception: the reimbursement
    # rows it excludes (pages 97, 103, 116 and 118) are executor fees, job
    # costs, TAA payments and VA mileage.
    - ia_ssa

In L/fixed.yaml, add after - ssi (:12):

    # The Definitions (page 81) name SSA benefits, SSI and SSDI. Appendix C
    # (page 114) puts "SSA (State Supplementary Assistance)" in the same
    # Social Security Benefits row as SSI, and that row records a minor's
    # payment "to capture source of income for AE fixed income criteria".
    - ia_ssa

and change its title (:28) to "Iowa LIHEAP FY26 Policy and Procedures Manual, Definitions, Fixed Income Household, Appendix C Pensions, Railroad Retirement and Social Security Benefits rows, and Appendix I Payment Matrix, Fixed Income Only targeting factor #page 81,109-110,114,137". Optional: add "Iowa State Supplementary Assistance" after "SSI" in the documentation of ia_liheap_countable_unearned_income and ia_liheap_fixed_income_only. Append to LT after Case 8:

- name: Case 9, a blind in-home care recipient's State Supplementary Assistance counts as fixed income.
  period: 2026
  absolute_error_margin: 0.01
  input:
    people:
      person1:
        age: 65
        is_blind: true
        ia_ssa_category: IN_HOME_CARE
        ia_ssa_ihhrc_monthly_cost: 4_800
    spm_units:
      spm_unit:
        members: [person1]
        heating_type: NATURAL_GAS
        gas_expense: 1_200
        spm_unit_cash_assets: 1_000
        ia_liheap_dwelling_type: DETACHED
    households:
      household:
        members: [person1]
        state_code: IA
  output:
    # SSI 994 * 12 = 11,928.
    ssi: 11_928
    # Blind allowance 22 plus the in-home health-related care payment of
    # 400 a month (4,800 a year): (22 + 400) * 12 = 5,064, as in the Iowa SSA
    # integration.yaml Case 9, where SNAP and HUD count only the 264.
    ia_ssa: 5_064
    # Appendix C, Social Security Benefits (SSA, SSI, SSDI), counts State
    # Supplementary Assistance and makes no exception for the in-home care
    # payment: 11,928 + 5,064 = 16,992.
    ia_liheap_countable_income: 16_992
    # SSI and the supplement are both in that fixed income row.
    ia_liheap_fixed_income_only: true
    # 16,992 / 15,650 = 1.086 -> 101 to 125 percent band (SSI alone: 0.762 -> 6).
    ia_liheap_poverty_points: 5
    # fixed income +1, elderly +1, detached +1
    ia_liheap_targeting_points: 3
    ia_liheap_fuel_points: 4
    # 5 + 3 + 4 = 12; 40 x 12
    ia_liheap: 480

In the PR body, add to the wiring paragraph: "Iowa LIHEAP counts the whole ia_ssa as unearned and fixed income (Appendix C p.114), including the in-home care payment."

Suggestions

New:

  • G70. The 1619(b) reason in the new comments is narrower than the rule (DTrim99's round-8 suggestion; confirmed). The flag comment (:59-61), the helper docstring (:5-8), the PR body SMME bullet and the #1837 flag row and SGA bullet say that a worker above the SGA level is in the 1619(b) group. 8-F p.88 gives 1619(b) to "some former SSI recipients who no longer qualify for SSI benefits because their earnings are too high". A new SMME applicant need not have received SSI; such a worker often has MEPD, where SGA "is not considered" (8-F p.114). The conclusion holds on 8-E p.12's "State Supplementary Assistance" and 6-B p.76's coverage rule. Name the coverage input, because the code tests it, not the SMME payment. Wording only; no behavior or test changes.
    • Replace flag :57-67 with:
        # 8-E p.12: "An ineligible spouse is a spouse who is not eligible for
        # SSI or non-MAGI-related Medicaid, or State Supplementary Assistance."
        # Those groups are for aged, blind or disabled people (8-F PDF pages
        # 73-74). SMME is itself State Supplementary Assistance, and an SMME
        # applicant must receive full Medicaid under "a Medicaid coverage group
        # that does not rely on eligibility for SSA" (6-B PDF page 76), which
        # ia_ssa_smme_coverage_eligible records. For a disabled worker above
        # the SGA level that can be MEPD with no premium, where SGA "is not
        # considered" (8-F PDF page 114), or the 1619(b) group of former SSI
        # recipients (8-F PDF page 88). So a spouse SSI treats as aged, blind
        # or disabled, or an SMME applicant working above the SGA level, is not
        # an ineligible spouse: the couple's income is combined with no $497
        # test, as SSI and msp_countable_income combine an eligible couple's
        # income (ia_ssa.yaml Cases 97, 102, 103 and 107). This test is broader
        # than is_ssi_ineligible_spouse.
  • In the flag tuple, change the comment to # 8-F PDF pages 73-74, 88, 114, and add "https://hhs.iowa.gov/media/3987/download?inline=#page=76", with the comment # 6-B PDF page 76.
  • In the helper docstring (:5-11), replace "who has full non-MAGI-related Medicaid (8-F PDF page 73, 1619(b) group)" with "who receives full Medicaid under a group that does not rely on State Supplementary Assistance (6-B PDF page 76), such as MEPD (8-F PDF page 114) or 1619(b) (8-F PDF page 88)".
  • In the PR body and #1837, replace "8-F pp.73 and 88 place that worker in the 1619(b) group" (body) and "whom 8-F p.88 treats as an SSI recipient" (#1837) with "who has full Medicaid under a group that does not rely on State Supplementary Assistance (6-B p.76), such as MEPD (8-F p.114) or 1619(b) (8-F p.88); SMME is itself State Supplementary Assistance".
  • G71. An ineligible spouse's student earnings are not excluded before deeming (20 CFR 416.1161(a)(27)). Record in code, and file a federal issue.
    • Where: helper :52 takes the spouse's student exclusion only when the spouse is not an ineligible spouse (* not_ineligible, from the round-7 SA36 text). Federal deeming (ssi_earned_income_deemed_from_ineligible_spouse) subtracts no student exclusion, and ssi_blind_or_disabled_working_student_exclusion is defined_for blind or disabled status.
    • Source: 416.1163(a) builds the ineligible spouse's income "using the appropriate exclusions in § 416.1161(a)". 416.1161(a) is "For an ineligible spouse or parent" and excludes "(27) Earned income of a student as described in § 416.1112(c)(3)". 416.1112(c)(3) has no blind or disabled condition. 8-E p.11: for the ineligible spouse, "do not include: Any excluded income".
    • Evidence (April 2026; applicant aged 50, disabled, wages 3,000, SMME; spouse aged 20, full-time student, disabled, wages 1,800, no Medicaid): the head gives 2,357.50 to the applicant and 1,952.08 to the spouse, and ia_ssa [1, 0]. The rule gives 1,952.08 to both and [0, 0]. Deleting * not_ineligible gives that and passes 138/138. A student spouse who is not disabled is not fixed by that change, because the federal exclusion variable is 0 for that spouse. An aged applicant on the SSI path has the same miss.
    • Why a suggestion: the factor leaves the gap as it was at the round-7 head and as SSI's own deeming has it; it does not make it worse. This is the G57(a) class: an inherited federal gap with flips, recorded and tracked. The population is married students under 22 with earnings; microsimulation reach is zero.
    • Fix (text): in the helper docstring list at :43-47, add ", and an ineligible spouse's student earned income is not excluded (416.1161(a)(27); issue NNNN)", with the new issue number. Optional now, and needed when the federal fix lands (the helper reads ssi_earned_income directly, so it will not follow the federal change): delete * not_ineligible, and add a case for the household above (expect exclusion [0, 810.83], flag [true, true], SMME [1,952.08, 1,952.08], ia_ssa [0, 0]; give the spouse is_full_time_student: true and immigration_status: UNDOCUMENTED, as in Case 107). The trade-off is G57's: until the federal fix lands, the SGA path and the aged path differ for this household.
  • G72. Small record and citation points (optional).
    • Add GL 6-B-47 (https://hhs.iowa.gov/media/18744/download?inline#page=1, "effective January 1, 2026") to dependent_amount.yaml and rcf_daily_limit.yaml. Its p.1 lists $518 and $38.47.
    • Countable :20: "Iowa Code 249.3(4)(a)(2) and (g); PDF pages 2-3", because (g) runs onto p.3.
    • Countable :62-63: "the figure 8-E gives for deeming" should be "the individual figure 8-E gives (8-E p.56)".
    • Helper docstring :45-47: cite PR #10146 for the tax-unit child search and the income-maintenance exception.
    • Case 73 comment: "(PR 10141 applies it)" will age better than "(issue 10138)".
    • us-ia:rcf-maximum-per-diem-rate: optionally add GL 6-B-45 #page=24 and the 2023 sheet as manual sources (G51's optional part).

Still open from earlier rounds (as written in rounds 4-7): G25 (accepted part), G36-G42, G46, G48 (couple 2,164 and the SGA switch), G50, G53, G54(a) (now also the spouse's exclusion), G55, G56, G63. None blocks.

Investigated and cleared

  • SA36 on new shapes. A working SMME spouse below the SGA level gets the same result on the SGA path and the aged path. The override can only raise the ABD spouse's figure, so no household loses SMME through it.
  • Equivalent terms. & ~abd in the status, coverage in countable's applicant, - applicant in the SGA-applicant test and the floor on spouse_earned cannot change any output. Keep them for readability.
  • Disability term in the spouse status. No case pins it. A case needs the coverage input on a spouse who is neither aged nor disabled, which the input's own definition (Medicare Part B) rules out. G62 precedent; no case asked.
  • Payer test on the spouse only. Still survives, as round 7 accepted.
  • Case 108 and the coverage term in the applicant test. Under that mutant, person2's SMME income is 0, not 2,597.50, because countable's own applicant still needs coverage. Case 108 still kills it.
  • Repeated helper calls, the flag name and the 93-character label line. Negligible cost; the house pattern; ruff is clean. No change.
  • Merge with main. #10283 and #10453 break no Iowa file. The deleted _smme_spouse_income.py is not in the live PR file list (46 files), and nothing imports it.

Out of scope / follow-up

  • New federal issue for G71: "SSI deeming does not exclude an ineligible spouse's or parent's student earned income (20 CFR 416.1161(a)(27))". Household: an aged claimant with Social Security of 600 and a spouse aged 20, a full-time student with wages of 1,800. main pays SSI 43.50; the rule pays 414 (in April the whole 1,800 is excluded). Related: #10454 and this PR.
  • Tracked: #10454 (416.1161(a)(10)), #10455 (when fixed, Case 96's person2 value changes from 2,106 to 500), #10456 (couple student exclusion; it also records the G54(a) averaging), #10243 item 2 (record only). PR #10141 closes #10138 (G72, Case 73 comment).
  • SA38 alternative: a tracked issue instead of the fix would leave SA38 open.

Validation Summary

Check Result
CI 32/32 pass at 4aae08a
Local tests Iowa SSA 138/138 at the head and on the merged tree; code health 462 (1 skipped); source conflicts 103; registry and source conflicts 888 (10 skipped); Iowa LIHEAP 164/164 on the merged tree
Regulatory SA36 correct for every tested shape; SA37 (249.3(4)(c)); SA38 (LIHEAP p.114); G70; G71 is SSI's own rule, inherited
References 35/35 new or changed cites correct; no printed page number; G72
Code patterns ruff clean; periods, entities and vectorization correct; no hard-coded value; the helper module follows the house pattern
Tests Cases 98-109 recompute; Case 73 swap correct; 31 mutants: 24 killed, 4 equivalent, 3 survive (one input-gated, G71, one accepted in round 7)
Fixes run SA37: 139/139 with the code change, rewrites and Case 110; two masked mutants killed again. SA38: the LIHEAP case fails before and passes after; LIHEAP 165/165
Branch 47 ahead, 32 behind; trial merge clean; MERGEABLE
Partner tests None touched
Other reviews DTrim99 round 8: SA38 (same item) and G70 (same wording point)
PR body axiom: line valid (process note); body sentences for SA37, SA38 and G70

Review Severity: REQUEST_CHANGES

Two should-address items are open: SA37 (an SSI recipient can get SMME through the round-7 override) and SA38 (Iowa LIHEAP wiring after a merge of main). No critical item is open, and SA35 and SA36 are resolved.

Next Steps

To auto-fix issues: run the fix-pr workflow for this PR.

  1. SA37: add the SSI term and the two comments; rewrite Cases 24, 44, 45, 78, 79 and 89 (Cases 22 and 23 optional); append Case 110.
  2. SA38: merge main; add - ia_ssa to both LIHEAP lists with the comments and the fixed.yaml title; append the LIHEAP case to LT.
  3. Run make format, then the Iowa SSA and Iowa LIHEAP folders and test_source_conflicts.py once with all changes.
  4. Update the PR body (SMME bullet, wiring paragraph, test counts) and rulespec-us#1837 (a row for Case 110).
  5. Optional: G70-G72 and the carried suggestions.
  6. Outside this PR: file the G71 federal issue.

hua7450 and others added 2 commits October 27, 2026 18:22
- SA37: no SMME for a person SSI pays (Iowa Code 249.3(4)(c); 6-B p.74),
  which the round-7 combined-income override allowed for the aged, blind or
  disabled spouse of an applicant working above the SGA level (Case 110).
  Cases 22-24, 44, 45, 78, 79 and 89 now give the person Social Security so
  that SSI is 0.
- SA38: Iowa LIHEAP counts ia_ssa as unearned and fixed income (LIHEAP FY26
  manual Appendix C p.114), with Iowa LIHEAP integration Case 9.
- G70: rest the SGA applicant's spouse status on 6-B p.76's coverage rule
  (MEPD, 1619(b)) rather than on 1619(b) alone.
- G71: NOTE citing issue 10521 (an ineligible spouse's student earnings).
- G72: GL 6-B-47 references, citation and comment fixes, and per diem
  candidate sources.

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

hua7450 commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks, Pavel and David. Both should-address items and the suggestions are fixed in 676dced, and main is merged in 2da0ed3 (8ea4342).

Still deferred: G36-G42, G46, the rest of G48, G50, G53, G54(a), G55, G56 and G63.

On the merged tree, 139 Iowa supplement cases (110 in ia_ssa.yaml) and 165 Iowa LIHEAP cases pass locally. test_source_conflicts.py and the registry tests also pass (891 passed, 10 skipped).

@DTrim99

DTrim99 commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator

PR Review (round 9): Add Iowa state supplementation for 2026

Summary

PR #8017 (author: hua7450). This round reviews head 676dced148. We requested changes in round 8 at 4aae08acae. Since then there is one author commit, 676dced148, "Address Pavel's and David's round-8 reviews of Iowa SSA" (13 files, 546 diff lines), and one clean merge of main at 8ea43422e6 (2da0ed363d). The author re-requested our review.

What the commit does.

  • SA38 (our round-8 Should 1): both Iowa LIHEAP source lists gain ia_ssa, the two LIHEAP income descriptions name the supplement, and Iowa LIHEAP integration.yaml gains Case 9.
  • SA37 (Pavel): ia_ssa pays SMME only when ssi_if_takes_up is 0 (Iowa Code 249.3(4)(c); 6-B p.74). New Case 110 tests this. Cases 22-24, 44, 45, 78, 79 and 89 now give the person Social Security, so SSI is 0 and each case still tests only its own term.
  • G70 (our round-8 Suggestion 1): the flag comment, the helper docstring, the PR body and rulespec-us#1837 now rest the worker's status on 6-B p.76's coverage rule. MEPD (8-F p.114) and 1619(b) (8-F p.88) are given as examples.
  • G71 and G72: a NOTE citing new issue SSI spousal deeming does not exclude an ineligible spouse's student earned income (20 CFR 416.1161(a)(27)) #10521, General Letter 6-B-47 references, citation fixes and two more sources for the per diem candidate.

What I found.

  • Both round-8 items are fixed.
    • ia_ssa is a monthly Person variable. Both LIHEAP formulas read each source with options=[ADD] over the year, so it is summed over twelve months and counted once.
    • ssi holds only the federal payment, so the supplement isn't counted twice.
    • The new LIHEAP case fails if ia_ssa is removed from either list.
  • I checked every new or changed expectation by hand (ten cases), and each one is right.
  • One new should-address item, with no code change. The LIHEAP fix changes Iowa LIHEAP's income rules, but its parity issue, rulespec-us#1834, still lists the old sources. The axiom: line names only Update New York tax rules for 2022 #1837.
  • One new suggestion: Update New York tax rules for 2022 #1837 doesn't yet quote the two sources that G70 now relies on.
  • CI and branch. CI is green: 33 of 33 checks pass at this head. The merge with main is clean (16 behind). No partner test file is touched.

Prior findings

Finding Status Evidence
Round 8, Should 1: on the merged tree, Iowa LIHEAP doesn't count the Iowa supplement, which its manual counts as income Fixed ia_ssa is in ia/hhs/liheap/income/sources/unearned.yaml and in fixed.yaml. ia_ssa is Person/MONTH. ia_liheap_countable_unearned_income adds person(source, period, options=[ADD]) for each source, and ia_liheap_fixed_income_only uses add(spm_unit, period, p.fixed). Both sum the twelve months once, and the fixed formula no longer treats the supplement as other income. Case 9 fails without the unearned entry (11,928, 6 poverty points, $520) and without the fixed entry (fixed income only false, 2 targeting points, $440). The p.114 row reads "SSA (State Supplementary Assistance) - Fully state-funded" (LIHEAP FY26 manual p.114). The fixed.yaml title gains page 114.
Round 8, Suggestion 1: the 1619(b) reason was narrower than the rule Fixed Flag comment (ia_ssa_smme_spousal_deeming_applies.py:59-73) and helper docstring (_ia_ssa_smme_spouse_income.py:4-13) now rest the status on 6-B p.76: "The person must be eligible under a Medicaid coverage group that does not rely on eligibility for SSA" (6-B p.76). They give MEPD with no premium and 1619(b) as examples. 8-F p.114 reads "attaining substantial gainful activity (SGA) is not considered in determining disability for the MEPD group" (8-F p.114). 6-B p.76 adds "MEDP with a premium are not eligible", which the "no premium" wording follows. #1837's flag row and SGA bullet say the same (see the new suggestion for the quote list).
Rounds 3-7 Closed No earlier finding is reopened. The new SMME condition leaves every earlier case's value unchanged, and CI confirms this.

Pavel's round-8 items in this commit (checked, not ours):

  • SA37: Iowa Code 249.3(4)(c) reads "Would be eligible for supplemental security income benefits but for having excess income or but for being engaged in substantial gainful activity and having excess income" (249.pdf p.2). 6-B p.74 reads "to provide a cash benefit to certain Medicaid recipients who do not qualify for other cash assistance benefits" (6-B p.74). So a person SSI pays is outside SMME, and ssi_if_takes_up == 0 encodes that.
    • ssi_if_takes_up is Person/MONTH, like ia_ssa.
    • It uses the take-up-independent amount, so a person who could get SSI but doesn't take it up is also barred, as "would be eligible" requires.
  • G71: 20 CFR 416.1161(a)(27) is "Earned income of a student as described in § 416.1112", as the docstring says. Issue SSI spousal deeming does not exclude an ineligible spouse's student earned income (20 CFR 416.1161(a)(27)) #10521 is open.
  • G72:
    • General Letter 6-B-47 p.1 lists "The income limit and payment standard for a dependent relative is $518 per month" and "The maximum residential care per diem rate is $38.47". So the new references corroborate dependent_amount.yaml (518) and rcf_daily_limit.yaml (38.47) for 2026.
    • Iowa Code 249.3(4)(g) runs from p.2 to p.3.
    • 8-E p.56 gives the presumed maximum value as "$351.33".
    • GL 6-B-45 p.24 gives "$36.82" and "$17.86", and the 2023 sheet gives "$35.89" and "$17.86". Both support the per diem candidate's two-option reading.

New findings

Critical (must fix)

None.

Should address

  1. The Iowa LIHEAP change has no Axiom parity coverage: rulespec-us#1834 still lists the old income sources.
    • What is wrong.
      • This commit changes Iowa LIHEAP. Countable unearned income and the fixed-income-only factor now include ia_ssa, which changes points and benefits for Iowa supplement recipients. Integration Case 9 goes from $520 to $480.
      • Add Iowa LIHEAP regular heating assistance #10292 put Iowa LIHEAP on main with axiom: TheAxiomFoundation/rulespec-us#1834 queued. Too many EITCs #1834 is OPEN and pe-parity, and was last updated 2026-10-26 18:12 UTC, before this commit.
      • Its required outputs still read "plus ssi (twelve monthly amounts), pension_income, ..." for ia_liheap_countable_unearned_income. For ia_liheap_fixed_income_only they read "F = sum ... of social_security ..., ssi, pension_income, military_retirement_income, railroad_benefits and veterans_benefits".
      • Its p.114 quote omits the "SSA (State Supplementary Assistance) - Fully state-funded" line.
      • This PR's axiom: line names only Update New York tax rules for 2022 #1837, and Update New York tax rules for 2022 #1837 covers the supplement, not LIHEAP.
      • So if Too many EITCs #1834 is dispatched as written, RuleSpec encodes Iowa LIHEAP without the supplement, and parity fails once this PR merges.
    • Rule. CLAUDE.md, Axiom Parity: "Any PR that adds, updates or fixes policy must also leave the same provision correct in rulespec-us." Missing axiom coverage is should-address in this batch (SSP checklist item 1). Round 8 didn't name Too many EITCs #1834; the gap comes from our own fix.
    • Fix (no code change).
      • In Too many EITCs #1834, add ia_ssa (twelve monthly amounts) to the countable unearned income row and to F in the fixed-income-only row.
      • Add the p.114 line "SSA (State Supplementary Assistance) - Fully state-funded" to the Social Security Benefits quote. Note the reading that the in-home care payment counts because Appendix C makes no exception for it.
      • Add a companion test from published amounts, not PolicyEngine output. For example, a blind SSI recipient aged 65 with natural gas heat. SSI is $994 and the blind supplement is $22 (GL 6-B-47 p.1; POMS SI 01415.058 F.2): 12,192 countable, fixed income only true. Or reuse Case 9's figures.
      • Update Too many EITCs #1834's test count (165 cases; integration.yaml 9).
      • Then name it in the PR body's line, for example ... TheAxiomFoundation/rulespec-us#1837 queued; TheAxiomFoundation/rulespec-us#1834 queued (Iowa LIHEAP income sources).

Suggestions

  1. Update New York tax rules for 2022 #1837 doesn't yet quote the two sources the G70 reading now rests on.
    • Update New York tax rules for 2022 #1837's flag row and SGA bullet cite "6-B p.76" and "MEPD (8-F p.114)". Its verbatim-law section doesn't quote either:
      • The 6-B list has only p.76's "The person must not be eligible for other SSA."
      • The 8-F list quotes pp.73 and 88 only.
      • The 8-F corpus row still reads "8-F pp.73-74, 88".
    • Fix.
      • Add 6-B p.76's "The person must be eligible under a Medicaid coverage group that does not rely on eligibility for SSA" and its MEPD-with-premium sentence.
      • Add 8-F p.114's "Note that attaining substantial gainful activity (SGA) is not considered in determining disability for the MEPD group."
      • Add p.114 to the 8-F corpus row.
    • Optional. In the flag's reference tuple, the comment # 6-B PDF page 76 could read # 6-B PDF pages 76-77, because the formula also cites 6-B Income (SMME) p.77.
    • This is wording only.

Verified

The LIHEAP wiring.

  • Entity and period: ia_ssa is Person/MONTH, defined for ia_ssa_eligible. Both LIHEAP formulas sum the twelve months.
    • Countable income also applies the 18-and-over gate, as p.114 requires ("Only count for HH members 18 and older").
    • The fixed test has no age gate, as the p.114 margin note requires.
  • No double counting:
    • ssi (ssi_if_takes_up × take-up) has no state supplement in it.
    • ia_ssa already includes ia_ssa_federal.
    • No other listed source contains either.
  • The in-home care payment. Counting it follows the manual text: p.114 counts State Supplementary Assistance with no exception. The four reimbursement rows the comment names are the only ones I found in Appendix C: executor fees (p.97), job-related reimbursements (p.103), TAA (p.116) and VA mileage (p.118). SNAP (7 CFR 273.9(c)(5); 7-E p.34) and HUD (24 CFR 5.609(b)(6)) exclude the payment under their own rules. The PR body says this.
  • The residential care payment counts in LIHEAP, as it does in SNAP and HUD.
  • NH Add New Hampshire state supplementation for 2026 #10156: no new variable. ia_ssa adds a float to a StateCode.IA list and isn't a parameter key.

SA37. The new term is a float comparison combined with &. It is gated like the other SMME terms.

  • Why the changed cases needed Social Security. Without income, SSI pays $994 and the new term alone would zero SMME. Cases 22, 23, 45 and 79 would then pass for the wrong reason. Case 24 would no longer test federally_paid == 0.
  • Mutations (traced by hand, not run):
    • Without the new term, Case 110's person2 gets $1.
    • Without federally_paid == 0, Case 24 pays 11 + 1 = 12.

Hand-checked expectations (every new or changed one). The 2026 figures are: SSI $994 / $1,491, child allocation $497, SGA $1,690. 120% of the guideline is $1,565 before April (2025 guideline) and $1,596 / $2,164 from April.

Case Hand computation Expected Result
22 (Jan) 24,240 / 12 = 2,020; 2,020 − 20 = 2,000 > 994, so SSI 0; no coverage input ssi 0; SMME 2,000; ia_ssa 0 Correct
23 (Jan) 12,240 / 12 = 1,020; 1,000 > 994, so SSI 0; 1,000 < 1,565 0; 1,000; 0 Correct
24 (Jan) 12,300 / 12 = 1,025; 1,005 > 994, so SSI 0. SSA-paid blind level 994 + 22 − 1,005 = 11. That bars SMME although the SMME input is 2,000 ≥ 1,565 ssi 0; ia_ssa_federal 11; ia_ssa 11 Correct
44 (Apr) 19,392 / 12 = 1,616; 1,596 ≥ 1.2 × 15,960 / 12 = 1,596 0; 1,596; 1 Correct
45 (Apr) 19,391.88 / 12 = 1,615.99; 1,595.99 < 1,596 0; 1,595.99; 0 Correct
78 (Jan) 19,020 / 12 = 1,585; 1,565 ≥ 1.2 × 15,650 / 12 = 1,565 0; 1,565; 1 Correct
79 (Jan) 19,019.88 / 12 = 1,584.99; 1,564.99 < 1,565 0; 1,564.99; 0 Correct
89 (Mar) As Case 78; the 2025 guideline still applies in March (441 IAC 75.1) 0; 1,565; 1 Correct
110 (Apr) Allocations 3 × 497 = 1,491. SSI deems 4,500 − 1,491 = 3,009 (yearly 36,108 > 5,964); (3,009 − 20 − 65) / 2 = 1,462; 1,491 − 1,462 = 29 (under the 994 cap, so #10141 doesn't change it). SMME: person2 is aged, so person1 combines with no allocations: (4,500 − 20 − 65) / 2 = 2,207.50 ≥ 1.2 × 21,640 / 12 = 2,164. person2 gets the override 2,207.50, but SSI pays 29, so no SMME. Children: 0 ssi [0, 29, 0, 0, 0]; SMME [2,207.5, 2,207.5, 0, 0, 0]; ia_ssa [1, 0, 0, 0, 0] Correct
LIHEAP 9 (2026) SSI 994 × 12 = 11,928. ia_ssa (22 + 4,800 / 12) × 12 = 5,064: no in-home care participation, as in Iowa SSA integration Case 9. Countable 16,992; fixed sources > 0 and no other source, so fixed income only. Guideline 15,650 (one-year lag): 1.086, so 101-125%, 5 points (SSI alone 0.762, so 6). Targeting: fixed 1 + elderly (65 ≥ 60) 1 + detached 1 = 3 (is_blind isn't is_disabled). Natural gas 4. 12 × 40 = 480, inside $80-$800 11,928; 5,064; 16,992; true; 5; 3; 4; 480 Correct

Case 73 changed only a comment (it now names PR 10141). No expectation changed.

Other checks.

Axiom line assessment

The line reads axiom: Iowa Code 249.3, ...; 20 CFR 416.1112(c)(3), 416.1124(c)(22), 416.1163, 416.1167; Iowa HHS Employees' Manual 6-B, 7-E, 8-E, 8-F; POMS SI 01415.058 F TheAxiomFoundation/rulespec-us#1837 queued.

CI status

gh pr checks 8017, rechecked at the end of this review: 33 pass, 0 fail, 0 pending.

Branch status

  • 49 ahead and 16 behind main (fe9ec1270f).
  • git merge-tree --write-tree PolicyEngine/main 676dced148 is clean (tree d198f5576f).
  • The PR's merge at 2da0ed363d (main at 8ea43422e6) had no hand-resolved blocks.
  • What the 16 newer commits change:
    • TANF fixes for DC, NC, WI, NH, MI, VA, SC, MD, MA, MS, HI, VT and KY.
    • The S.770 contributed reform.
    • New Hampshire, Utah and Wyoming LIHEAP, with their programs.yaml entries. Those merge cleanly with the Iowa entry.
    • None touches Iowa, SSI, the shared SSP wiring files or a code-health guard.
  • GitHub: MERGEABLE and BLOCKED. The review decision is CHANGES_REQUESTED (round 8, Pavel's and ours). Re-reviews are requested from Pavel and DTrim99.

Verdict: REQUEST_CHANGES

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

Requesting changes, round 9: 0 critical, 1 should. Both round-8 items are fixed (ia_ssa is now counted once in Iowa LIHEAP and pinned by Case 9). The one open item needs no code: the LIHEAP change needs axiom coverage. Update rulespec-us#1834 (add ia_ssa to the unearned and fixed-income rows, plus the p.114 quote and a companion test) and name it in the axiom line. Full report in the comment above.

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

Program Review

PR #8017, "Add Iowa state supplementation for 2026" (hua7450). Round 9, incremental review of 4aae08a..676dced.

IDs: C = critical, SA = should address, G = suggestion. New items continue the numbering after the highest prior ID in each class. This round adds one suggestion, G73. There is no new critical or should-address item, so C8 and SA39 are not used.

Paths: V/ = policyengine_us/variables/gov/states/ia/hhs/ssa/, T = policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml, L/ = policyengine_us/parameters/gov/states/ia/hhs/liheap/income/sources/, LT = policyengine_us/tests/policy/baseline/gov/states/ia/hhs/liheap/integration.yaml. "Countable" = V/ia_ssa_smme_countable_income.py, "flag" = V/ia_ssa_smme_spousal_deeming_applies.py, "helper" = V/_ia_ssa_smme_spouse_income.py. Line numbers refer to the reviewed head. "p.NN" is the PDF FILE page (8-E FILE = printed + 5; 6-B and 8-F FILE = printed + 4).

Source Documents

  • Reviewed head SHA: 676dced
  • Mode: incremental (round 9), from 4aae08a (round 8, CHANGES_REQUESTED)
  • Scope:
    • 676dced, "Address Pavel's and David's round-8 reviews of Iowa SSA" (13 files, +225 / -32): the SMME SSI term and comment in V/ia_ssa.py:154-169; comments in countable (:20, :63, :83-84); the flag comment and tuple (:21-24, :59-73); two helper docstrings (:4-13, :38-51); ia_ssa in L/unearned.yaml:20-29 and L/fixed.yaml:13-17 and the fixed.yaml title (:33); the two LIHEAP income descriptions; GL 6-B-47 in dependent_amount.yaml and rcf_daily_limit.yaml; two sources in us-ia:rcf-maximum-per-diem-rate (candidates.yaml:2096-2101); T Cases 22-24, 44, 45, 78, 79 and 89 rewritten, Case 73's comment and new Case 110; LT Case 9.
    • 2da0ed3, a merge of main at 8ea4342 with no hand-resolved block. It brings Iowa LIHEAP (#10292) into the branch. In the Iowa SSA and SSI files it changes only one comment in ssi_amount_if_eligible.py (1382(e)(1)(A) to (B)). The programs.yaml hunks in the diff are main noise; the Iowa SSA entry is unchanged.
    • The PR body: the SMME bullet, the LIHEAP sentence, the shared-files list, nine federal limitations and the test counts.
  • Iowa sources (downloaded this round): 6-B (https://hhs.iowa.gov/media/3987/download?inline=, pp.50, 74, 76), 8-F (media/4012, pp.73-74, 88, 114), 8-E (media/4011, p.56), GL 6-B-47 (media/18744, p.1), GL 6-B-45 (media/12206, p.24), the 2023 standards sheet (media/9237), Iowa Code ch. 249 (pp.2-3), and the Iowa LIHEAP FY26 manual (media/17262, pp.81, 97, 103, 114, 116, 118).
  • GitHub (read-only): issue #10521; PRs #10141 and #10146 (both open); TheAxiomFoundation/rulespec-us#1834 and #1837; DTrim99's round-9 review.

Branch Status

  • 49 ahead and 28 behind main (1976c4b). A trial merge (git merge-tree, trivial mode) shows no conflict. programs.yaml and source_conflicts/candidates.yaml change on both sides and merge cleanly.
  • The 28 newer main commits add Alaska, North Dakota, New Hampshire, Utah and Wyoming LIHEAP, fix TANF in nine states, and change S.770, the Maine EITC, the self-employed health insurance deduction and the Montana AGI invariant. One changes gov/hhs/liheap/fpg_limit.yaml, which no Iowa file reads. None touches an Iowa supplement, SSI, Iowa LIHEAP or a shared SSP wiring file.
  • CI at 676dced: 33 of 33 checks pass.
  • GitHub: MERGEABLE, BLOCKED. The review decision is CHANGES_REQUESTED (DTrim99, round 9, and mine, round 8).
  • No partner test file is touched. The changelog fragment (changelog.d/ia-ssp.added.md) is unchanged.
  • Process note (not counted): the axiom: line names rulespec-us#1837 only. See "Other reviews".

Round 8 items

ID Status Evidence
SA37 RESOLVED V/ia_ssa.py:169 adds & (person("ssi_if_takes_up", period) == 0), with the 249.3(4)(c) and 6-B p.74 comment at :154-161 and the pointer at countable :83-84. The source supports it: 249.3(4)(c), "Would be eligible for supplemental security income benefits but for having excess income ..." (249.pdf p.2); 6-B p.74, "certain Medicaid recipients who do not qualify for other cash assistance benefits" (6-B p.74). Case 110 (T:3655) fails without the term ([1, 1, 0, 0, 0]) and only Case 110 fails. Without federally_paid == 0, Case 24 fails again (12 against 11). The eight rewritten cases now reach their terms through the formula (see "Tests run"). This was a regression from my own round-7 SA36 proposal, as round 8 said. The round-8 fix is also my text; this round re-checked it independently, and it is right.
SA38 RESOLVED ia_ssa is in L/unearned.yaml:29 and L/fixed.yaml:17, with the round-8 comments; the fixed.yaml title adds p.114 (:33); both LIHEAP descriptions name the supplement. Both formulas sum the twelve monthly amounts (options=[ADD]; add(spm_unit, period, p.fixed)). The fixed test excludes fixed sources from "other" income, so the supplement no longer defeats the factor. LT Case 9 (:346) fails without the unearned.yaml entry (11,928), without the fixed.yaml entry (fixed income only false) and with ia_ssa_countable_for_snap in both lists (12,192). p.114 reads "SSA (State Supplementary Assistance) - Fully state-funded" (LIHEAP p.114). Agrees with DTrim99's round-9 review (round-8 Should 1, "Fixed")
G25 PARTIAL (accepted part stands) Case 110 uses 2026-04; it fits
G36 DECLINED for now Branches unchanged. A deferral of a test suggestion in untouched code is defensible
G37 STILL OPEN (deferred) The NOTE at V/ia_ssa.py:146-153 and the candidate still omit "At the discretion of the department". Defensible
G38 STILL OPEN (deferred) V/ia_ssa_federal.py unchanged. Defensible
G39 STILL OPEN (deferred) Coverage input documentation unchanged. Defensible
G40 STILL OPEN (deferred) Files unchanged. Defensible
G41 STILL OPEN (deferred) Iowa SSA integration.yaml unchanged. Defensible
G42 STILL OPEN (deferred) V/ia_ssa_ihhrc_participation.py unchanged. Defensible
G46 STILL OPEN (deferred) Manual sums unchanged; no new instance. Defensible (style)
G48 PARTIAL The one-person part is closed: Cases 44, 78 and 89 now reach 1,596 and 1,565 from Social Security through the formula, and a >= to > mutant fails all three. The couple at exactly 2,164 and the SGA switch are still open (Case 110 reaches 2,207.50, not the boundary)
G50 STILL OPEN (deferred) Unchanged. Defensible
G53 STILL OPEN (deferred) fpg_year_start_month.yaml unchanged. Defensible
G54 PARTIAL (a) The cap averaging is still undocumented (helper :56). Defensible
G55 STILL OPEN (deferred) V/ia_ssa.py:141 still reads f"{year}-01-01". Defensible
G56 STILL OPEN (deferred) No new 2025 case. Defensible
G63 STILL OPEN (deferred) No 2023 case; no 2024 DP case. Defensible
G70 RESOLVED The flag comment (:59-73), the tuple (:21-24, adds 8-F p.114 and 6-B p.76), the helper docstring (:4-13) and the PR body SMME bullet use the round-8 text. The quotes are on the cited pages: 6-B p.76, "under a Medicaid coverage group that does not rely on eligibility for SSA" and "MEPD with a premium are not eligible" (6-B p.76); 8-F p.114, SGA "is not considered in determining disability for the MEPD group" (8-F p.114); 8-F p.88, "some former SSI recipients" (8-F p.88); 8-F p.73 starts the non-MAGI section, "People who are aged, blind, or disabled" (8-F p.73). Agrees with DTrim99's round-9 review (round-8 Suggestion 1, "Fixed"). One follow-on wording point: G73(a)
G71 RESOLVED Helper docstring :49-51 cites 416.1161(a)(27) and issue #10521. #10521 is open and describes the gap correctly. You kept * not_ineligible so that the SGA path and the aged path agree until the federal fix lands. Round 8 made that part optional for now, and the reason holds
G72 RESOLVED All six points: GL 6-B-47 at dependent_amount.yaml:23-24 and rcf_daily_limit.yaml:24-25 (p.1 lists $518 and $38.47, effective January 1, 2026); countable :20 "PDF pages 2-3" (249.3(4)(g) runs onto p.3); countable :63 "the individual figure 8-E gives (8-E p.56)" (p.56: "$351.33 (one-third of the SSI benefit rate plus $20)"); helper :49 names PR 10146, whose body covers both the co-resident child search and the income-maintenance exception; Case 73 (T:2152) names PR 10141, which is still open, so "main does not yet apply" is still true; the per diem candidate adds GL 6-B-45 #page=24 ($36.82 and $17.86) and the 2023 sheet ($35.89 and $17.86)

Tally: 21 IDs were open after round 8. Now 5 are resolved (SA37, SA38, G70, G71, G72), 3 are partial (G25, G48, G54), 12 are still open as deferred suggestions and 1 is declined for now (G36). Every open item is a suggestion, and each deferral is defensible.

Withdrawals: none. SA37 came from my own round-7 SA36 patch, and round 8 said so. This round checked every round-8 item that came from my code or wording: the SA37 term and the six case rewrites, Case 110, the SA38 list entries, comments and LIHEAP Case 9, the G70 comment and docstring, and the G72 citations. Each one is correct against the source and the code. One small precision point follows from the G70 text (G73(a)).

New findings

Critical

None.

Should address

None.

Suggestions

  • G73. Small wording points (optional).
    • (a) The flag NOTE (:78-80) and the PR body "Not modeled" bullet say that "a disabled spouse working above the SGA level who has another non-MAGI-related Medicaid group, such as MEPD, but no SMME coverage is deemed rather than combined". The new G70 comment (:65-67) names MEPD with no premium as one of the groups the coverage input records, and the input's documentation reads "without a premium or spenddown, and eligible for Medicare Part B". So "such as MEPD" now reads against the comment above it. Write "such as MEPD with a premium, or without Medicare Part B". No behavior changes.
    • (b) Two lines were not re-wrapped: helper :10 ("(8-F PDF page 88). For an") and ia_liheap_fixed_income_only.py:11 (117 characters). ruff passes, because E501 is ignored. Re-wrap them if you touch the files again.

Other reviews

DTrim99 reviewed 676dced on 2026-10-28 (CHANGES_REQUESTED: 0 critical, 1 should).

  • Should 1 (rulespec-us#1834 still lists the old Iowa LIHEAP sources). The point is correct. #1834's rows for ia_liheap_countable_unearned_income and ia_liheap_fixed_income_only list ssi but not ia_ssa. #1834 was last updated 2:12pm EDT on 2026-10-26, before this commit. The axiom: line names only #1837. Under my 2026-10-26 rule, axiom coverage is a process note and does not count toward the verdict, so it is not an SA here. It is still a two-row update to #1834 and is worth doing before #1834 is dispatched.
  • Suggestion 1 (#1837 lacks the 6-B p.76 and 8-F p.114 quotes). Correct: #1837's 6-B list quotes only "The person must not be eligible for other SSA" from p.76, and its 8-F rows still read "pp.73-74, 88". Process note. The optional tuple comment "6-B PDF pages 76-77" is also reasonable, because the flag formula cites 6-B Income (SMME) p.77 (:28).
  • DTrim99's hand values for the ten new or changed cases match this round's.

Tests run

  • At the head (SNAPSHOT, policyengine_us imported from SNAPSHOT):
    • Iowa SSA folder: 139 passed (110 in T).
    • Iowa LIHEAP folder: 165 passed.
    • test_source_conflicts.py: 103 passed.
    • test_reference_urls.py, test_no_concatenated_reference_urls.py, test_parameter_yaml_keys.py, test_military_retirement_readers.py, test_unemployment_compensation_readers.py, test_no_group_variables_in_person_adds.py, test_known_dead_reference_urls.py: 172 passed.
    • ruff format --check and ruff check on the Iowa SSA and Iowa LIHEAP variable folders: clean (41 files).
  • Mutations (on package copies, deleted after the runs). In each pair, the second run also removes the new SSI term. The only difference within each pair is Case 110, so the new term hides no other kill:
Mutant Fails at the head Also fails without the SSI term
Remove the SSI term Case 110 n/a
Remove federally_paid == 0 Case 24 Case 110
Remove the coverage term Cases 22, 48 Case 110
Guideline test loosened by $0.011 Cases 45, 79 Case 110
>= to > Cases 44, 78, 89, 96, 99, 101 Case 110
No April guideline lag Cases 78, 80, 89 Case 110
Remove the guideline test 14 cases, including 23, 45, 79 Case 110
ssi in place of ssi_if_takes_up none (equivalent: a non-taker fails ia_ssa_nonfinancial_eligible) n/a
ia_ssa removed from L/unearned.yaml LT Case 9 (11,928) n/a
ia_ssa removed from L/fixed.yaml LT Case 9 (fixed income only false) n/a
ia_ssa_countable_for_snap in both lists LT Case 9 (12,192) n/a
  • Hand checks (2026: SSI $994 / $1,491; child allocation $497; SGA $1,690; guideline 15,650 before April and 15,960 / 21,640 from April, so 120% is 1,565 in January-March, 1,596 and 2,164 from April):
Case Hand computation Expected Result
22 (Jan) 24,240 / 12 = 2,020; 2,000 > 994, so SSI 0; no coverage ssi 0; SMME 2,000; ia_ssa 0 Correct
23 (Jan) 12,240 / 12 = 1,020; 1,000 > 994, so SSI 0; 1,000 < 1,565 0; 1,000; 0 Correct
24 (Jan) 12,300 / 12 = 1,025; 1,005 > 994, so SSI 0; blind level 994 + 22 − 1,005 = 11 (below the $1,016 limit, GL 6-B-47 p.1); SMME barred by the SSA-paid amount 0; ia_ssa_federal 11; ia_ssa 11 Correct
44 (Apr) 19,392 / 12 = 1,616; 1,596 ≥ 1,596 0; 1,596; 1 Correct
45 (Apr) 19,391.88 / 12 = 1,615.99; 1,595.99 < 1,596 0; 1,595.99; 0 Correct
78 (Jan) 19,020 / 12 = 1,585; 1,565 ≥ 1,565 0; 1,565; 1 Correct
79 (Jan) 19,019.88 / 12 = 1,584.99; 1,564.99 < 1,565 0; 1,564.99; 0 Correct
89 (Mar) As Case 78; the 2025 guideline applies until April (441 IAC 75.1) 0; 1,565; 1 Correct
110 (Apr) SSI deems 4,500 − 3 × 497 = 3,009; (3,009 − 85) / 2 = 1,462; person2's SSI 1,491 − 1,462 = 29 (below 994, so PR 10141 does not change it). SMME combined (4,500 − 85) / 2 = 2,207.50 ≥ 2,164 for both; person2 is paid SSI, so no SMME ssi [0, 29, 0, 0, 0]; SMME [2,207.5, 2,207.5, 0, 0, 0]; ia_ssa [1, 0, 0, 0, 0] Correct
LT 9 (2026) SSI 994 × 12 = 11,928; ia_ssa (22 + 4,800 / 12) × 12 = 5,064; countable 16,992; fixed only; 16,992 / 15,650 = 1.086, so 5 points (SSI alone 0.762, so 6); targeting fixed + elderly + detached = 3; natural gas 4; 12 × 40 = 480 11,928; 5,064; 16,992; true; 5; 3; 4; 480 Correct
  • References: every new or changed href, cite and quote in the commit (about 25) is on the cited FILE page. No href uses a printed page number. On LIHEAP p.81, "SSA" means Social Security Administration. The fixed-income entry rests on the p.114 row, which spells out "SSA (State Supplementary Assistance)" and carries the fixed-income margin note. The fixed.yaml comment states that reading correctly.
  • Investigated and cleared:
    • Reach of the SSI term. A single person whom SSI pays has countable income plus SSI of at most 994, below 1,565. An eligible couple or a couple with SSI deeming reaches at most 1,491, below 2,164. So the term changes ia_ssa only on the SA36 override path (the Case 110 shape), as intended. Microsimulation reach is zero, because the SMME inputs default to off.
    • No new dependency cycle: ia_ssa already reads ssi (V/ia_ssa.py:87). ssi_if_takes_up is Person/MONTH, like ia_ssa.
    • LIHEAP: no double counting (ssi excludes the state supplement, and ia_ssa already includes ia_ssa_federal). The 18-and-over gate applies to countable income but not to the fixed test, as p.114 requires. The four reimbursement rows that Appendix C excludes are the only ones on pp.85-125 (p.116 also counts the living-expense part of training stipends).
    • Pending federal PRs: under #10141, Case 110's SSI stays $29 (below the $994 cap). Under #10146, the three children have no parent ids, so the no-link proxy keeps their allocations.

Verdict

APPROVE: SA37 and SA38 are resolved, and the tests pin them. No critical or should-address item is open. The suggestions G25, G36-G42, G46, G48, G50, G53-G56, G63 and the new G73 do not block. DTrim99's rulespec-us#1834 point is correct, but it is a process note under my axiom rule.

@hua7450

hua7450 commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks, David. Should 1 and Suggestion 1 are done, with no code change, so the head stays 676dced.

Pavel's G73 wording points (the "such as MEPD" NOTE and two line wraps) touch code comments only, so I'll fold them into the final merge of main before this PR merges.

@hua7450
hua7450 requested a review from DTrim99 October 29, 2026 14:57
@DTrim99

DTrim99 commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

PR Review (round 10): Add Iowa state supplementation for 2026

Summary

PR #8017 (author: hua7450). The head is still 676dced148, which we reviewed in round 9. Round 9 requested changes with 0 critical, 1 should and 1 suggestion. Neither needed a code change. Since then, the author updated both parity issues (TheAxiomFoundation/rulespec-us#1834 and #1837, at 2026-10-29 14:57 UTC), added #1834 to the axiom: line and re-requested our review.

What I found.

  • Round 9's should item is fixed. Too many EITCs #1834 now encodes ia_ssa in both Iowa LIHEAP income rows. It quotes the p.114 "SSA (State Supplementary Assistance) - Fully state-funded" line and adds companion test 20, built from published amounts, which I checked by hand against the code at the head. Its case count (165; integration.yaml 9) matches the head file by file.
  • Round 9's suggestion was taken. Update New York tax rules for 2022 #1837 now quotes 6-B p.76 and 8-F p.114, and its 8-F corpus row lists p.114.
  • The axiom: line names Update New York tax rules for 2022 #1837 for the supplement and Too many EITCs #1834 for the LIHEAP p.114 change. Both issues are OPEN, labelled pe-parity, and record why the encoder is blocked.
  • One new suggestion, about issue wording only. Two passages in Too many EITCs #1834 are out of date: interpretation 8 and the description of Add Iowa LIHEAP regular heating assistance #10292 as not merged.
  • CI and branch. All 33 checks pass. The merge with main is clean (28 behind). No partner test file is touched.

Prior findings

Finding Status Evidence
Round 9, Should 1: the Iowa LIHEAP change had no Axiom parity coverage (#1834 listed the old sources, and the axiom line named only #1837) Fixed Countable unearned income row: for members aged 18 or over, "ssi and ia_ssa (twelve monthly amounts each ...)". Fixed-income-only row: "F = sum over all members, any age, of social_security ..., ssi, ia_ssa, pension_income, ...". Each row lists ia_ssa once. The inputs list says "ssi and ia_ssa are monthly". The p.114 Social Security Benefits quote now includes "SSA (State Supplementary Assistance) - Fully state-funded". New interpretation 17 says why the in-home care payment counts: Appendix C makes no exception for it, and its only reimbursement exclusions are on pp.97, 103, 116 and 118. Companion test 20 is correct (see below). The test count now reads "165 cases (integration.yaml 9)". The PR's axiom line now names #1834.
Round 9, Suggestion 1: #1837 didn't quote the sources that G70 relies on Taken The 6-B list now quotes p.76: "The person must be eligible under a Medicaid coverage group that does not rely on eligibility for SSA". It also quotes the sentence that people on "Medicaid for Employed People with Disabilities (MEPD) with a premium are not eligible". The 8-F list adds p.114: "Note that attaining substantial gainful activity (SGA) is not considered in determining disability for the MEPD group." The corpus row reads "8-F pp.73-74, 88, 114". The optional # 6-B PDF pages 76-77 comment edit wasn't made, because the head is unchanged; that was optional, so I'm dropping it.
Rounds 3-8 Closed The head is unchanged since round 9. No earlier finding is reopened.

Companion test 20, checked by hand against the head. The household is a blind SSI recipient aged 65 with natural gas heat. Inputs: ssi $994 a month, ia_ssa $22 a month, cash assets $1,000.

  • Countable income. ia_ssa is in unearned.yaml, and the formula sums its twelve months with options=[ADD]; the person is over 18. So 12 × (994 + 22) = 12,192.
  • Poverty points. Size 1, guideline 15,650 (fpg_year_lag 1, so the 2025 guideline). 12,192 / 15,650 = 0.779. The poverty_points scale has thresholds −inf, 0.75, 1, 1.25 and 2 with right=True, so the household scores 6.
  • Targeting points. Fixed income only is true: F = 12,192 > 0 and there is no other source. That gives +1, elderly (65 ≥ 60) +1 and detached (the default) +1. Savings of $1,000 don't exceed $50,000, and is_blind isn't is_disabled, so the total is 3.
  • Award. Natural gas scores 4 fuel points. 13 × $40 = $520, which is between $80 and $800.
  • The issue's two counterfactuals also hold. Without ia_ssa in fixed.yaml, the supplement counts as other income, so fixed income only is false and the award is 12 × $40 = $480. Without it in unearned.yaml, income is 11,928. That ratio is 0.762, still 6 points, so integration Case 9 is the case that catches that omission in the award.
  • Sources. All inputs come from published sources: the $994 federal benefit rate and the $22 blind supplement (General Letter 6-B-47 p.1; POMS SI 01415.058 F.2), the guideline (90 FR 5917) and manual pp.80-81, 114 and 137. None comes from PolicyEngine output.

Case count at the head. The 16 Iowa LIHEAP test files have 165 cases: ia_liheap 17, fuel_category 11, household_size 5, integration 9, eligible 12, fpg 4, has_energy_burden 9, income_eligible 6, income_limit 5, countable_earned_income 7, countable_income 9, countable_unearned_income 12, fixed_income_only 19, fuel_points 10, poverty_points 11 and targeting_points 19. These match #1834's list file by file, plus this PR's Case 9.

New findings

Critical (must fix)

None.

Should address

None.

Suggestions

  1. Two passages in Too many EITCs #1834 are out of date (issue wording only, no code change).

Axiom

The line reads axiom: Iowa Code 249.3, ...; Iowa HHS Employees' Manual 6-B, 7-E, 8-E, 8-F; POMS SI 01415.058 F TheAxiomFoundation/rulespec-us#1837 queued; Iowa LIHEAP FY26 manual Appendix C p.114 (State Supplementary Assistance as income) TheAxiomFoundation/rulespec-us#1834 queued.

  • It is valid for both provisions.
  • Update New York tax rules for 2022 #1837 (the Iowa supplement) is OPEN and labelled pe-parity. It still matches the head: 139 cases, 110 of them in ia_ssa.yaml, and the dispatch range "A to BU". It now has the p.76 and p.114 quotes.
  • Too many EITCs #1834 (Iowa LIHEAP) is OPEN and labelled pe-parity. It has everything a queued issue needs:
    • The module path for p.114 (.../fy2026/appendix-c/income-source-guide) and its corpus status ("needs ingest").
    • The verbatim p.114 text.
    • Both required-output rows with ia_ssa.
    • Companion test 20, from external amounts.
    • The encoder blockers (missing FY26 sources, the signed release not checked, no billed run approved).
  • Using queued for both is appropriate.

CI

gh pr checks 8017: 33 pass, 0 fail, 0 pending.

  • All 33 come from run 40596014001 on 676dced148, the same run as round 9. That run includes "Household API Partners" and all six Rest Python shards.
  • I ran no PolicyEngine tests locally, because nothing in the code changed. I checked the companion test by hand against the formulas and parameters at the head.

Branch

  • 49 ahead and 28 behind main (1976c4b600).
  • git merge-tree --write-tree PolicyEngine/main 676dced148 is clean (tree 9b2dd793c9).
  • Files both sides changed: programs.yaml and source_conflicts/candidates.yaml. Both merge automatically.
    • The merged programs.yaml parses.
    • The merged candidates.yaml has 295 ids with no duplicates.
  • The 12 commits since round 9:
    • Alaska and North Dakota LIHEAP. North Dakota adds a federal gov.hhs.liheap.fpg_limit, which Iowa LIHEAP doesn't read.
    • The Montana pension invariant.
    • The self-employed health insurance deduction limit.
    • The Maine childless EITC extension.
    • The owners-draw SECA reform.
    • Neither these nor the round-9 batch touches Iowa, SSI, the shared SSP wiring or a code-health guard.
  • GitHub: MERGEABLE and BLOCKED. The review decision is CHANGES_REQUESTED only because of our round-9 review. Pavel approved 676dced148 at 2026-10-29 14:23 UTC, and a re-review is requested from DTrim99.

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 round 10: 0 critical, 0 should. rulespec-us#1834 now covers ia_ssa in Iowa LIHEAP and the axiom line names it. CI is 33/33. Full report in the comment above.

@hua7450
hua7450 merged commit 52ffff9 into PolicyEngine:main Oct 29, 2026
33 checks passed
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