Skip to content

Recalibrate SNAP take-up per state to FNS household caseloads#376

Open
daphnehanse11 wants to merge 1 commit into
snap-caseload-targetsfrom
snap-state-take-up
Open

Recalibrate SNAP take-up per state to FNS household caseloads#376
daphnehanse11 wants to merge 1 commit into
snap-caseload-targetsfrom
snap-state-take-up

Conversation

@daphnehanse11

Copy link
Copy Markdown
Collaborator

Implements #372. Stacked on #371 (base branch is snap-caseload-targets) — the take-up calibration consumes the same compiled snap_households target specs that PR adds, so the seed and the weight-calibration objective agree by construction.

Why

#294's national-rate fill bakes in CPS state underreporting: the buildi-sparse release undershoots ten state SNAP benefit targets by 7–43% while a per-record feasibility audit shows every state but California reachable under the 5× weight cap, and state taker-household counts err from −38% to +325% against FNS caseloads (full numbers in #372 and the #371 preview comment). The states that are short cannot be fixed by reweighting — they lack taker households; this stage supplies them.

What

A snap_state_take_up source stage following the medicaid_take_up pattern (#331) at SPM-unit grain, using the shared binary-assignment ops (#338):

  1. Anchor — units with reported ASEC receipt (SPM_SNAPSUB > 0) always take up, identical to the national stage's anchor.
  2. Fill — non-reporters draw at an in-build state rate (FNS average-monthly household count over weighted modeled-eligible units; an assignment prior, never cited as provenance per the contract's model-relative-ratio rule), then calibrate_binary_assignment greedily calibrates among eligible non-anchored units so each unsaturated state hits its FNS FY2024 count within unit-weight granularity.

The national snap_take_up stage remains as the prior; this stage recomputes the final surface after target compilation (it needs is_snap_eligible from the engine and the compiled targets, mirroring the Medicaid builder placement).

Deliberate carry-overs from the Medicaid stage: off-domain units keep a draw-based propensity (no hard-coded zero reform response), and saturation is recorded rather than failed (CA's ceiling is 1.05× its caseload — an eligibility-undercount symptom, not an assignment bug). Persons caseloads stay untargeted: the SNAP assistance unit is often a subset of the SPM unit, so member counts overcount FNS participants ~50% (see #371's second commit).

Gates and diagnostics

  • us_snap_state_take_up_gate (release-blocking): every state must carry an FNS target; anchors must survive calibration in every state (unit-level check); unsaturated states must land on their count within max(2%, one unit weight); positive count with zero eligible weight fails as an eligibility-feed collapse; caseload==eligibility with a reachable floor below it fails as the universal-take-up landmine.
  • us_snap_state_take_up.json release artifact + staging telemetry: per-state eligible/anchored/caseload weights, targets, saturation, plus national rollup.
  • Take-up contract: SNAP entry stays out_of_scope for Bernoulli seeding (it keeps a sourced national rate, which count_calibrated forbids) with scope_owner updated to name this stage as the final surface owner.

Tests

  • New test_us_snap_state_take_up.py (14 tests): manifest declaration, anchor derivation from raw subsidy, state fill-rate prior, exact count calibration in unsaturated states, saturation, anchor survival under downward pressure, empty-target refusal, and gate failure modes (missing state target, eligibility collapse, dropped anchor, count miss, universal-take-up landmine).
  • Builder main-path test extended with the new stage's monkeypatches.
  • Full populace-build suite passes (517 tests).

🤖 Generated with Claude Code

The snap_take_up stage (#294) anchors take-up on reported ASEC receipt and
fills non-reporters to the national FNS participation rate. CPS SNAP
receipt underreporting is strongly state-dependent, so the national fill
starves the worst-underreporting states of taker households no reweighting
can recover: the buildi-sparse release undershoots ten state benefit
targets by 7-43% while a feasibility audit shows every state but
California reachable under the weight cap, and state taker-household
counts err from -38% to +325% against FNS caseloads (#372).

Add a snap_state_take_up stage following the medicaid_take_up pattern
(#331) at SPM-unit grain: reported recipients always take up; the fill
draws at an in-build state rate (FNS average-monthly household count over
weighted modeled-eligible units, an assignment prior, never cited as
provenance) and is greedily calibrated to the FNS FY2024 state counts
among eligible non-anchored units. The targets are the same
snap_households rows the weight-calibration targets compile from, so the
seed and the calibration objective agree. Saturation is recorded, not
failed; a release gate enforces anchor preservation, per-state count
fidelity within unit-weight granularity, full state target coverage, and
the universal-take-up landmine.

Persons caseloads stay untargeted: the SNAP assistance unit is often a
subset of the SPM unit, so member counts overcount FNS participants by
roughly half.

Implements #372; stacked on the #371 caseload-target compilation.

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