Assign SNAP take-up from reported receipt and the FNS participation rate#294
Draft
daphnehanse11 wants to merge 2 commits into
Draft
Assign SNAP take-up from reported receipt and the FNS participation rate#294daphnehanse11 wants to merge 2 commits into
daphnehanse11 wants to merge 2 commits into
Conversation
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>
MaxGhenis
added a commit
that referenced
this pull request
Jul 5, 2026
The two data-seeded take-up programs whose participation rate clears the provenance bar, assigned by calibrated Bernoulli at the administrative rate: - TANF (takes_up_tanf_if_eligible, spm_unit): 21.9% (HHS ASPE 24th Welfare Indicators Report, 2022, Table 10 Indicator 4). - EITC (takes_up_eitc, tax_unit): per-child rates (IRS National Taxpayer Advocate 2020, TY2016: 0=65%, 1=86%, 2=85%, 3+=82%). Child count is approximated from tax-unit member ages under 19; the rate is nearly flat above zero children so the coarse count picks the right bin. with_us_take_up_inputs seeds every program the take-up contract marks `seed` (and only those), keying draws on stable source identity so support-channel clones agree and reruns are bit-reproducible (the SNAP #294 keying). A frame already carrying a non-constant column passes through untouched; a missing or constant column is recomputed, so the published all-True landmine is healed. No reported-receipt column is threaded through the base spine, so assignment is calibrated Bernoulli rather than the SNAP reported-receipt anchor. us_take_up_summary and us_take_up_signal_gate expose the per-program participation-vs-administrative surface: weighted share, target rate, source, and a plausibility band, failing on a missing/constant column or an out-of-band share. Validated at n=8000: TANF share 0.210 (target 0.219); EITC per-bin 0.648/0.866/0.842/0.832 (targets 0.65/0.86/0.85/0.82); EITC overall 0.797 (IRS ~0.78). 17 seeding tests plus the gate failure modes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merged
9 tasks
MaxGhenis
added a commit
that referenced
this pull request
Jul 5, 2026
… take-up contract (#312) (#315) * Add engine-asserted take-up contract inventory (#312 step 1) The blocking first deliverable: a checked-in table classifying every policyengine-us take-up flag, asserted against the installed engine. - PolicyEngineUSEngine.take_up_variables() / take_up_contract() derive, from engine metadata, each takes_up_* flag's entity, default, whether the engine computes it (formula / adds / start-date formula), its consumers, and thus an engine_class (model_simulated / data_seeded / dead). Same metadata-derivation doctrine as the #301 formula-owned guard. - us/take_up_contract.json records the engine facts plus the curated populace treatment (seed / rate_unsourced / model_simulated / out_of_scope / near_universal) with each rate's administrative provenance. - assert_take_up_contract_current() fails the build when the table drifts from the pinned engine (new/renamed flag, a flag gaining a formula, a changed default); assert_take_up_treatments_consistent() catches treatments that contradict the engine class. The loader enforces the provenance rule: a program marked seed must carry a sourced administrative rate. Finding against pinned policyengine-us 1.752.2: all 13 take-up flags are data_seeded (default True, no formula, all consumed); there are no *_seed variables and no model-simulated take-up. The chip_take_up_seed / aca_take_up_seed model-side migration the issue references has not landed in the pinned engine. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Seed TANF and EITC take-up flags from administrative rates (#312 step 2) The two data-seeded take-up programs whose participation rate clears the provenance bar, assigned by calibrated Bernoulli at the administrative rate: - TANF (takes_up_tanf_if_eligible, spm_unit): 21.9% (HHS ASPE 24th Welfare Indicators Report, 2022, Table 10 Indicator 4). - EITC (takes_up_eitc, tax_unit): per-child rates (IRS National Taxpayer Advocate 2020, TY2016: 0=65%, 1=86%, 2=85%, 3+=82%). Child count is approximated from tax-unit member ages under 19; the rate is nearly flat above zero children so the coarse count picks the right bin. with_us_take_up_inputs seeds every program the take-up contract marks `seed` (and only those), keying draws on stable source identity so support-channel clones agree and reruns are bit-reproducible (the SNAP #294 keying). A frame already carrying a non-constant column passes through untouched; a missing or constant column is recomputed, so the published all-True landmine is healed. No reported-receipt column is threaded through the base spine, so assignment is calibrated Bernoulli rather than the SNAP reported-receipt anchor. us_take_up_summary and us_take_up_signal_gate expose the per-program participation-vs-administrative surface: weighted share, target rate, source, and a plausibility band, failing on a missing/constant column or an out-of-band share. Validated at n=8000: TANF share 0.210 (target 0.219); EITC per-bin 0.648/0.866/0.842/0.832 (targets 0.65/0.86/0.85/0.82); EITC overall 0.797 (IRS ~0.78). 17 seeding tests plus the gate failure modes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * WIP checkpoint: agent stopped mid-task; lead salvaged state Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * WIP checkpoint: agent killed (session limit / stop); lead salvaged Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Register take-up contract resource; fake take-up stages in the builder test; diagnostics test class Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Sort imports (ruff --fix) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #243. Second half of the SNAP work-requirements input surface (#248), alongside #293 (hours).
The published dataset ships
takes_up_snap_if_eligibleconstantTrue(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_upsource 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)
SPM_SNAPSUBreported receiving SNAP; survey measurement wins unconditionally.Draws are blake2b hashes keyed by stable source identity (
source_year/source_household_id/minsource_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
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
Follow-up (not in this PR)
State-calibrated take-up (greedy fill against FNS state household counts, the
calibrate_binary_assignmentmachinery) 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
takes_up_snap_if_eligiblereviewed exclusion in Gate releases on input columns stuck at the engine default #286's degenerate-input gate becomes stale and should be removed.🤖 Generated with Claude Code