Assign SNAP take-up from reported receipt and the FNS participation rate#294
Assign SNAP take-up from reported receipt and the FNS participation rate#294daphnehanse11 wants to merge 1 commit into
Conversation
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>
… 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>
Add a snap_take_up source stage (manifest entry, runtime handler, frame transform, release gate, builder wiring) following the immigration and hours templates. Reported SPM_SNAPSUB recipients always take up; non-reporters fill via seeded stable-identity draws to the cited FNS 0.82 participation rate. Heals the published all-True landmine. Closes #243; second half of #248 alongside #293.
751491d to
5c9f905
Compare
|
Rebased onto current main ( Conflict resolutions were the same 11 additive anchor points as #293 — main's TANF/EITC take-up (#315) and eCPS-parity (#316) wiring interleaved with this PR's SNAP wiring. In Intended changes beyond conflict resolution:
Verified the rebased net diff against the original with interdiff — no other semantic drift. Full Note for merge order with #293: both PRs insert at the same manifest/builder anchor points; whichever merges second gets the same-shape trivial conflict both descriptions anticipate. 🤖 Generated with Claude Code |
|
Heads-up from the medicaid take-up workstream (#334/#337): once #337 lands, parity_gate fails on stale known-gap exemptions — any register entry whose layer the candidate now populates. This branch's SNAP stage will make |
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