Repository navigation
Add Iowa state supplementation for 2026 - #8017
Conversation
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 Report✅ All modified and coverable lines are covered by tests. 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
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- 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>
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
left a comment
There was a problem hiding this comment.
Iowa State Supplementary Payment (SSP) — PR #8017 Review
Source Documents
- PDFs reviewed:
- IAC 441 Chapter 52 (Payment Standards) — https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.52.pdf
- IAC 441 Chapter 51 (Eligibility) — https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.51.pdf
- IAC 441 Chapter 177 (IHHRC) — https://www.legis.iowa.gov/docs/iac/chapter/01-07-2026.441.177.pdf
- SSA "State Assistance Programs for SSI Recipients" — Iowa, January 2011 — https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/ia.pdf (via Wayback Machine)
- Iowa HHS General Letter 6-B-46 (effective 2025-01-01) — https://hhs.iowa.gov/media/15607/download
- Iowa HHS State Supplementary Assistance current rates page (HTML) — https://hhs.iowa.gov/assistance-programs/state-supplementary-assistance
- Year coverage: 2011, 2017, 2018, 2025, 2026
- Scope: Full PR diff (38 files; new state program implementation — 17 variables, 13 parameters, 5 test YAMLs, plus SPM-unit roll-up registration and program registry)
Critical (Must Fix)
-
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_fbris clamped toindividual_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. Thestate_supplementYAML is back-calculated againstindividual_fbrfor every configuration, producing wildly inflated raw values that the author then bounds withmax_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.yamlanddependent_income_limit.yamlare byte-identical across all four years (379, 387, 503, 518), confirming the conflation. - Code-path verifier confirmed: for
BLIND_WITH_BLIND_SPOUSE_AND_DEPENDENT2025 with zero countable income, code returns $503; regulation requires $547 (= $1,997 standard − $1,450 couple FBR). $44/month error, locked in by testia_ssa.yamlCase 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)). Removemax_per_person_cap.
- Location:
-
$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, butssi_countable_incomealready 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.yamlRCF 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_disregardhelper that adds backmin(unearned_monthly, $20), and use it in RCF/FLH/IHHRC payment formulas and in the corresponding routing-layer gates.
- Location:
-
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_jointto flip both the resource pool (individual vs. marital sum) and the cap ($2,000 vs. $3,000).ssi_claim_is_jointreturns 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 ania_ssa_dp_*variable that already enumerates dependents) and sum resources across all 51.5-covered dependent relatives.
- Location:
-
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.yaml441—51.4(1) 441—51.5(1) 3 parameters/.../ssa/dp/max_per_person_cap.yaml441—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.pyline 39 commentIAC 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.
-
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.
- Location:
Should Address
-
FLH
state_supplementhistorical (pre-2025) values disagree with SSA published baselines —flh/state_supplement.yamlencodes $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.) -
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. Usepersonal_fpgfor individual claims and 2-person FPG for joint claims. (Regulatory S2.) -
DP
max_per_person_capparameter is duplicative and undocumented — Identical values todependent_income_limitacross all years. Conflates two regulatory concepts. Remove and replace with per-configuration state supplement encoding (related to Critical #1). (Regulatory S3.) -
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_diemare 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., defaultia_ssa_has_medicare_part_btois_medicare_eligible) where a federal PE variable already encodes the concept. (Regulatory S5/S6, Suggestion G1.) -
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 setsdefault_value = Falseonia_ssa_has_full_medicaidandia_ssa_has_medicare_part_bbut is inconsistent for the rest. (Code S2.) -
FBR acronym in parameter descriptions —
dp/state_supplement.yamlandflh/state_supplement.yamluse "(FBR)" in the description field, violating the parameter-patterns "no acronyms" rule. (Code S4.) -
Period-bridging convention undocumented —
ia_ssa.py:29,ia_ssa_living_arrangement.py:37,ia_ssa_smme_eligible.py:16access YEAR-period inputs (ssi_claim_is_joint,is_ssi_aged_blind_disabled) withperiod.this_yearfrom MONTH formulas. Technically correct but consider a single explanatory comment near the top ofia_ssa.py. (Code S1.) -
#page=anchor mismatch in IHHRCmax_cost_single.yaml— Reference for441-177.10(3)uses#page=4but the rule is on file page 5. (Reference S1.) -
Iowa Code 249.9A reference missing
#page=anchor —rcf/personal_needs_allowance.yaml. (Reference S2.) -
Iowa HHS GL 6-B-46 download URL has no page anchor — Multiple files cite
hhs.iowa.gov/media/15607/downloadbare. Add#page=1for explicitness or cite the manual chapter URL. (Reference S3.) -
Bare HHS landing page reference for 2026 values is insufficient —
hhs.iowa.gov/assistance-programs/state-supplementary-assistanceis dynamic. Add a Wayback snapshot URL or a(retrieved YYYY-MM-DD)note. (Reference S4.) -
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 contaminatedcountable_monthly, so cases at or within $20 of the boundary may be mis-classified. (Regulatory S7 — addressed by Critical #2 fix.) -
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.) -
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.) -
V-shape boundary at
countable == FBRnot directly tested — None of the BLIND/DP/FLH cases use asocial_security_retirementvalue engineered to putssi_countable_incomeexactly atindividual_fbr. (Test C3.) -
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.)
-
IHHRC combined countable equal to caps not tested —
ihhrc_countable_after_disregard <= ihhrc_capuses<=. No case sits exactly at $480.55 single or $961.10 couple. (Test C5.) -
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.) -
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 == 0boundary not tested, ineligible-person variants missing, DPhas_eligible_dependent: falsewith non-NONE configuration not tested. (Test S6, S8, S10, S11, S12, S13.)
Suggestions
-
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.) -
Default
ia_ssa_has_medicare_part_btois_medicare_eligible— Would let SMME fire automatically in microsim. (Code G1.) -
Extract DRY intermediate variables —
countable_monthly,ssi_monthly,basic_ssi_disregard,combined_countableare re-derived in bothia_ssa.pyandia_ssa_living_arrangement.py. Consider sharedia_ssa_countable_income_monthlyetc. per the variable-patterns "intermediate variables for code reuse" rule. (Code G1.) -
Add YAML comments in
dependent_income_limit.yamlandmax_per_person_cap.yamlclarifying they are intentionally not breakdowns — Prevents a future contributor from "fixing" them. (Code S3.) -
RCF
cost_per_diemdefault top.rcf.max_per_diemwhen resident is flagged as in RCF — Behavioral improvement so the default supplement is non-zero. (Code G2.) -
ia_ssa_resources_eligibledescription should note monthly recomputation of an annual SSI resource test. (Code G4.) -
Consolidate 2017/2018 IAC supplement citations with effective-date parentheticals. (Reference G1.)
-
Tighten SSA 2011 footnote-a documentation in
dp/state_supplement.yaml. (Reference G2.) -
Add YAML comment in
rcf/days_multiplier.yamlexplaining the "31 = largest possible days-in-a-month" derivation. (Reference G3.) -
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.)
-
Standardize
absolute_error_margin: 0.01across YAML test cases. (Test S19.) -
Test variants: negative income, explicit
ssi_claim_is_jointtoggling on couples, RCF per-diem exactly at cap, days-multiplier sensitivity, entity-scaffolding cleanup foria_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_eligiblechecks 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) passesis_ssi_eligibleand 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 onlyia_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
- 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. - Strip $20 disregard for RCF/FLH/IHHRC — Add an
ia_ssa_countable_income_no_disregardhelper that adds backmin(unearned_monthly, $20); use in RCF/FLH/IHHRC payment formulas and routing-layer income gates. - Fix resource-limit dispatcher — Replace
ssi_claim_is_jointwith an Iowa-specificia_ssa_has_dependent_spousethat covers ineligible-but-financially-dependent spouses per IAC 441-51.5(4). - Correct IAC subsection citations (5 locations) —
smme/minimum_income_fpl_multiplier.yaml(51.6(6)→51.7(6));dp/dependent_income_limit.yamlanddp/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:39comment (51.3(3)→51.4(3)). - Add minimum-recommended deductions — $65+½ earned-income disregard and dependent diversions for RCF and IHHRC.
…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.
|
Thanks, Pavel. All four are applied as you wrote them, in 99f005d, and
The optional suggestions (G57-G63 and the carried ones) are not in this round. 126 Iowa supplement cases pass locally (97 in |
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Program Review (round 7): Add Iowa state supplementation for 2026
IDs: C = critical, SA = should address, G = suggestion. Prior IDs keep their numbers. New findings start at SA35 and G66. There is no new critical item, so C8 is not used.
Source Documents
- Reviewed head SHA: 0ad5fc5
- Mode: incremental from 5837b95
- Commits since round 6: 99f005d "Address Pavel's round-6 review of Iowa SSA" (5 Iowa files, +237 / -9); 0ad5fc5 (merge of
mainat 6a92d6a; among PR-scope files onlyprograms.yamlandsource_conflicts/candidates.yamlchanged, with no Iowa line). - Scope:
_smme_spouse_income.py(newsmme_spouse_is_aged_blind_disabled; no child allocations for that spouse);ia_ssa_smme_spousal_deeming_applies.py(apart,eligible_spouse, two hrefs, two NOTEs); comment-only edits inia_ssa.pyandia_ssa_smme_countable_income.py; Cases 94-97 appended toia_ssa.yaml(no existing case edited; 126 Iowa cases in total). - Sources ("p.NN" = PDF FILE page; 6-B and 8-F FILE = printed + 4; 8-E FILE = printed + 5): 8-E https://hhs.iowa.gov/media/4011/download?inline ("Revised May 22, 2026"), 8-F https://hhs.iowa.gov/media/4012/download?inline and 6-B https://hhs.iowa.gov/media/3987/download?inline= (all downloaded again); eCFR (October 2026) 20 CFR 416.212, 416.414, 416.1112, 416.1142, 416.1149, 416.1160, 416.1161, 416.1163, 416.1167, 416.1801, 416.1802; POMS SI 00501.154, SI 00835.040, SI 02005.050, SI 01310.165; LII 42 U.S.C. 1382a; GitHub #10138, #10141, #10193, #10243 and TheAxiomFoundation/rulespec-us#1837 (read-only).
Branch Status
- 45 ahead, 34 behind
main(0e7ced1);MERGEABLE. CI: 27 pass, 0 fail. - Among Iowa files, the 34 newer commits change only Iowa income-tax files (
ia_other_additions,ia_other_subtractions). They change no Iowa supplement, SSI, poverty-guideline or MSP file. The federal SSI deeming, status and couple-computation files are the same at the head and onmain(0e7ced1 and dbfc017). The staleness did not affect any finding. A rebase is not necessary for review. - Local run at 0ad5fc5: 126/126 Iowa YAML cases; 452 code-health and aggregate-list tests (1 skipped);
test_source_conflicts.py103;test_programs_registry.py767 (10 skipped, none Iowa);ruff format --checkandruff checkclean on the 24 Iowa variable files. - No partner test file is touched. The changelog fragment is unchanged. Record only:
programs.yamlstill saysverified_years: "2026"for Iowa.
What round 7 fixed
- SA31, as proposed. The
apartterm, the 416.1167 href and the NOTE are in the flag (:16,:36-46,:64), and Case 96 pins~apart. Under 20 CFR 416.1167(a)(1), either spouse who has left the household is not a household member, whoever pays. (a)(2) needs 416.212 eligibility, which an applicant above the SGA level lacks. For a Medicaid-paid stay of an aged spouse, the SGA path and the aged path now agree (Cases 96 and 81). - SA32, as proposed. The helper is byte-identical to the proposal, the combined return is at
:58-66, and the 8-F href is added. Case 97 pinseligible_spouse. An aged, blind or disabled (ABD) spouse is not an ineligible spouse (8-E p.12; 8-F p.73), so the couple is combined with no $497 test and no allocations. The three round-6 flip rows now give [0, 0], and the control row (wages 1,700, spouse SS 3,000) still gives [1, 0]. - SA33 and SA34. Cases 94 and 95 are the proposed text and recompute by hand. A zeroed or earned-first allocation fails only Case 94. Dropping the spouse's unearned term fails Cases 95 and 97. A
>=in the $497 test fails Case 92, so "over $497" is pinned from both sides. - 126/126 Iowa cases pass on the merged tree, and the 452 code-health tests pass.
- 12 of 12 new or changed cites are correct, each read on the rendered page or in the eCFR text. No printed page number is used.
- PR body and issue: the
axiom:line is present, and G64 is done. rulespec-us#1837 has rows BF-BI, the flag row, "cases A to BI", "15 formulas", "Parameters from 2023-01-01", BD "April 2026" and a corrected Payment row (G65). - Also: G59's second bullet, and G52 in part (8-F href).
- No regression. No test line is removed. Cases 77, 82, 87, 88, 90-93 and the C4, C7, SA23, SA25, SA27 and SA28 cases pass, and no mutant of the new terms changes them.
- The head is right not to add the ABD spouse's SSI payment (G67).
Both new should-address items are in the SA31 and SA32 code: three new branches have no test (SA35), and the SA32 rule is applied to the applicant but not to the ABD spouse in the same couple (SA36).
Round-6 status
| ID | Status | Evidence at 0ad5fc5 |
|---|---|---|
| SA31 spouse in a facility | RESOLVED | apart, href, NOTE as proposed; Case 96 pins it. Facets untested: SA35 |
| SA32 ABD spouse status | RESOLVED | Helper and return as proposed; Case 97 pins it. Gaps: SA35, SA36 |
| SA33 child allocation | RESOLVED | Case 94 verbatim; allocation mutants fail only Case 94 |
| SA34 spouse unearned income | RESOLVED | Case 95 verbatim; the unearned-term mutant fails Cases 95 and 97 |
| G25 case periods | PARTIAL (accepted part stands) | 2026-01 (Cases 94-95) and 2026-04 (Cases 96-97) fit |
| G36 | STILL OPEN (no reply) | The four branches are unchanged |
| G37 | STILL OPEN (deferred) | NOTE (now ia_ssa.py:130-137) and Iowa candidates unchanged |
| G38 | STILL OPEN (deferred) | ia_ssa_federal.py unchanged |
| G39 | STILL OPEN (deferred) | Coverage input documentation unchanged |
| G40 | STILL OPEN (deferred) | Files unchanged |
| G41 | STILL OPEN (deferred) | integration.yaml unchanged |
| G42 | STILL OPEN (deferred) | ia_ssa_ihhrc_participation.py:49-51 unchanged |
| G44 | PARTIAL (deferred) | No GL 6-B-47 link; undated code/249.pdf |
| G45 | STILL OPEN (deferred) | Countable :19 still "249.3(4)(g)"; :23 unlabeled |
| G46 | STILL OPEN (deferred) | Manual sums unchanged; no new instance |
| G47 | STILL OPEN (deferred) | No RCF dividends case |
| G48 | PARTIAL (new) | Case 96 reaches the one-person 1,596 through the formula; a >= to > mutant at ia_ssa.py:142 fails it. Couple 2,164 and SGA switch open |
| G49 | STILL OPEN (deferred) | Only Case 65 asserts ia_ssa_has_spouse ([false, false]) |
| G50 | STILL OPEN (deferred) | Unchanged |
| G51 | STILL OPEN (deferred) | candidates.yaml:1988-1990 still from: 2026 |
| G52 | PARTIAL | Flag adds 8-F; ia_ssa.py:10-19 and countable :18-24 lack 8-E #page=12 |
| G53 | STILL OPEN (deferred) | fpg_year_start_month.yaml unchanged |
| G54 | STILL OPEN (deferred) | No NOTE at countable :50; SA36 extends it to the spouse |
| G55 | STILL OPEN (deferred) | ia_ssa.py:125 still f"{year}-01-01" |
| G56 | STILL OPEN (deferred) | No 2025 SMME or DP case |
| G57 | STILL OPEN (federal; record) | Docstring does not name (a)-(c); no issue for 416.1161(a)(10) |
| G58 | STILL OPEN (federal; partly tracked) | #10138 names (a) only; (b) untracked; new point (c) |
| G59 | PARTIAL | Second bullet done; first bullet open and wider (G66) |
| G60 | STILL OPEN (deferred) | 2023 sheet titles unchanged |
| G61 | STILL OPEN, wider | The new function is also unprefixed; label unchanged |
| G62 | STILL OPEN; wording corrected | Both operands' mutants pass 126/126; the guard cannot double count |
| G63 | STILL OPEN (deferred) | No 2023 case; no 2024 DP case |
| G64 | RESOLVED | SMME bullet, test list, 126 (97) count and not-modeled list updated |
| G65 | RESOLVED | All five round-6 points are in rulespec-us#1837 |
Tally: 34 IDs were open after round 6. Now 6 are resolved, 5 are partial (G25, G44, G48, G52, G59), 23 are still open and 0 are declined. You deferred G57-G63 and the carried suggestions. A deferral is acceptable for suggestions, and none of them blocks.
Critical (Must Fix)
None.
Should Address
SA35. Three new rule branches have no test, and each mutant flips ia_ssa
- What is wrong: Case 96 covers only a spouse in a Medicaid-paid stay, and Case 97 has no child. So no case reaches these branches:
- (a) no child allocations for an ABD spouse (
_smme_spouse_income.py:22-24); - (b)
apartis true when the applicant is in a facility (marital_unit.any, flag:44-46); - (c)
apartis true for a private-pay stay (ssi_lives_in_medical_treatment_facility, not the Medicaid-paid arrangement).
- (a) no child allocations for an ABD spouse (
- Source: 8-E p.12 takes the child allocations only in the steps for deeming from an ineligible spouse, and 416.1163(b) allocates only from an ineligible spouse's income. Under 416.1167(a)(1), "You, your ineligible spouse ..." who leaves the household stays a member only with a return "in the same month or the month immediately following"; the payer does not matter.
- Evidence (each mutant run on a copy of the branch, in two or three separate runs):
| Branch | Mutant | Iowa suite | Proposed case: head, then mutant |
|---|---|---|---|
| (a) | Allocations kept for every spouse | 126 pass | Case 98: SMME 2,186, then 1,689; ia_ssa [1, 0, 0], then [0, 0, 0] |
| (b) | apart tests the spouse only |
126 pass | Case 99: SMME 1,596, then 2,106; ia_ssa [1, 0], then [0, 0] |
| (c) | apart needs a Medicaid-paid stay (round 6's rejected variant) |
126 pass | Case 99: the same flip |
One improbable mutant (the payer test on the spouse only) still survives. No case is proposed for it.
- Why should address: Missing edge cases for an already-tested variable, in new code, and each mutant flips eligibility: the same class as SA29 and SA33. Round 6's optional ABD case would catch (a) only in SMME income, not in
ia_ssa. G62 is not a precedent, because its guard mutant never changesia_ssa. Not critical: the code is correct today. - Fix (no code change): append after Case 97. Both pass at the head. Case 98 kills (a); Case 99 kills (b), (c) and a
>=to>mutant of the SMME guideline test.
- name: Case 98, no child allocation comes off an aged spouse's income when an SMME applicant working above the SGA level is budgeted as a couple.
period: 2026-04
absolute_error_margin: 0.01
input:
people:
person1:
age:
2026: 50
meets_ssi_disability_criteria:
2026: true
# Wages of $3,277 a month, above the $1,690 SGA level.
employment_income:
2026: 39_324
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
person2:
age:
2026: 70
# Social Security of $600 a month.
social_security_retirement:
2026: 7_200
person3:
age:
2026: 10
marital_units:
couple:
members: [person1, person2]
child:
members: [person3]
tax_units:
tax_unit:
members: [person1, person2, person3]
spm_units:
spm_unit:
members: [person1, person2, person3]
households:
household:
members: [person1, person2, person3]
state_code:
2026: IA
output:
# 8-E p.12: the aged spouse is not an ineligible spouse, so the couple's
# income is combined with no allocation for the child (20 CFR 416.1163(b)
# allocates only from an ineligible spouse's income):
# (600 - 20) + (3,277 - 65) / 2 = 2,186, at least the two-person 2,164.
# With the 497 allocation it would be (103 - 20) + 1,606 = 1,689.
# person2's 1,937.50 is SSI's own deeming from person1, with the
# allocation: (600 - 20) + (3,277 - 497 - 65) / 2. The model uses SSI's
# income for anyone SSI counts; if person1 is not an ineligible spouse to
# person2 either (8-E p.12), person2's would also be 2,186.
ssi_ineligible_child_allocation: [0, 0, 497]
ia_ssa_smme_spousal_deeming_applies: [true, false, false]
ia_ssa_smme_countable_income: [2_186, 1_937.5, 0]
ia_ssa: [1, 0, 0]
- name: Case 99, nothing is deemed to an SMME applicant working above the SGA level who lives in a privately paid medical facility.
period: 2026-04
absolute_error_margin: 0.01
input:
people:
person1:
age:
2026: 50
meets_ssi_disability_criteria:
2026: true
# Wages of $3,277 a month, above the $1,690 SGA level.
employment_income:
2026: 39_324
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
ssi_lives_in_medical_treatment_facility: true
ssi_medicaid_pays_majority_of_care: false
person2:
age:
2026: 45
# A pension of $520 a month.
pension_income:
2026: 6_240
marital_units:
couple:
members: [person1, person2]
tax_units:
tax_unit:
members: [person1, person2]
spm_units:
spm_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code:
2026: IA
output:
# 20 CFR 416.1167(a)(1); 8-E p.11-12 "same household": the applicant, who
# is in a medical facility, is not a household member, whoever pays for
# the stay, so the spouse's 520 pension is not deemed.
# (3,277 - 20 - 65) / 2 = 1,596, at least the one-person 1,596. With
# deeming it would be (520 - 20) + (3,277 - 65) / 2 = 2,106, below the
# two-person 2,164. person2's own income is 520 - 20 = 500.
ia_ssa_smme_spousal_deeming_applies: [false, false]
ia_ssa_smme_countable_income: [1_596, 500]
ia_ssa: [1, 0]SA36 changes one value in Case 98. Nothing else in Cases 98 and 99 changes.
SA36. The SA32 rule is applied to the applicant only: the ABD spouse still gets SSI's deeming from the worker, with child allocations
- What is wrong: For anyone SSI counts, SMME income is SSI's own figure. SSI treats the SGA-level worker as an ineligible spouse (416.1160(d)), so it deems the worker's income to the ABD spouse after child allocations. Under 8-E p.12 the worker is not an ineligible spouse either. So the head budgets one couple two ways, and with ineligible children the ABD spouse's result flips. The helper also tests only SSI's ABD status, so two SGA-level SMME workers treat each other as ineligible spouses.
- Where:
ia_ssa_smme_countable_income.py:37, 69-70;_smme_spouse_income.py:4-9;ia_ssa.py:114-118. - Source: "An ineligible spouse is a spouse who is not eligible for SSI or non-MAGI-related Medicaid, or State Supplementary Assistance" (8-E p.12). The SMME person "must be eligible for and receiving full Iowa Medicaid benefits ... under a Medicaid coverage group that does not rely on eligibility for SSA" and for Medicare Part B (6-B p.76); SMME is itself State Supplementary Assistance. The non-MAGI groups include "State Supplementary Assistance (SSA) recipients" and 1619(b) workers (8-F p.73), and a 1619(b) worker "is considered to be an SSI recipient" (8-F p.88). The MAGI adult group excludes Medicare (8-F p.47), and the example on 8-F p.99 decides spouse status from the spouse's own disability and Medicare status.
- Evidence (April 2026; person1 aged 50, disabled, above the SGA level; both spouses have SMME category and coverage):
| Household (monthly) | Head: SMME [p1, p2]; ia_ssa |
Rule (eligible couple) | Aged applicant on main |
|---|---|---|---|
| Wages 2,500; spouse 70, SS 1,400; two children | 2,597.50, 2,100.50; [1, 0] | 2,597.50 each; [1, 1] | 2,597.50 each; [1, 1] |
| Wages 3,277; spouse 70, SS 1,000; two children | 2,586, 2,089; [1, 0] | 2,586 each; [1, 1] | — |
| Wages 1,700; spouse 70, SS 1,500; three children | 2,297.50, 1,480; [1, 0] | 2,297.50 each; [1, 1] | 2,297.50 each; [1, 1] |
| Two disabled workers (wages 2,500 and 2,000); two children | 1,710.50 each; [0, 0] | 2,207.50 each; [1, 1] | — |
| First row without children | 2,597.50 each; [1, 1] | match | — |
The gap needs ineligible children; without them, deeming equals combining. Round 6's optional case expected 1,491 for the spouse. That was the code's output, not a rule value; the rule gives 1,886, with no flip.
-
Why should address: Same class and reasons as SA32. 8-E p.12 names State Supplementary Assistance and non-MAGI Medicaid, and the SMME applicant has both by the program's own terms. The round-4 acceptance of SSI's figure predates SA32, and the head now contradicts itself inside one couple. A NOTE does not fix a contradiction with a clear rule. Not critical: the structure is otherwise right, the effect is $1 a month, and the population is input-gated.
-
Fix (tested on a copy of the branch:
ruffclean; the 126 Iowa cases and the new cases pass; Cases 82 and 90-97 and the SGA-path cases do not change; the aged and SGA paths agree on every probe row). Three traps:- Mirroring the applicant's income alone misses the two-worker couple.
- Without the
ia_ssa.pysize term, a spouse whom SSI deems nothing to (wages 1,700; spouse SS 1,000; three children) is wrongly paid against the one-person 1,596. The rule gives [0, 0]. - Without the spouse's student exclusion, the mirror drops it. With wages 3,277 and a disabled student spouse aged 20 who earns 1,200, the head gives the applicant 2,196 and [1] but the spouse 1,790.58; with the exclusion, both are 1,790.58 and [0]. The PR follows the current 416.1112(c)(3) (G54(b)), so subtract both spouses' exclusions.
Replace
_smme_spouse_income.pywith:
from policyengine_us.model_api import *
def smme_spouse_is_aged_blind_disabled(person, period):
"""Whether the other member of a two-person marital unit is not an
ineligible spouse under 8-E p.12: a person SSI treats as aged, blind or
disabled, or an SMME applicant working above the SGA level, who has full
non-MAGI-related Medicaid (8-F PDF page 73, 1619(b) group). For an
applicant whom SSI does not count, any such member is the spouse."""
abd = person("is_ssi_aged_blind_disabled", period.this_year)
sga_applicant = (
person("meets_ssi_disability_criteria", period.this_year)
& ~abd
& person("ia_ssa_smme_coverage_eligible", period)
)
status = abd | sga_applicant
return person.marital_unit.sum(status) - status > 0
def smme_spouse_is_sga_applicant(person, period):
"""Whether a person SSI treats as aged, blind or disabled is married to
an SMME applicant working above the SGA level whose SMME income combines
the couple's income. SSI deems from that applicant, but under 8-E p.12
the applicant is not an ineligible spouse, so the couple is combined."""
applicant = person("ia_ssa_smme_spousal_deeming_applies", period) & person(
"ia_ssa_smme_coverage_eligible", period
)
abd = person("is_ssi_aged_blind_disabled", period.this_year)
return abd & (person.marital_unit.sum(applicant) - applicant > 0)
def smme_spouse_income(person, period):
"""A spouse's SSI earned and unearned income. For an ineligible spouse,
allocations for ineligible children are deducted, from unearned income
first (20 CFR 416.1163(b)(3)). A spouse who is not an ineligible spouse
is combined as for an eligible couple, with no allocations and after the
spouse's own student earned income exclusion (20 CFR 416.1112(c)(3))."""
earned = person("ssi_earned_income", period)
unearned = person("ssi_unearned_income", period)
exclusion = person("ssi_blind_or_disabled_working_student_exclusion", period)
spouse_exclusion = (
person.marital_unit.sum(exclusion) - exclusion
) * smme_spouse_is_aged_blind_disabled(person, period)
spouse_earned = max_(person.marital_unit.sum(earned) - earned - spouse_exclusion, 0)
spouse_unearned = person.marital_unit.sum(unearned) - unearned
allocations = add(
person.tax_unit, period, ["ssi_ineligible_child_allocation"]
) * ~smme_spouse_is_aged_blind_disabled(person, period)
unearned_left = max_(spouse_unearned - allocations, 0)
earned_left = max_(spouse_earned - max_(allocations - spouse_unearned, 0), 0)
return earned_left, unearned_leftIn ia_ssa_smme_countable_income.py, import smme_spouse_is_sga_applicant, and add after :70 (income = where(counted_by_ssi, income, own_income)):
# The aged, blind or disabled spouse of that applicant gets the same
# combined income, not SSI's deeming from the applicant.
applicant = deemed & person("ia_ssa_smme_coverage_eligible", period)
combined = person.marital_unit.sum(where(applicant, income, 0))
income = where(smme_spouse_is_sga_applicant(person, period), combined, income)In ia_ssa.py, import it too, and add | smme_spouse_is_sga_applicant(person, period) as the last term of spouse_income at :114-118.
Comment updates (text only):
- Replace the flag comment at
:47-53with:# 8-E p.12: "An ineligible spouse is a spouse who is not eligible for SSI or non-MAGI-related Medicaid, or State Supplementary Assistance." Those groups are for aged, blind or disabled people (8-F PDF pages 73-74), and a worker above the SGA level who keeps Medicaid is in the 1619(b) group, "considered to be an SSI recipient" (8-F PDF page 88). So a spouse SSI treats as aged, blind or disabled, or an SMME applicant working above the SGA level, is not an ineligible spouse: the couple's income is combined with no $497 test, as SSI and msp_countable_income combine an eligible couple's income. This test is broader than is_ssi_ineligible_spouse.In the NOTE at:54-57, add "and the SMME coverage input" after "disabled status". This also settles G68. - Add
"https://hhs.iowa.gov/media/4012/download?inline#page=88", # 8-F PDF page 88to the flag's tuple. - Add "or, for the aged, blind or disabled spouse of such an applicant, the couple's combined income" to the countable
documentationand to the comment atia_ssa.py:107-113, with the new case numbers.
In Case 98, change [2_186, 1_937.5, 0] to [2_186, 2_186, 0], and replace the comment's last four lines (from "person2's 1,937.50") with # person1 is not an ineligible spouse to person2 either (8-E p.12), so person2 gets the same combined 2,186 (Case 102). Append these after Case 101. Both fail at the head and pass with the fix:
- name: Case 102, an SMME applicant working above the SGA level is not an ineligible spouse, so the aged spouse's SMME income is combined with no child allocations.
period: 2026-04
absolute_error_margin: 0.01
input:
people:
person1:
age:
2026: 50
meets_ssi_disability_criteria:
2026: true
# Wages of $2,500 a month.
employment_income:
2026: 30_000
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
person2:
age:
2026: 70
# Social Security of $1,400 a month.
social_security_retirement:
2026: 16_800
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
person3:
age:
2026: 10
person4:
age:
2026: 10
marital_units:
couple:
members: [person1, person2]
child1:
members: [person3]
child2:
members: [person4]
tax_units:
tax_unit:
members: [person1, person2, person3, person4]
spm_units:
spm_unit:
members: [person1, person2, person3, person4]
households:
household:
members: [person1, person2, person3, person4]
state_code:
2026: IA
output:
# 8-E p.12: an ineligible spouse is "not eligible for SSI or
# non-MAGI-related Medicaid, or State Supplementary Assistance". Each
# spouse is an SMME applicant with full non-MAGI-related Medicaid, so
# each is budgeted as an eligible couple, with no child allocations:
# (1,400 - 20) + (2,500 - 65) / 2 = 2,597.50, at least the two-person
# 2,164. SSI's own deeming from person1 to person2, after two 497
# allocations, gives (1,400 - 20) + (2,500 - 994 - 65) / 2 = 2,100.50.
ssi_ineligible_child_allocation: [0, 0, 497, 497]
ia_ssa_smme_spousal_deeming_applies: [true, false, false, false]
ia_ssa_smme_countable_income: [2_597.5, 2_597.5, 0, 0]
ia_ssa: [1, 1, 0, 0]
- name: Case 103, two SMME applicants working above the SGA level are budgeted as an eligible couple with no child allocations.
period: 2026-04
absolute_error_margin: 0.01
input:
people:
person1:
age:
2026: 50
meets_ssi_disability_criteria:
2026: true
# Wages of $2,500 a month.
employment_income:
2026: 30_000
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
person2:
age:
2026: 45
meets_ssi_disability_criteria:
2026: true
# Wages of $2,000 a month.
employment_income:
2026: 24_000
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
person3:
age:
2026: 10
person4:
age:
2026: 10
marital_units:
couple:
members: [person1, person2]
child1:
members: [person3]
child2:
members: [person4]
tax_units:
tax_unit:
members: [person1, person2, person3, person4]
spm_units:
spm_unit:
members: [person1, person2, person3, person4]
households:
household:
members: [person1, person2, person3, person4]
state_code:
2026: IA
output:
# 8-E p.12: neither spouse is an ineligible spouse, because each has
# full non-MAGI-related Medicaid as an SMME applicant. The couple's
# income is combined with no child allocations:
# (2,500 + 2,000 - 20 - 65) / 2 = 2,207.50, at least the two-person
# 2,164. With 994 of allocations taken from the other spouse's wages,
# it would be (2,500 + 1,006 - 85) / 2 = 1,710.50.
ia_ssa_smme_spousal_deeming_applies: [true, true, false, false]
ia_ssa_smme_countable_income: [2_207.5, 2_207.5, 0, 0]
ia_ssa: [1, 1, 0, 0]Optional size-trap case: wages 1,700; spouse aged 70 with SS 12,000 a year; three children; both SMME. Expect SMME income [1,797.5, 1,797.5] and ia_ssa [0, 0].
Case numbers assume that Cases 98-104 are all appended in order. If you skip an optional case (100, 101 or 104), renumber the later ones.
Suggestions
New:
- G66. The flag's comments, label and documentation still describe only the $497 test (merges G59's first bullet).
- Replace
ia_ssa_smme_spousal_deeming_applies.py:24-32with:6-B Income (SMME) p.77 determines income "according to SSI income criteria", and 8-E p.11 determines deemed income "for non-MAGI-related Medicaid and State Supplementary Assistance coverage groups according to SSI policies", except the Medically Needy, in-home health-related care, dependent person and MEPD groups. SSI's deeming variables apply only to people SSI treats as aged, blind or disabled, so this test covers a disabled applicant working above the SGA level (Iowa Code 249.3(4)(a)(2), (c)): it is true when the spouse is aged, blind or disabled (income combined) or the spouse's income after child allocations is more than the couple rate less the individual rate (income deemed), unless either spouse is in a medical facility. - Label (
:11): "Iowa SMME counts a spouse's income for an applicant working above the SGA level" (this also settles G61's label point). Countabledocumentation(:17): "...any spouse income deemed, or combined for an aged, blind or disabled spouse, under SSI's rules...". - The case lists at
ia_ssa.py:112-113and countable:49include Cases 92 and 96, where the one-person guideline applies. Optional: "Cases 82, 90, 91, 94, 95 and 97; Cases 92 and 96 use the one-person guideline". - Case 96 (
ia_ssa.yaml:2908-2912): the spouse is aged, so at home the income would be combined, not deemed. Use "the spouse's 520 pension is neither combined nor deemed (the spouse is aged, so at home the couple's income would be combined: 2,106, below the two-person 2,164)". - Optional NOTE after
:43: "The facility input is read as residence for the whole month (20 CFR 416.414(a)(1)); 8-E p.11 deems for a month in which the applicant lived 'for any part of a month in the same household' with the spouse."
- Replace
- G67. Say why the ABD spouse's SSI payment is not added (NOTE only). The joint path adds each spouse's
ssi(countable:37); the SA32 path does not. The head is right; do not addssi. SA32 budgets an eligible couple, which gets no SSI here. The spouse's SSI exists only because SSA treats the worker as an ineligible spouse and takes child allocations, and even then 416.1161(a)(2) and 416.1142(a)(2) exclude SSI. Probe: wages 4,000, spouse aged 70 with no income, three children aged 10 gives 1,957.50 and [0], as on the aged path; adding the spouse's SSI of 279 would give 2,236.50 and [1]. In a 120-household grid, adding SSI flips 18 households, all with three children, because the sum is 1,491 plus 248.50 per child. The joint path's+ ssiis harmless (countable plus SSI is at most 1,491, below 1,596). Add after countable:62:# NOTE: The aged, blind or disabled spouse's SSI payment is not added. SSI does not count its own payment as income, and that payment exists only because SSI treats the applicant as an ineligible spouse and takes child allocations (20 CFR 416.1160(d), 416.1163(b)); the eligible-couple budget (8-E p.12) gives no such payment.Optional Case 104 (the probe household; passes at the head and with SA36): expectssi[0, 279, 0, 0, 0], flag [true, false, false, false, false] andia_ssaall 0. A mutant that adds SSI fails it. - G68. The SA32 comment ties Iowa's test to a federal variable that an open issue may change.
ia_ssa_smme_spousal_deeming_applies.py:50-51says "as is_ssi_ineligible_spouse does". #10243 item 2 asks thatssi_claim_is_joint,is_ssi_eligible_spouseandis_ssi_ineligible_spousetest SSI eligibility, not ABD status; PR #10141 keeps the ABD test. If #10243 lands, the comment is stale, and the helper (which readsis_ssi_aged_blind_disabled) will not follow, which is right because 8-E p.12 is broader. SA36's comment settles this. Without SA36, add to the NOTE at:54-57: "Iowa's test is broader than SSI eligibility, so it does not follow a change to is_ssi_ineligible_spouse (#10243)." - G69. The source lists do not name the new sources (PR body and issue only). Add "8-F; 20 CFR 416.1163, 416.1167" to the
axiom:line. The corpus list in rulespec-us#1837 names only 6-B, while rows BF-BI cite 8-E, 8-F, 416.1163 and 416.1167; add those four.
Still open from earlier rounds (as written in rounds 4-6, with the updates noted):
- G36 Four removable branches. G37 Add the "At the discretion of the department" reading to the candidate and the NOTE at
ia_ssa.py:130-137. G38 DP couple level for a spouse in residential care: NOTE or "Not modeled" line. G39 State the 249.3(4)(g) upper bound and the 6-B p.77 premium exclusion in the coverage input. G40 Align or splitia_ssa_care_initial_partial_month. G41 Integration Case 12. G42 IHHRC allowance over the tax unit. - G44 Link GL 6-B-47 (https://hhs.iowa.gov/media/18744/download?inline). G45 Relabel countable
:19as 249.3(4)(a)(2); label:23. G46add()at countable:37,:56-58andia_ssa_federal.py:37-39; re-wrapia_ssa_rcf_couple_budget.py:32. G47 RCF dividends case (care income 1,100, pays 222.57). - G48 (PARTIAL) Add the couple at 2,164 through the formula and the SGA switch (wages 20,280 against 20,280.12, SSDI 10,800).
- G49
ia_ssa_has_spouse: [true, true]in Case 83. G50 IHHRC couple sum, day count, truncation, earnings after entry, later-entering spouse. G51from: 2023atcandidates.yaml:1988-1990. G52 8-E#page=12inia_ssa.py:10-19and countable:18-24. G53 (a)-(d) as in round 6. - G54 (a) Document the cap averaging. (b) The round-6 NOTE at countable
:50(current 416.1112(c)(3) has no marital test; 8-E p.19 says "Not married"); with SA36, say that both spouses' exclusions follow current law. - G55 FPG reform timing (
ia_ssa.py:125). G56 2025 tests (March 1 and April 0 with SS 18,720; DP 503). G59 (PARTIAL) Optional249.pdf#page=2in the flag tuple. G60 Title the 2023 sheetIowa HHS State Supplementary Assistance Standards (effective January 1, 2023). - G61 Rename the module to
_ia_ssa_smme_spouse_income.pyand prefix both functions; say in the docstrings that callers gate onia_ssa_has_spouse. With SA36, considersmme_spouse_is_not_ineligible. - G62 (corrected wording) Round 6 said that
~is_ssi_aged_blind_disabled"is the guarantee against double counting". That was wrong. The guard limits the flag to applicants whom SSI does not count. It cannot prevent double counting, because countable:69-70already uses SSI's income for anyone SSI counts; without it, the flag only repeats SSI's own switch to the two-person guideline. A mutant without it changes only the flag in Case 51, in Case 100 and in a 7,776-row household grid. A mutant withoutia_ssa_has_spouse(:63) can flipia_ssa, but only for a household entered with no marital units, which is an input shape, not a family situation. So G62 stays a suggestion. Cases 100 and 101 pin the two operands and pass at the head (a one-line alternative to Case 100: addia_ssa_smme_spousal_deeming_applies: [false, false, false, false]to Case 51):
- name: Case 100, the SGA-path deeming flag stays false for an SMME applicant whom SSI counts as disabled.
period: 2026-04
absolute_error_margin: 0.01
input:
people:
person1:
age:
2026: 50
meets_ssi_disability_criteria:
2026: true
# SSDI of $1,800 a month and no wages, so SSI counts the person as
# disabled.
social_security_disability:
2026: 21_600
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
person2:
age:
2026: 45
# Wages of $1,000 a month.
employment_income:
2026: 12_000
marital_units:
couple:
members: [person1, person2]
tax_units:
tax_unit:
members: [person1, person2]
spm_units:
spm_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code:
2026: IA
output:
# SSI deems the spouse's 1,000 > 497 (20 CFR 416.1163), so SSI's own
# deeming sets the two-person guideline and the SGA-path flag stays false:
# (1,800 - 20) + (1,000 - 65) / 2 = 2,247.50 > 1,491, so SSI is 0, and
# 2,247.50 is at least the two-person 2,164. person2's own income is
# (1,000 - 20 - 65) / 2 = 457.50.
ia_ssa_smme_spousal_deeming_applies: [false, false]
ia_ssa_smme_countable_income: [2_247.5, 457.5]
ia_ssa: [1, 0]
- name: Case 101, without marital units an SMME applicant working above the SGA level in a household of three adults is budgeted alone.
period: 2026-04
absolute_error_margin: 0.01
input:
people:
person1:
age:
2026: 50
meets_ssi_disability_criteria:
2026: true
# Wages of $3,277 a month, above the $1,690 SGA level.
employment_income:
2026: 39_324
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
person2:
age:
2026: 45
# A pension of $520 a month.
pension_income:
2026: 6_240
person3:
age:
2026: 30
tax_units:
tax_unit:
members: [person1, person2, person3]
spm_units:
spm_unit:
members: [person1, person2, person3]
households:
household:
members: [person1, person2, person3]
state_code:
2026: IA
output:
# With no marital units, the default unit holds all three people, so
# ia_ssa_has_spouse is false and each member is budgeted alone:
# (3,277 - 20 - 65) / 2 = 1,596, at least the one-person 1,596. If
# person2's 520 pension were deemed it would be 2,106, below the two-person
# 2,164. person2's own income is 520 - 20 = 500.
ia_ssa_has_spouse: [false, false, false]
ia_ssa_smme_spousal_deeming_applies: [false, false, false]
ia_ssa_smme_countable_income: [1_596, 500, 0]
ia_ssa: [1, 0, 0]- G63 2023 and 2024 cases:
2023-01RCF, SSI only, 318.59;2024-01DP, dependent income 100, 490;2023-01DP, 474.
Out of scope / follow-up (federal code on main; record only, not blockers)
- G57: no open issue covers 416.1161(a)(10). File the round-6 issue (deduct
child_support_expenseandalimony_expenseinssi_{earned,unearned}_income_deemed_from_ineligible_spouse). Since SA32, (b) and (c) matter only for a spouse who is not ABD. - G58 (SSI deeming and a medical-facility stay; the federal files are the same on
main):- (a) An applicant at the $30 facility rate still gets deemed income (416.1163(f)(5)). #10138 names this only in its "Related" line, and PR #10141 lists it as a follow-up. When it is fixed, Case 96's person2 value changes from 2,106 to 500.
- (b) A spouse who is not ABD and is in a facility is still deemed on the SSI path. No issue covers it.
- (c) New:
ssi_couple_computation_applieskeeps the couple computation, and SSI keeps deeming, when an ABD spouse is in a privately paid facility. Applicant aged 70 with wages 3,277, spouse aged 70 with a 520 pension: the model gives 2,106 and [0, 0]; the rule gives 1,596 and [1, 0]. 416.1801(c) ("Eligible spouse", (3)(iii)) needs the same household except during a 416.1149 temporary absence. A private-pay stay is temporary only under 416.1149(a)(2) (return in the same or next month), because the "regardless of length" rule in (c)(1)(i) is for Medicaid-paid stays. POMS SI 00835.040 C.1.b, SI 00501.154 B, SI 02005.050 D.2 and SI 01310.165 A.1 agree. Cash effect: the facility spouse's SSI is 0 in the model and 494 a month under the rule. #10193 lists separation as out of scope. - The two Iowa paths now disagree for a private-pay stay: the SGA path separates (Case 99), and the aged path inherits the Medicaid-only federal test.
- Proposed issue for (b) and (c): "SSI deeming and the couple computation ignore a spouse who has left the household for a medical facility (20 CFR 416.1167, 416.1149, 416.1801(c))". Include the probe rows, the 494 effect and Iowa Cases 96 and 99. Also consider POMS SI 02005.050 B.3: for a spouse temporarily absent in a Title XIX facility, eligibility uses the couple's combined income and each person's own income only for the payment; the federal variable drops the couple computation for both. This was not assessed for Iowa.
- In this PR, a NOTE beside
ia_ssa.py:114-118naming (a)-(c) stays optional.
- #10243 item 2 (eligibility-based couple and ineligible-spouse tests): record only; it is the premise of G68.
- Federal couple student exclusion:
ssi_countable_incometakes off only half of a student spouse's exclusion in a couple computation (1,993.29 against 1,790.58 in SA36's student example). The SMME joint path inherits it. A candidate for a federal issue.
Investigated and cleared
apartscope: either spouse and any payer is right under 416.1167(a)(1). It correctly overrideseligible_spouse: a Medicaid-paid stay gives 416.414(b)(3)'s separate computation, and a long private-pay stay ends couple status.- Both spouses in a facility: 416.414(b)(2) applies only by analogy (the applicant has no SSI), and the household is improbable.
sum - own: every call site is gated byia_ssa_has_spouse, directly or through the flag.- Periods and entities: YEAR
is_ssi_aged_blind_disabledwiththis_year; MONTH facility input withperiod;marital_unit.anyin a Person formula is the house pattern. - The merge: no Iowa supplement, SSI, MSP or FPG file changed, and the Iowa outputs are unchanged.
PDF Audit Summary
| Category | Count |
|---|---|
| Documents | 8-E, 8-F, 6-B (re-downloaded); eCFR 416.212, 416.414, 416.1112, 416.1142, 416.1149, 416.1160, 416.1161, 416.1163, 416.1167, 416.1801, 416.1802; four POMS sections; 42 U.S.C. 1382a |
| New or changed cites | 12 checked, 12 correct, 0 wrong (a second read checked 10 of them) |
| New hrefs | 2 of 2 corroborate (eCFR 416.1167; 8-F p.73) |
| Value mismatches | 0 |
| Rule mismatches (code run, pages re-read, confirmed) | 1: SA36 |
Rule branches with no test (mutation-proven, flip ia_ssa) |
3: SA35 |
| Inherited federal gaps | G57; G58 (a)-(c); couple student exclusion |
| Rejected | Adding the spouse's SSI payment (G67); round 6's optional-case spouse value of 1,491 |
Validation Summary
| Check | Result |
|---|---|
| Regulatory | SA31-SA34 resolved and correct; SA36; G58(c); G66, G68 |
| References and pages | 12/12 correct; no printed page number; G52, G59 partial; G69 |
| Code patterns | ruff clean; periods, entities, vectorization correct; no hard-coded value; G61 wider |
| Tests | Cases 94-97 recompute; 6 of 8 targeted mutants killed; all 5 survivors closed by Cases 98-101; SA35; G48 partial; G62 corrected |
| Verification | SA35's three gaps CONFIRMED (survive 126/126, flip ia_ssa); G48 PARTIAL CONFIRMED; G62 guard cannot double count (7,776-row grid); spouse SSI payment: head correct; SA36 CONFIRMED with four flip shapes, fix tested; G58(c) CONFIRMED (federal); #10138 and #10243 content CONFIRMED |
| Local runs | 126/126 Iowa; 452 code-health (1 skipped); source conflicts 103; registry 767 (10 skipped, none Iowa) |
| Branch | 45 ahead, 34 behind; MERGEABLE; CI 27/0; staleness did not affect findings |
| Partner tests | None touched |
Review Severity: REQUEST_CHANGES
Two should-address items are open (SA35, SA36), both in the round-7 code. No critical item is open. SA31-SA34, G64 and G65 are resolved.
Next Steps
- SA35: append Cases 98 and 99. No code change is needed.
- SA36: apply the helper,
ia_ssa_smme_countable_income.pyandia_ssa.pychanges with the comment updates; change Case 98's person2 value to 2,186; append Cases 102 and 103. - Run the Iowa suite once with all changes, and update the PR body and rulespec-us#1837 for the new cases.
- Optional: G66-G69, the G62 pins (Cases 100 and 101), the rest of G48 and the carried suggestions.
- Outside this PR: file the federal issues for G57(a) and G58(b)-(c).
- To auto-fix issues: run the fix-pr workflow for this PR.
PR Review (round 7): Add Iowa state supplementation for 2026SummaryPR #8017 (author: hua7450). This round reviews head What the commit does. It applies Pavel's round-6 items SA31-SA34 as he proposed them:
What I found.
Prior findings
Pavel's round-6 items, applied as he proposed them and checked as new code:
New findingsCritical (must fix)None. Should address
Suggestions
VerifiedThe rule.
The code.
Edge cases I checked and am not raising.
Hand-checked expectations (all new). The 2026 figures are: SSI 994 / 1,491, SGA 1,690. 120% of the guideline is 1,596 / 2,164 from April (2026 guideline) and 1,565 / 2,115 before April (2025 guideline).
Other checks.
Axiom line assessmentThe line reads
CI status
Branch status
Verdict: REQUEST_CHANGES |
DTrim99
left a comment
There was a problem hiding this comment.
Round 7: Pavel's SA31-SA34 are applied correctly (no deeming when either spouse is in a facility, an ABD spouse combined, child-allocation order pinned), all 13 new expectations hand-check, and our round-6 suggestions are done. Two should-address items, both matching Pavel's newer SA35/SA36: (1) the SA32 rule runs one way only, so an ABD spouse is still deemed from the SGA applicant and one couple is budgeted two ways ([1, 0] where 8-E p.12 gives [1, 1]); (2) three new branches have no test, and each mutant passes all 126 cases while flipping ia_ssa (his Cases 98 and 99 hand-check). Full report in the comment above.
- SA36: apply 8-E p.12's ineligible-spouse rule from both sides. An SMME applicant working above the SGA level is not an ineligible spouse, so the aged, blind or disabled spouse gets the couple's combined income with the two-person guideline, and two such applicants are combined with no child allocations. The spouse's own student exclusion comes off before combining. - SA35: Cases 98 and 99; Cases 100-108 pin every new term (mutation-checked); Case 109 pins the residential care dividend exclusion. - Rename the helper module and functions with the ia_ssa prefix (G61), and update comments, labels, documentation and references (G44, G45, G49, G51, G52, G54, G59, G60, G66, G67). - NOTEs cite the new federal issues 10454, 10455 and 10456; register the married student exclusion as a source-conflict candidate. - Case 73 pins the deeming flag instead of the June SSI amount that PR 10141 changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, Pavel and David. SA35 and SA36 are applied as you wrote them in a330305, and Should address
Tests for the SA36 terms (mutation-checked). Removing each term below fails the listed case:
Cases 107 and 108 give the uncovered worker an undocumented status, so the expected value holds under any reading of MEPD. The NOTE says a disabled worker with another non-MAGI group but no SMME coverage input is deemed. Suggestions done
Federal issues (G57, G58 and the couple student exclusion)
Still deferred:
138 Iowa supplement cases pass locally (109 in |
PR Review (round 8): Add Iowa state supplementation for 2026SummaryPR #8017 (author: hua7450). This round reviews head What the commit does.
What I found.
Prior findings
Pavel's round-7 suggestions in this commit (checked, not ours):
New findingsCritical (must fix)None. Should address
Suggestions
VerifiedThe new rule matches the sources I re-read.
The code.
Mutation claims (traced by hand, not run).
Each of these contradicts the expected values. Hand-checked expectations (every new or changed one). The 2026 figures are: SSI 994 / 1,491, child allocation 1,491 − 994 = 497, SGA 1,690, student exclusion 2,410 a month / 9,730 a year. 120% of the guideline is 1,596 / 2,164 from April.
Other checks.
Axiom line assessmentThe line reads
CI status
Branch status
Verdict: REQUEST_CHANGES |
DTrim99
left a comment
There was a problem hiding this comment.
Requesting changes, round 8: 0 critical, 1 should. All round-7 items are fixed. The one open item comes from main: Iowa LIHEAP (#10292) merged after this push. Its income sources need ia_ssa, which this PR adds, plus one case. Full report in the comment above.
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Program Review (round 8): Add Iowa state supplementation for 2026
PR #8017 (hua7450). Round 8, incremental review of the changes since round 7.
IDs: C = critical, SA = should address, G = suggestion. Prior IDs keep their numbers. New findings start at SA37 and G70. There is no new critical item, so C8 is not used.
Paths: V/ = policyengine_us/variables/gov/states/ia/hhs/ssa/, T = policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml, L/ = policyengine_us/parameters/gov/states/ia/hhs/liheap/income/sources/ (on main), LT = policyengine_us/tests/policy/baseline/gov/states/ia/hhs/liheap/integration.yaml (on main). "Countable" = V/ia_ssa_smme_countable_income.py, "flag" = V/ia_ssa_smme_spousal_deeming_applies.py, "helper" = V/_ia_ssa_smme_spouse_income.py. Line numbers refer to the reviewed head. "p.NN" is the PDF FILE page (8-E FILE = printed + 5; 6-B and 8-F FILE = printed + 4).
Source Documents
- Reviewed head SHA: 4aae08a
- Mode: incremental from 0ad5fc5 (round 7, CHANGES_REQUESTED)
- Commits since round 7: a330305 "Address Pavel's and David's round-7 reviews of Iowa SSA" (11 files, +862 / -80); 4aae08a, a merge of
mainat dbfc017 that changes no Iowa supplement, SSI deeming, MSP or poverty-guideline file. - Scope: the new helper (replaces
_smme_spouse_income.py); the combined override in countable; the size term inV/ia_ssa.py; comments, NOTEs and hrefs in the flag, countable,V/ia_ssa.pyandV/ia_ssa_federal.py; three parameter titles and the GL 6-B-47 href; Cases 98-109 appended and Cases 73, 83 and 96 edited (138 Iowa cases, 109 inT);source_conflicts/candidates.yaml(from: 2023, newus-ia:smme-student-exclusion-married). - Iowa sources: 8-E (https://hhs.iowa.gov/media/4011/download?inline), 8-F (media/4012) and 6-B (media/3987), downloaded again with the same checksums as round 7; GL 6-B-47 (media/18744, p.1); GL 6-B-45 p.24; the 2023 standards sheet (media/9237); Iowa Code ch. 249 pp.2-3 (2023 and 2026); 441 IAC ch. 51 and 52; Iowa LIHEAP FY26 manual (media/17262, pp.81, 97, 103, 114, 116, 118) and the FFY2026 state plan, Section 1.9.
- Federal sources: eCFR 20 CFR 416.414, 416.1112, 416.1124, 416.1140, 416.1149, 416.1160, 416.1161, 416.1163, 416.1167, 416.1801; LII 42 U.S.C. 1382a with the 2004 amendment note.
- GitHub (read-only): #10138, #10243, #10454, #10455, #10456; PRs #10141, #10146, #10292; TheAxiomFoundation/rulespec-us#1837.
Branch Status
- 47 ahead and 32 behind
main(4c65c82, 2026-10-27 17:03 UTC). A trial merge is clean:programs.yamlandsource_conflicts/candidates.yamlchange on both sides and merge automatically. GitHub:MERGEABLE, review decisionCHANGES_REQUESTED. CI: 32 pass, 0 fail at 4aae08a. - What the newer
maincommits change:- #10292 adds Iowa LIHEAP, which does not count
ia_ssa(SA38). - #10283 removes
gov.ssa.ssi.amount.institutional. No Iowa file reads it. - #10453 moves poverty-guideline uprating to
gov.hhs.fpg_uprating. The 2026 values do not change. SMME reads the projected 2027 guideline only from April 2027, which no case reaches; from then the one-person threshold rises by about $6 a month. - The six newest commits change Illinois EITC, Minnesota AMT, Virginia TANF, Florida TCA and the version. None touches an Iowa supplement, SSI, SSA or LIHEAP file.
- #10292 adds Iowa LIHEAP, which does not count
- Local runs: at the head, Iowa SSA 138/138, code health 462 passed (1 skipped),
test_source_conflicts.py103, andruff format --checkandruff checkclean on the 24 Iowa variable files. On the head merged withmain(5d093eb): Iowa SSA 138/138 and Iowa LIHEAP 164/164; source-conflict and registry tests 888 passed (10 skipped) on the merge with c2785f6. - No partner test file is touched. The changelog fragment and the Iowa
programs.yamlentry (verified_years: "2026") are unchanged. - Process note (not counted): the
axiom:line is present and valid (rulespec-us#1837 is open and labelledpe-parity).
What round 8 fixed
- SA36, as proposed. The helper bodies, the three-line override (countable
:91-98), the size term (V/ia_ssa.py:133) and the comment text are the round-7 text. Your two departures are defensible: the program prefix is G61, and folding 8-F p.88 into one 8-F entry follows the one-href-per-source rule. The rule check holds for every shape tested, including a working SMME spouse whose wages are below the SGA level (2,307.50 for each spouse, [1, 1], the same as on the aged path). - SA35. Cases 98 and 99 are the proposed text, with Case 98's person2 value at 2,186 for SA36.
- Cases 100-109 pin every new term. Your mutation table reproduces exactly: each term fails the cases that you name. Of 31 one-site mutants of the new code, 24 are killed, 4 are equivalent and 3 survive (see G71 and "Investigated and cleared"). The five round-7 survivors that had a proposed case are now killed.
- Hand values. Every expected value in Cases 98-109 recomputes by hand, and DTrim99 checked them by hand too. Case 106's comment gives 1,790.585 against 1,790.583 in code, inside the 0.01 margin.
- Case 73. The old June pin (SSI 843.50) protected no Iowa output: June
ia_ssais 615.52 for any June SSI from 0 to 1,421. Case 59 pins the entry-month rule. The new flag pin also holds under PR #10141. - Federal issues. #10454, #10455 and #10456 exist, are open and match their NOTEs. The
ia_ssa_federal.pymove from #10138 to #10243 is right, because PR #10141 keeps the ABD test inssi_claim_is_joint. - References. 35 of 35 new or changed hrefs, titles and cites are correct. No href uses a printed page number.
- Candidates. G51's
from: 2023is correct. The married-student candidate is a real conflict, follows the statute and cites correctly. - No regression. The test diff removes only Case 73's June pin and two comments. No prior expected value changed.
Both new should-address items concern State Supplementary Assistance paid alongside SSI. SA37 comes from the round-7 SA36 patch, which this review proposed: an aged spouse whom SSI pays can now also get the $1 SMME. SA38 comes from main: Iowa LIHEAP does not count ia_ssa.
Round-7 status
| ID | Status | Evidence at 4aae08a; is the deferral defensible? |
|---|---|---|
| SA35 | RESOLVED | Cases 98 and 99. The three round-7 mutants fail them, and each flips ia_ssa |
| SA36 | RESOLVED | As proposed, with G61 names. Cases 102-108 pin every term. New edge from the override: SA37 |
| G25 | PARTIAL (accepted part stands) | New cases use 2026-04 and 2026-01; both fit |
| G36 | DECLINED for now | Branches unchanged; three of the four still survive the suite. The reason ("no published example") is weak, because Cases 94-109 are also derived by hand. A deferral of a test suggestion in untouched code is defensible |
| G37 | STILL OPEN (deferred) | NOTE V/ia_ssa.py:146-153 and the candidate still omit "At the discretion of the department". Defensible |
| G38 | STILL OPEN (deferred) | V/ia_ssa_federal.py changed only in the NOTE cite. Defensible |
| G39 | STILL OPEN (deferred) | Coverage input documentation unchanged; the 249.3(4)(g) upper bound is still unstated. Defensible |
| G40 | STILL OPEN (deferred) | Files unchanged. Defensible |
| G41 | STILL OPEN (deferred) | integration.yaml unchanged. Defensible |
| G42 | STILL OPEN (deferred) | V/ia_ssa_ihhrc_participation.py unchanged. Defensible |
| G44 | RESOLVED | GL 6-B-47 linked (rcf_personal_needs.yaml:34-35); p.1 states $130, effective January 1, 2026 |
| G45 | RESOLVED | Countable labels :20, :22, :24. The round-4 remainder (other page lists; unlabeled hrefs at V/ia_ssa_has_spouse.py:14-15) stays optional |
| G46 | STILL OPEN (deferred) | Manual sums unchanged; ia_ssa_rcf_couple_budget.py:32 not re-wrapped; no new instance. Defensible (style) |
| G47 | RESOLVED | Case 109 (222.57). Removing dividends from excluded_unearned_sources fails only Case 109 |
| G48 | PARTIAL | No case reaches 2,164 or the SGA switch through the formula. SA37's rewrites of Cases 44, 78 and 89 close the one-person part |
| G49 | RESOLVED | Case 83 asserts ia_ssa_has_spouse: [true, true] (T:2461) |
| G50 | STILL OPEN (deferred) | Unchanged. Defensible |
| G51 | RESOLVED | candidates.yaml:2081. The 2023 sheet lists the $17.86 flat and $35.89 maximum rates; GL 6-B-45 p.24 has both for 2024 |
| G52 | RESOLVED | 8-E #page=12 at V/ia_ssa.py:22-23 and countable :26-27 |
| G53 | STILL OPEN (deferred) | fpg_year_start_month.yaml unchanged; RC-0130 still unlinked (T:2264). Defensible |
| G54 | PARTIAL | (b) RESOLVED: the NOTE at countable :56-61 covers both spouses, and the candidate is correct. (a) not answered: the cap averaging is undocumented and now also applies to the spouse's exclusion (helper :50). Defensible |
| G55 | STILL OPEN (deferred) | V/ia_ssa.py:141 still reads f"{year}-01-01"; gov/hhs/fpg.yaml still exists after #10453. Defensible |
| G56 | STILL OPEN (deferred) | Only Case 86 (RCF) is in 2025. Defensible |
| G57 | RESOLVED | Helper docstring :43-47 names (a)-(c); #10454 covers (a); open PR #10146 covers (b)-(c) |
| G58 | RESOLVED | #10455 covers (a)-(c); NOTE V/ia_ssa.py:121-128; Case 96 cites it |
| G59 | RESOLVED | 8-E p.11 scope sentence (flag :26-31); 249.pdf#page=2 in the flag tuple |
| G60 | RESOLVED | The three titles match the sheet's heading |
| G61 | RESOLVED | Prefixed module and functions; gate sentence in all three docstrings; label |
| G62 | RESOLVED | Cases 100 and 101. Dropping the ABD guard fails Cases 100 and 106; dropping ia_ssa_has_spouse fails Case 101 |
| G63 | STILL OPEN (deferred) | No 2023 case; no 2024 DP case. Defensible |
| G66 | RESOLVED | Flag comment :26-37, label :11, countable documentation :18, case lists, Case 96 comment, whole-month NOTE :47-53 |
| G67 | RESOLVED | NOTE countable :78-82 and Case 104. Adding the spouse's SSI fails Cases 104 and 105 |
| G68 | RESOLVED | "This test is broader than is_ssi_ineligible_spouse" (flag :66-67) |
| G69 | RESOLVED | The axiom: line names 8-F, 416.1163 and 416.1167; the #1837 corpus table lists 8-E, 8-F, 416.1112(c)(3), 416.1163 and 416.1167 |
Tally: 34 IDs were open after round 7. Now 18 are resolved, 3 are partial (G25, G48, G54), 12 are still open as deferred suggestions and 1 is declined for now (G36). Every open one is a suggestion, and each deferral is defensible.
Critical (Must Fix)
None.
Should Address
SA37. The SA36 override lets an aged spouse whom SSI pays also get the $1 SMME
- What is wrong: The override gives the ABD spouse of an applicant working above the SGA level the couple's combined income. SSA still treats that applicant as an ineligible spouse, deems after child allocations and can pay the ABD spouse SSI. So that spouse can get both SSI and the $1 SMME. Before SA36 this could not happen: countable income plus SSI is at most 1,491, below 1,596 for one person and 2,164 for two. The round-7 SA36 proposal missed this; the cause is that patch, not your changes to it.
- Where: countable
:94-98(override) andV/ia_ssa.py:154-161(thesmmeterm). - Source: Iowa Code 249.3(4) requires "all of the following paragraphs", including "c. Would be eligible for supplemental security income benefits but for having excess income or but for being engaged in substantial gainful activity and having excess income" (p.2). A person whom SSA pays is eligible for SSI, so (c) fails. 6-B p.74 states the purpose: "to provide a cash benefit to certain Medicaid recipients who do not qualify for other cash assistance benefits" (6-B p.74). Iowa's eligible-couple budget (8-E p.12) cannot remove an SSI payment that SSA computes under 416.1160 and 416.1163.
- Evidence (April 2026; person1 aged 50, disabled, SMME with coverage; person2 aged 70, no income, SMME with coverage; children aged 10):
| Household | person2 ssi |
Head: SMME [p1, p2]; ia_ssa |
Rule | Round 7 head |
|---|---|---|---|---|
| Wages 4,500; three children | 29 | 2,207.50 each; [1, 1] | [1, 0] | [1, 0] |
| Wages 4,450 / 4,550; three children | 54 / 4 | [1, 1] | [1, 0] | [1, 0] |
| Wages 4,800; four children | 127.50 | [1, 1] | [1, 0] | [1, 0] |
| Wages 4,600; three children (control) | 0 | [1, 1] | [1, 1] | [1, 0] (the SA36 gap) |
| Same as row 1, person1 aged 70 (SSI path) | 0 | [1, 1] | [1, 1] | [1, 1] |
In row 1, SSA deems 4,500 − 3 × 497 = 3,009, so (3,009 − 85) / 2 = 1,462 and SSI is 1,491 − 1,462 = 29. The override gives (4,500 − 85) / 2 = 2,207.50, at least the two-person 2,164.
- Reach: three or more ineligible children and a narrow wage band (about 4,413-4,558 a month with three children; 4,413-5,055 with four), plus the SMME inputs on an SSI recipient. $1 a month. Zero in microsimulation:
ia_ssa_categorydefaults to REGULAR and the coverage input to false. - Why should address: the SA36 class (a clear rule, a $1 flip, input-gated), and a regression in this round's code. Not critical: the structure is right, and one term closes it. Not a suggestion: 249.3(4)(c) leaves nothing open, and nothing documents the choice.
- Fix (tested on a copy of the branch). In
V/ia_ssa.py, after the NOTE that ends at:153, and in thesmmeterm:
# Iowa Code 249.3(4)(c) limits SMME to a person who "Would be eligible
# for supplemental security income benefits but for having excess
# income or but for being engaged in substantial gainful activity and
# having excess income", and 6-B p.74 pays it to "certain Medicaid
# recipients who do not qualify for other cash assistance benefits".
# So a person SSI pays gets no SMME, including the aged, blind or
# disabled spouse of an applicant working above the SGA level, whom
# SSI still pays after deeming from that applicant (Case 110).
smme = (
person("ia_ssa_smme_coverage_eligible", period)
& (
person("ia_ssa_smme_countable_income", period)
>= p.smme_minimum_fpg_rate * poverty
)
& (federally_paid == 0)
& (person("ssi_if_takes_up", period) == 0)
)In countable, add after the G67 NOTE (:82):
# A spouse whom SSI pays gets no SMME (Iowa Code 249.3(4)(c); ia_ssa,
# Case 110).ssi_if_takes_up tests eligibility, not take-up; a person eligible for SSI who does not take it up already fails ia_ssa_nonfinancial_eligible. There is no new cycle, because ia_ssa already reads ssi. Do not gate the override instead: that changes no ia_ssa value in the suite, but Cases 104 and 105 would show SSI's figure for person2, so the couple would be budgeted two ways again.
The gate also blocks six cases that set SMME income on a person with no income (SSI 994). Cases 44, 78 and 89 then fail. Cases 24, 45 and 79 still pass, but only through the new gate: dropping federally_paid == 0 (killed today by Case 24) and loosening the guideline test by one cent (killed today by Cases 45 and 79) would both survive. Give each case Social Security income so that SSI is 0. Replace these six cases with:
- name: Case 24, SMME cannot stack with blind payment.
period: 2026-01
absolute_error_margin: 0.01
input:
state_code:
2026: IA
age:
2026: 65
# Social Security of $1,025 a month.
social_security_retirement:
2026: 12_300
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
ia_ssa_smme_countable_income: 2_000
is_blind: true
output:
# 1,025 - 20 = 1,005 is above 994, so SSI is 0, and SSA pays the blind
# supplement of 994 + 22 - 1,005 = 11. A federally paid supplement
# excludes SMME even with SMME income set above the guideline.
ssi: 0
ia_ssa_federal: 11
ia_ssa: 11
- name: Case 44, SMME income at exactly 120 percent of poverty qualifies under Iowa Code 249.3(4)(g).
period: 2026-04
absolute_error_margin: 0.01
input:
state_code:
2026: IA
age:
2026: 65
# Social Security of $1,616 a month.
social_security_retirement:
2026: 19_392
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
output:
# 1,616 - 20 = 1,596 is above 994, so SSI is 0. From April, Iowa uses the
# 2026 guideline (441 IAC 75.1): 1.2 * 15,960 / 12 = 1,596; the statute
# requires income "of at least" 120 percent, so 1,596 qualifies.
ssi: 0
ia_ssa_smme_countable_income: 1_596
ia_ssa: 1
- name: Case 45, SMME income one cent below 120 percent of poverty.
period: 2026-04
absolute_error_margin: 0.01
input:
state_code:
2026: IA
age:
2026: 65
# Social Security of $1,615.99 a month.
social_security_retirement:
2026: 19_391.88
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
output:
# 1,615.99 - 20 = 1,595.99 is above 994, so SSI is 0, but below April's
# 1.2 * 15,960 / 12 = 1,596, so no SMME.
ssi: 0
ia_ssa_smme_countable_income: 1_595.99
ia_ssa: 0
- name: Case 78, in January SMME income at the prior year's 120 percent qualifies.
period: 2026-01
absolute_error_margin: 0.01
input:
state_code:
2026: IA
age:
2026: 65
# Social Security of $1,585 a month.
social_security_retirement:
2026: 19_020
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
output:
# 1,585 - 20 = 1,565 is above 994, so SSI is 0, and equals January's
# 1.2 * 15,650 / 12 = 1,565.
ssi: 0
ia_ssa_smme_countable_income: 1_565
ia_ssa: 1
- name: Case 79, in January SMME income one cent below the prior year's 120 percent.
period: 2026-01
absolute_error_margin: 0.01
input:
state_code:
2026: IA
age:
2026: 65
# Social Security of $1,584.99 a month.
social_security_retirement:
2026: 19_019.88
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
output:
# 1,584.99 - 20 = 1,564.99 is above 994, so SSI is 0, but below 1,565.
ssi: 0
ia_ssa_smme_countable_income: 1_564.99
ia_ssa: 0
- name: Case 89, in March SMME income at the prior year's 120 percent still qualifies.
period: 2026-03
absolute_error_margin: 0.01
input:
state_code:
2026: IA
age:
2026: 65
# Social Security of $1,585 a month.
social_security_retirement:
2026: 19_020
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
output:
# 1,585 - 20 = 1,565 is above 994, so SSI is 0.
# 1.2 * 15,650 / 12 = 1,565 until April (441 IAC 75.1; RC-0130 Rev. 04/25).
ssi: 0
ia_ssa_smme_countable_income: 1_565
ia_ssa: 1Optional, for clarity only (Cases 48 and 49 also pin these terms): Case 22 with social_security_retirement: 24_240 (countable 2,000) and Case 23 with 12_240 (countable 1,000), each with ssi: 0. Append after Case 109:
- name: Case 110, an aged spouse whom SSI pays gets no SMME although the couple's combined income reaches the two-person guideline.
period: 2026-04
absolute_error_margin: 0.01
input:
people:
person1:
age:
2026: 50
meets_ssi_disability_criteria:
2026: true
# Wages of $4,500 a month, above the $1,690 SGA level.
employment_income:
2026: 54_000
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
person2:
age:
2026: 70
ia_ssa_category: SMME
ia_ssa_smme_coverage_eligible: true
person3:
age:
2026: 10
person4:
age:
2026: 10
person5:
age:
2026: 10
marital_units:
couple:
members: [person1, person2]
child1:
members: [person3]
child2:
members: [person4]
child3:
members: [person5]
tax_units:
tax_unit:
members: [person1, person2, person3, person4, person5]
spm_units:
spm_unit:
members: [person1, person2, person3, person4, person5]
households:
household:
members: [person1, person2, person3, person4, person5]
state_code:
2026: IA
output:
# SSI treats person1 as an ineligible spouse: 4,500 - 3 * 497 = 3,009 is
# deemed, (3,009 - 20 - 65) / 2 = 1,462, so person2's SSI is
# 1,491 - 1,462 = 29. Iowa Code 249.3(4)(c) limits SMME to a person who
# "Would be eligible for supplemental security income benefits but for
# having excess income", so person2 gets no SMME although the combined
# (4,500 - 20 - 65) / 2 = 2,207.50 is at least the two-person 2,164.
ssi: [0, 29, 0, 0, 0]
ia_ssa_smme_countable_income: [2_207.5, 2_207.5, 0, 0, 0]
ia_ssa: [1, 0, 0, 0, 0]Results: the rewritten cases pass at the head, so they can land first. With the code change, the rewrites and Case 110, the Iowa SSA folder passes 139/139; at the head, Case 110 fails ([1, 1, 0, 0, 0]). The two mutants above are killed again. In the PR body SMME bullet, add "and SSI pays nothing (Iowa Code 249.3(4)(c))" after "no SSA-paid supplement is paid".
SA38. After a merge of main, Iowa LIHEAP does not count ia_ssa
- What is wrong: #10292 put Iowa LIHEAP on
mainat 2026-10-26 19:49 UTC, 42 minutes after your push.L/unearned.yaml:21andL/fixed.yaml:12listssibut notia_ssa, which does not exist onmain. After this PR merges, LIHEAP leaves out every Iowa supplement. This is a merge-time item, not an author error. DTrim99 raised the same item in round 8 (Should 1); this review confirms it and adds the variable choice and a case that pins it. No issue or PR tracks it. - Source: LIHEAP FY26 manual, Appendix C, row "Social Security Benefits (SSA, SSI, SSDI)" (p.114): counted as income (code C); the definition column reads "SSA (State Supplementary Assistance) - Fully state-funded". The Definitions (p.81) name SSA benefits, SSI and SSDI as fixed income. The p.114 row groups State Supplementary Assistance with SSI and records a payment "to capture source of income for AE fixed income criteria", so both lists need it.
- Which variable: plain
ia_ssa, notia_ssa_countable_for_snap. The p.114 row makes no exception. The in-home health-related care payment "is made to the adult recipient" (6-B p.50). Appendix C excludes only narrow reimbursements: executor fees (p.97), job costs (p.103), TAA (p.116) and VA mileage (p.118). The state plan's unchecked "Reimbursements" are "for mileage, gas, lodging, meals, etc." The SNAP and HUD exclusions rest on 7 CFR 273.9(c)(5) and 24 CFR 5.609(b), which do not govern LIHEAP. - Evidence (the head merged with
main; the proposed case below):
| Lists contain | Proposed case | ia_liheap |
|---|---|---|
| Nothing (as merged) | Fails: countable 11,928 vs 16,992 | 520 |
ia_ssa in both |
Passes | 480 |
ia_ssa in unearned.yaml only |
Fails: fixed-income-only is false | 440 |
ia_ssa_countable_for_snap in both |
Fails: 12,192 vs 16,992 | 520 |
With the fix, the Iowa LIHEAP folder passes 164/164 (165/165 with the case), Iowa SSA stays 138/138, the parameter and reference code-health tests pass, and there is no dependency cycle. A blind-only case (DTrim99's household, 12,192) passes with either variable, so it does not pin the choice.
- Why should address: missing aggregate wiring on the merged tree, as DTrim99 rated it (precedents #10300 and #9558). It is in scope, because this PR adds
ia_ssaand already wires it into SNAP, HUD,spm_unit_benefitsandhousehold_state_benefits. Not critical: two separately correct changes interact, Iowa LIHEAP is not a program this PR encodes, and most amounts are small. Blind SSI recipients are reached in microsimulation (+$264 a year). - Fix: merge
main. InL/unearned.yaml, replace:20-21with:
# ssi and ia_ssa are monthly variables; the formula sums the twelve months.
- ssi
# Appendix C, Social Security Benefits (SSA, SSI, SSDI) (page 114), also
# counts "SSA (State Supplementary Assistance) - Fully state-funded".
# ia_ssa includes the in-home health-related care payment, which is made
# to the recipient (6-B PDF page 50). SNAP and HUD exclude that payment as
# a reimbursement, but Appendix C has no such exception: the reimbursement
# rows it excludes (pages 97, 103, 116 and 118) are executor fees, job
# costs, TAA payments and VA mileage.
- ia_ssaIn L/fixed.yaml, add after - ssi (:12):
# The Definitions (page 81) name SSA benefits, SSI and SSDI. Appendix C
# (page 114) puts "SSA (State Supplementary Assistance)" in the same
# Social Security Benefits row as SSI, and that row records a minor's
# payment "to capture source of income for AE fixed income criteria".
- ia_ssaand change its title (:28) to "Iowa LIHEAP FY26 Policy and Procedures Manual, Definitions, Fixed Income Household, Appendix C Pensions, Railroad Retirement and Social Security Benefits rows, and Appendix I Payment Matrix, Fixed Income Only targeting factor #page 81,109-110,114,137". Optional: add "Iowa State Supplementary Assistance" after "SSI" in the documentation of ia_liheap_countable_unearned_income and ia_liheap_fixed_income_only. Append to LT after Case 8:
- name: Case 9, a blind in-home care recipient's State Supplementary Assistance counts as fixed income.
period: 2026
absolute_error_margin: 0.01
input:
people:
person1:
age: 65
is_blind: true
ia_ssa_category: IN_HOME_CARE
ia_ssa_ihhrc_monthly_cost: 4_800
spm_units:
spm_unit:
members: [person1]
heating_type: NATURAL_GAS
gas_expense: 1_200
spm_unit_cash_assets: 1_000
ia_liheap_dwelling_type: DETACHED
households:
household:
members: [person1]
state_code: IA
output:
# SSI 994 * 12 = 11,928.
ssi: 11_928
# Blind allowance 22 plus the in-home health-related care payment of
# 400 a month (4,800 a year): (22 + 400) * 12 = 5,064, as in the Iowa SSA
# integration.yaml Case 9, where SNAP and HUD count only the 264.
ia_ssa: 5_064
# Appendix C, Social Security Benefits (SSA, SSI, SSDI), counts State
# Supplementary Assistance and makes no exception for the in-home care
# payment: 11,928 + 5,064 = 16,992.
ia_liheap_countable_income: 16_992
# SSI and the supplement are both in that fixed income row.
ia_liheap_fixed_income_only: true
# 16,992 / 15,650 = 1.086 -> 101 to 125 percent band (SSI alone: 0.762 -> 6).
ia_liheap_poverty_points: 5
# fixed income +1, elderly +1, detached +1
ia_liheap_targeting_points: 3
ia_liheap_fuel_points: 4
# 5 + 3 + 4 = 12; 40 x 12
ia_liheap: 480In the PR body, add to the wiring paragraph: "Iowa LIHEAP counts the whole ia_ssa as unearned and fixed income (Appendix C p.114), including the in-home care payment."
Suggestions
New:
- G70. The 1619(b) reason in the new comments is narrower than the rule (DTrim99's round-8 suggestion; confirmed). The flag comment (
:59-61), the helper docstring (:5-8), the PR body SMME bullet and the #1837 flag row and SGA bullet say that a worker above the SGA level is in the 1619(b) group. 8-F p.88 gives 1619(b) to "some former SSI recipients who no longer qualify for SSI benefits because their earnings are too high". A new SMME applicant need not have received SSI; such a worker often has MEPD, where SGA "is not considered" (8-F p.114). The conclusion holds on 8-E p.12's "State Supplementary Assistance" and 6-B p.76's coverage rule. Name the coverage input, because the code tests it, not the SMME payment. Wording only; no behavior or test changes.- Replace flag
:57-67with:
- Replace flag
# 8-E p.12: "An ineligible spouse is a spouse who is not eligible for
# SSI or non-MAGI-related Medicaid, or State Supplementary Assistance."
# Those groups are for aged, blind or disabled people (8-F PDF pages
# 73-74). SMME is itself State Supplementary Assistance, and an SMME
# applicant must receive full Medicaid under "a Medicaid coverage group
# that does not rely on eligibility for SSA" (6-B PDF page 76), which
# ia_ssa_smme_coverage_eligible records. For a disabled worker above
# the SGA level that can be MEPD with no premium, where SGA "is not
# considered" (8-F PDF page 114), or the 1619(b) group of former SSI
# recipients (8-F PDF page 88). So a spouse SSI treats as aged, blind
# or disabled, or an SMME applicant working above the SGA level, is not
# an ineligible spouse: the couple's income is combined with no $497
# test, as SSI and msp_countable_income combine an eligible couple's
# income (ia_ssa.yaml Cases 97, 102, 103 and 107). This test is broader
# than is_ssi_ineligible_spouse.- In the flag tuple, change the comment to
# 8-F PDF pages 73-74, 88, 114, and add"https://hhs.iowa.gov/media/3987/download?inline=#page=76",with the comment# 6-B PDF page 76. - In the helper docstring (
:5-11), replace "who has full non-MAGI-related Medicaid (8-F PDF page 73, 1619(b) group)" with "who receives full Medicaid under a group that does not rely on State Supplementary Assistance (6-B PDF page 76), such as MEPD (8-F PDF page 114) or 1619(b) (8-F PDF page 88)". - In the PR body and #1837, replace "8-F pp.73 and 88 place that worker in the 1619(b) group" (body) and "whom 8-F p.88 treats as an SSI recipient" (#1837) with "who has full Medicaid under a group that does not rely on State Supplementary Assistance (6-B p.76), such as MEPD (8-F p.114) or 1619(b) (8-F p.88); SMME is itself State Supplementary Assistance".
- G71. An ineligible spouse's student earnings are not excluded before deeming (20 CFR 416.1161(a)(27)). Record in code, and file a federal issue.
- Where: helper
:52takes the spouse's student exclusion only when the spouse is not an ineligible spouse (* not_ineligible, from the round-7 SA36 text). Federal deeming (ssi_earned_income_deemed_from_ineligible_spouse) subtracts no student exclusion, andssi_blind_or_disabled_working_student_exclusionisdefined_forblind or disabled status. - Source: 416.1163(a) builds the ineligible spouse's income "using the appropriate exclusions in § 416.1161(a)". 416.1161(a) is "For an ineligible spouse or parent" and excludes "(27) Earned income of a student as described in § 416.1112(c)(3)". 416.1112(c)(3) has no blind or disabled condition. 8-E p.11: for the ineligible spouse, "do not include: Any excluded income".
- Evidence (April 2026; applicant aged 50, disabled, wages 3,000, SMME; spouse aged 20, full-time student, disabled, wages 1,800, no Medicaid): the head gives 2,357.50 to the applicant and 1,952.08 to the spouse, and
ia_ssa[1, 0]. The rule gives 1,952.08 to both and [0, 0]. Deleting* not_ineligiblegives that and passes 138/138. A student spouse who is not disabled is not fixed by that change, because the federal exclusion variable is 0 for that spouse. An aged applicant on the SSI path has the same miss. - Why a suggestion: the factor leaves the gap as it was at the round-7 head and as SSI's own deeming has it; it does not make it worse. This is the G57(a) class: an inherited federal gap with flips, recorded and tracked. The population is married students under 22 with earnings; microsimulation reach is zero.
- Fix (text): in the helper docstring list at
:43-47, add ", and an ineligible spouse's student earned income is not excluded (416.1161(a)(27); issue NNNN)", with the new issue number. Optional now, and needed when the federal fix lands (the helper readsssi_earned_incomedirectly, so it will not follow the federal change): delete* not_ineligible, and add a case for the household above (expect exclusion [0, 810.83], flag [true, true], SMME [1,952.08, 1,952.08],ia_ssa[0, 0]; give the spouseis_full_time_student: trueandimmigration_status: UNDOCUMENTED, as in Case 107). The trade-off is G57's: until the federal fix lands, the SGA path and the aged path differ for this household.
- Where: helper
- G72. Small record and citation points (optional).
- Add GL 6-B-47 (
https://hhs.iowa.gov/media/18744/download?inline#page=1, "effective January 1, 2026") todependent_amount.yamlandrcf_daily_limit.yaml. Its p.1 lists $518 and $38.47. - Countable
:20: "Iowa Code 249.3(4)(a)(2) and (g); PDF pages 2-3", because (g) runs onto p.3. - Countable
:62-63: "the figure 8-E gives for deeming" should be "the individual figure 8-E gives (8-E p.56)". - Helper docstring
:45-47: cite PR #10146 for the tax-unit child search and the income-maintenance exception. - Case 73 comment: "(PR 10141 applies it)" will age better than "(issue 10138)".
us-ia:rcf-maximum-per-diem-rate: optionally add GL 6-B-45#page=24and the 2023 sheet as manual sources (G51's optional part).
- Add GL 6-B-47 (
Still open from earlier rounds (as written in rounds 4-7): G25 (accepted part), G36-G42, G46, G48 (couple 2,164 and the SGA switch), G50, G53, G54(a) (now also the spouse's exclusion), G55, G56, G63. None blocks.
Investigated and cleared
- SA36 on new shapes. A working SMME spouse below the SGA level gets the same result on the SGA path and the aged path. The override can only raise the ABD spouse's figure, so no household loses SMME through it.
- Equivalent terms.
& ~abdin the status, coverage in countable'sapplicant,- applicantin the SGA-applicant test and the floor onspouse_earnedcannot change any output. Keep them for readability. - Disability term in the spouse status. No case pins it. A case needs the coverage input on a spouse who is neither aged nor disabled, which the input's own definition (Medicare Part B) rules out. G62 precedent; no case asked.
- Payer test on the spouse only. Still survives, as round 7 accepted.
- Case 108 and the coverage term in the applicant test. Under that mutant, person2's SMME income is 0, not 2,597.50, because countable's own
applicantstill needs coverage. Case 108 still kills it. - Repeated helper calls, the flag name and the 93-character label line. Negligible cost; the house pattern;
ruffis clean. No change. - Merge with
main. #10283 and #10453 break no Iowa file. The deleted_smme_spouse_income.pyis not in the live PR file list (46 files), and nothing imports it.
Out of scope / follow-up
- New federal issue for G71: "SSI deeming does not exclude an ineligible spouse's or parent's student earned income (20 CFR 416.1161(a)(27))". Household: an aged claimant with Social Security of 600 and a spouse aged 20, a full-time student with wages of 1,800.
mainpays SSI 43.50; the rule pays 414 (in April the whole 1,800 is excluded). Related: #10454 and this PR. - Tracked: #10454 (416.1161(a)(10)), #10455 (when fixed, Case 96's person2 value changes from 2,106 to 500), #10456 (couple student exclusion; it also records the G54(a) averaging), #10243 item 2 (record only). PR #10141 closes #10138 (G72, Case 73 comment).
- SA38 alternative: a tracked issue instead of the fix would leave SA38 open.
Validation Summary
| Check | Result |
|---|---|
| CI | 32/32 pass at 4aae08a |
| Local tests | Iowa SSA 138/138 at the head and on the merged tree; code health 462 (1 skipped); source conflicts 103; registry and source conflicts 888 (10 skipped); Iowa LIHEAP 164/164 on the merged tree |
| Regulatory | SA36 correct for every tested shape; SA37 (249.3(4)(c)); SA38 (LIHEAP p.114); G70; G71 is SSI's own rule, inherited |
| References | 35/35 new or changed cites correct; no printed page number; G72 |
| Code patterns | ruff clean; periods, entities and vectorization correct; no hard-coded value; the helper module follows the house pattern |
| Tests | Cases 98-109 recompute; Case 73 swap correct; 31 mutants: 24 killed, 4 equivalent, 3 survive (one input-gated, G71, one accepted in round 7) |
| Fixes run | SA37: 139/139 with the code change, rewrites and Case 110; two masked mutants killed again. SA38: the LIHEAP case fails before and passes after; LIHEAP 165/165 |
| Branch | 47 ahead, 32 behind; trial merge clean; MERGEABLE |
| Partner tests | None touched |
| Other reviews | DTrim99 round 8: SA38 (same item) and G70 (same wording point) |
| PR body | axiom: line valid (process note); body sentences for SA37, SA38 and G70 |
Review Severity: REQUEST_CHANGES
Two should-address items are open: SA37 (an SSI recipient can get SMME through the round-7 override) and SA38 (Iowa LIHEAP wiring after a merge of main). No critical item is open, and SA35 and SA36 are resolved.
Next Steps
To auto-fix issues: run the fix-pr workflow for this PR.
- SA37: add the SSI term and the two comments; rewrite Cases 24, 44, 45, 78, 79 and 89 (Cases 22 and 23 optional); append Case 110.
- SA38: merge
main; add- ia_ssato both LIHEAP lists with the comments and thefixed.yamltitle; append the LIHEAP case toLT. - Run
make format, then the Iowa SSA and Iowa LIHEAP folders andtest_source_conflicts.pyonce with all changes. - Update the PR body (SMME bullet, wiring paragraph, test counts) and rulespec-us#1837 (a row for Case 110).
- Optional: G70-G72 and the carried suggestions.
- Outside this PR: file the G71 federal issue.
- SA37: no SMME for a person SSI pays (Iowa Code 249.3(4)(c); 6-B p.74), which the round-7 combined-income override allowed for the aged, blind or disabled spouse of an applicant working above the SGA level (Case 110). Cases 22-24, 44, 45, 78, 79 and 89 now give the person Social Security so that SSI is 0. - SA38: Iowa LIHEAP counts ia_ssa as unearned and fixed income (LIHEAP FY26 manual Appendix C p.114), with Iowa LIHEAP integration Case 9. - G70: rest the SGA applicant's spouse status on 6-B p.76's coverage rule (MEPD, 1619(b)) rather than on 1619(b) alone. - G71: NOTE citing issue 10521 (an ineligible spouse's student earnings). - G72: GL 6-B-47 references, citation and comment fixes, and per diem candidate sources. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, Pavel and David. Both should-address items and the suggestions are fixed in 676dced, and
Still deferred: G36-G42, G46, the rest of G48, G50, G53, G54(a), G55, G56 and G63. On the merged tree, 139 Iowa supplement cases (110 in |
PR Review (round 9): Add Iowa state supplementation for 2026SummaryPR #8017 (author: hua7450). This round reviews head What the commit does.
What I found.
Prior findings
Pavel's round-8 items in this commit (checked, not ours):
New findingsCritical (must fix)None. Should address
Suggestions
VerifiedThe LIHEAP wiring.
SA37. The new term is a float comparison combined with
Hand-checked expectations (every new or changed one). The 2026 figures are: SSI $994 / $1,491, child allocation $497, SGA $1,690. 120% of the guideline is $1,565 before April (2025 guideline) and $1,596 / $2,164 from April.
Case 73 changed only a comment (it now names PR 10141). No expectation changed. Other checks.
Axiom line assessmentThe line reads
CI status
Branch status
Verdict: REQUEST_CHANGES |
DTrim99
left a comment
There was a problem hiding this comment.
Requesting changes, round 9: 0 critical, 1 should. Both round-8 items are fixed (ia_ssa is now counted once in Iowa LIHEAP and pinned by Case 9). The one open item needs no code: the LIHEAP change needs axiom coverage. Update rulespec-us#1834 (add ia_ssa to the unearned and fixed-income rows, plus the p.114 quote and a companion test) and name it in the axiom line. Full report in the comment above.
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Program Review
PR #8017, "Add Iowa state supplementation for 2026" (hua7450). Round 9, incremental review of 4aae08a..676dced.
IDs: C = critical, SA = should address, G = suggestion. New items continue the numbering after the highest prior ID in each class. This round adds one suggestion, G73. There is no new critical or should-address item, so C8 and SA39 are not used.
Paths: V/ = policyengine_us/variables/gov/states/ia/hhs/ssa/, T = policyengine_us/tests/policy/baseline/gov/states/ia/hhs/ssa/ia_ssa.yaml, L/ = policyengine_us/parameters/gov/states/ia/hhs/liheap/income/sources/, LT = policyengine_us/tests/policy/baseline/gov/states/ia/hhs/liheap/integration.yaml. "Countable" = V/ia_ssa_smme_countable_income.py, "flag" = V/ia_ssa_smme_spousal_deeming_applies.py, "helper" = V/_ia_ssa_smme_spouse_income.py. Line numbers refer to the reviewed head. "p.NN" is the PDF FILE page (8-E FILE = printed + 5; 6-B and 8-F FILE = printed + 4).
Source Documents
- Reviewed head SHA: 676dced
- Mode: incremental (round 9), from 4aae08a (round 8, CHANGES_REQUESTED)
- Scope:
- 676dced, "Address Pavel's and David's round-8 reviews of Iowa SSA" (13 files, +225 / -32): the SMME SSI term and comment in
V/ia_ssa.py:154-169; comments in countable (:20,:63,:83-84); the flag comment and tuple (:21-24,:59-73); two helper docstrings (:4-13,:38-51);ia_ssainL/unearned.yaml:20-29andL/fixed.yaml:13-17and thefixed.yamltitle (:33); the two LIHEAP income descriptions; GL 6-B-47 independent_amount.yamlandrcf_daily_limit.yaml; two sources inus-ia:rcf-maximum-per-diem-rate(candidates.yaml:2096-2101);TCases 22-24, 44, 45, 78, 79 and 89 rewritten, Case 73's comment and new Case 110;LTCase 9. - 2da0ed3, a merge of
mainat 8ea4342 with no hand-resolved block. It brings Iowa LIHEAP (#10292) into the branch. In the Iowa SSA and SSI files it changes only one comment inssi_amount_if_eligible.py(1382(e)(1)(A) to (B)). Theprograms.yamlhunks in the diff aremainnoise; the Iowa SSA entry is unchanged. - The PR body: the SMME bullet, the LIHEAP sentence, the shared-files list, nine federal limitations and the test counts.
- 676dced, "Address Pavel's and David's round-8 reviews of Iowa SSA" (13 files, +225 / -32): the SMME SSI term and comment in
- Iowa sources (downloaded this round): 6-B (https://hhs.iowa.gov/media/3987/download?inline=, pp.50, 74, 76), 8-F (media/4012, pp.73-74, 88, 114), 8-E (media/4011, p.56), GL 6-B-47 (media/18744, p.1), GL 6-B-45 (media/12206, p.24), the 2023 standards sheet (media/9237), Iowa Code ch. 249 (pp.2-3), and the Iowa LIHEAP FY26 manual (media/17262, pp.81, 97, 103, 114, 116, 118).
- GitHub (read-only): issue #10521; PRs #10141 and #10146 (both open); TheAxiomFoundation/rulespec-us#1834 and #1837; DTrim99's round-9 review.
Branch Status
- 49 ahead and 28 behind
main(1976c4b). A trial merge (git merge-tree, trivial mode) shows no conflict.programs.yamlandsource_conflicts/candidates.yamlchange on both sides and merge cleanly. - The 28 newer
maincommits add Alaska, North Dakota, New Hampshire, Utah and Wyoming LIHEAP, fix TANF in nine states, and change S.770, the Maine EITC, the self-employed health insurance deduction and the Montana AGI invariant. One changesgov/hhs/liheap/fpg_limit.yaml, which no Iowa file reads. None touches an Iowa supplement, SSI, Iowa LIHEAP or a shared SSP wiring file. - CI at 676dced: 33 of 33 checks pass.
- GitHub:
MERGEABLE,BLOCKED. The review decision isCHANGES_REQUESTED(DTrim99, round 9, and mine, round 8). - No partner test file is touched. The changelog fragment (
changelog.d/ia-ssp.added.md) is unchanged. - Process note (not counted): the
axiom:line names rulespec-us#1837 only. See "Other reviews".
Round 8 items
| ID | Status | Evidence |
|---|---|---|
| SA37 | RESOLVED | V/ia_ssa.py:169 adds & (person("ssi_if_takes_up", period) == 0), with the 249.3(4)(c) and 6-B p.74 comment at :154-161 and the pointer at countable :83-84. The source supports it: 249.3(4)(c), "Would be eligible for supplemental security income benefits but for having excess income ..." (249.pdf p.2); 6-B p.74, "certain Medicaid recipients who do not qualify for other cash assistance benefits" (6-B p.74). Case 110 (T:3655) fails without the term ([1, 1, 0, 0, 0]) and only Case 110 fails. Without federally_paid == 0, Case 24 fails again (12 against 11). The eight rewritten cases now reach their terms through the formula (see "Tests run"). This was a regression from my own round-7 SA36 proposal, as round 8 said. The round-8 fix is also my text; this round re-checked it independently, and it is right. |
| SA38 | RESOLVED | ia_ssa is in L/unearned.yaml:29 and L/fixed.yaml:17, with the round-8 comments; the fixed.yaml title adds p.114 (:33); both LIHEAP descriptions name the supplement. Both formulas sum the twelve monthly amounts (options=[ADD]; add(spm_unit, period, p.fixed)). The fixed test excludes fixed sources from "other" income, so the supplement no longer defeats the factor. LT Case 9 (:346) fails without the unearned.yaml entry (11,928), without the fixed.yaml entry (fixed income only false) and with ia_ssa_countable_for_snap in both lists (12,192). p.114 reads "SSA (State Supplementary Assistance) - Fully state-funded" (LIHEAP p.114). Agrees with DTrim99's round-9 review (round-8 Should 1, "Fixed") |
| G25 | PARTIAL (accepted part stands) | Case 110 uses 2026-04; it fits |
| G36 | DECLINED for now | Branches unchanged. A deferral of a test suggestion in untouched code is defensible |
| G37 | STILL OPEN (deferred) | The NOTE at V/ia_ssa.py:146-153 and the candidate still omit "At the discretion of the department". Defensible |
| G38 | STILL OPEN (deferred) | V/ia_ssa_federal.py unchanged. Defensible |
| G39 | STILL OPEN (deferred) | Coverage input documentation unchanged. Defensible |
| G40 | STILL OPEN (deferred) | Files unchanged. Defensible |
| G41 | STILL OPEN (deferred) | Iowa SSA integration.yaml unchanged. Defensible |
| G42 | STILL OPEN (deferred) | V/ia_ssa_ihhrc_participation.py unchanged. Defensible |
| G46 | STILL OPEN (deferred) | Manual sums unchanged; no new instance. Defensible (style) |
| G48 | PARTIAL | The one-person part is closed: Cases 44, 78 and 89 now reach 1,596 and 1,565 from Social Security through the formula, and a >= to > mutant fails all three. The couple at exactly 2,164 and the SGA switch are still open (Case 110 reaches 2,207.50, not the boundary) |
| G50 | STILL OPEN (deferred) | Unchanged. Defensible |
| G53 | STILL OPEN (deferred) | fpg_year_start_month.yaml unchanged. Defensible |
| G54 | PARTIAL | (a) The cap averaging is still undocumented (helper :56). Defensible |
| G55 | STILL OPEN (deferred) | V/ia_ssa.py:141 still reads f"{year}-01-01". Defensible |
| G56 | STILL OPEN (deferred) | No new 2025 case. Defensible |
| G63 | STILL OPEN (deferred) | No 2023 case; no 2024 DP case. Defensible |
| G70 | RESOLVED | The flag comment (:59-73), the tuple (:21-24, adds 8-F p.114 and 6-B p.76), the helper docstring (:4-13) and the PR body SMME bullet use the round-8 text. The quotes are on the cited pages: 6-B p.76, "under a Medicaid coverage group that does not rely on eligibility for SSA" and "MEPD with a premium are not eligible" (6-B p.76); 8-F p.114, SGA "is not considered in determining disability for the MEPD group" (8-F p.114); 8-F p.88, "some former SSI recipients" (8-F p.88); 8-F p.73 starts the non-MAGI section, "People who are aged, blind, or disabled" (8-F p.73). Agrees with DTrim99's round-9 review (round-8 Suggestion 1, "Fixed"). One follow-on wording point: G73(a) |
| G71 | RESOLVED | Helper docstring :49-51 cites 416.1161(a)(27) and issue #10521. #10521 is open and describes the gap correctly. You kept * not_ineligible so that the SGA path and the aged path agree until the federal fix lands. Round 8 made that part optional for now, and the reason holds |
| G72 | RESOLVED | All six points: GL 6-B-47 at dependent_amount.yaml:23-24 and rcf_daily_limit.yaml:24-25 (p.1 lists $518 and $38.47, effective January 1, 2026); countable :20 "PDF pages 2-3" (249.3(4)(g) runs onto p.3); countable :63 "the individual figure 8-E gives (8-E p.56)" (p.56: "$351.33 (one-third of the SSI benefit rate plus $20)"); helper :49 names PR 10146, whose body covers both the co-resident child search and the income-maintenance exception; Case 73 (T:2152) names PR 10141, which is still open, so "main does not yet apply" is still true; the per diem candidate adds GL 6-B-45 #page=24 ($36.82 and $17.86) and the 2023 sheet ($35.89 and $17.86) |
Tally: 21 IDs were open after round 8. Now 5 are resolved (SA37, SA38, G70, G71, G72), 3 are partial (G25, G48, G54), 12 are still open as deferred suggestions and 1 is declined for now (G36). Every open item is a suggestion, and each deferral is defensible.
Withdrawals: none. SA37 came from my own round-7 SA36 patch, and round 8 said so. This round checked every round-8 item that came from my code or wording: the SA37 term and the six case rewrites, Case 110, the SA38 list entries, comments and LIHEAP Case 9, the G70 comment and docstring, and the G72 citations. Each one is correct against the source and the code. One small precision point follows from the G70 text (G73(a)).
New findings
Critical
None.
Should address
None.
Suggestions
- G73. Small wording points (optional).
- (a) The flag NOTE (
:78-80) and the PR body "Not modeled" bullet say that "a disabled spouse working above the SGA level who has another non-MAGI-related Medicaid group, such as MEPD, but no SMME coverage is deemed rather than combined". The new G70 comment (:65-67) names MEPD with no premium as one of the groups the coverage input records, and the input's documentation reads "without a premium or spenddown, and eligible for Medicare Part B". So "such as MEPD" now reads against the comment above it. Write "such as MEPD with a premium, or without Medicare Part B". No behavior changes. - (b) Two lines were not re-wrapped: helper
:10("(8-F PDF page 88). For an") andia_liheap_fixed_income_only.py:11(117 characters).ruffpasses, because E501 is ignored. Re-wrap them if you touch the files again.
- (a) The flag NOTE (
Other reviews
DTrim99 reviewed 676dced on 2026-10-28 (CHANGES_REQUESTED: 0 critical, 1 should).
- Should 1 (rulespec-us#1834 still lists the old Iowa LIHEAP sources). The point is correct. #1834's rows for
ia_liheap_countable_unearned_incomeandia_liheap_fixed_income_onlylistssibut notia_ssa. #1834 was last updated 2:12pm EDT on 2026-10-26, before this commit. Theaxiom:line names only #1837. Under my 2026-10-26 rule, axiom coverage is a process note and does not count toward the verdict, so it is not an SA here. It is still a two-row update to #1834 and is worth doing before #1834 is dispatched. - Suggestion 1 (#1837 lacks the 6-B p.76 and 8-F p.114 quotes). Correct: #1837's 6-B list quotes only "The person must not be eligible for other SSA" from p.76, and its 8-F rows still read "pp.73-74, 88". Process note. The optional tuple comment "6-B PDF pages 76-77" is also reasonable, because the flag formula cites 6-B Income (SMME) p.77 (
:28). - DTrim99's hand values for the ten new or changed cases match this round's.
Tests run
- At the head (SNAPSHOT,
policyengine_usimported from SNAPSHOT):- Iowa SSA folder: 139 passed (110 in
T). - Iowa LIHEAP folder: 165 passed.
test_source_conflicts.py: 103 passed.test_reference_urls.py,test_no_concatenated_reference_urls.py,test_parameter_yaml_keys.py,test_military_retirement_readers.py,test_unemployment_compensation_readers.py,test_no_group_variables_in_person_adds.py,test_known_dead_reference_urls.py: 172 passed.ruff format --checkandruff checkon the Iowa SSA and Iowa LIHEAP variable folders: clean (41 files).
- Iowa SSA folder: 139 passed (110 in
- Mutations (on package copies, deleted after the runs). In each pair, the second run also removes the new SSI term. The only difference within each pair is Case 110, so the new term hides no other kill:
| Mutant | Fails at the head | Also fails without the SSI term |
|---|---|---|
| Remove the SSI term | Case 110 | n/a |
Remove federally_paid == 0 |
Case 24 | Case 110 |
| Remove the coverage term | Cases 22, 48 | Case 110 |
| Guideline test loosened by $0.011 | Cases 45, 79 | Case 110 |
>= to > |
Cases 44, 78, 89, 96, 99, 101 | Case 110 |
| No April guideline lag | Cases 78, 80, 89 | Case 110 |
| Remove the guideline test | 14 cases, including 23, 45, 79 | Case 110 |
ssi in place of ssi_if_takes_up |
none (equivalent: a non-taker fails ia_ssa_nonfinancial_eligible) |
n/a |
ia_ssa removed from L/unearned.yaml |
LT Case 9 (11,928) |
n/a |
ia_ssa removed from L/fixed.yaml |
LT Case 9 (fixed income only false) |
n/a |
ia_ssa_countable_for_snap in both lists |
LT Case 9 (12,192) |
n/a |
- Hand checks (2026: SSI $994 / $1,491; child allocation $497; SGA $1,690; guideline 15,650 before April and 15,960 / 21,640 from April, so 120% is 1,565 in January-March, 1,596 and 2,164 from April):
| Case | Hand computation | Expected | Result |
|---|---|---|---|
| 22 (Jan) | 24,240 / 12 = 2,020; 2,000 > 994, so SSI 0; no coverage | ssi 0; SMME 2,000; ia_ssa 0 |
Correct |
| 23 (Jan) | 12,240 / 12 = 1,020; 1,000 > 994, so SSI 0; 1,000 < 1,565 | 0; 1,000; 0 | Correct |
| 24 (Jan) | 12,300 / 12 = 1,025; 1,005 > 994, so SSI 0; blind level 994 + 22 − 1,005 = 11 (below the $1,016 limit, GL 6-B-47 p.1); SMME barred by the SSA-paid amount | 0; ia_ssa_federal 11; ia_ssa 11 |
Correct |
| 44 (Apr) | 19,392 / 12 = 1,616; 1,596 ≥ 1,596 | 0; 1,596; 1 | Correct |
| 45 (Apr) | 19,391.88 / 12 = 1,615.99; 1,595.99 < 1,596 | 0; 1,595.99; 0 | Correct |
| 78 (Jan) | 19,020 / 12 = 1,585; 1,565 ≥ 1,565 | 0; 1,565; 1 | Correct |
| 79 (Jan) | 19,019.88 / 12 = 1,584.99; 1,564.99 < 1,565 | 0; 1,564.99; 0 | Correct |
| 89 (Mar) | As Case 78; the 2025 guideline applies until April (441 IAC 75.1) | 0; 1,565; 1 | Correct |
| 110 (Apr) | SSI deems 4,500 − 3 × 497 = 3,009; (3,009 − 85) / 2 = 1,462; person2's SSI 1,491 − 1,462 = 29 (below 994, so PR 10141 does not change it). SMME combined (4,500 − 85) / 2 = 2,207.50 ≥ 2,164 for both; person2 is paid SSI, so no SMME | ssi [0, 29, 0, 0, 0]; SMME [2,207.5, 2,207.5, 0, 0, 0]; ia_ssa [1, 0, 0, 0, 0] |
Correct |
LT 9 (2026) |
SSI 994 × 12 = 11,928; ia_ssa (22 + 4,800 / 12) × 12 = 5,064; countable 16,992; fixed only; 16,992 / 15,650 = 1.086, so 5 points (SSI alone 0.762, so 6); targeting fixed + elderly + detached = 3; natural gas 4; 12 × 40 = 480 |
11,928; 5,064; 16,992; true; 5; 3; 4; 480 | Correct |
- References: every new or changed href, cite and quote in the commit (about 25) is on the cited FILE page. No href uses a printed page number. On LIHEAP p.81, "SSA" means Social Security Administration. The fixed-income entry rests on the p.114 row, which spells out "SSA (State Supplementary Assistance)" and carries the fixed-income margin note. The
fixed.yamlcomment states that reading correctly. - Investigated and cleared:
- Reach of the SSI term. A single person whom SSI pays has countable income plus SSI of at most 994, below 1,565. An eligible couple or a couple with SSI deeming reaches at most 1,491, below 2,164. So the term changes
ia_ssaonly on the SA36 override path (the Case 110 shape), as intended. Microsimulation reach is zero, because the SMME inputs default to off. - No new dependency cycle:
ia_ssaalready readsssi(V/ia_ssa.py:87).ssi_if_takes_upis Person/MONTH, likeia_ssa. - LIHEAP: no double counting (
ssiexcludes the state supplement, andia_ssaalready includesia_ssa_federal). The 18-and-over gate applies to countable income but not to the fixed test, as p.114 requires. The four reimbursement rows that Appendix C excludes are the only ones on pp.85-125 (p.116 also counts the living-expense part of training stipends). - Pending federal PRs: under #10141, Case 110's SSI stays $29 (below the $994 cap). Under #10146, the three children have no parent ids, so the no-link proxy keeps their allocations.
- Reach of the SSI term. A single person whom SSI pays has countable income plus SSI of at most 994, below 1,565. An eligible couple or a couple with SSI deeming reaches at most 1,491, below 2,164. So the term changes
Verdict
APPROVE: SA37 and SA38 are resolved, and the tests pin them. No critical or should-address item is open. The suggestions G25, G36-G42, G46, G48, G50, G53-G56, G63 and the new G73 do not block. DTrim99's rulespec-us#1834 point is correct, but it is a process note under my axiom rule.
|
Thanks, David. Should 1 and Suggestion 1 are done, with no code change, so the head stays 676dced.
Pavel's G73 wording points (the "such as MEPD" NOTE and two line wraps) touch code comments only, so I'll fold them into the final merge of |
PR Review (round 10): Add Iowa state supplementation for 2026SummaryPR #8017 (author: hua7450). The head is still What I found.
Prior findings
Companion test 20, checked by hand against the head. The household is a blind SSI recipient aged 65 with natural gas heat. Inputs:
Case count at the head. The 16 Iowa LIHEAP test files have 165 cases: New findingsCritical (must fix)None. Should addressNone. Suggestions
AxiomThe line reads
CI
Branch
Verdict: APPROVE |
DTrim99
left a comment
There was a problem hiding this comment.
Approving round 10: 0 critical, 0 should. rulespec-us#1834 now covers ia_ssa in Iowa LIHEAP and the axiom line names it. CI is 33/33. Full report in the comment above.
What and why
Iowa's State Supplementary Assistance was missing from PolicyEngine-US. Add
ia_ssafor 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.
ia_ssa_federalcomputes 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.2026 levels:
Payment:
ia_ssa_care_initial_partial_monthmarks that month.ia_ssa_rcf_couple_budgetmarks 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).Who qualifies:
is_ssi_aged_blind_disabledinia_ssa_nonfinancial_eligible, oris_ssi_agedormeets_ssi_disability_criteriafor SMME, since SMME disability ignores substantial gainful activity (Iowa Code 249.3(4)(a)(2); 441 IAC 51.7(2); 6-B p.10)takes_up_ssi_if_eligibleoruncapped_ssi <= 0. An applicant whose income would qualify for SSI must take it up; an applicant over income needn'timmigration_statusoris_ssi_qualified_noncitizenis_incarceratedbarsssi_countable_resources, plusia_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_spouseidentifies the spouseia_ssa_categoryinputdefined_for = StateCode.IAChildren 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_parentstherefore deems parental income by the Iowa method:Couples:
ia_ssa_has_spouse). Without explicit marital units, a parent isn't paired with an adult child the parent claims, and a default unit of three or more people budgets each member alone (Case 101).COLA: 441 IAC 52.1 adjusts the assistance standards each January 1 for SSA's COLA but publishes no method.
Inputs: all are Person and monthly, and all default to 0, false or
REGULAR.ia_ssa_categoryrecords the certified arrangement.NONEexcludes the person, including from the blind supplement.ia_ssa_dependent_countable_income,ia_ssa_ihhrc_monthly_costandia_ssa_rcf_daily_ratecarry forward until changed.ia_ssa_rcf_daily_rateis only for a facility rate below the maximum; 0 pays the maximum.ia_ssa_smme_coverage_eligibleis full Medicaid without a spenddown or premium, plus Medicare Part B. For a disabled person working above the SGA level, it also means the person isn't an ineligible spouse (8-E p.12), so it changes the other spouse's SMME budget.ia_ssa_care_partial_month_days(0 is a full month),ia_ssa_care_initial_partial_month(a first in-home month, or the month of entry to residential care from home) andia_ssa_care_additional_deductionsare one-month entries. They have zero formulas, so an entry stays in its month.ia_ssa_care_additional_deductionsat 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.Source conflicts: where the sources disagree, the model follows the manual, except for the residential care entry month, where it follows the rule. For SMME income, SMME for a blind person under 65 and the residential care rate, it follows the Iowa Code, and for a married student's earned income exclusion in SMME income it follows 42 U.S.C. 1382a(b)(1) and 20 CFR 416.1112(c)(3), under PolicyEngine-US's statute-first rule (CONTRIBUTING.md, "Source conflicts", merged with Tie source-conflict markers to the register shared with Axiom #10287). All four are listed in
source_conflicts/candidates.yaml(us-ia:smme-income-at-least-120-percent,us-ia:smme-blind-under-65,us-ia:rcf-maximum-per-diem-rate,us-ia:smme-student-exclusion-married) until they are registered. For a dependent's income of exactly $518 and the in-home dependent allowance, the rule agrees with the reading taken. The in-home cost ceiling is no longer a conflict. The rulespec-us issue's conflicts comment quotes each side.The supplement is added to
household_state_benefits(all four year blocks, under a new# Iowa benefitscomment) and tospm_unit_benefits. SNAP and HUD count it throughia_ssa_countable_for_snapandia_ssa_countable_for_hud, which leave out the in-home care payment:Iowa LIHEAP counts the whole
ia_ssaas unearned and fixed income (LIHEAP FY26 manual Appendix C p.114), including the in-home care payment.Files:
Shared files:
household_state_benefits.yamlgains one Iowa entry per year block.income/sources/unearned.yamlandspm_unit_benefits.pyeach gain one Iowa entry.income/sources/unearned.yamlandfixed.yamleach gainia_ssa, the two LIHEAP income variables' descriptions name it, and the Iowa LIHEAPintegration.yamlgains Case 9.programs.yamlIowa entry changes fromin_progresstopartial.source_conflicts/candidates.yamlgains four statute-conflict entries: the two SMME entries, the residential care per diem (2023-2026) and a married student's earned income exclusion in SMME income.gov/ssa/ssi/income/exclusions/child_support_share.yaml, the one-third exclusion of 20 CFR 416.1124(c)(11), came tomainwith Add Oklahoma state supplementation for 2026 #10165. This PR leaves it as onmain.ia_ssa_care_countable_incomereads it, as Oklahoma's supplement does._ssi_parental_resource_pool, andia_ssa_has_spouseimports SSI's_ssi_spouse_index. The shared state supplement helper andminimum_payment.yamlare 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:
ia_ssa_care_additional_deductions.DEPENDENT_PERSONcertification covers;ia_ssa_care_additional_deductions;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:
ia_ssa_category, the care costs and rates, oria_ssa_smme_coverage_eligible. So in microsimulation only the blind supplement is paid.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:
spm_unit_benefits(such as the Texas rebate's), which this PR leaves unchanged.Interactions with open federal PRs
excluded_unearned_sources.yamland its two uses, inia_ssa_care_countable_income.pyandia_ssa.py, or Iowa excludes them twice. Case 109 catches this: a residential care resident with $1,100 of Social Security and $50 of dividends gets $222.57, and a double exclusion gives $272.57.is_ssi_spousal_deeming_applies, and itsia_ssavalues are the same under either amount.is_ssi_spousal_deeming_appliesinia_ssa.py,ssi_countable_incomeinia_ssa_smme_countable_income.pyandia_ssa_federal.py, and the tax-unit sums ofssi_ineligible_child_allocationin_ia_ssa_smme_spouse_income.pyandia_ssa_ihhrc_participation.py, which would use the couple-scoped allocations.Test plan
ia_ssa.yaml, 12 inintegration.yaml, 7 inia_ssa_resources_deemed_from_parents.yaml, 6 inia_ssa_nonfinancial_eligible.yaml, 4 inia_ssa_income_deemed_from_parents.yaml) pass locally in onepolicyengine-corerun on this branch merged withmainat 8ea4342 (2da0ed3). They cover:household_state_benefitsandspm_unit_benefitstotals, with the in-home payment left out of SNAP and HUD income.ia_ssa_nonfinancial_eligible.yamlCase 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".ia_ssafrom either Iowa LIHEAP list fails LIHEAP integration Case 9.ia_ssa, and eachhousehold_net_incomematches its single-state control.test_source_conflicts.pyand the program registry tests pass locally on the merged tree (891 passed, 10 skipped).ruff format,ruff checkandgit diff --check.test_selective_test_batchescases that need thecoveragemodule the local environment lacks;test_no_group_variables_in_person_adds.pyneedshypothesisand wasn't run. They involve no Iowa file, and CI has the modules.changelog.d/.axiom: Iowa Code 249.3, 249.9A(1), 249.12(3); 441 IAC 51.4(3), 51.5(1)-(2), 51.7(2), 51.7(6), 52.1(1)-(4), 52.1(7), 75.1, 177.2(1)"f"-"g", 177.8(2), 177.9(4), and 177.4(1), 177.10(2) (IAC 2/5/25); 20 CFR 416.1112(c)(3), 416.1124(c)(22), 416.1163, 416.1167; Iowa HHS Employees' Manual 6-B, 7-E, 8-E, 8-F; POMS SI 01415.058 F TheAxiomFoundation/rulespec-us#1837 queued; Iowa LIHEAP FY26 manual Appendix C p.114 (State Supplementary Assistance as income) TheAxiomFoundation/rulespec-us#1834 queued