Add KFF eligible-uninsured moments and Medicaid 100% take-up reform rows - #69
Add KFF eligible-uninsured moments and Medicaid 100% take-up reform rows#69MaxGhenis wants to merge 14 commits into
Conversation
…ct probe The reported Medicaid-at-interview input sums to 24.6M under-65 on the sparse Build P artifact versus roughly 60M survey-reported Medicaid, leaving an 80.9M reported-uninsured denominator against roughly 27M ACS-reported nonelderly uninsured. Named on the joined rows so the 43.15% primary share reads with that context; modeled-uninsured and eligible-not-enrolled rows flagged as the informative counterparts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI runs pytest without pandas; the builder now reads extracts with csv/gzip and computes masks as boolean lists, matching the other pipeline modules. Rerunning it on the full-file extracts reproduces all 208 committed staged rows (worst relative value difference 1.7e-9, every non-numeric field identical). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolves the three blockers from the merge audit: - Blank or non-finite values in age/person_weight/medicaid now raise at parse (the denominator column keeps NaN, used only in the paired retention check); identity/anchor/bridge gates use NaN-proof inverted comparisons; JSON writes set allow_nan=False. - The full path requires the exact certified provenance triple via a shared require_certified_provenance (engine 1.764.6 / us-5.0.2 / Build P id) instead of trusting any self-consistent sidecar; the extractor calls the same pin. - The extractor validates provenance before any computation or write, and publishes CSV + metadata sidecar together via temp-and-rename, so a rejected rerun can no longer leave a fresh CSV beside a stale certified sidecar. New tests cover blank-cell rejection, denominator NaN tolerance, the anchor-passing full path, and rejection of a wrong-but-self-consistent triple (179 -> 183). Committed artifacts are unaffected: they are all finite, and under the previous lenient parser any blank in a strict column would have propagated NaN into them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vahid-ahmadi
left a comment
There was a problem hiding this comment.
Review — KFF eligible-uninsured moments + 100% take-up rows
Ran the branch locally (179 passed / 4 skipped, ruff clean, CI green) and verified the external side against the live source:
Verified:
- KFF values re-fetched from the live indicator page: US 24.9 / AL 9.5 / CA 32.5 / AK 40.8 / MD 23.3 all match
raw/state_indicator_2024acs_2025levels.mdexactly, vintage confirmed (2024 ACS, 2025 eligibility levels). Bonus: the page's own column header reads "Medicaid/Other Public Eligible" — matching the stagedSTATE_SOURCE_COLUMN, so thekff-column-label-verbatimcaution (annotations.json:47,source.jsondiagnosis_upstream) can be retired. - Take-up vocabulary is the engine's real input:
takes_up_medicaid_if_eligible(compute_kff_medicaid_extract.py:30) is incompute_counterparts.py's proven fulltakeup set (line 60), not a guessed name. - Arithmetic identities hold: 77.325 − 72.336 = 4.989M enrollment change; bridge 2.792 + 2.196 = 4.988 ≈ Δ within fp.
- reform_ref exhibit route is fail-loud: mutual exclusion with
external_claim_match, framework pin,reform_keycross-check all raise (ingest_campaign.py:176-199); idempotency stays exact-run_id, no prefix sweep. - The 80.9M reported-uninsured denominator anomaly is measured and honestly diagnosed (
annotations.jsonkff-medicaid-reported-denominator-sanity: thinned Medicaid-at-interview input, 24.6M vs ~60M survey).
Should consider:
- Primary/alternative designation contradicts the lane's own sanity annotation. The denominator annotation concludes the reported-uninsured share "is not a survey-faithful uninsured measure on this artifact" and names the modeled variant + eligible-and-not-enrolled counts as "the informative PolicyEngine rows for this join" — yet reported-uninsured (43.15%) is the primary construct and modeled (5.71%) the annotated alternative. A consumer surfacing primary rows shows exactly the comparison the lane says is uninformative. Either swap primacy, or carry the annotation's verdict onto the primary rows' display status so the 43.15%-vs-24.9% pairing can't render unqualified.
- Minor:
meta["note"](ingest_campaign.py:205,240) raises a bare KeyError on a note-less exhibit row rather than the labeled ValueError every sibling contract violation gets.
Solid lane overall — the construct-difference annotations are the most complete of any source in the repo.
|
Flagging a CI issue on this branch that isn't about its contents. This PR is running an older workflow than I found this auditing all 16 open PRs after hitting it on two of my own (#49 and #64, both since fixed). Four branches were affected; this is one of the two remaining. The fix is mechanical and nothing about your own changes needs to move: I haven't pushed to your branch. Happy to if you'd rather I did — say the word. There's also a structural fix in flight at #95: a |
Summary
policyengine_us_inputsReformRef route and stage the reform that forces annual Medicaid take-up to 100%, including enrollment, spending, and marginal-enrollee bridge rows for the US and every state.different_model,held_out, and eitherconcept_mismatchfor 2024 ornot_computedwith a dated 2024 reference for the 2022 claims.Results
The national eligible and enrolled estimates differ from the lane anchors by 0.03% and 0.05%, respectively. Enrollment change equals eligible minus enrolled, and the two bridge components sum to the enrollment change within floating-point precision.
The three largest absolute state differences in the primary eligible-share comparison are California (+31.99 percentage points PE minus KFF), Connecticut (+31.74), and Maryland (+28.25). These rows carry named construct differences rather than accuracy labels.
Construct annotations
has_esi, Marketplace-at-interview, non-Marketplace direct-purchase-at-interview, Medicaid-at-interview, TRICARE, VA, CHAMPVA, other-means-tested, or IHS coverage, plus not modeledmedicare_enrolled. The under-65 restriction is applied during moment aggregation.medicaid_enrolled, including anchor-and-fill enrollees presumed to have survey underreporting. KFF states no analogous underreporting correction.years_since_us_entry, so the engine's five-year-bar leg uses that variable's default.Staging and ingest
app/public/data/moments.json: 603 total rows, including 52 KFFconcept_mismatchrows and five KFFnot_computedrows with 2024 references.data/pe/.sources/campaign-20260818/us/, covering four components across the US plus 50 states and DC.data/scorecard.dbas 208 exhibits under canonical ReformRef key849973669b6526d6; offline re-ingest is idempotent./private/tmp.Ready-to-run ingest command:
Validation
pe.us.managed_microsimulation()on policyengine-us 1.764.6 and certified bundlepopulace-us-2024-buildp-sparse-rmloss100-cae8640-20260728T011454Z(us-5.0.2).uv run --offline --no-project --active pytest tests/ -q: 179 successful tests.app/node_modules; network access was prohibited, so no dependency install was attempted.Review findings (main session)
A post-lane probe of the certified artifact's person inputs found the
reported-uninsured denominator is not survey-faithful: 80.9M people under 65
carry none of the nine reported-coverage inputs, versus roughly 27M
ACS-reported nonelderly uninsured in 2024. Employer (146.9M under 65) and
Marketplace (21.4M) inputs sit near survey levels, but the reported
Medicaid-at-interview input sums to 24.6M under 65 against roughly 60M
survey-reported Medicaid — the sparse build thins it, and CMS-calibrated
modeled enrollment does not backfill the reported flag. Consequences, now
annotated on the joined rows:
denominator context; the modeled-uninsured variant (5.71%) and the
eligible-and-not-enrolled counts (2.79M uninsured marginal enrollees) are the
informative PE rows for this join.
denominator effect with a genuine construct difference: PE's eligibility
formula includes state coverage regardless of immigration status (e.g.
CA's
is_ca_medicaid_immigration_status_eligibleleg), while KFF's ACA-lenscategories class those people as ineligible due to immigration status.
thinning in the sparse build (adjacent to the untargeted-input zeroing class,
microcosm#361).
Follow-ups
Medicaid/Other Publicto a more specific metric label.🤖 Generated with Claude Code