Implement DC Optional State Supplemental Payment (OSSP)#7730
Implement DC Optional State Supplemental Payment (OSSP)#7730mattunrath wants to merge 7 commits intoPolicyEngine:mainfrom
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7730 +/- ##
===========================================
- Coverage 100.00% 94.00% -6.00%
===========================================
Files 18 7 -11
Lines 353 100 -253
Branches 4 2 -2
===========================================
- Hits 353 94 -259
- Misses 0 6 +6
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…t legal sources - Convert all variables to definition_period = MONTH - Derive OS-G from federal ssi_federal_living_arrangement (Code D) - Check both is_ssi_eligible AND ssi > 0 for actual SSI receipt - Use adds pattern for dc_ossp benefit variable - Add to spm_unit_benefits.py - Remove unused variables (dc_ossp_in_nursing_facility, dc_ossp_ssi_eligible, dc_ossp_resource_eligible) - Remove unused parameters (personal_needs_allowance, resource_limit) - Flatten parameter folder structure - Add 2011 historical values from SSA report - Verify 2026 values against SSA Publication No. 05-11162 - Fix changelog to use changelog.d/ format - Add integration tests through real SSI chain Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Couple rates now require both spouses to be OSSP-eligible and in the same living arrangement, matching SSI couple rules (20 CFR § 416.1101). Previously, any married person got couple/2 regardless of spouse status. Add payment values for 2018, 2023, 2024, 2025 from SSA POMS tables (SI 01415.050, .055, .056, .057, .058). Add OS-B and OS-G couple tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace 6 per-category files (os_a/individual.yaml, etc.) with 2 files using DCOSSPLivingArrangement enum breakdown (individual.yaml, couple.yaml). Add NONE: 0 so parameter lookup handles ineligible arrangements directly. Gate dc_ossp_payment_amount with defined_for = "dc_ossp_eligible" so ineligible people get 0 instead of a non-zero standard amount. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Closing — conflicts for 2+ weeks. Reopen after rebasing from upstream/main. |
PavelMakarchuk
left a comment
There was a problem hiding this comment.
Full Program Review: PR #7730 -- Implement DC Optional State Supplemental Payment (OSSP)
Source Documents Consulted
| Source | URL | Accessible | Notes |
|---|---|---|---|
| DC Code 4-205.49 | https://code.dccouncil.gov/us/dc/council/code/sections/4-205.49 | Yes | Defines facility size thresholds (50 beds), payment structure |
| SSA POMS SI 01415.058 (2026) | https://secure.ssa.gov/apps10/poms.nsf/lnx/0501415058 | Yes | 2026 payment tables verified |
| SSA POMS SI 01415.057 (2025) | https://secure.ssa.gov/apps10/poms.nsf/lnx/0501415057 | Yes | 2025 payment tables verified |
| SSA POMS SI 01415.056 (2024) | https://secure.ssa.gov/poms.nsf/lnx/0501415056 | Yes | 2024 payment tables verified |
| SSA POMS SI 01415.055 (2023) | https://secure.ssa.gov/apps10/poms.nsf/lnx/0501415055 | Yes | 2023 payment tables verified; OS-G effective 2/2023 |
| SSA POMS SI 01415.050 (2018) | https://secure.ssa.gov/apps10/poms.nsf/lnx/0501415050 | Yes | 2018 payment tables verified |
| SSA State Assistance 2011 DC | https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/dc.pdf | Blocked (403) | Cannot independently verify 2011 values |
| SSA POMS SI 01401.001 | https://secure.ssa.gov/apps10/poms.nsf/lnx/0501401001 | Yes | Confirms "state supplement only" cases exist |
| SSA Pub EN-05-11162 | https://www.ssa.gov/pubs/EN-05-11162.pdf | Blocked (403) | Referenced in code but inaccessible |
Critical (Must Fix)
C1. Missing income-excess reduction for "state supplement only" cases
Severity: HIGH
DC's OSSP is a federally administered supplement (confirmed by POMS SI 01415.058). Under SSA policy (POMS SI 01401.001, SI 02005.001), "state supplement only" recipients have countable income above the Federal Benefit Rate (FBR) but below the combined federal+state payment level. They receive $0 federal SSI but are still entitled to a reduced state supplement.
The PR's dc_ossp_eligible.py requires:
receives_ssi = person("ssi", period) > 0This excludes "state supplement only" cases. The correct pattern is to:
- Drop the
ssi > 0requirement from eligibility (use onlyis_ssi_eligible) - Add income-excess reduction in the payment variable using
uncapped_ssi
Reference implementations that do this correctly:
- Hawaii OSS (
hi_oss_eligible.py): uses onlyis_ssi_eligible, nossi > 0check - Hawaii OSS (
hi_oss.py):income_excess = max_(0, -uncapped_ssi); return max_(0, payment_standard - income_excess) - Delaware SSP (
de_ssp.py):reduction = max_(0, -uncapped_ssi); supplement = max_(0, per_person_amount - reduction)
Files affected:
policyengine_us/variables/gov/states/dc/dhcf/ossp/dc_ossp_eligible.py-- removereceives_ssirequirementpolicyengine_us/variables/gov/states/dc/dhcf/ossp/dc_ossp.py-- add reduction logic instead of bareadds
C2. Integration test Case 4 validates the wrong behavior
Severity: HIGH
Test Case 4 in integration.yaml ("income too high for SSI means no OSSP") asserts dc_ossp_eligible: false and dc_ossp: 0 for a person with $24,000/yr Social Security. This person has countable income of $1,980/mo which exceeds the FBR ($994) but may be below the combined FBR+supplement level ($994+$681=$1,675 for OS-A). If below the combined level, they should receive a reduced OSSP supplement as a "state supplement only" case.
Once C1 is fixed, this test case needs to be re-evaluated: the person would be eligible and would receive max(0, $681 - ($1,980 - $994)) = max(0, $681 - $986) = $0. So they'd still get $0 in this specific case (income excess exceeds supplement), but they should also be marked dc_ossp_eligible: true since they pass the categorical eligibility test.
Should Address
S1. Parameter values for 2011 cannot be independently verified
The 2011 values (individual OS_A=$485, OS_B=$595, OS_G=$40; couple OS_A=$1,307, OS_B=$1,527, OS_G=$80) are sourced from a PDF that returns HTTP 403. While the PR references this document, reviewers cannot verify these amounts.
Recommendation: Consider adding an alternative reference or noting that these are based on the cited SSA publication.
S2. URL casing inconsistency in reference
In couple.yaml and individual.yaml, the 2025 POMS reference uses mixed case:
href: https://secure.ssa.gov/apps10/poms.Nsf/lnx/0501415057#d
Note the capital N in poms.Nsf. While the SSA server appears case-insensitive, this is inconsistent with all other POMS URLs in the file which use lowercase poms.nsf. This should be normalized to lowercase for consistency.
S3. Missing programs.yaml entry
Per project instructions, policyengine_us/programs.yaml is the single source of truth for program coverage metadata. The DC OSSP program is not added to this file. An entry should be added following the pattern of other SSI state supplement programs.
S4. OS-G effective date for 2023 uses February, not January
Both individual.yaml and couple.yaml use 2023-02-01 for the OS_G values, while all other categories use 2023-01-01. The POMS confirms this is correct ("effective 2/2023"), so the code is accurate, but a brief code comment explaining why OS-G has a different effective date would help future maintainers.
S5. Couple rate logic does not use nb_persons() guard
In dc_ossp_payment_amount.py, the couple detection uses:
both_eligible = person.marital_unit.sum(eligible) == 2This is technically correct since marital units have at most 2 members, but the Hawaii implementation uses a more robust pattern:
both_ssi_eligible = person.marital_unit.sum(is_eligible) == person.marital_unit.nb_persons()This is more defensive against edge cases. Consider adopting the Hawaii pattern.
Suggestions (Non-blocking)
G1. Consider reusing ssi_medicaid_pays_majority_of_care variable name in test labels
Test case 4 references "Medicaid facility" in the test name but uses ssi_lives_in_medical_treatment_facility and ssi_medicaid_pays_majority_of_care as inputs. The terminology is consistent with SSA nomenclature but could be clarified in test names to distinguish between "medical treatment facility" (the federal SSI concept) and "Medicaid facility" (the DC OSSP OS-G concept).
G2. Consider adding test for boundary facility size
There is no test with dc_ossp_facility_size = 50 (exactly at the threshold). The threshold parameter uses <=, so a facility with exactly 50 beds should be OS-A. Adding a boundary test would strengthen confidence.
G3. Consider adding test for blind SSI recipients
The implementation correctly inherits blind eligibility via is_ssi_eligible -> is_ssi_aged_blind_disabled, but no tests exercise a blind person's path to OSSP eligibility.
G4. Consider adding test for a person who is in both AFC and medical facility
The select() in dc_ossp_living_arrangement.py gives priority to AFC (OS-A/OS-B) over medical facility (OS-G). If a person has dc_ossp_in_adult_foster_care = true AND ssi_lives_in_medical_treatment_facility = true, the AFC codes would take precedence. This priority ordering should be verified against regulations and tested.
G5. dc_ossp uses adds but should likely use a formula
The dc_ossp variable uses adds = ["dc_ossp_payment_amount"] which is a simple passthrough. Once C1 is addressed (adding income-excess reduction), this will need a formula. Even without C1, using adds with a single component is unusual -- a formula is more explicit.
Validation Summary
| Parameter | Year | Source | PR Value | Verified |
|---|---|---|---|---|
| Individual OS-A | 2026 | POMS 01415.058 | $681 | Yes |
| Individual OS-B | 2026 | POMS 01415.058 | $791 | Yes |
| Individual OS-G | 2026 | POMS 01415.058 | $79 | Yes |
| Couple OS-A | 2026 | POMS 01415.058 | $1,717 | Yes |
| Couple OS-B | 2026 | POMS 01415.058 | $1,937 | Yes |
| Couple OS-G | 2026 | POMS 01415.058 | $158 | Yes |
| Individual OS-A | 2025 | POMS 01415.057 | $678 | Yes |
| Individual OS-B | 2025 | POMS 01415.057 | $788 | Yes |
| Individual OS-G | 2025 | POMS 01415.057 | $76 | Yes |
| Couple OS-A | 2025 | POMS 01415.057 | $1,711 | Yes |
| Couple OS-B | 2025 | POMS 01415.057 | $1,931 | Yes |
| Couple OS-G | 2025 | POMS 01415.057 | $152 | Yes |
| Individual OS-A | 2024 | POMS 01415.056 | $674.16 | Yes |
| Individual OS-B | 2024 | POMS 01415.056 | $784.16 | Yes |
| Individual OS-G | 2024 | POMS 01415.056 | $73.20 | Yes |
| Couple OS-A | 2024 | POMS 01415.056 | $1,704.32 | Yes |
| Couple OS-B | 2024 | POMS 01415.056 | $1,924.32 | Yes |
| Couple OS-G | 2024 | POMS 01415.056 | $146.40 | Yes |
| Individual OS-A | 2023 | POMS 01415.055 | $640 | Yes |
| Individual OS-B | 2023 | POMS 01415.055 | $750 | Yes |
| Individual OS-G | 2023 (Feb) | POMS 01415.055 | $70 | Yes |
| Couple OS-A | 2023 | POMS 01415.055 | $1,636 | Yes |
| Couple OS-B | 2023 | POMS 01415.055 | $1,856 | Yes |
| Couple OS-G | 2023 (Feb) | POMS 01415.055 | $140 | Yes |
| Individual OS-A | 2018 | POMS 01415.050 | $640 | Yes |
| Individual OS-B | 2018 | POMS 01415.050 | $750 | Yes |
| Individual OS-G | 2018 | POMS 01415.050 | $40 | Yes |
| Couple OS-A | 2018 | POMS 01415.050 | $1,636 | Yes |
| Couple OS-B | 2018 | POMS 01415.050 | $1,856 | Yes |
| Couple OS-G | 2018 | POMS 01415.050 | $80 | Yes |
| Individual OS-A | 2011 | SSA 2011 DC PDF | $485 | Unverifiable (403) |
| Individual OS-B | 2011 | SSA 2011 DC PDF | $595 | Unverifiable (403) |
| Individual OS-G | 2011 | SSA 2011 DC PDF | $40 | Unverifiable (403) |
| Couple OS-A | 2011 | SSA 2011 DC PDF | $1,307 | Unverifiable (403) |
| Couple OS-B | 2011 | SSA 2011 DC PDF | $1,527 | Unverifiable (403) |
| Couple OS-G | 2011 | SSA 2011 DC PDF | $80 | Unverifiable (403) |
| Facility threshold | All | DC Code 4-205.49 | 50 | Yes |
Code Pattern Assessment
| Check | Status | Notes |
|---|---|---|
| Variable naming | Pass | Follows dc_ossp_* convention |
| Entity levels | Pass | All Person-level, consistent with HI/DE SSP |
| Period usage | Pass | period.this_year correctly used for YEAR-defined inputs |
| Changelog fragment | Pass | changelog.d/add-dc-ossp.added.md present |
| Parameter formatting | Pass | YAML structure follows project conventions |
defined_for usage |
Pass | Uses StateCode.DC and "dc_ossp_eligible" |
| Import pattern | Pass | Cross-module enum imports follow HI OSS pattern |
| SPM unit benefits | Pass | Added to spm_unit_benefits.py |
| Household state benefits | Pass | Added to both 2023 and 2024 blocks |
programs.yaml |
Missing | No entry added |
Review Severity
REQUEST_CHANGES
The missing income-excess reduction logic (C1) is a substantive regulatory accuracy issue. DC's OSSP is a federally administered supplement, and SSA policy explicitly requires supporting "state supplement only" cases. The current implementation would incorrectly exclude these recipients. Both Hawaii OSS and Delaware SSP -- the closest comparable implementations in the codebase -- correctly implement this reduction. The integration test (C2) validates the incorrect behavior.
Generated with Claude Code
Summary
Implements DC's Optional State Supplemental Payment (OSSP) — a state supplement to federal SSI for people in adult foster care homes and Medicaid facilities in the District of Columbia.
Closes #7729
Regulatory Authority
Program Overview
Eligibility
is_ssi_eligiblessi > 0defined_for = StateCode.DCdc_ossp_living_arrangement != NONELiving Arrangement Categories
dc_ossp_in_adult_foster_care+dc_ossp_facility_size <= 50dc_ossp_in_adult_foster_care+dc_ossp_facility_size > 50ssi_federal_living_arrangement == MEDICAL_TREATMENT_FACILITYBenefit Amounts — State Supplementation Only
All values from SSA POMS "State Supplement Level" column:
Year coverage: 2011, 2018, 2023, 2024, 2025, 2026
Sources by year:
Couple treatment: Couple rate requires both spouses OSSP-eligible in the same arrangement (per SSI couple rules, 20 CFR § 416.1101). Total couple amount divided by 2 per person. Mixed couples (one spouse not eligible or different arrangement) get individual rate.
Not Modeled (by design)
Files
Test plan
🤖 Generated with Claude Code