Skip to content

Keep the SSI take-up flag informative under universal saturation#423

Merged
MaxGhenis merged 1 commit into
mainfrom
ssi-take-up-candidate-universe
Jul 14, 2026
Merged

Keep the SSI take-up flag informative under universal saturation#423
MaxGhenis merged 1 commit into
mainfrom
ssi-take-up-candidate-universe

Conversation

@MaxGhenis

Copy link
Copy Markdown
Contributor

Build M's sparse run failed the SSI take-up gate: takes_up_ssi_if_eligible came out True for the entire pool (constant; weighted share 1.0 on both channels). Diagnosis credit: the Build M runner agent, whose decomposition falsified the resource/SCF suspects (byte-identical across bases), localized the kill to _assign_sources, and produced the per-band table.

Mechanism. The assigner draws a population-wide reform propensity Bernoulli(min(target/capacity, 1)), then count-calibrates candidates. The restored disability battery (is_blind, is_disabled — engine-default False on every prior base) correctly created SSI candidates in all three SSA age bands; every band saturated (candidate capacity ≪ SSA target); the ratio degenerated to 1.0; Bernoulli(1.0) flagged everyone. Build J passed by accident — zero non-aged candidates meant only the 65+ band flagged, and 17.3% happened to sit in range.

Fix. Under saturation the reform-domain propensity falls back to the observed take-up rate among today's candidates (reporter mass / candidate capacity) — "a reform-newly-eligible household takes up at the rate today's modeled eligibles are observed reporting." Current-law recipiency is untouched in both regimes: only candidates are ever paid, and the saturated branch still selects every candidate. The subsampling regime is byte-identical to before.

Verification. New test saturates all three bands and pins: candidates fully selected, output non-constant, gate passes — fails on the old code, passes on the fix. Full SSI/take-up/contract suites green (65 tests); CI-version ruff clean.

The substantive finding underneath — modeled SSI candidate mass (~2M scaled) far below SSA's 7,404,820 recipients, the same undercount as the local artifact's SSI measurement — is a launch-documented modeling limitation for architecture week, not something this stage can repair; the gate now stays honest about it instead of degenerate.

🤖 Generated with Claude Code

Build M's first sparse run failed the SSI take-up gate with a constant
universal-True output. The restored disability battery (is_blind,
is_disabled — engine-default False on every prior base) correctly put
SSI candidates in all three SSA age bands; every band's candidate
capacity fell short of its SSA recipient target; the count-matching
ratio degenerated to 1.0; and the reform-domain Bernoulli then flagged
the entire pool. Build J only ever had aged candidates, so the same
code path flagged just the 65+ band and the share landed in range by
accident.

The count-matching ratio is a meaningful reform propensity only while
it subsamples. Under saturation, fall back to the observed take-up rate
among today's candidates (reporter mass over candidate capacity): a
household made eligible by a reform takes up at the rate today's
modeled eligibles are observed reporting. Current-law recipiency is
unchanged in both regimes — only candidates are ever paid, and the
saturated branch still selects every candidate.

The substantive gap the gate surfaced — modeled SSI candidate mass far
below SSA's 7.4M recipients, the same undercount visible in the local
artifact's SSI measurement — is a modeling issue tracked separately;
this change makes the take-up stage honest about it instead of
degenerate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@MaxGhenis MaxGhenis merged commit a228a91 into main Jul 14, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant