Skip to content

Add Iowa state supplementation for 2026 - #8017

Open
hua7450 wants to merge 45 commits into
PolicyEngine:mainfrom
hua7450:ia-ssp
Open

hua7450 wants to merge 45 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, and no SSA-paid supplement is paid (Iowa Code 249.3(4)(g); 441 IAC 51.7(3), (6); 6-B pp.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 or SSI spousal deeming), 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 is deemed to that person as 8-E pp.12-13 do, and the two-person guideline then applies. A spouse SSI treats as aged, blind or disabled is not an ineligible spouse (8-E p.12), so the couple's income is combined with no $497 test, and nothing is deemed from a spouse in a medical treatment facility, who isn't a household member (20 CFR 416.1167).
  • 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, or income that includes deemed spouse income, 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.
  • 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.
    • 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, 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 three 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) 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).

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.

Files:

policyengine_us/parameters/gov/states/ia/hhs/ssa/              blind_amount, dependent_amount, excluded_unearned_sources, family_life_supplement,
                                                               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_countable_for_snap, ia_ssa_countable_for_hud, and the eight inputs above
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.
  • The programs.yaml Iowa entry changes from in_progress to partial.
  • source_conflicts/candidates.yaml gains three statute-conflict entries: the two SMME entries and the residential care per diem.
  • 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, income deemed from a parent, a spouse's intent to return from a medical facility, and an aged, blind or disabled spouse who qualifies for none of SSI, non-MAGI-related Medicaid or State Supplementary Assistance, whose income is combined rather than deemed (code NOTEs);
  • 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:

Test plan

  • 126 Iowa supplement YAML cases (97 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 6a92d6a. 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, which care income excludes;
      • 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);
    • 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, and parental resources deemed to an in-home care child;
    • 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".
  • 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.
  • The aggregate list integrity and program registry tests pass locally (727 passed, 10 skipped).
  • ruff format, ruff check and git diff --check. The code-health tests' helper functions report no violations in the Iowa files; the code-health suite itself wasn't run.
  • Changelog fragment in changelog.d/.
  • CI passes. This includes the code-health tests, which weren't run locally.

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), 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.1124(c)(22); Iowa HHS Employees' Manual 6-B, 7-E, 8-E; POMS SI 01415.058 F TheAxiomFoundation/rulespec-us#1837 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 21, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks, David. Suggestions 1 and 4 are in 24231f8, and main is merged in 4fabd46, which brings in #10334 for the red check.

Suggestion 1, the SGA exception: fixed.

Suggestion 2, SMME without marital units: not changed. As you note, a household without marital units is malformed under CONTRIBUTING.md.

Suggestion 3, the care income's wage count: not changed. The code already follows 52.1(3)"a" and 6-B p.59, as you confirmed. I didn't add the NOTE.

Suggestion 4: fixed. The us-ia:smme-blind-under-65 question now names the Supplement for Medicare and Medicaid Eligibles, and Case 65's comment says SSI's child test reaches students only while they're under 22.

106 Iowa supplement cases pass locally (77 in ia_ssa.yaml), and test_source_conflicts.py passes 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 4): Add Iowa state supplementation for 2026

IDs: C = critical, SA = should address, G = suggestion. Round-3 IDs keep their numbers; new findings start at C7, SA25 and G37. Commit 24231f8 landed after DTrim99 approved 040662b, so DTrim99 has not reviewed it; items that come from that commit say so.

Source Documents

Branch and CI

  • 38 ahead, 0 behind main (328d172); GitHub MERGEABLE. C5 is resolved: the HUD unearned list and spm_unit_benefits.py keep mt_ssp, ok_ssp, ny_ssp, ri_ssp, sd_ssp and va_ag and add Iowa once.
  • CI was still running at review time (17 pass / 10 pending, no failures); local run 106/106 Iowa YAML cases and 103/103 source-conflict guard tests pass at 4fabd46.
  • Branch note: the open sibling SSP PRs (#10156, #10164, #10166, #10170, #10171, #10173) will conflict with this branch on spm_unit_benefits.py (and most on the HUD list). Whichever lands first, the others keep both lines.
  • No partner test file is touched.

Critical (Must Fix)

C7. SMME compares one person's own income with the two-person guideline

  • Where: ia_ssa.py:104 sizes the guideline by ia_ssa_has_spouse (size = where(has_spouse, 2, 1)). ia_ssa_smme_countable_income.py:36, 44-55 adds a spouse's income only when ssi_couple_computation_applies, or when SSI deems spouse income above $497. On three paths the income is one person's own and the guideline is for two. The comment at ia_ssa.py:100-103 says the two-person line matches combined income; on these paths it does not. The SGA path (ia_ssa_smme_countable_income.py:37-53) came in 24231f8, after DTrim99's approval.
  • Rule: 6-B Income (SMME): "Income for eligibility is determined according to SSI income criteria. See 8-E, Income" (6-B p.77). 8-E applies SSI deeming to State Supplementary Assistance groups (8-E p.11); when the ineligible spouse's income is $497 or less, "Process as a one-person household" (8-E p.12); the poverty test then uses "a household size of one" (8-E p.14). SSI computes spouses separately when one is in a medical treatment facility (20 CFR 416.414(b)(3); the model's ssi_couple_computation_applies). The statute covers SGA workers ("shall not preclude a determination of disability", 249.3(4)(a)(2)) and people in "A medical facility" (249.3(4)(b)(4)) (Code 249 p.2); 441 IAC 51.7(5)"d" and (6) (IAC 51 p.2) set no family size. No source compares one person's own income with the two-person guideline. All pages re-read at 600 DPI.
  • Failing inputs (2026-01; SMME category and coverage set; 120% = 1,596 for one person, 2,164 for two; checked by running the model at the head):
Household Model Own income vs 1-person Combined vs 2-person
Both 70, Social Security $1,700 each; person2 in a medical treatment facility all year [0, 0] (no facility: [1, 1], Case 47) 1,680: [1, 1] 3,360: [1, 1]
Both SSDI $900 + wages $2,000 a month (above the $1,690 SGA level) [0, 0] (same couple at wages $1,600: [1, 1]) 1,847.50: [1, 1] 3,747.50: [1, 1]
Case 77 worker + spouse 45 earning $1,000 [0, 0] [1, 0] 2,347.50: [1, 0]
Aged 70, SS $1,700; spouse 60 with a $497 pension (SSI deems nothing) [0, 0] (at $498 SSI deems: [1, 0]) [1, 0] 2,177: [1, 0]
  • Why critical: the small, input-gated population argues for SHOULD ADDRESS; I keep it critical because it is the C4 pairing defect again, every reading pays $1 where the model pays $0, and round 3 rated C4 critical at the same $1. The NOTE at ia_ssa_smme_countable_income.py:31-35 covers only the last row, and 8-E p.12 contradicts that row, so the NOTE does not save it. A $90 rise in wages that crosses SGA moves a couple from [1, 1] to [0, 0], which is what 249.3(4)(a)(2) rules out.
  • Fix: size the guideline by whether the income includes a spouse's income, for example combined = joint | person("is_ssi_spousal_deeming_applies", period.this_year) and size = where(combined, 2, 1). A run at the head with only line 104 changed gives the rule's result in all four rows and leaves Cases 38, 47-49 and 77 unchanged. Rewrite the comment at ia_ssa.py:100-103 and the NOTEs at ia_ssa_smme_countable_income.py:24-35, 42-43 (cite 8-E p.12). The "Not modeled" line for spouse income on the SGA path can stay.
  • Tests to add: (a) row 1 with ssi_federal_living_arrangement: MEDICAL_TREATMENT_FACILITY on person2 for 2026: [1, 1]; (b) row 3 (SSDI 10,800 + wages 24,000 a year; spouse wages 12,000): ia_ssa_smme_countable_income [1,847.50, 457.50], ia_ssa [1, 0]; (c) row 4 (SS 20,400; spouse pension_income 5,964): [1, 0]; (d) the deeming pair: aged SS $1,620 a month + spouse $497 gives [1, 0], + spouse $498 gives [0, 0].

Should Address

SA25. SMME uses the 2026 poverty guideline in January-March 2026; Iowa adopts it on April 1

  • Where: ia_ssa.py:105-109 reads parameters(period).gov.hhs.fpg at the month, so January 2026 uses 15,960 / 5,680 (1,596 / 2,164). Cases 44-45 (ia_ssa.yaml:1031-1061), 47-49 (:1123-1258) and the candidates.yaml:1831 example ("exactly $1,596") all sit in 2026-01.
  • Rule: 441 IAC 75.1 defines the federal poverty level as the HHS levels "revised annually on April 1" (IAC 75 p.2; also 75.6(5), p.13). Iowa's desk aid RC-0130 gives 120% = $1,565 / $2,115 "Effective 4/1/25" (Rev. 04/25 p.2) and $1,596 / $2,164 "Effective 4/1/26" (Rev. 04/26 p.2). GL 8-F-111, effective January 1, 2026, still uses "$1,565 / $2,115" (p.18). The 8-E table with $1,565 / $2,115 (8-E p.7) is an October 15, 2025 snapshot reissued for a typo (GL 8-E-106, p.1), so it does not show that Iowa kept the 2025 levels all year. From April 2026 the model matches Iowa.
  • Failing input: Case 45 (single, SMME income 1,595.99, 2026-01): model 0; at Iowa's $1,565 the rule pays 1. Case 49 (couple, 2,162): model [0, 0]; at $2,115 the rule pays [1, 1]. A run of the PR's 12 SMME cases with the 2025 guideline flips exactly Cases 45 and 49; Cases 44 and 48 stop testing the boundary in January. The lag recurs every January-March.
  • Why should address, not critical: the April 1 date reaches SMME by inference (75.1 defines the term for the Medicaid chapters 74-88; the SSA chapters, Code 249.1 and 6-B p.77 do not define it), the repo's Medicaid and MSP variables also use the January guideline, and the effect is $1 a month for at most three months.
  • Fix: add a parameter for Iowa's adoption month (April), citing 441 IAC 75.1 and RC-0130, and read the prior year's guideline before it (pattern: tanf_non_cash_fpg.py fpg_year_start_month; wic_income_limit.py). At minimum, add a NOTE.
  • Tests: January 2026 boundary at $1,565 / $1,564.99 (single) and $2,115 / about $2,113 (couple; SSI couple totals are even); move Cases 44-45 and 47-49 to 2026-04 (or add April copies) for $1,596 and $2,164; make the candidate example say "from April 2026", and update the comments that state 1,596 or 2,164 for a January period.

SA26. The RCF per diem statute-vs-manual conflict is not in source_conflicts/candidates.yaml

  • Where: the deciding line is ia_ssa.py:43-48 (default p.rcf_daily_limit, $38.47). The NOTE at :33-42 quotes 52.1(3) and 51.4(3) against 6-B p.72 but does not cite Iowa Code 249.12(3); rcf_daily_limit.yaml:9-13, 19-20 cites 249.12(3) only for the appropriation.
  • Rule: Code 249.12(3): "Beginning July 1, 2017, privately operated licensed custodial facilities in Iowa shall be reimbursed based on the maximum per diem rates established by the general assembly" (Code 249 p.5); 52.1(3): "For periods of eligibility beginning July 1, 2017, and thereafter, payment ... will be based on the maximum per diem rate" (IAC 52 p.1); 6-B still gives "two options", a cost-related rate up to $38.47 or "A flat per diem rate ... $17.86 beginning February 1, 2004" (6-B p.72). Re-read at 600 DPI. CONTRIBUTING.md:82: "Every such conflict is recorded"; test_source_conflicts.py:36: candidates.yaml "lists every known conflict not yet registered".
  • Concrete input: SSI-only resident, no rate entered, January 2026: model 328.57 (Case 15); the manual's flat rate gives 31 x 17.86 = 553.66 < 864, so $0.
  • Why should address: the PR records its two other statute conflicts this way (candidates.yaml:1778-1839), and an issue comment on rulespec-us#1837 is neither the register nor the backlog. DTrim99's round 2 treated conflict 6 as rule-vs-manual with no statute; 249.12(3) puts a statute on one side. The guard checks only the entries that exist, so CI cannot catch this. Not critical: the model follows the statute.
  • Fix: add us-ia:rcf-maximum-per-diem-rate in the shape of :1778-1839: sources 249.12(3) #page=5 (statute), 52.1(3) #page=1 (regulation), 6-B #page=72 (manual); readings "based on the maximum per diem rates" vs the two options; example Case 15 ($328.57 vs $0); follows: statute, code: [], this PR, state: ruled, note "Code not yet on main: ia_ssa, ia_ssa_rcf_daily_rate" and that 249.12(3) names privately operated facilities. Add 249.12(3) to the NOTE at ia_ssa.py:33-42. No # Source conflict marker until the entry is registered.
  • Test: no new YAML case; Case 15 is the example, and test_source_conflicts.py checks the entry.

SA27. Entry-month resource pooling for a residential care couple is untested

  • Where: ia_ssa_eligible.py:42-44, couple = has_spouse & (community | ia_ssa_rcf_couple_budget). Only Cases 57 (March) and 59 set the couple budget, and both have no resources. With | ia_ssa_rcf_couple_budget removed, all 106 cases still pass (run at the head).
  • Rule: "When the applicant is living with a spouse, count the spouse's resources", and "$3,000 for a married couple living together" (6-B p.12); "follow SSI eligibility policy to determine if the spouse's income and resources must be considered" and "treat the spouses as a couple during the month of entry" (6-B p.60). Re-read at 600 DPI. The code is right; the test is missing.
  • Failing input: Case 57 (Mr. K) plus ssi_countable_resources: 2_100 on person1. Head: March ia_ssa_eligible [true, true], ia_ssa [846.34, 0]. Without the term: March [false, true], [0, 0].
  • Test to add (the Case 57 variant above, period: 2026): ia_ssa_rcf_couple_budget March [true, false], April [false, false]; ia_ssa_eligible March [true, true], April [false, true]; ia_ssa March [846.34, 0], April [0, 0]. It passes at the head and fails without the term.

SA19 (still open). 2026 levels back-fill 2025 while ia_ssa is in the 2023-2025 aggregates (also raised by DTrim99 in round 1)

  • Where: every Iowa parameter starts 2026-01-01 (dependent_amount.yaml:3, rcf_daily_limit.yaml:3, rcf_personal_needs.yaml:3), and ia_ssa is in household_state_benefits.yaml:97, 213, 334 (and 455), the SNAP list (2009 block), the HUD list (2024 block) and the undated spm_unit_benefits.py:35. The NOTE at rcf_personal_needs.yaml:13-15 itself quotes $123 and $126 for 2024-2025, but the parameter returns 130 for both years; the new uprating runs forward only.
  • Rule: GL 6-B-46: "The income limit and payment standard for a dependent relative is $503 per month", "The maximum residential care per diem rate is $37.60", personal needs allowance "$126" (GL 6-B-46 p.1); "Effective Date / January 1, 2025" (p.2). Re-read at 600 DPI.
  • Failing input (2025-01, age 70, SSI only; checked by running the model at the head): dependent person 518 vs 503 (+$15 a month); residential care, 31 days, 31 x 38.47 - (967 - 130) = 355.57 vs 31 x 37.60 - (967 - 126) = 324.60 (+$30.97). A dependent-person group with countable income from $1,470 to $1,485 is paid where the law pays 0. Microsimulation pays only the blind $22, which is right for 2025, so the aggregate effect is about nil; the error is per household.
  • Decision on the decline: not accepted. For it: twelve SSP PRs in this batch (six merged with DTrim99's acceptance, six open) put 2026-only programs in all four blocks, and the PR claims only 2026. Against it: #8974 covers only the 2017-2019 POMS levels and has no comments, and no issue covers 2020-2025, so "#8974 tracks history" is not accurate for 2025; Iowa's dependent amount, per diem and allowance change every January, so the back-filled 2025 levels are known wrong (unlike Montana's in #8233); the 2025 values are in a letter this review already holds; and the aggregate list allows start-year placement (nj_property_tax_relief is only in the 2026 block). The sources do not leave 2025 open, so the batch convention alone does not close SA19.
  • Fix: three 2025-01-01 entries (dependent amount 503, per diem 37.60, allowance 126) citing GL 6-B-46 p.1-2, then an issue for Iowa 2020-2024 levels (or widen #8974). Removing ia_ssa from the 2023-2025 blocks is weaker: SNAP, HUD and spm_unit_benefits still count the back-filled levels.
  • Test to add: residential care, SSI only, 31 days, period 2025-01: ia_ssa 324.60 (and, optionally, an aged dependent-person recipient: 503).

Suggestions

  • G36 (still open) Four branches can still be removed with all cases passing: the ~adult guard on child support, the family-life home marital_unit.any(has_other_income), the family-life home recipients split, and parental deeming with an SSI parent or two eligible children. The decline says these "cover branches already tested", which is not true for these four.
  • G37 candidates.yaml:1810-1839: Code 249.3(4) opens "At the discretion of the department" (Code 249 p.2). Under one reading, 51.7(6)'s "exceed" uses that discretion and is not a conflict. Add this reading to the entry and the NOTE at ia_ssa.py:110-117. Effect: only income of exactly 120%.
  • G38 Dependent-person couple level continues on a spouse in residential care: ia_ssa_federal.py:58-64 applies it when either spouse is certified, and federal joint keeps the couple after entry. 6-B tells the worker to "terminate the payment for the dependent relative" when a DP recipient enters an RCF (6-B p.66); Mrs. W at home "also receives a dependent person allowance" (p.71). Mr. W, June: model [529.10, 259], manual [270.10, 518]; same total (788.10), wrong split. Add a NOTE or a "Not modeled" line.
  • G39 Code 249.3(4)(g)'s upper bound, "not exceeding the medical assistance income limit for the eligibility group" (Code 249 p.3), is carried only by ia_ssa_smme_coverage_eligible. Say so in that input's documentation or in "Not modeled".
  • G40 One flag drives two rules with different scopes: ia_ssa_care_initial_partial_month sets the from-home deduction (ia_ssa.py:63-67) and the couple budget (ia_ssa_rcf_couple_budget.py:38). 52.1(3)"a"(6) covers only "a resident who lived at home in the month of entry" (IAC 52 p.2); 6-B p.60 applies to any entry. A resident entering from a hospital (SS $500, 20 days, aged spouse at home) gets 0 with the flag off, 143.90 under the couple budget alone, and the couple-rate deduction with the flag on. Align the ia_ssa_category and flag documentation, or split the trigger.
  • G41 Integration Case 12 (integration.yaml:269) certifies DEPENDENT_PERSON with no dependent relative in the household (6-B p.24). Add the dependent, and a NOTE that the DP payment stays out of in-home care income because 8-E excludes State Supplementary Assistance (8-E p.18; 416.1124(c)(2)).
  • G42 ia_ssa_ihhrc_participation.py:49-53 sums the dependent allowance over the tax unit. For a joint couple it is right and not double counted (515 on each row, applied once to the pooled cost). Spouses on separate returns get 515 / 1,509, so the household gets 105.71 or 79.29 instead of 185; without marital units each spouse takes the full child allowance (688). Optional: compute it once per couple, or comment that the tax unit stands in for "each dependent living in the home".
  • G43 Case 65 comment (ia_ssa.yaml:1881-1884, changed in 24231f8 after DTrim99's approval): "SSI's child test reaches students only while under 22". The model's is_ssi_ineligible_child uses is_child (age under 18), so a student aged 18-21 gets no allowance either. Reword the comment to describe the model, or note the gap.
  • G44 Link the sources behind the RCF NOTEs: rcf_personal_needs.yaml:13-16 infers rounding from GL 6-B-45 to 6-B-47 but links none (GL 6-B-46 p.1 shows $126 and $37.60; the 6-B-45 $123 is not checked). For the 2026-only candidate entries (candidates.yaml:1789, 1821) and new Code hrefs, consider https://www.legis.iowa.gov/docs/code/2026/249.pdf (same pages; :1761 already uses code/2026/422.pdf).
  • G45 Page lists and titles: add 6-B p.76 to ia_ssa_nonfinancial_eligible.py:15 and p.60 to ia_ssa_eligible.py:13; "PDF pages 1-2, 4" on the 8/5/26 line of ia_ssa_ihhrc_participation.py:12-13 ("g" is p.2, 177.8(2) is p.4); "PDF pages 1-2" at ia_ssa_care_additional_deductions.py:13; label the bare URLs at ia_ssa_has_spouse.py:14-15 and ia_ssa_smme_countable_income.py:20, and cite 249.3(4)(a)(2) at :16. The titles at ihhrc_cost_limit.yaml:21 and smme_minimum_fpg_rate.yaml:10 say "(revised May 22, 2026)", while 6-B p.41 and p.77 print "Revised March 7, 2025" (edition date vs page date).
  • G46 Style: re-wrap ia_ssa_rcf_couple_budget.py:32 (109 characters; the NOTE wraps at 88 elsewhere); use add(person, period, ["ssi_countable_income", "ssi"]) at ia_ssa_smme_countable_income.py:36 and ia_ssa_federal.py:37-39.
  • G47 Removing dividend_income from excluded_unearned_sources.yaml passes all cases, and no case would catch the double exclusion the NOTE warns about once #10079 lands (an SSI recipient's care income is the same either way). Add an RCF resident without SSI: SS $13,200 + qualified_dividend_income $600 a year gives care income 1,100 and pays 222.57 by hand (172.57 without the entry; 272.57 if double-excluded).
  • G48 SMME boundaries through the formula (Cases 44-45 set the income as an input): single from SS $19,392 a year (1,596: 1); couple at combined 2,164.00 (SS $13,104 a year each: [1, 1]); SGA switch at wages $20,280 vs $20,280.12 a year with SSDI $10,800 (both 1; the two income paths agree). Place them by SA25's months.
  • G49 ia_ssa_has_spouse has no direct true assertion: add [true, true] to Case 47 and [false, false, false] to Case 75 (the default unit of three is unpinned).
  • G50 Other branches no case pins: the in-home couple deduction sum (ia_ssa_ihhrc_participation.py:31; integration Case 6 with 100 on person2 gives 291, 191 without it); a day count of at least the month's length (ia_ssa.py:31; 40 days in January gives 328.57, 674.80 without min_); the SSA third-decimal truncation (ia_ssa_federal.py:127; raw 5.5501 gives 5.55); individual SSI with earnings after entry (Case 58 with person2 wages $500: 318.57); a spouse who enters after the other spouse's month of entry (NOTE only, ia_ssa_rcf_couple_budget.py:30-35).

Prior findings

Round 3 and earlier (66 IDs): 54 resolved, 2 still open, 1 partial, 9 accepted declines.

ID Status Evidence at the head
C1-C3, SA1-SA3, SA7-SA12, G1-G4, G8, G10-G13 RESOLVED (before round 3; no regression)
C4 SMME couples RESOLVED Combined couple income (ia_ssa_smme_countable_income.py:54-55), two-person size, >=; Cases 38, 44-49 recompute. Under the statute-first "at least", the round-3 example at 2,164.00 now gives [1, 1] (recorded as a candidate). The paths that are not combined are C7.
C5 Merge conflict RESOLVED 0 behind, MERGEABLE; all six main lines kept
C6 RCF couples after entry RESOLVED ia_ssa_rcf_couple_budget; Mr. K 270.10 (Case 57), [0, 308.57] (58), 721.84 each (59), Mr. B 890 and 270.10 (60), resources alone (61), Mr. A 845.07 (73). Pooling test: SA27
SA4 State resource parameters ACCEPTED DECLINE Unchanged
SA5 Boundary tests RESOLVED #1 Case 69, #5 Case 64, #7 Cases 53 and 57
SA6 Defaults RESOLVED default_value on all four inputs
SA13 Code 249 anchors RESOLVED #page=2 in ia_ssa.py:12, ia_ssa_eligible.py:12, ia_ssa_nonfinancial_eligible.py:12
SA14 IHHRC dependent allowance RESOLVED Cases 50 (34 / 366) and 51 (0 / 400); Ms. C 19 / 381 by run; no double count for a couple
SA15 RCF rate default RESOLVED $38.47 default; Cases 14, 15, 56. Register gap: SA26
SA16 RCF entry month RESOLVED Cases 52 (685.75), 53 (882.75); the round-3 961.75 and 885.75 reproduce; Case 33 is a discharge month (97.75)
SA17 IRWE RESOLVED (documented) Entering IRWE / 2 equals 52.1(3)"a"(1): Case 62, 1,054 / 138.57
SA18 PNA uprating RESOLVED gov.ssa.uprating, nearest $1; 2027 = 135; Case 40 = 298.57
SA19 2025 back-fill STILL OPEN Decline not accepted; see SA19 above
SA20 FLH anchor RESOLVED #page=35
SA21 Interest and dividends RESOLVED excluded_unearned_sources.yaml cites 416.1124(c)(22) and 8-E p.23, p.36; Cases 63 (162), 74 (328.57). Dividends untested: G47
SA22 Spouse tests RESOLVED ia_ssa_has_spouse in seven places; Case 65 (380)
SA23 Rounding RESOLVED Cases 66 ($1) and 67 (5.56)
SA24 SSI child deeming RESOLVED is_ssi_resource_deeming_child; Case 68 keeps $22
G5, G6 RESOLVED Cases 54-55; Cases 70-71
G9, G14, G15, G16, G21, G23, G24, G26 RESOLVED Citations, NOTEs, editions, comments and case splits as asked
G17 DP on one spouse RESOLVED Integration Case 11 [259, 259]; side effect G38
G18, G35 RESOLVED (documented) ia_ssa_category documentation; NOTEs and "Not modeled" list
G19 Child support RESOLVED NOTE and Case 46 comment link #10242
G25 Case periods PARTIAL Case 10 explains its 28 days; June periods kept (YEAR inputs keyed 2026:; accepted)
G30, G31, G33 RESOLVED Test details fixed; shared-deduction guidance (sum untested: G50); page comments fixed, and #f2 / #f2a exist in the POMS HTML
G7, G20, G22, G27, G28, G29, G32, G34 ACCEPTED DECLINE Out of scope or reasons accepted (#10242, #10304, house label style, refactors, OR kept with the YEAR read gone, "Not modeled"). C7's fix touches the lines G27 named.
G36 Low cases STILL OPEN See G36 above

DTrim99 round 2 (approved 040662b): Suggestion 1 (SGA) is fixed in 24231f8, after his approval; the single case is right, and the married cases are in C7. Suggestion 2 (default unit) declined; accepted as malformed input under CONTRIBUTING.md. Suggestion 3 (wage NOTE) not added; optional. Suggestion 4 fixed, but the new Case 65 wording describes SSI law, not the model (G43).

Investigated and cleared

  • SMME disability read from meets_ssi_disability_criteria (24231f8): a person entered only as is_ssi_disabled: true now gets SMME 0 (1 before). Cleared: is_ssi_disabled is meets_ssi_disability_criteria & ~ssi_engaged_in_sga, so under consistent inputs the change drops no one and adds the SGA workers that Code 249.3(4)(a)(2) and 6-B p.10 cover. The default dataset supplies only meets_ssi_disability_criteria, and the app shows only formula-free inputs. Optional: also OR in is_ssi_disabled for callers who override it.
  • Iowa uses the 2025 guideline for all of 2026 (8-E p.7): rejected; that page is an October 2025 snapshot, and RC-0130 shows the April 1, 2026 switch. Narrowed to SA25.
  • DP and in-home care on one spouse (integration Case 12, [259, 659]): only the blind $22 (52.1(4)) and SMME (51.7(3)) bar another type; 6-B p.20 expects programs received "simultaneously"; 8-E p.18 excludes the DP payment from care income. Test-data nit only (G41).
  • ia_ssa_has_spouse as a reinvented variable: it wraps the federal _ssi_spouse_index; no public Person/MONTH variable does the same.
  • C4 statute-first reversal: income of exactly 120% now qualifies under 249.3(4)(g), recorded as a candidate under CONTRIBUTING.md "Source conflicts". Accepted; G37 adds a reading.
  • Case 59 (both enter, no SSI, couple budget) vs p.60 "separately": p.60 is under "Spouses Living Separately"; p.61 and 51.4(3) cover spouses sharing a room. Consistent.
  • SA17 workaround edge: the IRWE / 2 entry differs from the rule only when earnings are below $65 plus IRWE ($32.50 of participation in a run). Accepted as documented.
  • SA18 uprating basis: the CPI-W ratio and the announced COLA percentage give the same allowance through 2031; a $1 difference appears from 2032, in forecast years only.
  • Merge and aggregates: every sibling line kept; ia_ssa_federal is not counted twice with ssi; the deleted ia_ssa_ihhrc_initial_partial_month has no remaining reference.
  • Tests: no margin of 1 or more, no duplicate case, no YEAR-input or period mistake in the new cases.

PDF Audit Summary

Category Count
Documents 5 PDFs (6-B, IAC 52, 177 in two editions, 51, Code 249) + POMS F, 8-E, GL 6-B-46/47, eCFR (reused); new: IAC 75, RC-0130 (Rev. 04/25 and 04/26), GL 8-E-106, GL 8-F-111
Values, rules, NOTE quotes and manual examples confirmed 102 (18 values, 44 rules, 17 anchors, 16 NOTE quotes, 7 manual examples)
2026 values mismatched 0 of 9 parameter files
Rule mismatches (code run + page re-read) 2: C7 (three paths), SA25 (January-March 2026)
Out-of-year value mismatch 1: SA19 (2025)
Source-conflict record gap 1: SA26
Documented source conflicts (not defects) 8
Rejected / narrowed 1 rejected (is_ssi_disabled input); 1 narrowed (guideline year)
Page citations and anchors 102 checked (40 hrefs, 6 candidate URLs, 22 code comments, 34 test comments): 101 correct, 1 refinable, 0 wrong. References: 75 of 75 corroborate

Validation Summary

Check Result
Regulatory C7, SA25, SA26; SA19 open; G37-G41
References 75 of 75 correct, none missing; SA13, SA20, G9, G16, G33 resolved; G44-G45
Code patterns C7 (two couple tests meet in one comparison); G42, G46. Code-health tests (201) and registry tests (705) pass; ruff clean
Tests 0 of 22 variables untested; no non-functional test; 37 new or changed ia_ssa.yaml cases and 10 integration cases recompute by hand. Gaps: SA27, C7 cases, G36, G47-G50
CI CI was still running at review time (17 pass / 10 pending, no failures); local run 106/106 Iowa YAML cases and 103/103 source-conflict guard tests pass at 4fabd46.
Branch 38 ahead, 0 behind main; MERGEABLE
Partner tests None touched

Review Severity: REQUEST_CHANGES

One critical item (C7) and four should-address items (SA19, SA25, SA26, SA27) are open. The round-3 criticals C4, C5 and C6 are resolved, and every 2026 value matches its source.

Next Steps

  1. Fix C7 with the guideline-size change and its four cases.
  2. Add Iowa's April adoption month for the guideline (SA25) and re-anchor the SMME boundary cases and the candidate example.
  3. Add the per diem candidate and the 249.12(3) cite (SA26), and the entry-month pooling case (SA27).
  4. Add the three 2025 values and one 2025 case (SA19).
  5. Ask DTrim99 to review 24231f8 and these fixes; let CI finish.
  6. To apply fixes: /fix-pr 8017.

@DTrim99

DTrim99 commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

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

Summary

PR #8017 (author: hua7450). This round reviews head 4fabd46979; round 2 approved 040662b003. Two commits landed since then: 24231f8cb0, "Keep SGA workers in Iowa's SMME disability test" (4 files, 153 diff lines), and 4fabd46979, a clean merge of main at 328d1721e2, which brings in #10334. Ziming applied our round-2 Suggestion 1 (the SGA exception) and Suggestion 4 (polish). He declined Suggestions 2 and 3, and I accept both reasons. The disability switch is right. SMME now reads meets_ssi_disability_criteria, which is SSI disability before the SGA screen, as Iowa Code 249.3(4)(a)(2), 441 IAC 51.7(2) and 6-B p.10 require. My round-2 household (Case 77) now pays $1, and I traced every output by hand. Ziming also found that my "one-line fix" was not enough. ssi_countable_income returns 0 for anyone SSI does not treat as aged, blind or disabled, so he added an own-income path. That path is a partial copy of SSI's countable-income formula. It applies the $20/$65/half exclusions but skips two SSI income rules that ssi_countable_income applies: the student earned income exclusion and in-kind support and maintenance. So a disabled full-time student under 22 who works above SGA gets $1 where SSI's income rules give $0. A worker who receives shelter support from others gets $0 where they give $1. Both households are rare and the amount is $1. Still, each is a wrong result in 2026 that contradicts 6-B p.77's "SSI income criteria", and the code, the documentation and the PR body all claim "SSI's exclusions". The batch rule makes that critical however rare the case. The fix is two lines and two cases. CI is 27/27 green on the head, and the merge with main is clean.

What changed since our approval

Change Round-2 item Status Evidence
ia_ssa_nonfinancial_eligible.py:46-48: SMME tests is_ssi_aged | meets_ssi_disability_criteria instead of is_ssi_disabled; the "not modeled" NOTE is replaced by a comment quoting 249.3(4)(a)(2), 51.7(2) and 6-B p.10 Suggestion 1 (SGA exception) Fixed (eligibility) is_ssi_disabled is meets_ssi_disability_criteria & ~ssi_engaged_in_sga. The new read drops only the SGA screen. Blindness is still excluded for SMME, so Cases 72 and 76 keep 0 and 1. The Iowa tests already enter disability through meets_ssi_disability_criteria (14 uses in ia_ssa.yaml), so no expectation moves. Both reads are YEAR variables called with period.this_year.
ia_ssa_smme_countable_income.py:37-53: for a person with is_ssi_aged_blind_disabled false, income is _apply_ssi_exclusions(ssi_earned_income, ssi_unearned_income) on that person's own income Suggestion 1 (follow-through) Added; incomplete (see Critical 1) The gate matches ssi_countable_income's ~is_eligible branch, because SMME's nonfinancial test already requires citizen or qualified noncitizen. The monthly-annual conversions are consistent: the monthly reads of YEAR variables are multiplied by 12, the helper works on annual amounts, and the result is divided by 12. max_(earned, 0) matches ssi_countable_income. The NOTE documents that there is no spouse combination and no deeming.
ia_ssa.yaml Case 77 (new) Suggestion 1 (test) Added; correct SGA: 24,000 / 12 = 2,000 > 1,690, so ssi_engaged_in_sga is true and is_ssi_disabled false. ssi is 0 (not aged, blind or disabled). SMME income: (900 − 20) + (2,000 − 65) / 2 = 880 + 967.50 = 1,847.50. The threshold is 1.2 × 15,960 / 12 = 1,596, with no spouse. ia_ssa_federal is 0, so ia_ssa is 1.
ia_ssa.yaml Case 65's comment Suggestion 4(b) Fixed It now says "SSI's child test reaches students only while under 22". The person is 22, so not a child under 20 CFR 416.1856. No value changed.
candidates.yaml us-ia:smme-blind-under-65 question Suggestion 4(a) Fixed It now names the "Supplement for Medicare and Medicaid Eligibles (SMME)".
— Suggestion 2 (SMME without marital units) Declined (accepted) Those households are malformed under CONTRIBUTING.md, as round 2 noted.
— Suggestion 3 (wage-count NOTE) Declined (accepted) It was optional. Round 2 confirmed the code already follows 52.1(3)"a" and 6-B p.59.
Body, the ia_ssa_smme_countable_income documentation, #1837 — Updated The "Not modeled" list now has the own-income-only line. The body, the documentation and #1837 say "own income after SSI's exclusions". #1837 adds companion test AQ (Case 77).

Merge-resolution check

4fabd46979 merges main at 328d1721e2 with no hand-resolved block. Against the PR parent 24231f8cb0, the merge touches no Iowa file and no shared list (programs.yaml, spm_unit_benefits.py, household_state_benefits.yaml, SNAP or HUD unearned). The only file whose name matched my filter was South Carolina TANF's unearned.yaml, which comes from #9687. Nothing to resolve.

New findings

Critical (must fix)

1. The own-income path for an SMME applicant working above SGA skips the student earned income exclusion and in-kind support and maintenance, both of which SSI's income rules apply.

  • Where. ia_ssa_smme_countable_income.py:44-51 builds own income from ssi_earned_income and ssi_unearned_income only. ssi_countable_income, which this path stands in for, does more:
    • it uses max_(earned − ssi_blind_or_disabled_working_student_exclusion, 0) as earned income;
    • it adds ssi_in_kind_support_and_maintenance to unearned income before the exclusions.
  • The law.
    • The variable's own comment quotes 6-B p.77: SMME income "is determined according to SSI income criteria".
    • Those criteria include the student exclusion (20 CFR 416.1112(c)(3)) and in-kind support and maintenance counted as unearned income (20 CFR 416.1130 and 416.1140).
    • The SGA screen does not switch off the student exclusion. main's is_ssi_blind_or_disabled_working_student_exclusion_eligible deliberately reads meets_ssi_disability_criteria so that the exclusion, "also used by MSP and Medicaid income methodologies, must not vanish above the SGA threshold".
  • Example A: an overpayment (January 2026; Case 77's household, but age 20 and a full-time student).
    • The model's path gives 1,847.50 ≥ 1,596, so it pays $1.
    • SSI's income rules exclude the student's wages. In the model's annual form, the exclusion is min(2,410 × 12, 9,730) = 9,730 a year, so (2,000 − 810.83 − 65) / 2 + 880 = 1,442.08. SSA's monthly application excludes the whole $2,000 in January, giving 880. Either way the income is below 1,596, so the answer is $0.
  • Example B: an underpayment (a single disabled adult; SSDI $500; wages $1,700, above the $1,690 SGA level; lives in their own household and receives outside shelter support).
    • The model's path gives (500 − 20) + (1,700 − 65) / 2 = 1,297.50 < 1,596, so it pays $0.
    • SSI's income rules add the PMV of 994 / 3 + 20 = 351.33: (851.33 − 20) + 817.50 = 1,648.83 ≥ 1,596, so the answer is $1.
  • Why critical.
    • These are wrong results in 2026, the claimed year, against the governing manual and regulation. The batch rule makes that critical however rare the case.
    • The gaps are not documented. The NOTE lists only the spouse and deeming omissions, while the documentation, the PR body and Update New York tax rules for 2022 #1837 all say "SSI's exclusions".
    • Round 2 called the SGA gap a suggestion only because it was documented.
  • Fix.
    • In the own-income path, use earned = max_(ssi_earned_income − ssi_blind_or_disabled_working_student_exclusion, 0) and unearned = ssi_unearned_income + ssi_in_kind_support_and_maintenance. That is the personal computation in ssi_countable_income, without the spouse and parent amounts already documented as not modeled.
    • Add Examples A and B as cases (expected 0 and 1), and add them to Update New York tax rules for 2022 #1837 next to AQ.
    • Documenting both omissions instead would put this back at round 2's suggestion level, but the code fix is smaller than the NOTE.

Should address

None.

Suggestions

None new.

Axiom, CI and branch

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 3: thanks for adding the SGA exception. The eligibility side is right, and Case 77 pays $1. One critical in the new own-income path: it skips two SSI income rules that 6-B p.77 applies to SMME, the student earned income exclusion (416.1112(c)(3)) and in-kind support and maintenance (416.1130/1140). A disabled full-time student with Case 77's income gets $1 (should be $0), and an SGA worker with shelter support gets $0 (should be $1). The fix is small: mirror ssi_countable_income's personal computation and add the two cases. Full report in the comment above.

hua7450 and others added 2 commits October 22, 2026 09:49
- Size SMME's poverty guideline by whether SMME income includes a spouse's
  income (couple computation or SSI spousal deeming), per 6-B p.77 and
  8-E p.12 (Cases 81-84).
- Use the prior year's poverty guideline before April, when Iowa adopts
  the new one (441 IAC 75.1; Cases 78-80); move the SMME boundary cases to
  April.
- List the residential care per diem statute conflict as a candidate and
  cite Iowa Code 249.12(3) in the NOTE.
- Add the 2025 dependent amount, per diem and personal needs allowance from
  General Letter 6-B-46 (Case 86), and a test of entry-month resource
  pooling (Case 85).
- Describe the model's child test in Case 65's comment.

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

hua7450 commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks, Pavel. These changes are in 8cbe544, and main (with the six merged sibling SSP PRs) is merged in 0cd88d1.

C7, the SMME guideline size: fixed as proposed.

  • ia_ssa now uses the two-person guideline only when SMME income includes a spouse's income: ssi_couple_computation_applies | is_ssi_spousal_deeming_applies. Otherwise it uses the one-person guideline, as 8-E p.12 says ("Process as a one-person household"). The comment and the NOTEs in ia_ssa_smme_countable_income cite 8-E p.12.
  • New ia_ssa.yaml cases, all in April:
    • Case 81 is your facility couple: [1, 1].
    • Case 82 is your SGA worker with a spouse earning $1,000: SMME income [1,847.50, 457.50] and ia_ssa [1, 0].
    • Cases 83 and 84 are your deeming pair: Social Security of $1,620 with a $497 spouse pension gives [1, 0], and with $498 gives [0, 0].
  • I left out your test (c). It is the same branch as Case 83 (SSI deems nothing, so the one-person guideline applies), and Case 83 sits right at the one-person threshold ($1,600 against $1,596).
  • The expected values in Cases 38, 47-49 and 77 are unchanged.

SA25, Iowa's April 1 guideline: fixed.

  • New fpg_year_start_month (4) cites 441 IAC 75.1 and RC-0130. Before April, SMME uses the prior year's guideline.
  • Cases 44-45 and 47-49 now run in April 2026, so they still pin $1,596 and $2,164.
  • New Cases 78-79 pin January's $1,565 (1, and 0 at $1,564.99). Case 80 is a couple at $2,116, which is at least January's $2,115 and pays [1, 1].
  • The us-ia:smme-income-at-least-120-percent example now says "From April 2026", and the January comments in Cases 38, 76 and 77 use $1,565.

SA26, the per diem candidate: fixed. source_conflicts/candidates.yaml adds us-ia:rcf-maximum-per-diem-rate in the shape you gave: 249.12(3) against 52.1(3) and 6-B p.72, with the Case 15 example ($328.57 against $0). The NOTE in ia_ssa.py now quotes 249.12(3). Conflict 6 on TheAxiomFoundation/rulespec-us#1837 adds the statute.

SA27, entry-month resource pooling: fixed. New Case 85 is your Case 57 variant with $2,100 of resources. March is [true, false] for the couple budget, [true, true] eligible and [846.34, 0]. April is [false, false], [false, true] and [0, 0].

SA19, 2025 values: fixed. dependent_amount, rcf_daily_limit and rcf_personal_needs add 2025 values of $503, $37.60 and $126, citing General Letter 6-B-46 pp.1-2. New Case 86 is residential care in January 2025: 324.60. The body now says only these three carry 2025 values and that #8974 covers 2017-2019.

G43, Case 65's comment: fixed. It now says the model's SSI child test (is_child) covers only children under 18.

The other suggestions (G36-G42 and G44-G50) are not in this round.

TheAxiomFoundation/rulespec-us#1837 is updated: 115 cases, the SMME guideline-size and April bullets, and companion tests AR-AX for Cases 78-86.

115 Iowa supplement cases pass locally (86 in ia_ssa.yaml), and test_source_conflicts.py passes on the merged tree.

@DTrim99

DTrim99 commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

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

Summary

PR #8017 (author: hua7450). This round reviews head 0cd88d1536. Our round 3 reviewed 4fabd46979 and requested changes for one critical. One author commit landed since: 8cbe544ae7, "Address Pavel's round-4 review of Iowa SSA" (647 diff lines). It was followed by 0cd88d1536, a merge of main at 505f530e49 that brings in the six merged sibling SSP PRs. That merge's tree is identical to an automatic merge, so nothing was resolved by hand.

The commit handles Pavel's round 4 well, and I reviewed all of it as new code:

  • C7: the SMME guideline is sized by whether SMME income includes a spouse's income.
  • SA25: Iowa's April 1 poverty-guideline switch.
  • SA26: the per diem statute candidate.
  • SA27: an entry-month resource-pooling case.
  • SA19: the 2025 dependent amount, per diem and personal needs allowance.
  • G43: the Case 65 comment.

I checked by hand every new or changed expectation (Cases 38, 44-49, 65, 76-86), and all of them are right. I also checked the three 2025 values against General Letter 6-B-46 itself. No new variable was added, so the NH #10156 state-gated key lesson does not apply. The new fpg_year_start_month is a scalar, not a breakdown key.

Our round-3 critical is still open. The commit doesn't touch it, and there is no reply to it. Only Pavel's items are answered. The SGA own-income path in ia_ssa_smme_countable_income still skips SSI's student earned income exclusion and in-kind support and maintenance. I re-traced both round-3 households at the new head, under both January's $1,565 line and April's $1,596 line:

  • Example A, a working disabled student, still gets $1 where SSI's income rules give $0.
  • Example B, a worker who receives outside shelter support, still gets $0 where they give $1.

The documentation, the code comment, the PR body and rulespec-us#1837 all still say "SSI's exclusions".

CI shows 19 passing and 8 pending (seven Contrib shards and Rest Python), with no failures. Quick Feedback ran all 86 ia_ssa.yaml cases, and the source-conflict ratchet passed on the merged tree. The merge with main is clean.

Prior findings

Finding Status Evidence
Round 3, Critical 1: the SMME own-income path for an applicant working above SGA skips the student earned income exclusion (20 CFR 416.1112(c)(3)) and in-kind support and maintenance (416.1130, 416.1140) Open (not changed; no reply) See the details below this table.
Round 2, Suggestions 1-4 Closed in round 3 (1 and 4 fixed; 2 and 3 declined with accepted reasons) No change this round. Suggestion 4's Case 65 comment was reworded again for Pavel's G43 and now describes the model's child test (is_child, under 18). That is accurate.

Evidence for round-3 Critical 1.

  • The code. ia_ssa_smme_countable_income.py:43-50 still builds own income only from ssi_earned_income and ssi_unearned_income. ssi_countable_income does two more things:
    • it subtracts ssi_blind_or_disabled_working_student_exclusion from earned income;
    • it adds ssi_in_kind_support_and_maintenance to unearned income before the exclusions.
  • The claims. The documentation (line 14), the comment at lines 38-39, the PR body ("budgeted on own income after SSI's exclusions") and the Update New York tax rules for 2022 #1837 interpretation bullet all still claim SSI's exclusions.
  • The tests. No new case covers a student or ISM; Cases 78-86 cover other branches. Update New York tax rules for 2022 #1837 has no companion rows for either household.

Re-trace of round-3 Critical 1 at 0cd88d1536

Since SA25, SMME's 120% line is $1,565 in January-March 2026 and $1,596 from April. Neither household lands between the two lines, so the defect holds in every month of 2026.

  • Example A: a disabled full-time student, age 20. SSDI is $900 a month and wages are $2,000 a month, which is above the $1,690 SGA level.
    • The model gives (900 − 20) + (2,000 − 65) / 2 = 1,847.50. That is at least 1,565 and at least 1,596, so it pays $1.
    • SSI's income criteria exclude the student's wages first. In the model's annual form, the exclusion is min(min(2,410, 2,000) × 12, 9,730) = 9,730 a year, or 810.83 a month. Income is then 880 + (2,000 − 810.83 − 65) / 2 = 1,442.08. SSA's monthly application excludes all $2,000 in January, giving 880.
    • Either way, income is below both lines, so the answer is $0.
  • Example B: a single disabled adult in their own household who receives outside shelter support. SSDI is $500 and wages are $1,700, above SGA.
    • The model gives (500 − 20) + (1,700 − 65) / 2 = 1,297.50, so it pays $0.
    • SSI's criteria add the PMV of 994 / 3 + 20 = 351.33 as unearned income: (851.33 − 20) + 817.50 = 1,648.83.
    • That is at least 1,565 and at least 1,596, so the answer is $1.
  • The law.
    • 6-B Income (SMME) says income "is determined according to SSI income criteria". This is p.77 of the 2026 manual; the 2025 edition bundled with General Letter 6-B-46 has the same text.
    • Those criteria include 20 CFR 416.1112(c)(3), 416.1130 and 416.1140.
    • On main, is_ssi_blind_or_disabled_working_student_exclusion_eligible deliberately reads meets_ssi_disability_criteria, so that the exclusion "must not vanish above the SGA threshold".
  • Why it stays critical. These are wrong results in the claimed year, and they contradict the governing manual and regulation. The gap is also undocumented, because every description claims SSI's exclusions.
  • Fix (unchanged from round 3).
    • In the own-income path, use earned = max_(ssi_earned_income − ssi_blind_or_disabled_working_student_exclusion, 0) and unearned = ssi_unearned_income + ssi_in_kind_support_and_maintenance.
    • Add Examples A and B as cases. Expect 0 and 1, in either month. With April periods, the expected SMME income is 1,442.08 for A and 1,648.83 for B.
    • Add matching companion rows and a bullet to Update New York tax rules for 2022 #1837.
    • Documenting the two omissions instead would drop this to a suggestion, as in round 2, but the code fix is smaller.

New findings

Critical (must fix)

None new. Round-3 Critical 1 is still open (above).

Should address

None.

Suggestions

None new.

Verified

C7, the SMME guideline size (ia_ssa.py:103-113). The guideline is for two people only when ssi_couple_computation_applies | is_ssi_spousal_deeming_applies (YEAR, read with period.this_year). That matches 6-B p.77's "SSI income criteria" and 8-E p.12's "Process as a one-person household".

  • For an SGA worker, is_ssi_spousal_deeming_applies is false because it is defined_for SSI-eligible individuals, so the worker is compared with the one-person line. The NOTE documents this.
  • I found no path where one person's own income still meets the two-person line, or where combined income meets the one-person line.

SA25, the April 1 switch (ia_ssa.py:114-119; new fpg_year_start_month.yaml, value 4).

  • Before April, the code reads parameters(f"{year - 1}-01-01").gov.hhs.fpg. That is the same pattern as tanf_non_cash_fpg.py's fpg_year_start_month.
  • The guideline values are 15,650 / 5,500 for 2025 and 15,960 / 5,680 for 2026, which give $1,565 / $2,115 and $1,596 / $2,164.
  • The parameter is a scalar, not a state-keyed breakdown, so multi-state simulations are unaffected.
  • The references are 441 IAC 75.1 #page=2 and RC-0130 #page=2. The description follows the existing TANF parameter's wording.

SA26, the per diem candidate. us-ia:rcf-maximum-per-diem-rate has the same shape as the PR's two other candidates: statute 249.12(3) #page=5, regulation 52.1(3), manual 6-B #page=72, follows: statute, state: ruled.

  • Its example is correct: 994 − 130 = 864 of participation; 38.47 × 31 − 864 = 328.57; 17.86 × 31 = 553.66 < 864, which gives $0.
  • The NOTE in ia_ssa.py:33-45 now quotes 249.12(3).
  • test_source_conflicts.py passed in CI's Rest shard-1 on the merged tree.

SA19, the 2025 values. I checked the three values against General Letter 6-B-46, which I downloaded and read:

  • p.1: "The income limit and payment standard for a dependent relative is $503 per month", "The maximum residential care per diem rate is $37.60", and a personal needs allowance of "$126".
  • p.2: "Effective Date / January 1, 2025".
  • The bundled 2025 manual's Billing and Payments page also says "$37.60, beginning January 1, 2025".
  • The reference format follows CLAUDE.md: the title is quoted and ends "#page 1-2", and the href is #page=1.
  • The new 2025 levels reproduce the letter's derived standards: dependent-person limits 967 + 503 = 1,470 and 1,450 + 503 = 1,953; family-life home 967 + 162 = 1,129.
  • The other Iowa parameters are the same in 2025 ($22, $162, $480.55, $1, 1.2). So 2025 is now right for every supplement's parameters, and the body's "only these three carry 2025 values" is accurate.

Hand-checked expectations (all new or changed).

Case Period Hand computation Expected Result
38 (comment only) 2026-01 2,000 − 20 = 1,980 ≥ January's 1.2 × 15,650 / 12 = 1,565 1,980; $1 Correct
44 (moved to April) 2026-04 1,596 ≥ 1.2 × 15,960 / 12 = 1,596 ("at least") $1 Correct
45 (moved) 2026-04 1,595.99 < 1,596 $0 Correct
47 (moved) 2026-04 Couple SSI 3,400 − 20 = 3,380 > 1,491, so SSI is 0 and countable income is 1,690 each; combined 3,380 ≥ 1.2 × 21,640 / 12 = 2,164 [1, 1] Correct
48 (moved) 2026-04 2,186 − 20 = 2,166 ≥ 2,164; only person1 has coverage [1, 0] Correct
49 (moved) 2026-04 2,182 − 20 = 2,162 < 2,164 [0, 0] Correct
65 (comment only) 2026-01 No value changed; the comment now describes is_child (under 18) 380 Correct
76 (comment only) 2026-01 2,020 − 20 = 2,000 ≥ 1,565 2,000; $1 Correct
77 (comment only) 2026-01 (900 − 20) + (2,000 − 65) / 2 = 1,847.50 ≥ 1,565 1,847.50; $1 Correct (as coded; see the open critical)
78 2026-01 1,565 ≥ 1,565 $1 Correct
79 2026-01 1,564.99 < 1,565 $0 Correct
80 2026-01 1,068 × 2 − 20 = 2,116 > 1,491, so SSI is 0; combined 2,116 ≥ 1.2 × 21,150 / 12 = 2,115 (below April's 2,164) [2,116, 2,116]; [1, 1] Correct
81 2026-04 person2 is in a medical treatment facility with Medicaid paying most of the care, so ssi_couple_computation_applies is [false, false] (416.414(b)(3)); each 1,700 − 20 = 1,680 ≥ the one-person 1,596 [1,680, 1,680]; [1, 1] Correct
82 2026-04 person1 is above SGA and not counted by SSI: 1,847.50 ≥ 1,596 (one person). person2's own (1,000 − 20 − 65) / 2 = 457.50; person2 has no category [1,847.50, 457.50]; [1, 0] Correct
83 2026-04 The spouse's 497 is not more than 1,491 − 994 = 497, so no deeming; 1,620 − 20 = 1,600 ≥ 1,596. person2's own 497 − 20 = 477 deeming [false, false]; [1,600, 477]; [1, 0] Correct
84 2026-04 498 > 497, so deeming applies; the deemed amount is (2,118 − 20) − (1,620 − 20) = 498; 2,098 < the two-person 2,164. person2 478 deeming [true, false]; [2,098, 478]; [0, 0] Correct
85 2026 March: couple budget (SSI was paid; 6-B p.60), so resources are 2,100 ≤ 3,000 and the payment is 38.47 × 22 − 0 = 846.34. April: the resident is tested alone (p.12), 2,100 > 2,000; the spouse at home is still tested as a couple budget [T, F] / [F, F]; eligible [T, T] / [F, T]; [846.34, 0] / [0, 0] Correct
86 2025-01 37.60 × 31 = 1,165.60; SSI 967; participation 967 − 126 = 841; 1,165.60 − 841 = 324.60 324.60 Correct

Other checks.

Axiom line assessment

The line reads TheAxiomFoundation/rulespec-us#1837 queued. It is valid: the issue is OPEN and labelled pe-parity, and it was updated at 13:52 UTC, three minutes after 8cbe544ae7.

  • It matches the head for this round's changes: 115 cases, companion tests AR-AX for Cases 78-86, and the guideline-size, April and history bullets.
  • Once round-3 Critical 1 is fixed, it needs two more companion rows (Examples A and B). It also needs its SGA bullet ("applies SSI's exclusions to that person's own income") extended to name the student exclusion and ISM.

CI status

gh pr checks 8017, rechecked at 15:21 UTC: 19 pass, 8 pending, 0 failing.

  • The 8 pending checks are Contrib states-shard-1/2/3, congress, other-shard-1/2b/3, and Python Rest (Python + variables).
  • Passed checks include Quick Feedback (all five Iowa files), all baseline shards, Rest shard-1 (2,518 passed, including the source-conflict guard), Microsimulation, Household API Partners and PR validation.
  • Run 39790563134 is on 0cd88d1536. No local runs this round.

Branch status

  • 40 ahead and 2 behind main (Add Georgia LIHEAP regular heating assistance #9968 Georgia LIHEAP and a version bump; neither touches Iowa, SSI or the shared SSP lists).
  • git merge-tree --write-tree PolicyEngine/main 0cd88d1536 is clean (tree a3ad4a11b6). GitHub shows MERGEABLE and BLOCKED (pending reviews).
  • 0cd88d1536 absorbed the six merged sibling SSP PRs with an automatic merge; its tree equals git merge-tree of its parents.

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 4: Pavel's round-4 items are all correct, and every new or changed expectation hand-checks. But our round-3 critical looks like it slipped through: this commit doesn't change it and there's no reply. The SMME SGA own-income path still skips SSI's student earned income exclusion (416.1112(c)(3)) and in-kind support and maintenance (416.1130/1140), so Example A (a student) still pays $1 instead of $0 and Example B (shelter support) still pays $0 instead of $1, while the docs and #1837 say 'SSI's exclusions'. The fix is the same small one as in round 3, plus two cases and two #1837 rows. Full report in the comment above.

A disabled SMME applicant working above the SGA level is budgeted on own
income. That income now subtracts SSI's student earned income exclusion
(20 CFR 416.1112(c)(3)) and adds in-kind support and maintenance (416.1130,
416.1140), as ssi_countable_income does (Cases 87-88).

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

hua7450 commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks, David, and sorry I missed your round-3 critical. It came in after my last status check, and I didn't check again before pushing the round-4 fixes. It's fixed in 647fdf4.

Round-3 Critical 1, the SMME SGA path: fixed as proposed.

117 Iowa supplement cases pass locally (88 in ia_ssa.yaml), and test_source_conflicts.py passes.

@hua7450
hua7450 requested a review from DTrim99 October 22, 2026 16:01
@DTrim99

DTrim99 commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

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

Summary

PR #8017 (author: hua7450). This round reviews head 647fdf4ee2. Our round 4 reviewed 0cd88d1536 and requested changes for one critical carried from round 3. One author commit landed since: 647fdf4ee2, "Apply SSI's student exclusion and in-kind support on the SMME SGA path" (114 diff lines). There are no merges since round 4.

The round-3 critical is fixed, as proposed. In ia_ssa_smme_countable_income, the own-income path for a disabled applicant working above the SGA level now follows ssi_countable_income's personal computation:

  • earned income is max_(ssi_earned_income − ssi_blind_or_disabled_working_student_exclusion, 0);
  • unearned income is ssi_unearned_income + ssi_in_kind_support_and_maintenance.

I traced both round-3 households at the new head, and they now match SSI's income rules. Example A (Case 87) gets $0 with SMME income 1,442.08. Example B (Case 88) gets $1 with SMME income 1,648.83. Nothing is counted twice. ISM is not among SSI's unearned income sources, and the where keeps the SSI-counted and own-income branches apart. No other Iowa case sets a student or shelter-support input, so every existing expectation is unchanged. The documentation, the code comment, the PR body and rulespec-us#1837 now describe the change accurately, and #1837 has companion rows AY and AZ.

I have no new critical or should findings. There is one optional suggestion: #1837's paste-ready dispatch text still says "cases A to AP".

CI is still running on 647fdf4ee2, with no failures so far. Quick Feedback passed: it ran all 117 Iowa cases on the merge with today's main, including Cases 87 and 88. The 11 baseline shards, Python Rest, Microsimulation, Household API Partners and Package are pending. The merge with main is clean. With no critical or should findings open, I'm approving, but let CI finish green before merging.

Prior findings

Finding Status Evidence
Round 3, Critical 1 (open in round 4): the SMME own-income path for an applicant working above SGA skipped the student earned income exclusion (20 CFR 416.1112(c)(3)) and in-kind support and maintenance (416.1130, 416.1140) Fixed ia_ssa_smme_countable_income.py:46-53 now subtracts ssi_blind_or_disabled_working_student_exclusion and adds ssi_in_kind_support_and_maintenance. New Cases 87 and 88 are Examples A and B, with the expected values we gave. The documentation, comment, body and #1837 are updated. See the traces below.
Round 2, Suggestions 1-4 Closed in round 3 (1 and 4 fixed; 2 and 3 declined with accepted reasons) No change this round.

New findings

Critical (must fix)

None.

Should address

None.

Suggestions

  1. rulespec-us#1837's dispatch text stops at case AP. Step 1's paste-ready review_finding ends "Companion tests, each assigning every leaf input: cases A to AP in the issue's Companion tests table, plus the conflicts comment's cases." The table now runs to AZ. An encoder who follows the paste text literally would skip AQ-AZ: the SGA rows (AQ, AU, AY, AZ), the January guideline rows (AR, AS), and AT, AV, AW and AX. The range has been stale since AQ was added in round 3; we missed it in rounds 3 and 4. Fix: change "A to AP" to "A to AZ" in the issue. The PR itself doesn't need to change, and this is non-blocking.

Verified

The formula (ia_ssa_smme_countable_income.py:34-63).

  • Variables and periods. ssi_earned_income, ssi_unearned_income, ssi_blind_or_disabled_working_student_exclusion and ssi_in_kind_support_and_maintenance are all YEAR floats. Read with a MONTH period, Core returns one-twelfth of the annual value (calculate_divide), and the formula multiplies by 12 again before _apply_ssi_exclusions. That is the same pattern as the existing ssi_earned_income read, which Case 77 already exercises.
  • No double counting.
    • gov.ssa.ssi.income.sources.unearned lists 17 sources. Item (h), "Support and maintenance in kind", is a comment with no variable, so ISM is not already inside ssi_unearned_income.
    • ssi_earned_income doesn't net out the student exclusion. The exclusion is computed from ssi_earned_income itself, as min(min(amount, monthly earnings) × 12, annual cap). The max_(…, 0) floor is the same as in ssi_countable_income.
    • For a person SSI counts, the formula uses ssi_countable_income + ssi, which already includes ISM and the student exclusion. where(counted_by_ssi, income, own_income) picks only one branch.
  • It mirrors ssi_countable_income. That variable's personal computation is max_(ssi_marital_earned_income − ssi_blind_or_disabled_working_student_exclusion, 0) plus ssi_marital_unearned_income + parent_deemed + ism. The SGA path takes the person's own amounts instead. It deliberately leaves out deeming and marital attribution, as the existing NOTE says (Case 82). Since SSI doesn't treat this person as eligible, the marital variables would equal own income anyway.
  • The student exclusion above SGA. is_ssi_blind_or_disabled_working_student_exclusion_eligible reads meets_ssi_disability_criteria, not is_ssi_disabled. So the exclusion still applies to a student who is above SGA, which is the case this path serves.
  • ISM for this person. ssi_pmv_amount uses the couple FBR only when ssi_couple_computation_applies | is_ssi_spousal_deeming_applies. Both are false for someone SSI doesn't count, so the PMV is the individual 994 × 1/3 + 20. That is consistent with the one-person guideline that ia_ssa applies to this person.
  • No new cycle. ssi_countable_income already computes both new inputs for every person.

The law. 6-B Income (SMME) p.77 says income "is determined according to SSI income criteria". Those criteria include 20 CFR 416.1112(c)(3), the student earned income exclusion, and 416.1130 and 416.1140, ISM valued under the presumed maximum value rule.

Case inputs and periods.

  • Both cases run in April 2026. They key YEAR inputs (age, is_full_time_student, meets_ssi_disability_criteria, income) by 2026:. ia_ssa_category and ia_ssa_smme_coverage_eligible are MONTH variables, entered as in Cases 44-49.
  • ssi_receives_outside_shelter_support is a MONTH bool keyed by 2026:. Core dispatches a STOCK input to every month, and ssi_pmv_applies (YEAR) reads the last month. That is the same shape as main's ssi_countable_income.yaml ISM case (4,108 a year in 2025).
  • ssi_federal_living_arrangement defaults to own household, so the PMV rule applies.
  • SGA test. ssi_engaged_in_sga compares gross monthly earnings with 1,690 using ">". Case 87 has 2,000 and Case 88 has 1,700, so both are above SGA and use the own-income path.

Hand-checked expectations. Cases 87 and 88 are new. Cases 77 and 82 are unchanged, but they run through the changed formula, so I re-traced them.

Case Period Hand computation Expected Result
87, SMME income 2026-04 Student exclusion: min(min(2,410, 2,000) × 12, 9,730) = 9,730 a year, or 810.833 a month. Earned 2,000 − 810.833 = 1,189.167; unearned 900; (900 − 20) + (1,189.167 − 65) / 2 = 880 + 562.083 = 1,442.083 1,442.08 (±0.01) Correct
87, ia_ssa 2026-04 1,442.08 < 1.2 × 15,960 / 12 = 1,596 (one person) 0 Correct
88, SMME income 2026-04 PMV 994 × 0.333333333 + 20 = 351.333; unearned 500 + 351.333 = 851.333; (851.333 − 20) + (1,700 − 65) / 2 = 831.333 + 817.50 = 1,648.833 1,648.83 (±0.01) Correct
88, ia_ssa 2026-04 1,648.83 ≥ 1,596; coverage input set; no SSA-paid supplement 1 Correct
77 (unchanged) 2026-01 Age 50, not a student, no shelter support: exclusion 0 and ISM 0, so (900 − 20) + (2,000 − 65) / 2 = 1,847.50 ≥ 1,565 1,847.5; 1 Correct
82 (unchanged) 2026-04 Neither spouse is a student or has shelter support: person1 1,847.50; person2 (1,000 − 20 − 65) / 2 = 457.50 [1,847.50, 457.50]; [1, 0] Correct
  • Other cases. A grep of all five Iowa test files at the head finds is_full_time_student only in Case 65 and Case 87. In Case 65 it belongs to a 22-year-old who isn't disabled and isn't in SMME. Shelter-support inputs appear only in Case 88. So no other expectation can move.
  • The student exclusion's annual form. Case 87's 1,442.08 uses the federal variable's annualized exclusion, the same one ssi_countable_income uses. SSA applies the exclusion month by month until the annual cap is used up. With $2,000 a month, January-April total 8,000, which is within 9,730, so SSA would exclude all of April's wages and income would be 880. Under either form the April result is $0. Months after the cap runs out could differ, but that comes from main's federal method, not from this PR.

Documentation, comment, body and #1837.

  • Documentation. It now reads "the person's own income, including in-kind support and maintenance, after SSI's exclusions, including the student earned income exclusion." That is accurate.
  • Comment (lines 35-45). It names the student exclusion (416.1112(c)(3)), ISM (416.1130, 416.1140) and the general and earned income exclusions, and cites Cases 77, 87 and 88. That is accurate.
  • PR body.
    • The SMME bullet now says "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".
    • The test list gives 117 cases (88 / 12 / 7 / 6 / 4). I counted the same in each file at the head.
    • The coverage bullet names Cases 87 and 88.
  • Update New York tax rules for 2022 #1837.
    • The issue is OPEN and labelled pe-parity, and it was updated at 16:01:33 UTC with the push.
    • It now says 117 cases (88 in ia_ssa.yaml).
    • It adds rows AY (Case 87: 810.83; 1,442.08 < 1,596; $0; 416.1112(c)(3); p.77) and AZ (Case 88: PMV 351.33; 1,648.83 ≥ 1,596; $1; 416.1130; 416.1140; p.77).
    • The SGA interpretation bullet now lists the student exclusion, ISM and the general and earned income exclusions, with cases AQ, AU, AY and AZ.
    • Both new rows match the head.

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: module paths, corpus citations, verbatim law, required outputs and companion tests.
  • It was updated with this push, and it matches the head: 117 cases, rows AY and AZ, and the extended SGA bullet.
  • The companion rows derive their values from the regulation amounts and the manual, not from PolicyEngine output.
  • The one stale detail, the "A to AP" range in the paste text, is Suggestion 1.

CI status

gh pr checks 8017, rechecked at 16:41 UTC: 2 pass, 15 pending, 0 failing (run 39810269603, on 647fdf4ee2).

  • Passed.
    • PR validation (lock, guard tests, lint, changelog).
    • Quick Feedback ran on the merge ref 297266a240, which is this head merged into main at 271d5e945b, with policyengine-core 3.33.12. It ran all five Iowa files: ia_ssa.yaml 88 passed (including Cases 87 and 88), integration.yaml 12, ia_ssa_resources_deemed_from_parents.yaml 7, ia_ssa_nonfinancial_eligible.yaml 6 and ia_ssa_income_deemed_from_parents.yaml 4.
  • Pending.
    • Still running: Household API Partners, Package and compatibility, and Microsimulation.
    • Queued: the 11 baseline shards (contrib-hhs, household, irs, reform, rest-a, rest-b, ssa-usda, states-shard-1 to 4) and Python Rest (shard-1 + variables). Rest shard-1 includes the source-conflict guard.
  • No local runs this round. Let CI finish green before merging.

Branch status

  • 41 ahead and 3 behind main: Add Georgia LIHEAP regular heating assistance #9968 (Georgia LIHEAP), a version bump, and Model state school meal coverage beyond universal meals #10238 (school meal coverage). None of them touches Iowa, SSI or the shared SSP lists.
  • git merge-tree --write-tree PolicyEngine/main 647fdf4ee2 is clean (tree d9957cd636).
    • Both sides edit programs.yaml: main in the school-meals state_implementations, this PR in the Iowa SSA entry. They auto-merge, and the Iowa entry is intact.
  • GitHub showed MERGEABLE and BLOCKED at 16:33 UTC; the review decision is CHANGES_REQUESTED, from our round 4. At 16:41 it was recomputing (UNKNOWN) after main moved.

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.

Round 5: the round-3 critical is fixed as proposed. The SMME SGA path now applies SSI's student earned income exclusion and in-kind support and maintenance without double counting, Case 87 (student) gives $0 and Case 88 (shelter support) gives $1, and the docs, body and #1837 (rows AY/AZ) match. Thanks for the quick turnaround. CI was still running when I checked (Quick Feedback ran all 117 Iowa cases green), so please let it finish green before merging. One minor suggestion on the #1837 text. 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 5): Add Iowa state supplementation for 2026

IDs: C = critical, SA = should address, G = suggestion. Round-4 IDs keep their numbers. New findings start at SA28 and G51. There is no new critical item, so C8 is not used. DTrim99 approved this head (647fdf4). SA28 concerns a NOTE that he accepted; SA29, SA30 and the SA19 residual are not in his reviews.

Source Documents

Branch Status and CI

  • Branch: 41 ahead, 5 behind main (2bc4ccc). The 5 commits are #9968 (Georgia LIHEAP), #10238 (school meals), #9973 (Arkansas LIHEAP) and 2 version bumps. None touches Iowa, SSI, the HUD or SNAP lists, household_state_benefits or spm_unit_benefits. git merge-tree 2bc4ccc970 HEAD is clean, and GitHub shows MERGEABLE. A rebase is not necessary for review.
  • CI: 26 pass, 1 cancelled ("Python tests / Full Suite - Microsimulation", cancelled, not a test failure); no failures at review time
  • Local run at 647fdf4: 117/117 Iowa YAML cases pass (ia_ssa 88, integration 12, resources deemed 7, nonfinancial 6, income deemed 4). 848 passed and 10 skipped in the source-conflict guard, programs registry and aggregate-list tests. 163 code-health tests pass, and ruff is clean on the 22 Iowa variables.
  • No partner test file is touched.

Fixed since round 4

  • C7 (guideline size): ia_ssa.py:110-113 uses the two-person guideline only when ssi_couple_computation_applies | is_ssi_spousal_deeming_applies. Cases 81-84 pin each branch. By probe, all four round-4 rows now give the rule's result ([1, 1], [1, 1], [1, 0], [1, 0]). Cases 38 and 47-49 do not change. I accept the decline of my test (c): row 4 gives [1, 0] under both readings, and Case 83 (1,600 against 1,596; combined 2,097 < 2,164) is the case that separates them.
  • SA25 (April 1 guideline): fpg_year_start_month.yaml (4) and ia_ssa.py:114-119. Probe: 2026-03 uses 1,565 and 2026-04 uses 1,596. 2025-01 uses 1,506 and 2025-04 uses 1,565, which agrees with RC-0130 Rev. 04/25. Cases 78-80 pin January, and Cases 44-49 now run in April. Test gap: SA29.
  • SA26 (per diem candidate): candidates.yaml:1778-1810 has the three sources, follows: statute, the "privately operated" note and the correct example (328.57 against $0). The NOTE at ia_ssa.py:33-45 quotes 249.12(3) word for word. Year span: G51.
  • SA27 (entry-month pooling): Case 85. A mutation run without | ia_ssa_rcf_couple_budget at ia_ssa_eligible.py:42-44 fails Case 85 only (1 failed, 116 passed).
  • DTrim99's SGA critical: ia_ssa_smme_countable_income.py:46-53 subtracts the student earned income exclusion and adds in-kind support and maintenance. Case 87 (1,442.08, so 0) and Case 88 (1,648.83, so 1) recompute by hand. ISM is not counted twice.
  • G43: the Case 65 comment now describes is_child (under 18).
  • SA19, 2025 part: 503 / 37.60 / 126 match GL 6-B-46 p.1-2, and Case 86 gives 324.60. The 2023-2024 part stays open (below).

Critical (Must Fix)

None.

Should Address

SA28. The SMME SGA path ignores the spouse's income, but SSI deeming and MEPD family income both count it

For a disabled applicant who works above the SGA level, ia_ssa_smme_countable_income uses only the person's own income, and ia_ssa then uses the one-person guideline. SSI's deeming variables apply only to people SSI treats as eligible, so a spouse's income never enters this path. The sources count the spouse on every route that they give. The error goes in both directions, and in two households it changes the result under either guideline size. In round 4 I said that the "Not modeled" line for spouse income on this path could stay. I did not test that line against deeming then. DTrim99 also accepted the NOTE in round 5. 8-F p.120 and the deeming exceptions on 8-E p.11 were not part of either check.

  • Where: ia_ssa_smme_countable_income.py:43-45 (NOTE: "not combined with a spouse's, and none is deemed") and :46-61 (own-income path). ia_ssa.py:110-112 reads is_ssi_spousal_deeming_applies, which has defined_for = is_ssi_eligible_individual, so it is false for an SGA worker. Case 82 (ia_ssa.yaml:2378-2420).
  • Source:
    • 6-B Income (SMME): "Income for eligibility is determined according to SSI income criteria. See 8-E, Income." (6-B p.77)
    • SSI income "includes any income deemed from a parent, spouse, or sponsor" (8-E p.8).
    • Deem for "State Supplementary Assistance coverage groups according to SSI policies except for" Medically Needy, in-home care, dependent person and MEPD (8-E p.11). SMME is not an exception.
    • At $497 or less, "Process as a one-person household"; above $497, combine both incomes and compare with the couple standard (8-E p.12, p.13).
    • MEPD, the group open to an SGA worker under 65: "The total income of the family is considered for eligibility." (8-F p.120)
    • Code 249.3(4)(c), "would be eligible for supplemental security income benefits but for ... being engaged in substantial gainful activity and having excess income" (Code 249 p.2), and 51.7(2) (IAC 51 p.2) treat the person as an SSI claimant. The PR already uses this reading for the student exclusion and ISM on this path (Cases 87-88).
    • Counter-text: "If Mr. M's own income makes him ineligible for SSI, it's not necessary to consider Mrs. M's income" (8-E p.14). Read literally, it stops deeming on every SMME path, because SMME income is always above $994. That would also make Case 84 wrong. It does not support a carve-out for the SGA path only.
  • Failing inputs (April 2026; applicant under 65 with meets_ssi_disability_criteria, SMME category and coverage set; spouse aged 45, not disabled; model run at the head; 120% = 1,596 for one person, 2,164 for two):
Household (monthly) Model: SMME income, ia_ssa Rule (8-E deeming; 8-F family income)
Row 1: wages $1,700; spouse wages $3,000 807.50: [0, 0] (1,700 + 3,000 - 20 - 65) / 2 = 2,307.50 >= 2,164: [1, 0]
Row 2: wages $3,085; spouse wages $1,500 1,500: [0, 0] (3,085 + 1,500 - 85) / 2 = 2,250 >= 2,164: [1, 0]
Row 3: wages $3,277; spouse wages $600 1,596: [1, 0] (3,277 + 600 - 85) / 2 = 1,896 < 2,164: [0, 0]
Row 1 with the applicant aged 70 (SSI path) 2,307.50: [1, 0] Same as the rule
  • Why should address: rows 1 and 2 give $1 under any guideline size, and only the repo's own-income reading gives $0. The same household gets the opposite result at age 70. The NOTE states a mechanism, not a source. Under the documented-choice rule, a NOTE does not save a choice that contradicts 8-E p.11-13 and 8-F p.120; round 4 applied the same test to C7's NOTE. This is not critical: the rule reaches this path by the "would be eligible but for" inference, the effect is $1 a month, the population is input-gated (a married SGA worker under 65 with coverage set), and my round-4 text let the line stay.
  • Fix: on the own-income path, deem as 8-E p.12-13 do. Take the spouse's income after the ineligible-child allocations. If it is more than $497 (couple FBR minus individual FBR), put both spouses' earned and unearned income through _apply_ssi_exclusions once. Then use the two-person guideline, for example by adding that flag to spouse_income at ia_ssa.py:110-112. The federal ssi_*_deemed_from_ineligible_spouse variables cannot be reused as they are, because they multiply by is_ssi_aged_blind_disabled. Rewrite the NOTE at :43-45 and the Case 82 comment. Alternative: keep own income, cite a source for the carve-out, and record a source_conflicts candidate. No review role found such a source.
  • Tests: add row 1: ia_ssa_smme_countable_income [2,307.50, 1,457.50], ia_ssa [1, 0]. Add row 3: [1,896, 257.50], [0, 0]. Update Case 82: [2,347.50, 457.50] ((900 - 20) + (2,000 + 1,000 - 65) / 2); ia_ssa stays [1, 0]. Add a control: Case 82's worker with a spouse pension of $497 and no wages gives [1,847.50, 477] and [1, 0] (nothing deemed, one-person guideline).

SA29. No case pins the April switch month; a start month of 2 or 3 passes every test

The SMME cases in 2026 run in January (Cases 78-80) or April (Cases 44-49, 81-84, 87-88). None runs in February or March. So the tests show that the switch is after January and not after April, but not that it is in April.

  • Where: fpg_year_start_month.yaml:3 (2026-01-01: 4) and ia_ssa.py:116-119.
  • Source: the federal poverty level is "revised annually on April 1" (IAC 75 p.2); RC-0130 Rev. 04/26 gives $1,596 / $2,164 "Effective 4/1/26" (RC-0130 p.2).
  • Probe (coordinator, scratch copy, snapshot not changed): start month 2 gives 117 passed; start month 3 gives 117 passed; start month 5 fails Cases 45 and 49.
  • Why should address: this is a missing edge case for a tested variable, and the month is the point of SA25.
  • Fix: add this case. It fails with start month 2 or 3, because March would then use 1,596. With Case 45 (April, 1,595.99, so 0; fails at month 5 or later), only month 4 passes. A one-cent-below March case (1,564.99, so 0) passes under any start month from 2 to 4, so the case must sit at or above 1,565.
- 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
    ia_ssa_category: SMME
    ia_ssa_smme_coverage_eligible: true
    ia_ssa_smme_countable_income: 1_565
  output:
    # 1.2 * 15,650 / 12 = 1,565 until April (441 IAC 75.1; RC-0130 Rev. 04/25).
    ia_ssa: 1

Optional formula version: period: 2026, age 70, social_security_retirement: 19_200, month-keyed category and coverage for 2026-03 and 2026-04. Then SMME income is 1,580 in both months, and ia_ssa is {2026-03: 1, 2026-04: 0}.

SA30. The fpg_year_start_month.yaml description does not follow the parameter description template

The description at fpg_year_start_month.yaml:1 reads "Iowa begins applying the current calendar year's federal poverty guidelines to the State Supplementary Assistance SMME income test in this month." The template in the policyengine-model-development skill (parameters.md, and the implementation validator's "Parameter formatting — SHOULD ADDRESS" item) asks for one sentence, an allowed verb (limits, provides, sets, excludes, deducts, uses), the program name spelled out with no acronym, and the ending "under the [Full Program Name] program". This description has three breaks: the verb, the acronym "SMME", and no program ending. The 9 sibling Iowa parameters follow the template; smme_amount.yaml:1 and smme_minimum_fpg_rate.yaml:1 spell out "Supplement for Medicare and Medicaid Eligibles".

  • Why should address: a formatting and pattern item, the same class as round-1 SA7 on this PR. CI does not check descriptions. The federal TANF fpg_year_start_month.yaml uses "begin applying", but the acronym and the missing ending have no precedent in the Iowa files.
  • Fix: use this exact text:
    description: Iowa uses the current calendar year's federal poverty guidelines from this month for the Supplement for Medicare and Medicaid Eligibles income test under the State Supplementary Assistance program.

SA19 (PARTIAL). 2023 and 2024 still back-fill the 2025 levels while ia_ssa is in the 2023 and 2024 aggregates (also raised by DTrim99 in round 1)

The 2025 part is fixed. 2023 and 2024 now return the 2025 levels. Iowa published lower levels for both years, and this round read them. The NOTE in rcf_personal_needs.yaml states $123 for 2024, but the parameter returns 126. Round 4 asked for an issue for 2020-2024 if the values were not added. There is no issue and no reply to that part (gh: #8974 is open with 0 comments and covers 2017-2019 only; no other issue covers Iowa 2020-2024).

  • Where: the first value is 2025-01-01 in dependent_amount.yaml:3, rcf_daily_limit.yaml:3 and rcf_personal_needs.yaml:3; NOTE at rcf_personal_needs.yaml:14-17. ia_ssa is in household_state_benefits.yaml:109 (2023) and :237 (2024), the SNAP list (gov/usda/snap/income/sources/unearned.yaml:37, from 2009), the HUD list (gov/hud/annual_income/sources/unearned.yaml:39, from 2024) and the undated spm_unit_benefits.py:40.
  • Source: GL 6-B-45, "Effective Date January 1, 2024": "The income limit and payment standard for a dependent relative is $490 per month", "The maximum residential care per diem rate is $36.82", and the personal needs allowance "is $123" (GL 6-B-45 p.1; per diem also on p.24). The 2023 standards sheet gives a dependent-person "Maximum Payment" of $474, an RCF "Personal Needs Allowance" of $120 and a "Maximum Cost-Related per Diem Rate" of $35.89 (2023 standards, one page). Both pages were read as images. The blind $22 and the family-life home supplement $162 back-fill correctly.
  • Error (model run at the head; age 70, January, 31 days):
Household 2024 model / law 2023 model / law
Residential care, SSI only 348.60 / 321.42 (+27.18) 377.60 / 318.59 (+59.01)
Dependent person, SSI only, dependent income 100 503 / 490 (+13) 503 / 474 (+29)
Dependent person, dependent income 495 (2024) or 480 (2023) 503 / 0 503 / 0

Hand check for 2024: 31 x 36.82 - (943 - 123) = 321.42. Microsimulation reaches only the blind $22, which is correct in both years, so the aggregate effect is nil. The error is per household, for web-app users who select a category.

  • Why still should address: the sources do not leave 2023-2024 open, which is the reason round 4 gave for 2025. The tracking step that would make this a documented choice was not done. This is not critical: the microsimulation effect is nil, and the PR claims only 2025-2026.
  • Fix (either option closes SA19; option A is stronger and about as cheap):
    • A. Add 2024-01-01 values 490 / 36.82 / 123 with GL 6-B-45 #page=1, and 2023-01-01 values 474 / 35.89 / 120 with the 2023 standards sheet. Test: residential care, SSI only, 31 days, period: 2024-01, ia_ssa 321.42. Back-fill before 2023 is then the batch convention, which is a suggestion.
    • B. File an issue for Iowa 2020-2024 levels (or widen #8974) that names both sources. Add a NOTE line to the three files: "Values before 2025 back-fill the 2025 level; see #N."
    • Removing ia_ssa from the 2023 and 2024 blocks of household_state_benefits alone is weaker, because SNAP, HUD and spm_unit_benefits still count the back-filled levels.
    • With option A, also correct the rounding NOTE at rcf_personal_needs.yaml:14-17: 120 x 1.032 = 123.84, but Iowa published $123, so nearest-dollar rounding does not fit 2024. This affects only projected years (2027 and later).

Suggestions

New:

  • G51 The per diem candidate covers 2026 only (candidates.yaml:1780-1783, from: 2026), but the PR now applies the maximum rate in 2025 (rcf_daily_limit.yaml, Case 86). The 2025 manual has the same "two options": "$37.60, beginning January 1, 2025" and the $17.86 flat rate (GL 6-B-46 p.74). 2025 example: 324.60 against $0 (31 x 17.86 = 553.66 < 841). Set from: 2025, and optionally add GL 6-B-46 #page=74 as the 2025 manual source.
  • G52 The 8-E p.12 rule now sets the guideline size (ia_ssa.py:103-113), but 8-E is cited only in comments. Neither reference tuple (ia_ssa.py:10-19, ia_ssa_smme_countable_income.py:15-21) links it. Add "https://hhs.iowa.gov/media/4011/download?inline#page=12", # 8-E Deeming from an Ineligible Spouse; PDF pages 11-12, 14 to both. This is not higher: both tuples cite 6-B p.77 ("See 8-E, Income"), the comment cites are verified, and round-1 G8 rated the same pattern a suggestion.
  • G53 FPG timing notes (fpg_year_start_month.yaml, ia_ssa.py:114-115). (a) 75.1's definitions "apply to 441—Chapters 74 through 88" (IAC 75 p.1), and SMME is in chapter 51. Add 6-B p.77 to the parameter's references and one sentence: SMME uses the Medicaid group's poverty level (6-B p.77, RC-0130). (b) 8-E p.7 (revised May 22, 2026) still prints $1,565 / $2,115 after April 2026, because GL 8-E-106 p.1 dates that content October 15, 2025. Name this in a NOTE. (c) media/6948/download is a rolling URL. Cases 78-80 cite "(RC-0130)" for $1,565 / $2,115, which only Rev. 04/25 p.2 shows; cite that capture. (d) Optional: add 2025-01-01: 4 with Rev. 04/25, so that 2025 does not rely on back-fill.
  • G54 The SGA-path student exclusion inherits two federal simplifications. Document them in the Case 87 comment or the NOTE at ia_ssa_smme_countable_income.py:43-45. (a) The annual cap is averaged. SSA's monthly method gives Case 87's household 880 in January-April, 982.50 in May and 1,847.50 from June, so the rule pays $1 a month for 7 months where the model pays $0 (1,442.08 in every month). (b) The federal eligibility tests only age and full-time study, but 8-E p.19 also requires "Not married" and "Not the head of the household". Both come from main's federal method; DTrim99 noted (a).
  • G55 An FPG reform that does not start on January 1 reaches Iowa SMME one year late, because ia_ssa.py:119 always reads {year}-01-01. Probe: a reform from 2026-04-01 changes nothing until 2027-04. wic_income_limit.py and tanf_non_cash_fpg.py have the same limit, so this is not a pattern violation. Optional: read parameters(period) from the start month on, or reuse the year_lag helper in tax_unit_fpg.py (which would also answer G27).
  • G56 2025 tests. The start month exists only from 2026-01-01, so 2025 relies on back-fill, and no 2025 SMME case pins it. Add period: 2025, age 70, Social Security $18,720 a year (1,540): March 1 (>= 1,506) and April 0 (< 1,565). The 2025 dependent-person amount is also unpinned: add period: 2025-01, DEPENDENT_PERSON, dependent income 100, which gives 503 (518 under the old back-fill).

Carried (author: "not in this round"; no regression found): G36, G37, G38, G39, G40, G41, G42, G47 and G50 stay as written in round 4. Updates:

  • G44 (partial): GL 6-B-46 is now linked in three parameters. GL 6-B-45 (now located: https://hhs.iowa.gov/media/12206/download#page=1) and GL 6-B-47 are still not linked for the rounding NOTE. The new candidate URL at candidates.yaml:1789 is another undated code/249.pdf.
  • G45: ia_ssa_smme_countable_income.py:16 still says "Iowa Code 249.3(4)(g)", while the comment at :37-38 relies on 249.3(4)(a)(2). :20 is still an unlabeled URL.
  • G46: one more manual sum at ia_ssa_smme_countable_income.py:51-53. House form: add(person, period, ["ssi_unearned_income", "ssi_in_kind_support_and_maintenance"]).
  • G48, values for SA25's months: April single, Social Security $19,392 a year (1,596, so 1); April couple, $13,104 each (2,164, so [1, 1]); January couple, $12,816 + $12,804 (2,115, so [1, 1]); SGA switch at wages $20,280 against $20,280.12 with SSDI $10,800 (both 1; the two income paths agree).
  • G49: add ia_ssa_has_spouse: [true, true] to Case 83. It also shows C7's point (spouse present, one-person guideline).

Prior findings

Round 4 and earlier (84 IDs): 59 resolved, 3 partial, 13 still open, 9 accepted declines. Of the 21 items open after round 4: 5 resolved, 3 partial, 13 still open.

ID Status Evidence at the head
C1-C6, SA1-SA3, SA5-SA18, SA20-SA24, G1-G6, G8-G19, G21, G23, G24, G26, G30, G31, G33, G35 RESOLVED (before round 5) No regression. C4 (Cases 38, 47-49) and SA23 (Cases 66-67) re-checked because the SMME lines changed.
C7 SMME guideline size RESOLVED ia_ssa.py:110-113; Cases 81-84; all four round-4 rows give the rule's result. Test (c) decline accepted. Spouse income on the SGA path: SA28
SA25 April guideline RESOLVED fpg_year_start_month.yaml; Cases 78-80 and 44-49; probe 1,565 / 1,596 by month. Month not pinned: SA29
SA26 Per diem candidate RESOLVED candidates.yaml:1778-1810; NOTE at ia_ssa.py:33-45. Years: G51
SA27 Entry-month pooling RESOLVED Case 85; the mutation fails Case 85 only
SA19 Pre-2026 back-fill PARTIAL 2025 fixed (GL 6-B-46; Case 86). 2023-2024 open: SA19 above
G43 Case 65 comment RESOLVED The comment describes is_child (under 18)
G25 Case periods PARTIAL (accepted part stands) June periods unchanged. The new April periods follow SA25; Case 85 uses period: 2026 with month keys
G44 Source links PARTIAL See G44 above
G36-G42, G45-G50 STILL OPEN Suggestions; G36's four removable branches are still untested
SA4, G7, G20, G22, G27, G28, G29, G32, G34 ACCEPTED DECLINE Unchanged. G27's lines were rewritten for C7 and SA25; the guideline is still inline (G55 names a helper)

DTrim99: his round-3 and round-4 critical (the SGA path skipped the student exclusion and ISM) is resolved in 647fdf4, and he approved this head. His round-5 suggestion (rulespec-us#1837 dispatch text "A to AP" to "A to AZ") is issue-only, and I do not repeat it. His reviews do not cover the SA19 residual or SA28-SA30.

Investigated and cleared

  • 8-E p.12 only in comments, as a missing reference (verify-4): rejected as critical and as should address. Both tuples are non-empty and cite the governing rule (249.3(4)(g), 51.7(6), 6-B p.77). The guideline size is not a parameter value. Merged state SSP variables cite secondary sources in comments in the same way. Kept as G52.
  • FPG year logic: the if acts on scalars only (period.start.month and an integer parameter). Reading parameters(f"{year}-01-01") is a house pattern, and reforms from January 1 flow through. unit: month and period: year match the federal TANF precedent.
  • Month-keyed ssi_federal_living_arrangement: a month-keyed override is averaged as a couple by the YEAR federal ssi_countable_income (1,690 instead of 1,680). This is a federal period issue that also affects SSI. Case 81's facility and Medicaid inputs are the robust form.
  • 8-E p.11, "do not apply the deeming procedure if the applicant's income alone ... is over income limits": for SMME the limit is the Medicaid group's limit (6-B p.77), so Case 84 is consistent.
  • 441 IAC 75.6(5) COLA disregard until April 1: it applies to QMB, SLMB and E-SLMB only. SMME needs full Medicaid, so there is no gap.
  • January-March 2025 levels (1,506 / 2,044): RC-0130 Rev. 04/24 is not on disk, but Rev. 04/25 "Effective 4/1/25" implies the switch, and the PR claims 2026.
  • is_ssi_spousal_deeming_applies as an annual test (12 x $497) against 8-E's monthly test: edge cases only, in a federal variable.
  • SGA-path arithmetic: MONTH reads of YEAR variables times 12 into _apply_ssi_exclusions and divided by 12 give the annual form (probe 1,793.42 both ways). ISM is not in gov.ssa.ssi.income.sources.unearned, and where(counted_by_ssi, ...) selects one branch.
  • Candidate entry: same keys and order as the two earlier Iowa entries; ids in order; the example and the "From April 2026" example recompute; the guard passes.

PDF Audit Summary

Category Count
Documents Reused: 6-B, 8-E, IAC 51, 52, 75, Code 249, GL 6-B-46, RC-0130 Rev. 04/25 and 04/26, GL 8-E-106. New: GL 6-B-45, 2023 standards sheet, 8-F, eCFR 416.1160
Values, rules, anchors and candidate readings confirmed 29 (9 values, 6 derived 2025 levels, 6 rules, 5 anchors, 3 candidate readings and examples)
2025 and 2026 values mismatched 0
Rule mismatches (code run + page re-read) 1: SA28
Out-of-year value mismatches 6 (3 parameters x 2023-2024): SA19
Source-conflict record gap 1 year span: G51
Rejected or narrowed 1 rejected as should address (8-E reference tuple, G52); FPG notes kept as a suggestion (G53)
Page citations 26 checked: 22 correct, 0 wrong; 4 eCFR sections not on disk (416.414 and 416.1112 read on LII; 8-E p.53 and p.56 give 416.1130 and 416.1140)
References 23 of 23 corroborate (5 parameter entries, 3 candidate URLs, 15 comment citations)

Validation Summary

Check Result
Regulatory SA28; SA19 partial; G51, G53, G54
References 23 of 23 correct, none missing; G44 partial, G45 open; G52
Code patterns SA30; G55; one more G46 instance. 163 code-health tests pass; ruff clean
Tests 20 items recomputed by hand (Cases 44, 45, 47-49, 78-88; comments in 38, 65, 76, 77), all correct; no non-functional test. Mutation probes: Case 85 pins SA27; start month 2 or 3 passes all cases (SA29). G56
Local runs 117/117 Iowa YAML cases; 848 passed, 10 skipped (guard, registry, aggregate lists). CI: see Branch Status and CI
Branch 41 ahead, 5 behind main; clean merge; MERGEABLE
Partner tests None touched

Next Steps

  1. Fix SA28: deem the spouse's income on the SGA path, or cite a source and record a candidate. Add rows 1 and 3, update Case 82, and add the $497 control.
  2. Add the March 2026 case (SA29).
  3. Replace the fpg_year_start_month description (SA30).
  4. Add the 2023-2024 values, or file the issue and add the NOTE line (SA19).
  5. Optional: G51-G56 and the carried suggestions.
  6. Ask DTrim99 to look at SA28, because it changes a NOTE that he accepted. To apply fixes: /fix-pr 8017.

Review Severity: REQUEST_CHANGES

Four should-address items are open (SA19 partial, SA28, SA29, SA30) and no critical item is open; C7, SA25, SA26, SA27 and DTrim99's SGA critical are resolved.

hua7450 and others added 2 commits October 22, 2026 17:44
- Deem a spouse's income to an SMME applicant working above the SGA level
  as 8-E pp.12-13 do, and use the two-person guideline when it is deemed
  (ia_ssa_smme_spousal_deeming_applies; Case 82 updated, Cases 90-92).
- Pin the April guideline switch with a March case (Case 89).
- Reword the fpg_year_start_month description to the parameter template.
- Add the 2023 and 2024 dependent amount, per diem and personal needs
  allowance (General Letter 6-B-45 and the 2023 standards; Case 93), and
  correct the rounding NOTE.

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

hua7450 commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks, Pavel. These changes are in 1738284, and main is merged in 5837b95.

SA28, spouse income on the SMME SGA path: fixed as proposed.

  • New ia_ssa_smme_spousal_deeming_applies covers a disabled applicant working above the SGA level. It takes the spouse's SSI earned and unearned income after the ineligible-child allocations, deducted from unearned income first. When that income is more than the couple rate less the individual rate ($497), ia_ssa_smme_countable_income puts both spouses' income through _apply_ssi_exclusions once, and ia_ssa adds the flag to spouse_income, so the two-person guideline applies (8-E pp.11-13).
  • The federal deeming variables aren't reused, as you noted. The steps live in a small helper, _smme_spouse_income.py.
  • The NOTE now covers only income deemed from a parent. The PR body's "Not modeled" line matches.
  • Tests, all in April:
    • Case 82 now gives [2,347.50, 457.50] and ia_ssa [1, 0].
    • Case 90 is your row 1: [2,307.50, 1,457.50] and [1, 0].
    • Case 91 is your row 3: [1,896, 257.50] and [0, 0].
    • Case 92 is the $497 control: [1,847.50, 477] and [1, 0].

SA29, the March case: fixed. Case 89 is your case: March, $1,565, pays 1.

SA30, the description: fixed with your exact text.

SA19, 2023 and 2024: fixed (option A).

  • dependent_amount, rcf_daily_limit and rcf_personal_needs add the 2024 values 490, 36.82 and 123 (General Letter 6-B-45, pp.1 and 24 for the per diem) and the 2023 values 474, 35.89 and 120 (the 2023 standards sheet).
  • New Case 93 is residential care in January 2024: 321.42.
  • The rounding NOTE now says the nearest-dollar rule doesn't fit 2024 ($123 against 120 × 1.032 = 123.84), so it only approximates projected years.

The optional suggestions (G44-G56) are not in this round.

TheAxiomFoundation/rulespec-us#1837 is updated: 122 cases, the 2023-2025 values, companion test AU and the SGA interpretation bullet rewritten for deeming, new rows BA-BE, and the dispatch range now runs "A to BE".

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

@DTrim99

DTrim99 commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

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

Summary

PR #8017 (author: hua7450). This round reviews head 5837b95c64. We approved round 5 at 647fdf4ee2. Since then there is one author commit, 1738284df5, "Address Pavel's round-5 review of Iowa SSA" (426 diff lines), and one clean merge of main at 2bc4ccc970 (5837b95c64). The commit answers four items from Pavel's round-5 review:

  • SA28: spouse income on the SMME SGA path.
  • SA29: a March case.
  • SA30: a parameter description.
  • SA19: the rest of it, the 2023 and 2024 values.

SA28 is correct. I reviewed it as new code.

  • What it adds. A new variable, ia_ssa_smme_spousal_deeming_applies, and a small helper, _smme_spouse_income.py, deem a spouse's income to a disabled SMME applicant who works above the SGA level.
  • It follows the rule step by step. The steps match 8-E's "Deeming from an Ineligible Spouse" (PDF pages 11-13) and 20 CFR 416.1163(b)(3) and (d):
    • Child allocations come off the spouse's unearned income first, then off earned income.
    • At $497 or less, nothing is deemed.
    • Above $497, both spouses' income goes through SSI's exclusions once, and ia_ssa uses the two-person guideline.
  • Nothing is counted twice. The flag is true only for people SSI doesn't count. So it can't overlap the SSI deeming path or the couple-computation path.
  • Examples A and B are unchanged. Cases 87 and 88 have one person each, so their expectations don't move.
  • The NH Add New Hampshire state supplementation for 2026 #10156 key lesson doesn't apply. The new variable is a bool. The code only combines it with | and & or multiplies by it, and never uses it as a parameter key.

Tests and the other replies.

  • I hand-traced every new or changed expectation (Cases 82 and 89-93), and all of them are correct.
  • Case 89 pins April as the switch month.
  • The SA30 description is Pavel's exact text.
  • The new values match their sources, which I read:
    • 2023 (474, 35.89 and 120): the 2023 standards sheet.
    • 2024 (490, 36.82 and 123): General Letter 6-B-45 p.1, with the per diem also on p.24.
  • Our round-5 suggestion is fixed: rulespec-us#1837's dispatch text now says "cases A to BE".

Findings and verdict.

  • I have no critical or should findings.
  • There are three optional suggestions:
  • CI hasn't run on this head yet. Its only check, PR validation, has been queued since 21:46 UTC.
  • The merge with main is clean (0 behind).
  • I'm approving, but let CI finish green before merging.

Prior findings

Finding Status Evidence
Round 5, Suggestion 1: #1837's paste-ready dispatch text said "cases A to AP" Fixed Step 1's review_finding now ends "Companion tests, each assigning every leaf input: cases A to BE in the issue's Companion tests table". The table runs from A to BE, including the new rows BA-BE.
Round 3, Critical 1: the SMME SGA path skipped the student exclusion and in-kind support and maintenance Closed in round 5 Cases 87 and 88 still expect 1,442.08 / $0 and 1,648.83 / $1. Both are one-person cases, so the new flag is false and nothing changes.
Round 2, Suggestions 1-4 Closed in round 3 No change.

Pavel's round-5 items (Ziming's reply), checked as new code:

Item Status Evidence
SA28: spouse income on the SMME SGA path Fixed as proposed; correct See Verified. Case 82 was updated, and Cases 90-92 were added. These are Pavel's rows 1 and 3, his $497 control and his Case 82 values.
SA29: no case pinned the April switch Fixed Case 89 (March, $1,565, pays 1). With Case 45 (April, $1,595.99, pays 0), only a start month of 4 passes both. With month 2 or 3, March would use $1,596 and Case 89 fails. With month 5 or later, April would use $1,565 and Case 45 fails.
SA30: fpg_year_start_month description Fixed Pavel's exact text. It follows the template: the verb "uses", the program name spelled out, and the ending "under the State Supplementary Assistance program".
SA19: 2023 and 2024 values back-filled from 2025 Fixed (option A) The values are in all three parameters and match the sources. Case 93 gives 321.42. The rounding NOTE is corrected. See Verified.

New findings

Critical (must fix)

None.

Should address

None.

Suggestions

  1. Add a case for the child-allocation step.

    • What is untested. _smme_spouse_income.py:12-14 deducts ineligible-child allocations from the spouse's unearned income first, then from earned income. That is the rule's order: 416.1163(b)(3) says "We first deduct the allocations from your ineligible spouse's unearned income", and 8-E PDF p.12 has the same order in steps 1-2. No SMME case has a child. So all 122 cases still pass if the allocation is dropped or the order is reversed.
    • The code is right today. I traced it. It is also the step a later refactor is most likely to break. Pavel noted in SA28 that main's federal ssi_earned_income_deemed_from_ineligible_spouse multiplies the allocation by is_ssi_aged_blind_disabled, which is false for this applicant. So switching to that variable would drop the allocation from earned income.
    • Suggested case. Take Case 82 and add a child, aged 10, with no income. Put the child in the tax unit, and keep the explicit marital unit [person1, person2]. The allocation is 497 − 0 = 497 a month. The spouse has no unearned income, so it comes off earned income: 1,000 − 497 = 503, which is more than 497, so it is deemed. SMME income is (900 − 20) + (2,000 + 503 − 65) / 2 = 880 + 1,219 = 2,099, below the two-person 2,164.
    • Expected outputs. ia_ssa_smme_countable_income [2,099, 457.50, 0]; ia_ssa [0, 0, 0]. Without the allocation, person1 would get 2,347.50 and $1.
    • Why this is non-blocking. The arithmetic mirrors main's tested federal deeming formulas, and it reuses ssi_ineligible_child_allocation, which main tests.
  2. PR body: one stale clause in the test list.

    • The clause. The SMME coverage bullet still lists "the one-person guideline for a spouse in a medical facility, an SGA worker with a spouse and a spouse whose $497 pension SSI doesn't deem, against the two-person guideline for a $498 pension that it does (Cases 81-84)".
    • Why it is stale. "An SGA worker with a spouse" is Case 82. That case now deems the spouse's wages and uses the two-person guideline. The same bullet's next clause describes Case 82 correctly.
    • Fix. Drop "an SGA worker with a spouse" from the first clause, and change "(Cases 81-84)" to "(Cases 81, 83 and 84)".
    • Why only a suggestion. The behavior descriptions are accurate: the SMME bullet, the "Not modeled" line and the variable documentation. Only the description of one test is out of date.
  3. rulespec-us#1837: a few stale details. These are in the issue only, and none changes an expected outcome.

    • Parameter years. Step 1's paste text says "Parameters from 2026-01-01: the standards row of the Required outputs table", and that row has 2026 values only. The 2023-2025 values appear only in the summary at the top, but companion rows AX (2025) and BE (2024) need them. Name them in item 1, for example "from 2023-01-01, with the 2023-2025 values listed in the summary". We missed this in round 5, when AX already needed the 2025 values.
    • The new variable. The summary's "14 formulas" doesn't count ia_ssa_smme_spousal_deeming_applies, and the Required outputs table doesn't list it.
    • The Payment row. It still says the guideline is "for the recipient and any spouse", which predates Pavel's C7. The "SMME couples" and "SMME and substantial gainful activity" bullets state the current rule.
    • Row BD's month. Row BD says "As AQ" without "April 2026", so it inherits the table's January default. AQ's own derivation says "≥ 1,596", which is the April figure, although Case 77 runs in January against 1,565. Both rows give the same outcomes in either month.

Verified

The rule.

  • 8-E PDF p.11 deems "for non-MAGI-related Medicaid and State Supplementary Assistance coverage groups according to SSI policies", except for Medically Needy, in-home health-related care, dependent person and MEPD. SMME is not on that list.
  • 8-E PDF p.12, steps 1-3:
    • Subtract "an allocation for each ineligible child" from unearned income ("$497 ... minus the child's income").
    • Take any remaining balance from earned income.
    • "If the total of the ineligible spouse's income is equal to or less than $497, there is no income available to be deemed to the applicant. Process as a one-person household."
  • 8-E PDF p.13, steps 4-8:
    • Combine unearned with unearned and earned with earned.
    • Take the $20 from unearned income first.
    • Then take the $65 and one-half.
  • 20 CFR 416.1163(d)(2) says the same: "we treat you and your ineligible spouse as an eligible couple" by combining the remainders and "applying all appropriate income exclusions".
  • For SMME, the "couple" comparison is the two-person 120% guideline. 6-B p.77 sets income "according to SSI income criteria".

The code.

  • Gating (ia_ssa_smme_spousal_deeming_applies.py:29-37).
    • The new variable is bool, Person, MONTH, with defined_for = StateCode.IA.
    • meets_ssi_disability_criteria & ~is_ssi_aged_blind_disabled (both YEAR, read through period.this_year) is exactly the group that ia_ssa_smme_countable_income budgets on its own income. That variable sets counted_by_ssi = is_ssi_aged_blind_disabled (line 68).
    • ia_ssa_has_spouse limits the flag to a two-person marital unit that SSI's spouse test pairs. So the helper's "marital-unit sum minus own" is the other spouse only. A default unit of three or more people is never a couple, so a child's income can't leak in.
  • Threshold.
    • parameters(period).gov.ssa.ssi.amount is monthly, so the threshold is 1,491 − 994 = 497.
    • When a MONTH formula reads a YEAR float, Core divides it by 12, because floats default to FLOW. That matches the federal comparison of annual income with the difference × 12.
    • > matches "not more than" in 416.1163(d)(1) and 8-E's "equal to or less than $497".
  • The helper (_smme_spouse_income.py:4-15).
    • It takes unearned income first: max_(unearned − allocations, 0).
    • It takes earned income for the rest: max_(earned − max_(allocations − unearned, 0), 0).
    • Allocations are summed over the tax unit, as main's federal deeming variables do. ssi_ineligible_child_allocation is not gated on anyone being SSI-eligible, so it works for this applicant.
  • Exclusions are applied once (ia_ssa_smme_countable_income.py:50-67).
    • The spouse's earned and unearned income is added to the applicant's before _apply_ssi_exclusions. That takes the $20 from unearned income first, then the $65 and one-half (8-E steps 6-7).
    • The student exclusion still comes off only the applicant's own earnings, before the spouse's earnings are added. That is the order in 416.1112(c), where the student exclusion comes before the $20 and the $65.
  • No double counting.
    • For this applicant, ssi_couple_computation_applies and is_ssi_spousal_deeming_applies are both false: both need the applicant to be aged, blind or disabled for SSI, and the second is defined_for = is_ssi_eligible_individual. So in ia_ssa (line 112), spouse_income can be true only through the new flag, and where(joint, …) doesn't combine the income again.
    • The deemed income enters only own_income. where(counted_by_ssi, income, own_income) uses that only for people SSI doesn't count.
    • The flag is false for everyone SSI counts, so the SSI-path cases are unchanged: 47-49, 80-81 and 83-84.
    • Case 83 also shows the flag is off for an aged applicant. If it were on, the two-person guideline would turn that case's 1,600 into $0.
  • Consistency between the two paths. Pavel's row 1 household now gets the same SMME income, 2,307.50, whether the applicant is 50 (SGA path, Case 90) or 70 (SSI path: 807.50 of own income plus 1,500 deemed).
  • Callers. Only ia_ssa (line 115) and ia_ssa_smme_countable_income (line 58) read the flag. Only ia_ssa's SMME row reads SMME income.
  • No new cycle. The flag reads the federal SSI income variables that the own-income path already reads, plus ssi_ineligible_child_allocation, which SSI already computes for every person.
  • NH Add New Hampshire state supplementation for 2026 #10156.
    • The new variable is used only with |, & and multiplication.
    • No parameter or breakdown is keyed by it.
    • The helper reads only federal variables and the federal benefit rates.
    • fpg_year_start_month is a scalar.
    • So there is no multi-state lookup risk.
  • Examples A and B and Case 77. All three have one person, so ia_ssa_has_spouse and the flag are false. The diff leaves their expectations untouched.

Edge cases I checked and am not raising.

  • 8-E PDF p.11's own-income rule. It says: "For all coverage groups except Medically Needy, do not apply the deeming procedure if the applicant's income alone, after appropriate exclusions and deductions, is over income limits." SMME's test is a floor (at least 120%). With no upper limit, the sentence has nothing to act on. Deeming whenever the spouse has more than $497 is the reading Pavel proposed. Case 91 shows the effect: own income of 1,596 qualifies alone, but the deemed 1,896 doesn't.
  • Which spouses count as "ineligible". 8-E PDF p.12 defines an ineligible spouse as "a spouse who is not eligible for SSI or non-MAGI-related Medicaid, or State Supplementary Assistance". The helper doesn't check the spouse's status, while main's federal deeming counts only a spouse who isn't aged, blind or disabled.
    • A spouse who receives SSI. This can't change ia_ssa. SSI then deems the applicant's above-SGA income to that spouse, so the spouse is paid only if the combined countable income is below 1,491. That is below 2,164. The applicant's own income can't exceed the combined income, so it is below 1,596 too. The applicant gets $0 under either reading.
    • An aged spouse with too much income for SSI. That spouse is "not eligible for SSI", and deeming their income is what 8-E says.
  • In-kind support and maintenance on the deeming path. It stays at the individual PMV, $351.33. That is the only figure in 8-E's PMV rule: "one-third of the SSI benefit rate plus $20", PDF p.51. Main's federal deeming path halves the couple PMV (POMS SI 01320.150), which 8-E doesn't mention. The case is rare and untested: it also needs outside shelter support.

SA19's values and references.

  • General Letter 6-B-45, effective January 1, 2024, p.1:
    • "The income limit and payment standard for a dependent relative is $490 per month";
    • "The maximum residential care per diem rate is $36.82";
    • "The personal needs allowance for residential care facility and family-life home is $123".
    • Page 24 also shows $36.82.
  • The 2023 standards sheet, effective January 1, 2023, one page:
    • Dependent person "Maximum Payment $474.00";
    • residential care "Personal Needs Allowance $120.00";
    • "Maximum Cost-Related per Diem Rate $35.89".
  • References. There is one entry per document. The per diem title ends "#page 1,24", with the href on page 1, as the repo's reference rule asks. The other two link page 1 with no page in the title.
  • Rounding NOTE. 120 × 1.032 = 123.84 against the published $123 is accurate. The 3.2% COLA is on GL 6-B-45 p.1.
  • Uprating. It applies only after the last value (2026), so the new earlier values don't change 2027. Case 40 still expects 298.57.

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

Case Period Hand computation Expected Result
82 (changed), flag 2026-04 person1: disabled, 50, wages 2,000 > 1,690, so not counted by SSI; the spouse's wages of 1,000 > 497 with no children. person2 isn't disabled. [true, false] Correct
82, SMME income 2026-04 (900 − 20) + (2,000 + 1,000 − 65) / 2 = 880 + 1,467.50 = 2,347.50; person2 (1,000 − 20 − 65) / 2 = 457.50 [2,347.5, 457.5] Correct
82, ia_ssa 2026-04 2,347.50 ≥ 2,164 (two people); person2 isn't eligible [1, 0] Correct
89 2026-03 Before April, so the 2025 guideline: 1.2 × 15,650 / 12 = 1,565; 1,565 ≥ 1,565; single, so one person 1 Correct
90, SMME income 2026-04 Wages 1,700 > 1,690; spouse 3,000 > 497. No unearned income, so the $20 comes off earned: (1,700 + 3,000 − 20 − 65) / 2 = 2,307.50; person2 (3,000 − 85) / 2 = 1,457.50 [2,307.5, 1,457.5] Correct
90, ia_ssa 2026-04 2,307.50 ≥ 2,164 [1, 0] Correct
91, SMME income 2026-04 Wages 3,277; spouse 600 > 497: (3,277 + 600 − 85) / 2 = 1,896; person2 (600 − 85) / 2 = 257.50. Own income alone would be (3,277 − 85) / 2 = 1,596 [1,896, 257.5] Correct
91, ia_ssa 2026-04 1,896 < 2,164 [0, 0] Correct
92, flag 2026-04 Pension 5,964 / 12 = 497, not more than 497 [false, false] Correct
92, SMME income 2026-04 person1 own income: (900 − 20) + (2,000 − 65) / 2 = 1,847.50; person2 497 − 20 = 477 [1,847.5, 477] Correct
92, ia_ssa 2026-04 No spouse-income flag, so one person: 1,847.50 ≥ 1,596 [1, 0] Correct
93 2024-01 36.82 × 31 = 1,141.42; SSI 943 (the 2024 rate), so participation is 943 − 123 = 820; 1,141.42 − 820 = 321.42 321.42 Correct
  • A mutation check from the table. Case 92 pins the comparator. With >=, the flag would be [true, false] and person1's income 2,344.50, so the case would fail.

Other checks.

  • Source-conflict ratchet. The new comments contain none of the guard's phrases, and no Iowa file is in KNOWN_UNMARKED. CI hasn't run the guard on this head yet.
  • Batch lessons.
  • Documentation. These updates are accurate:
    • the variable documentation ("any spouse income deemed under SSI's rules");
    • the comments in ia_ssa.py:103-111 and ia_ssa_smme_countable_income.py:38-49;
    • the PR body's SMME bullet and its "Not modeled" line (now only "income deemed from a parent").
  • Test counts. 93 / 12 / 7 / 6 / 4 = 122 cases, matching the body and Update New York tax rules for 2022 #1837.
  • Scope. No partner test file is touched. The changelog fragment is unchanged, and the author commit doesn't change programs.yaml.

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 21:47:37 UTC, with the push.
  • It matches the head:
    • 122 cases (93 in ia_ssa.yaml), and the 2023-2025 values in the summary.
    • Row AU is rewritten for Case 82's deemed result (2,347.50 ≥ 2,164).
    • New rows: BA (Case 89), BB-BD (Cases 90-92) and BE (Case 93). Each matches my hand traces.
    • The SGA interpretation bullet is rewritten for deeming, with cases AQ, AU, AY, AZ and BB-BD.
  • Sources. The companion values come from 8-E, the regulation and the General Letter, not from PolicyEngine output.
  • The remaining stale details are in Suggestion 3.

CI status

gh pr checks 8017, rechecked at 22:12 UTC: 1 check, pending.

  • PR validation (lock, guard tests, lint, changelog) is still queued (run 39859973704, created 21:46:47 UTC on 5837b95c64).
  • The test suites haven't started, so no Iowa case has run in CI at this head.
  • No local runs this round (low-RAM). I checked every new or changed expectation by hand.
  • The author reports that the 122 Iowa cases, test_source_conflicts.py and the registry tests pass locally on the merged tree.
  • Let CI finish green before merging.

Branch status

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.

Round 6: SA28 is correct as new code. The SMME spousal deeming for SGA workers matches 8-E pp.11-13 and 416.1163(b)(3)/(d) (child allocations first, nothing deemed at $497 or less, exclusions applied once, two-person guideline), it can't overlap the SSI couple or deeming paths, and Cases 87/88/77 are unchanged. Every new or changed case hand-checks, and Pavel's SA29/SA30/SA19 are fixed. CI hadn't started any suite on this head when I checked, so please let it finish green before merging. Three suggestions, including a case with a child for the allocation step. 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 6): Add Iowa state supplementation for 2026

IDs: C = critical, SA = should address, G = suggestion. Prior IDs keep their numbers. New findings start at SA31 and G57. There is no new critical item, so C8 is not used. DTrim99 approved this head with three suggestions. They are credited below as SA33, G64 and G65.

Source Documents

Branch Status

  • 43 ahead, 14 behind main (12b899c); MERGEABLE. git merge-tree --write-tree 12b899c11a 5837b95c64 is clean.
  • The 14 commits change no Iowa file, no SSI variable or parameter, and no Iowa entry in candidates.yaml or programs.yaml. They touch Social Security benefit-tax revenue, other states' programs, a new programs.yaml entry and other candidates.yaml entries. Verifiers 1 and 4 confirmed that the federal SSI deeming, status and couple-computation files are the same at the head and on main. The staleness did not affect any finding. A rebase is not necessary for review. (DTrim99's "0 behind" was measured against 2bc4ccc.)
  • CI: 27 pass, 0 fail.
  • Local run at 5837b95: 122/122 Iowa YAML cases pass; 448 code-health and aggregate-list tests pass (1 skipped); ruff format --check and ruff check are 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", while three parameters now carry 2023-2024 values.

What round 6 got right

  • SA28, the core fix, is correct. The new flag and helper follow 8-E steps 1-8 (8-E p.12, p.13) and 20 CFR 416.1163(b)(3) and (d).
    • Child allocations come off the spouse's unearned income first, then off earned income.
    • Nothing is deemed at $497 or less. The test is >, and Case 92 pins it.
    • Both spouses' income goes through _apply_ssi_exclusions once (ia_ssa_smme_countable_income.py:58-67), and ia_ssa.py:112-117 uses the two-person guideline.
    • My four round-5 rows now give the rule's result. For a spouse at home, the age-50 and age-70 paths agree.
    • The flag requires ~is_ssi_aged_blind_disabled, so it cannot overlap joint or is_ssi_spousal_deeming_applies.
    • You were right not to reuse the federal deeming variables: each one is gated on aged, blind or disabled (ABD) status.
    • Cases 82 and 90-92 recompute by hand.
  • SA29 is fixed. Case 89 (ia_ssa.yaml:2618, March 2026, 1,565, pays 1) pins April. In the coordinator's probes, start months 2 and 3 fail Case 89, and start month 5 fails Cases 45 and 49.
  • SA30 is fixed. fpg_year_start_month.yaml:1 is the exact proposed text.
  • SA19 is fixed (option A). The 2023 values (474 / 35.89 / 120) and the 2024 values (490 / 36.82 / 123) match the 2023 sheet and GL 6-B-45 p.1 and p.24. Four reports read these pages as images. The effective dates are right, Case 93 gives 321.42, and the rounding NOTE is corrected (120 x 1.032 = 123.84, but $123 was published).
  • No regression in C4, C7, SA23, SA25, SA27 or DTrim99's SGA critical. Cases 77, 87 and 88 are one-person cases, so the new flag is false for them.
  • All 8 new reference entries and all 14 new or changed comment citations corroborate. No printed page number is used.

The four new should-address items are all in the new SA28 code. Two are rule gates that the flag does not test (SA31, SA32). Two are rule steps that no test pins (SA33, SA34).

Round-5 status

ID Status Evidence at 5837b95
SA28 SGA-path spouse income RESOLVED New flag and helper; ia_ssa_smme_countable_income.py:58-61; ia_ssa.py:115; Cases 82, 90-92. Gaps in the new code: SA31-SA34
SA29 April switch month RESOLVED Case 89; months 2 and 3 fail Case 89, month 5 fails Cases 45 and 49
SA30 description RESOLVED fpg_year_start_month.yaml:1, exact text
SA19 2023-2024 levels RESOLVED Values match the sources (images); Case 93 = 321.42; NOTE fixed. The 2023 values and the 2024 DP amount are not pinned: G63
G25 case periods PARTIAL (accepted part stands) The new periods 2026-03, 2026-04 and 2024-01 fit their cases
G36 removable branches STILL OPEN (no reply) The four branches are unchanged. The new child-allocation gap is SA33
G37 "discretion" reading STILL OPEN (no reply) Iowa candidates.yaml entries and the NOTE at ia_ssa.py:128-135 unchanged
G38 DP couple level into RCF STILL OPEN (no reply) ia_ssa_federal.py unchanged
G39 SMME upper bound in the input only STILL OPEN (no reply) Unchanged. New point below
G40 one flag, two rules STILL OPEN (no reply) Files unchanged
G41 integration Case 12 STILL OPEN (no reply) integration.yaml unchanged
G42 IHHRC allowance over the tax unit STILL OPEN (no reply) ia_ssa_ihhrc_participation.py:49-51 unchanged
G44 source links PARTIAL (deferred) GL 6-B-45 is now linked in 3 parameters. GL 6-B-47 (named in the NOTE for $130) is not linked; the undated code/249.pdf stays
G45 page lists and titles STILL OPEN (deferred) ia_ssa_smme_countable_income.py:19 still says "249.3(4)(g)" while :40-41 relies on (a)(2); :23 is unlabeled
G46 manual sums STILL OPEN (deferred) ia_ssa_smme_countable_income.py:37, 55-57, ia_ssa_federal.py:37-39, ia_ssa_rcf_couple_budget.py:32; no new instance
G47 RCF dividends case STILL OPEN (deferred) No case
G48 formula boundaries STILL OPEN (deferred) The guideline lines are still input overrides; Case 92 pins only the $497 boundary
G49 ia_ssa_has_spouse true STILL OPEN (deferred) Only Case 65's [false, false]. Case 82's flag depends on it only indirectly (verifier 4)
G50 other branches STILL OPEN (deferred) Unchanged
G51 per diem candidate years STILL OPEN, wider candidates.yaml:1793-1795 still has from: 2026, but the maximum rate now applies from 2023 (Cases 86, 93). GL 6-B-45 p.24 and the 2023 sheet give the same two options. 2024: 321.42 against $0; 2023: 318.59 against $0 (31 x 17.86 = 553.66)
G52 8-E in reference tuples PARTIAL The new flag links 8-E #page=11; ia_ssa.py:10-19 and ia_ssa_smme_countable_income.py:18-24 still do not
G53 FPG timing notes STILL OPEN (deferred) fpg_year_start_month.yaml:10-14 unchanged. Case 89 names "RC-0130 Rev. 04/25" in text only; Cases 78-80 (:2263) still say "(RC-0130)" (verifier 4)
G54 SGA-path student exclusion STILL OPEN; (b) is now documentation only (a) unchanged. (b): every deemed applicant is married, so the case is now reachable. But verifier 4 found that 8-E p.19's "Not married" conflicts with the current 416.1112(c)(3) and 42 U.S.C. 1382a(b)(1), amended in 2004, which have no marital test. The repo follows current law, so do not zero the exclusion. Add the NOTE in the list below
G55 FPG reform timing STILL OPEN (deferred) ia_ssa.py:123 still reads f"{year}-01-01"
G56 2025 tests STILL OPEN (deferred) No 2025 SMME or DP case. The 2025 deeming threshold is 1,450 - 967 = 483

Tally: 25 IDs were open after round 5. Now 4 are resolved, 3 are partial (G25, G44, G52), 18 are still open and 0 are declined. You deferred G44-G56 ("not in this round") and did not reply on G36-G42. A deferral is acceptable for suggestions, and none of them blocks.

Critical (Must Fix)

None.

Should Address

SA31. The new flag deems income from a spouse who lives in a medical facility

  • What is wrong: ia_ssa_smme_spousal_deeming_applies deems whenever the marital unit has a spouse. It does not test whether the spouse lives in the same household. A spouse in a medical treatment facility for the whole month is not a household member, so nothing is deemed. For an ABD spouse (the usual facility resident), the SSI path already budgets the applicant alone (Case 81; 416.414(b)(3)). So the age-50 and age-70 paths now disagree for the same household, and that parity was the reason for SA28. The regulatory role found this, and verifier 1 confirmed it.
  • Where: ia_ssa_smme_spousal_deeming_applies.py:34-38. ia_ssa_has_spouse.py:25-26 tests only the marital unit and SSI's spouse index.
  • Source: Deeming applies when "An eligible person was living for any part of a month in the same household with an ineligible spouse" (8-E p.11), and it counts the spouse's income when "an ineligible spouse lives in the same household" (8-E p.12). Under 20 CFR 416.1167(a), an absent spouse stays a household member only if the spouse "leaves the household but intends to and does return in the same month or the month immediately following". (a)(2) covers only the eligible person. 416.1160 defines the ineligible spouse as "someone who lives with you". 416.1149 is about valuing in-kind support, so it does not change this.
  • Evidence (verifier 1, v1/parity_probe*.out): April 2026. The applicant is aged 50, disabled and above SGA, with SMME category and coverage. The spouse has ssi_lives_in_medical_treatment_facility and ssi_medicaid_pays_majority_of_care.
Household (monthly) Head: SMME income, ia_ssa Rule Applicant aged 70, same household
Wages 3,277; disabled spouse, pension 520, in a facility 2,106, [0, 0] own 1,596, [1, 0] 1,596, [1, 0]
Wages 1,700; disabled spouse, pension 3,000, in a facility 3,797.50, [1, 0] own 807.50, [0, 0] 994, [0, 0]
Wages 3,277; spouse aged 70, pension 520, in a facility 2,106, [0, 0] own 1,596, [1, 0] 1,596, [1, 0]
  • Why should address: The rule is clear, and the code is new this round. The facility signal is already used and tested (Case 81). It is not critical: the effect is $1 a month, the population is input-gated, and SMME is input-only in microsimulation.
  • Fix: On a copy of the branch, the 122 existing cases and the new case pass, and the new case fails at the head. Add "https://www.ecfr.gov/current/title-20/section-416.1167", to reference. Then add this term before the return at :34, and & ~apart in the return (the combined return is under SA32):
        # 8-E p.11 deems only while the applicant lives "in the same
        # household" with the spouse. Under 20 CFR 416.1167(a)(1) an absence
        # is temporary only if the person returns in the same or the next
        # month, so a spouse (or the applicant) in a medical treatment
        # facility for the month is not a household member and nothing is
        # deemed (ia_ssa.yaml Case 96).
        # NOTE: Intent to return is not modeled, as in
        # ssi_couple_computation_applies.
        apart = person.marital_unit.any(
            person("ssi_lives_in_medical_treatment_facility", period)
        )

The regulatory role's variant (ssi_federal_living_arrangement == MEDICAL_TREATMENT_FACILITY) gives the same results for every Medicaid-paid stay. But it still deems for a private-pay stay, and 416.1167 does not support that.

  • Test (append; this is verifier 1's case, renumbered):
- name: Case 96, nothing is deemed to an SMME applicant working above the SGA level from a spouse who lives in a medical facility.
  period: 2026-04
  absolute_error_margin: 0.01
  input:
    people:
      person1:
        age:
          2026: 50
        meets_ssi_disability_criteria:
          2026: true
        employment_income:
          2026: 39_324
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person2:
        age:
          2026: 70
        pension_income:
          2026: 6_240
        ssi_lives_in_medical_treatment_facility: true
        ssi_medicaid_pays_majority_of_care: true
    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 spouse's 520
    # pension is not deemed. person1's own income is (3,277 - 20 - 65) / 2 =
    # 1,596, at least the one-person 1,596 (with deeming it would be 2,106,
    # below the two-person 2,164). person2's 2,106 comes from SSI's federal
    # deeming, which does not yet apply 20 CFR 416.1163(f)(5).
    ia_ssa_smme_spousal_deeming_applies: [false, false]
    ia_ssa_smme_countable_income: [1_596, 2_106]
    ia_ssa: [1, 0]

SA32. The new flag deems from a spouse who is not an "ineligible spouse"

  • What is wrong: The flag deems from any spouse whose income after allocations is above $497. But 8-E defines the ineligible spouse by status. An ABD spouse who gets SSI or SSA, or who qualifies for a Medicare Savings Program, is in a non-MAGI group, so that spouse is not an ineligible spouse. Under "SSI policies", the pair is then budgeted as an eligible couple: the income is combined, the couple standard applies, and there is no $497 test and no child allocation. Main's is_ssi_ineligible_spouse is false for each such spouse, but the helper sums all of the spouse's income. Three households flip ia_ssa. The pdf-rules role found the gap but saw no payment effect. Verifier 2 found the flips.
  • Where: ia_ssa_smme_spousal_deeming_applies.py:32-38; _smme_spouse_income.py:8-14.
  • 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 non-MAGI groups are for "People who are aged, blind, or disabled", and the list includes SSI and SSA recipients and "People in Medicare savings programs". Workers must "Use the Supplemental Security Income program policies" for these groups (8-F p.73, p.74). 8-E p.11 deems "according to SSI policies".
  • Evidence (verifier 2, v2/v2_probe.out; April 2026; applicant aged 50, disabled, above SGA, SMME; spouse aged 70 at home):
Household (monthly) Head: SMME income, ia_ssa Rule (eligible couple, combined) Applicant aged 70 on main
Wages 3,277; spouse SS 400 1,596, [1, 0] (400 - 20) + (3,277 - 65) / 2 = 1,986 < 2,164: [0, 0] 1,986, [0, 0]
Wages 3,277; spouse SS 300 with SSI 102; two children 1,596, [1, 0] 1,886: [0, 0] 1,886, [0, 0]
Wages 3,500; spouse with no income 1,707.50 (one person), [1, 0] 1,707.50 < 2,164: [0, 0] 1,707.50, [0, 0]

The head and the couple method agree when the spouse's income is above $497 and there are no children. That is the case for Cases 82 and 90-92 and for the control rows in verifier 2's probe. Verifier 2 rejected the "budget each spouse alone" values in the queue (pdf-rules P6 807.50 and P8 [1, 0]; tests NEW-5(b)), because SSI policy has no such step. It also found that main's MSP combines these couples, and that at the head one applicant could be SLMB-eligible and SMME-eligible in the same month.

  • Why should address: The definition is clear, and main already encodes a status test. The choice is not documented. It is not critical: the structure is otherwise right, the couple method is inferred from "SSI policies", the effect is $1, and the population is very small and input-gated.
  • Fix: This fix is ruff clean and passes 122/122 on a copy of the branch. The three rows above become [0, 0], and Cases 82 and 90-92, the control rows and DTrim99's child case do not change. 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 a person SSI
    treats as aged, blind or disabled. For an applicant whom SSI does not
    count, any such member of the marital unit is the spouse."""
    abd = person("is_ssi_aged_blind_disabled", period.this_year)
    return person.marital_unit.sum(abd) - abd > 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 whom SSI treats as aged, blind or
    disabled is not an ineligible spouse, and the couple's income is combined
    as for an eligible couple, with no allocations."""
    earned = person("ssi_earned_income", period)
    unearned = person("ssi_unearned_income", period)
    spouse_earned = person.marital_unit.sum(earned) - earned
    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 the flag, import smme_spouse_is_aged_blind_disabled. Then replace :32-38 with the code below, which includes SA31's apart from above. Each fix was run alone on a copy of the branch, but the combined form was not run as one, so run the suite once.

        # 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), so, as is_ssi_ineligible_spouse does, a spouse
        # SSI treats as aged, blind or disabled 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.
        # NOTE: 8-E tests eligibility for SSI, non-MAGI-related Medicaid or
        # State Supplementary Assistance. The model uses SSI's aged, blind or
        # disabled status, so an aged, blind or disabled spouse who qualifies
        # for none of them is combined rather than deemed.
        eligible_spouse = smme_spouse_is_aged_blind_disabled(person, period)
        earned, unearned = smme_spouse_income(person, period)
        p = parameters(period).gov.ssa.ssi.amount
        return (
            applicant
            & person("ia_ssa_has_spouse", period)
            & ~apart
            & (eligible_spouse | (earned + unearned > p.couple - p.individual))
        )

Also update the comments at ia_ssa_smme_countable_income.py:45-48 and ia_ssa.py:103-111 ("a spouse's income above the couple rate less the individual rate, or an aged, blind or disabled spouse's income"). Optionally, add "https://hhs.iowa.gov/media/4012/download?inline#page=73" to the tuple. A NOTE alone does not fix a contradiction with a clear rule. Gating alone (budgeting each spouse alone when the spouse is ABD) is also wrong: it breaks the case of an aged spouse whose income is too high for SSI (wages 1,700, spouse SS 3,000: [1, 0] is correct today).

  • Test (append; verifier 2's case, renumbered; it passes with the fix and fails at the head):
- name: Case 97, an aged spouse is not an ineligible spouse, so 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
        employment_income:
          2026: 39_324
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person2:
        age:
          2026: 70
        social_security_retirement:
          2026: 4_800
    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:
    # 8-E p.12: an ineligible spouse is "not eligible for SSI or
    # non-MAGI-related Medicaid, or State Supplementary Assistance". The
    # spouse is aged, so the couple's income is combined with no $497 test:
    # (400 - 20) + (3,277 - 65) / 2 = 1,986 < 2,164. Alone, 1,596 would
    # qualify against the one-person 1,596.
    ia_ssa_smme_spousal_deeming_applies: [true, false]
    ia_ssa_smme_countable_income: [1_986, 1_986]
    ia_ssa: [0, 0]

Optional second case: the spouse gets SSI and there are two children aged 10 (second row above). The expected values are SMME income [1,886, 1,491], ia_ssa [0, 0] and ssi [0, 102].

SA33. No test pins the child-allocation step (DTrim99's suggestion 1)

  • What is wrong: No SMME case has a child, so nothing tests _smme_spouse_income.py:12-14. You can drop the allocation, reverse the order, or skip the carry-over to earned income, and all 122 cases still pass. DTrim99 raised this first. He rated it a suggestion because the arithmetic mirrors main's federal variables. But the helper is a separate implementation, written to avoid main's earned-income variable, and only two Iowa variables call it. So main's tests do not cover it.
  • Where: _smme_spouse_income.py:12-14; ia_ssa.yaml (no SMME case with a person under 18).
  • Source: 8-E steps 1-2 (8-E p.12): subtract "an allocation for each ineligible child" from the spouse's unearned income, then "any remaining balance" from earned income. 416.1163(b)(3) gives the same order. Your SA28 fix text named this step.
  • Evidence (verifier 3, v3/): Each one-line mutant passes all 122 cases, and the proposed case fails on each of them. Each mutant also flips ia_ssa from 0 to 1.
Mutant person1 SMME income ia_ssa Existing 122 Case 94
Head 2,099 0 pass pass
Allocations zeroed (the coordinator's noalloc probe) 2,437.50 1 pass fails
Allocation from earned income first 2,189 1 pass fails
No carry-over to earned income 2,247.50 1 pass fails

DTrim99's case (Case 82 plus a child with no income: [2,099, 457.50, 0], [0, 0, 0]) is correct. It catches the first and third mutants. It misses the order, because his spouse has no unearned income. Case 94 catches all three.

  • Why should address: This is a missing edge case for an already-tested variable, in new code. It is the same class as SA29, where a probe showed that a rule step could change with every test passing. It is not critical, because the code is correct today.
  • Fix (no code change; append after Case 93 with one blank line before it; this is verifier 3's text byte for byte, and it passes at the head):
- name: Case 94, a child's allocation comes off a spouse's pension first and then wages before deeming to an SMME applicant working above the SGA level.
  period: 2026-01
  absolute_error_margin: 0.01
  input:
    people:
      person1:
        age:
          2026: 50
        meets_ssi_disability_criteria:
          2026: true
        # Wages of $1,700 a month, above the $1,690 SGA level.
        employment_income:
          2026: 20_400
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person2:
        age:
          2026: 45
        # A pension of $200 and wages of $2,880 a month.
        pension_income:
          2026: 2_400
        employment_income:
          2026: 34_560
      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 steps 1-3: the child's 497 allocation takes the spouse's 200 of
    # pension and 297 of wages, leaving 2,880 - 297 = 2,583 > 497 to deem.
    # (1,700 + 2,583 - 20 - 65) / 2 = 2,099, below January's two-person 2,115.
    # person2's own income is (200 - 20) + (2,880 - 65) / 2 = 1,587.50.
    ssi_ineligible_child_allocation: [0, 0, 497]
    ia_ssa_smme_spousal_deeming_applies: [true, false, false]
    ia_ssa_smme_countable_income: [2_099, 1_587.5, 0]
    ia_ssa: [0, 0, 0]

SA34. No test deems a spouse's unearned income on the SGA path

  • What is wrong: In Cases 82, 90 and 91 the spouse has wages only, and in Case 92 the spouse's pension is not deemed. So the unearned term at ia_ssa_smme_countable_income.py:61 always adds 0, and the unearned summand of the flag test is never decisive. The $497.01 side of the threshold is also untested on this path.
  • Where: ia_ssa_smme_countable_income.py:61 (unearned + deemed * spouse_unearned); ia_ssa_smme_spousal_deeming_applies.py:37 (earned + unearned).
  • Source: 8-E step 4 combines "the applicant's unearned income and the ineligible spouse's remaining unearned income" (8-E p.13). The deeming test is "over $497" (8-E p.12).
  • Evidence (verifier 3): If you drop the :61 term, all 122 cases pass. The proposed case then gives 1,847.50 against the two-person 2,115, so ia_ssa flips from 1 to 0. If the flag tests earned income only (:37), all 122 cases pass, and the proposed case fails on the flag. With Cases 94 and 95 both appended, the Iowa folder gives 124 passed at the head. Each case pins its own step.
  • Why should address: This is a missing edge case for an already-tested variable, and the mutant flips eligibility. It is not critical, because the code is correct.
  • Fix (append after Case 94; this is verifier 3's text byte for byte, and it passes at the head). With Case 92, it pins the > test from both sides:
- name: Case 95, a spouse's 497.01 dollar pension is deemed to an SMME applicant working above the SGA level.
  period: 2026-01
  absolute_error_margin: 0.01
  input:
    people:
      person1:
        age:
          2026: 50
        meets_ssi_disability_criteria:
          2026: true
        # Case 77's worker: SSDI of $900 and wages of $2,000 a month.
        social_security_disability:
          2026: 10_800
        employment_income:
          2026: 24_000
        ia_ssa_category: SMME
        ia_ssa_smme_coverage_eligible: true
      person2:
        age:
          2026: 45
        # A pension of $497.01 a month and no wages.
        pension_income:
          2026: 5_964.12
    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:
    # 497.01 is more than 1,491 - 994 = 497, so the pension is deemed as
    # unearned income: (900 + 497.01 - 20) + (2,000 - 65) / 2 = 2,344.51, at
    # least January's two-person 2,115. person2's own income is 497.01 - 20.
    ia_ssa_smme_spousal_deeming_applies: [true, false]
    ia_ssa_smme_countable_income: [2_344.51, 477.01]
    ia_ssa: [1, 0]

Append the cases in number order (94, 95, 96, 97). Cases 94, 95 and 92 have a spouse aged 45 who is not in a facility, so the SA31 and SA32 fixes do not change them.

Suggestions

New:

  • G57. The spouse's income on the new path copies three federal deeming simplifications. This comes from regulatory NEW-2, code NEW-1 and verifier 4.
    • Where: _smme_spouse_income.py:8-14.
    • (a) Court-ordered support and alimony that the spouse pays are not deducted. 8-E says "Deduct support payments from the income of the ineligible spouse ... first from unearned income" (8-E p.12), and 416.1161(a)(10) says the same. Probe (April 2026): with wages 3,277 and spouse wages 600 that pay child support 200, the model gives [0, 0] and the rule gives [1, 0]. With wages 1,700 and spouse wages 3,000 that pay alimony 2,600, the model gives [1, 0] and the rule gives [0, 0].
    • (b) Children are found through the applicant's tax unit. When the spouses file separately and the child is on the spouse's return, nothing is allocated (Case 82 plus a child: 2,347.50, [1, 0, 0]; rule 2,099, [0, 0, 0]).
    • (c) The 416.1163(b) exception for a child who receives public income-maintenance is not applied.
    • Why a suggestion: main's federal deeming has all three gaps, and the age-70 SSI path gives the same results. A helper-only fix would split the two paths again (verifier 4, Part C). On main, the same gap also underpays SSI itself. An aged applicant with SS 500, whose spouse has wages 1,500 and pays support 1,200, gets SSI 293.50 instead of 514.
    • Fix: name (a)-(c) in the helper docstring, citing 8-E p.12 and 416.1161(a)(10). File a federal issue to deduct child_support_expense and alimony_expense in ssi_{earned,unearned}_income_deemed_from_ineligible_spouse, with that SSI household as the test. No open issue covers 416.1161(a)(10).
  • G58. Main's SSI deeming ignores a stay in a medical facility, in both directions. This comes from regulatory NEW-3 and verifier 1, section 7.
    • (a) An SMME applicant in a facility still gets income deemed from a spouse at home. 416.1163(f)(5) says that when "the $30 Federal benefit rate applies, we do not deem your ineligible spouse's income to you". Probe: the applicant is aged 70 and in a facility with own income 1,600, and the spouse is aged 45 at home with a pension of 520. The model gives 2,120 and [0, 0]; the rule gives 1,600 and [1, 0].
    • (b) A non-ABD spouse in a facility is still deemed on the SSI path. With an applicant aged 70, wages 3,277 and a spouse aged 45 with a pension of 520 in a facility, the model gives 2,106 and [0, 0]; the rule gives 1,596 and [1, 0].
    • Where: ia_ssa.py:114 and ia_ssa_smme_countable_income.py:37 read the federal variables.
    • This is federal code, it also affects ssi, and SA31 cannot reach it. Fix: file a federal issue. Optionally, add a NOTE beside ia_ssa.py:112-116.
  • G59. The new comments give the 8-E exception list the wrong scope, and two cites can be more exact. This comes from regulatory NEW-4, references NEW-1 and pages note 2.
    • ia_ssa_smme_spousal_deeming_applies.py:21-23 calls the exceptions "State Supplementary Assistance groups", but Medically Needy and MEPD are Medicaid groups (8-E p.11). Use: 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.
    • Cite "416.1163(b)(3)" at _smme_spouse_income.py:6. SA32's docstring already does.
    • Optionally, add https://www.legis.iowa.gov/docs/code/249.pdf#page=2 to the flag's tuple, because the comment at :26 relies on 249.3(4)(a)(2) and (c).
  • G60. Reference titles. This comes from references NEW-2 and pages note 1.
    • The 2023 sheet titles at dependent_amount.yaml:27, rcf_daily_limit.yaml:28 and rcf_personal_needs.yaml:38 read "Iowa HHS 2023 State Supplementary Assistance standards". Use the document's own title and date: Iowa HHS State Supplementary Assistance Standards (effective January 1, 2023).
    • Optional: end the GL 6-B-45 titles with "#page 1,3" at dependent_amount.yaml:25 (FILE 3 has the $490 DP income limit) and "#page 1,16" at rcf_personal_needs.yaml:36 (FILE 16 has the $123), as rcf_daily_limit.yaml:26 does.
  • G61. Helper and label naming. This comes from code NEW-2.
    • Four of the six state helper modules carry the program prefix (_nh_ssp_couple.py, _ok_ssp_income.py, _ga_liheap_housing.py, _ky_combined_separate.py). Rename the module to _ia_ssa_smme_spouse_income.py and the function to ia_ssa_smme_spouse_income.
    • The label at ia_ssa_smme_spousal_deeming_applies.py:10 is a clause, but the other Iowa labels are noun phrases. Use "Iowa SMME spousal deeming applies to an applicant working above the SGA level".
    • In the docstring, say that "marital-unit sum minus own" is the spouse only because callers gate on ia_ssa_has_spouse.
  • G62. Two gate operands are not pinned. This comes from tests NEW-3 (static trace; run once). If you remove ~is_ssi_aged_blind_disabled (ia_ssa_smme_spousal_deeming_applies.py:29-31) or ia_ssa_has_spouse (:36), every case still passes. The first operand is the guarantee against double counting.
    • Fix: add ia_ssa_smme_spousal_deeming_applies: [false, false, false, false] to Case 51 (ia_ssa.yaml:1309). Its disabled person1 has a spouse who earns 4,500, so without ~ABD the flag would be true.
    • For the second operand, use a Case 94 variant with no marital_units. It gives flag [false, false, false], SMME income 807.50 for person1 and ia_ssa 0.
  • G63. The 2023 values and the 2024 dependent amount are not pinned. This comes from tests NEW-4. Add these cases, in the shape of Cases 4 and 93. Each one fails if its year's entry is removed, and the regulatory probe gives the same values.
    • 2023-01, age 70, RESIDENTIAL_CARE, SSI only: ia_ssa 318.59 (31 x 35.89 - (914 - 120)).
    • 2024-01, age 65, DEPENDENT_PERSON, ia_ssa_dependent_countable_income: 100: ia_ssa 490.
    • 2023-01, the same household: ia_ssa 474.
  • G64. The PR body has one stale clause (DTrim99's suggestion 2). The SMME coverage bullet still lists "an SGA worker with a spouse ... (Cases 81-84)", but Case 82 now deems. Drop that clause, and change "(Cases 81-84)" to "(Cases 81, 83 and 84)". After SA31-SA34, add Cases 94-97 to the test list and update the counts.
  • G65. rulespec-us#1837 has stale details (DTrim99's suggestion 3; issue only).
    • Step 1 says "Parameters from 2026-01-01", but rows AX and BE need the 2023-2025 values.
    • The "14 formulas" count and the Required outputs table do not include ia_ssa_smme_spousal_deeming_applies.
    • The Payment row still says "for the recipient and any spouse".
    • Row BD does not say "April 2026".
    • After the fixes, add rows for Cases 94-97.

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

  • G36 Four removable branches: the ~adult child-support guard, the FLH marital_unit.any, the FLH recipients split, and parental deeming with an SSI parent or two eligible children.
  • G37 Add the "At the discretion of the department" reading of Code 249.3(4) to the candidate and the NOTE at ia_ssa.py:128-135.
  • G38 The DP couple level continues on a spouse in residential care (6-B p.66, p.71). Add a NOTE or a "Not modeled" line.
  • G39 The 249.3(4)(g) upper bound is carried only by ia_ssa_smme_coverage_eligible. New point: 6-B p.77 also excludes a person who must pay a premium, and an MEPD member whose gross income is above 150% FPL pays one (8-F p.121). So Cases 77, 82, 88 and 92 imply a group with no premium. Say both in the input's documentation.
  • G40 ia_ssa_care_initial_partial_month drives two rules with different scopes. Align the documentation or split the trigger.
  • G41 Integration Case 12 certifies DEPENDENT_PERSON with no dependent in the household.
  • G42 The IHHRC dependent allowance is summed over the tax unit (ia_ssa_ihhrc_participation.py:49-51).
  • G44 Link GL 6-B-47 (https://hhs.iowa.gov/media/18744/download?inline) in rcf_personal_needs.yaml. Consider the dated code/2026/249.pdf.
  • G45 Relabel ia_ssa_smme_countable_income.py:19 as 249.3(4)(a)(2), label :23, and apply the round-4 page-list items.
  • G46 Use add() at ia_ssa_smme_countable_income.py:37 and :55-57 and at ia_ssa_federal.py:37-39, and re-wrap ia_ssa_rcf_couple_budget.py:32.
  • G47 Add an RCF dividends case (SS 13,200 + qualified_dividend_income 600 a year: care income 1,100, pays 222.57).
  • G48 Add the formula boundaries: single at 1,596, and couple at 2,164. The SGA switch (wages 20,280 against 20,280.12) is now also a switch between the two deeming paths. In January, with SSDI 10,800 and spouse wages 12,000, both give about 2,192.50 and [1, 0] (static).
  • G49 Add ia_ssa_has_spouse: [true, true] to Case 83.
  • G50 Pin the IHHRC couple sum, the day-count min_, the third-decimal truncation, earnings after entry and a later-entering spouse.
  • G51 Set from: 2023 at candidates.yaml:1794. Optionally, add GL 6-B-45 #page=24 and the 2023 sheet as manual sources.
  • G52 Add "https://hhs.iowa.gov/media/4011/download?inline#page=12", # 8-E Deeming from an Ineligible Spouse; PDF pages 12-13 to the tuples at ia_ssa.py:10-19 and ia_ssa_smme_countable_income.py:18-24.
  • G53 (a) Add the 6-B p.77 reference and a scope sentence. (b) Add a NOTE on the stale 8-E p.7 figures. (c) Link the RC-0130 Rev. 04/25 capture from Cases 78-80 and 89. (d) Optionally, add 2025-01-01: 4.
  • G54 (a) Document the cap averaging. (b) Add this NOTE at ia_ssa_smme_countable_income.py:49: "The student exclusion follows 20 CFR 416.1112(c)(3) and 42 U.S.C. 1382a(b)(1) as amended in 2004, which have no marital or head-of-household test. 8-E p.19 still lists 'Not married' and 'Not the head of the household'."
  • G55 An FPG reform that does not start on January 1 reaches Iowa a year late (ia_ssa.py:123).
  • G56 Add 2025 tests: SS 18,720 a year gives 1 in March and 0 in April, and a DP case in 2025-01 with dependent income 100 gives 503.

Investigated and cleared

  • 8-E p.11, "income alone ... over income limits": SMME's test is a floor. Case 91 follows p.12 ("also consider the ineligible spouse's income").
  • 8-F p.120, MEPD family income: this is the MEPD group's own test, and the coverage input carries it. 8-E p.11 sends only MEPD to 8-F. The results are the same under either reading.
  • 8-E p.13 "lesser of" and 416.1163(e)(2): these limit the SSI payment, not countable income.
  • ISM on the deeming path: the individual PMV ($351.33) is the only figure in 8-E. The spouse's ISM is excluded (416.1161(a)(11)).
  • Timing of the $497 threshold: 8-E uses the current month. The second-prior-month rule is for the benefit amount.
  • MONTH reads of YEAR variables in the helper: these divide by 12 (allocation 497 less the child's monthly income).
  • The married student on the deemed path (verifier 4): the repo follows current federal law, so G54(b) is documentation only.
  • LII href for 416.1163: this is the house form, and its text agrees with the eCFR.
  • 2023 sheet URL: the media id still serves the 2023 sheet in October 2026.
  • The dependent-income boundary at exactly $490 or $474 gives 0 (<). This choice predates this round.

PDF Audit Summary

Category Count
Documents Reused: 6-B, 8-E, 8-F, GL 6-B-45, 2023 standards sheet, Code 249, IAC 75, RC-0130 Rev. 04/25, eCFR 416.1160. New: eCFR 416.1163, 416.1161, 416.1167, 416.1149, 416.1112, 416.1856, 416.1861; 42 U.S.C. 1382a, 1382c
Values, rules, anchors and cites confirmed (pdf-rules) 36 (8 new values and dates, 1 unchanged-values check, 9 derived 2023/2024 levels and cases, 11 deeming rules, 7 anchors and cites)
Value mismatches 0
Rule mismatches (code run, page re-read, verifier-confirmed) 2: SA31 (spouse in a facility), SA32 (spouse status)
Rule steps with no test (mutation-proven) 2: SA33, SA34
Inherited federal gaps G57, G58 (suggestions; federal issues); G54(b) documentation only
Source-conflict record gap 1 year span: G51 (now 2023-2026)
Rejected "Budget each spouse alone" values (pdf-rules P6 and P8, tests NEW-5(b)); zeroing a married student's exclusion (regulatory)
Page citations 21 checked, 21 correct, 0 wrong
References 22 of 22 corroborate (6 parameter entries, 2 variable hrefs, 14 comment citations)

Validation Summary

Check Result
Regulatory SA28 and SA19 resolved; SA31; G57, G58, G59; G51 wider; G39 premium point
References 22/22 correct; G44 and G52 partial; G45 and G53 open; G59, G60
Code patterns No critical or should-address item; SA30 resolved; G61; no duplicate of a federal variable; ruff clean
Tests Cases 82 and 89-93 (and their comments) recompute, all correct; Cases 77, 87, 88 unchanged; no non-functional test; SA33, SA34; G62, G63
PDF rules 36 matches, 0 value mismatches; spouse-status gap (SA32 after verifier 2)
Pages 21/21 correct
Verifiers 1: facility gap CONFIRMED (SA31). 2: spouse status CONFIRMED with three flips (SA32); "budget alone" values REJECTED. 3: Cases 94 and 95 CONFIRMED (SA33, SA34); 124 pass with both. 4: support and alimony CONFIRMED as a federal gap (G57); married student NOT CONFIRMED as a mismatch (G54(b) NOTE); G53 and G49 STILL OPEN
Local runs 122/122 Iowa YAML; 448 code-health and aggregate-list tests pass, 1 skipped; 4 coordinator mutation runs (start month 2, 3, 5; no allocation)
Branch 43 ahead, 14 behind main; clean merge; MERGEABLE; staleness did not affect findings
Partner tests None touched

Review Severity: REQUEST_CHANGES

Four should-address items are open (SA31-SA34), all in the new SA28 code. No critical item is open. SA28, SA29, SA30 and SA19 are resolved.

Next Steps

  1. SA31 and SA32: add the household test and the spouse-status test to ia_ssa_smme_spousal_deeming_applies (combined code in SA32), and append Cases 96 and 97.
  2. SA33 and SA34: append Cases 94 and 95. No code change is needed.
  3. Run the Iowa suite once with all four changes, and update the comments at ia_ssa_smme_countable_income.py:45-48 and ia_ssa.py:103-111.
  4. Update the PR body (G64) and rulespec-us#1837 (G65) for Cases 94-97.
  5. Optional: G57-G63 and the carried suggestions. File the federal issues for G57(a) and G58.
  6. To auto-fix issues: run the fix-pr workflow for this PR.

hua7450 and others added 2 commits October 23, 2026 19:21
- Deem nothing on the SMME SGA path from a spouse in a medical treatment
  facility, who is not a household member (20 CFR 416.1167; 8-E p.11;
  Case 96).
- Treat a spouse SSI counts as aged, blind or disabled as an eligible
  spouse, combining the couple's income with no $497 test or child
  allocations (8-E p.12; 8-F pp.73-74; Case 97).
- Pin the child-allocation order and a deemed spouse pension at $497.01
  (Cases 94-95).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@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.

This branch has not been deployed

No deployments
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