Skip to content

Assign SNAP take-up from reported receipt and the FNS participation rate#294

Draft
daphnehanse11 wants to merge 2 commits into
mainfrom
snap-take-up-stage
Draft

Assign SNAP take-up from reported receipt and the FNS participation rate#294
daphnehanse11 wants to merge 2 commits into
mainfrom
snap-take-up-stage

Conversation

@daphnehanse11

Copy link
Copy Markdown
Collaborator

Summary

Closes #243. Second half of the SNAP work-requirements input surface (#248), alongside #293 (hours).

The published dataset ships takes_up_snap_if_eligible constant True (or omits it — same engine default), so PolicyEngine-US pays SNAP to 100% of eligible units. FNS measures participation among the eligible at ~82%. Universal take-up misstates who receives SNAP and overstates the reach of any eligibility-side reform.

This adds a snap_take_up source stage following the #266/#293 template: manifest entry + shared runtime handler + frame transform + release gate + builder wiring.

Semantics (identical to the retired enhanced-CPS pipeline)

  1. Reported recipients always take up — SPM units with positive raw ASEC SPM_SNAPSUB reported receiving SNAP; survey measurement wins unconditionally.
  2. Non-reporters fill to the published rate — seeded draws grant take-up at exactly the fill rate needed for the overall weighted share to land on the manifest's cited FNS rate (0.82). When reporters alone exceed the rate, nothing is forced — the share is emergent.
  3. Eligibility stays the engine's job — the flag is assigned across all units and PE-US intersects it with modeled eligibility, matching the retired pipeline.

Draws are blake2b hashes keyed by stable source identity (source_year/source_household_id/min source_person_id), so support-channel clones of one source unit always agree and reruns are bit-reproducible. The rate lives in the manifest with its FNS citation — a rate without a citation refuses to run.

Healing + gate

  • The frame transform is idempotent on a signal-carrying column and recomputes when the column is constant — the published all-True landmine is repaired, not trusted.
  • Release gate (snap_take_up_signal): column nonconstant, every reporting unit takes up (anchor preserved), weighted share within [0.70, 0.95]. Threaded through release gate failures, calibration diagnostics, and both manifests, mirroring the immigration and hours gates.

Verification

  • 18 new tests (manifest declaration, anchor/fill/overflow semantics, seed stability, clone consistency, citation enforcement, healing path, gate failure modes); full populace-build suite green.
  • End-to-end against the current 233,716-SPM-unit base: take-up share 0.821 (target 0.82), reported share 0.107 (CPS underreporting is exactly why the fill exists), zero reporters denied, gate green.

Follow-up (not in this PR)

State-calibrated take-up (greedy fill against FNS state household counts, the calibrate_binary_assignment machinery) is deliberately deferred: FNS state counts are average-monthly while the flag is annual-ever, and that bridge deserves its own reviewed decision — see the discussion on #292. National-rate + reported-anchor matches the retired pipeline's published behavior.

Merge-order notes

🤖 Generated with Claude Code

daphnehanse11 and others added 2 commits July 2, 2026 13:38
The published dataset either omits takes_up_snap_if_eligible or ships
it constant True — the engine default — so PolicyEngine-US pays SNAP
to 100% of eligible units. FNS measures participation among the
eligible at roughly 82%, so universal take-up misstates who receives
SNAP and overstates the reach of eligibility-side reforms (populace
#243).

Add a snap_take_up source stage with the retired enhanced-CPS
pipeline's semantics: SPM units whose raw ASEC SPM_SNAPSUB subsidy is
positive reported receiving SNAP and always take up; non-reporting
units receive seeded draws at exactly the fill rate needed for the
overall weighted take-up share to land on the manifest's cited FNS
participation rate (0.82), with the share emergent when reporters
alone exceed it. Draws are blake2b hashes keyed by stable source
identity so support-channel clones of one source unit always agree
and reruns are bit-reproducible. The rate is manifest data with its
citation, not code.

The frame transform is idempotent when the column carries signal and
recomputes when it is constant, healing the published all-True
landmine. A release gate requires the column nonconstant, every
reporting unit taking up, and the weighted share within [0.70, 0.95];
it threads through release gate failures, calibration diagnostics,
and both manifests alongside the immigration gate.

Verified against the current 233,716-unit base: take-up share 0.821,
reported share 0.107, zero reporters denied, gate green.

Closes #243

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

Carry SNAP reported amounts and take-up inputs through Populace US outputs

1 participant