You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Pooled ASEC 2022/2023 vintages lack the NOW_* coverage recodes: reported Medicaid at interview thins to 24.6M vs ~58M survey under 65 on the certified artifact #720
On the certified default artifact (hf://policyengine/populace-us/populace_us_2024.h5@populace-us-2024-buildp-sparse-rmloss100-cae8640-20260728T011454Z), the reported-coverage person input has_medicaid_health_coverage_at_interview sums to 24.6M weighted under-65 persons versus ~57.5M survey-reported (CPS ASEC 2023 NOW_MCAID, MARSUPWT). Root cause: the pooled support spine stacks three ASEC vintages keyed by income year (source_year 2022/2023/2024 = the ASEC 2023/2024/2025 survey files), and the income-year-2022 and -2023 raw H5 inputs carry only 2 of the 18 NOW_* at-interview coverage recodes (NOW_GRP and NOW_MRK). The CPS-carried derivation maps missing/NaN source values to False, so roughly two-thirds of the weighted population — every 2022- and 2023-vintage person, 173.2M weighted under 65 — is structurally unable to report Medicaid (or TRICARE, VA, CHAMPVA, IHS, other-means-tested, or non-marketplace direct-purchase) coverage.
has_esi and has_marketplace_health_coverage_at_interview escape only because NOW_GRP and NOW_MRK happen to be the two NOW_* columns the archived raw-lane converter carried for all vintages.
Downstream consequence (policyengine-scorecard PR #69, annotation kff-medicaid-reported-denominator-sanity): the "no reported coverage" construct identifies 80.9M under-65 persons versus 25.9M survey uninsured-at-interview (NOW_COV==2, ASEC 2023) and ~27M ACS nonelderly uninsured, so uninsured-population constructs on the certified artifact are not survey-faithful. Modeled enrollment is separately CMS-calibrated and does not backfill the reported flag.
No artifacts were published or promoted as part of this investigation.
Reproduction
Weighted person counts on the certified artifact (person-table columns × household weight; the columns are physically present in the h5 and the engine surface reads them as-is), against full-file CPS ASEC 2023 (MARSUPWT/100):
The marketplace flag tracks NOW_MRK one-to-one on all vintages, so its level above the ASEC 2023 survey reflects vintage composition and calibration-era weighting, not the missing-column mechanism (out of scope here).
Artifact totals: 340.1M persons, 278.9M under 65 (57,240 households, 166,321 person rows; pe-us pin 1.764.6 per the build manifest).
The pooled spine stacks three ASEC vintages keyed by income year.source_year on the certified person table: 2022 = ASEC 2023 survey (54,464 rows, 106.8M weighted), 2023 = ASEC 2024 (54,654 rows, 105.7M), 2024 = ASEC 2025 (57,203 rows, 127.6M). Pooling unions per-year columns via pd.concat (asec_pool.py#L141), leaving NaN where a vintage lacks a column.
The 2022/2023 raw H5 inputs carry only 2 of the 18 NOW_* fields. On the certified frame, NOW_MCAID, NOW_CAID, NOW_COV, NOW_MRKS, NOW_MRKUN, NOW_PCHIP, NOW_CHAMPVA, NOW_VACARE, NOW_MIL, NOW_IHSFLG, NOW_NONM, NOW_OTHMT, NOW_PUB, NOW_PRIV, NOW_DIR are populated on exactly the 57,203 2024-vintage rows and NaN on all 109,118 rows from 2022/2023. Only NOW_GRP and NOW_MRK are populated for all vintages. This is a property of the SHA-locked inputs themselves: policyengine_us_data/storage/census_cps_2022.h5 (146,133 persons = pppub23, 100% PERIDNUM match; 137 person columns; NOW_* = {NOW_GRP, NOW_MRK}), census_cps_2023.h5 (144,265 persons = ASEC 2024; 138 columns; the same two), census_cps_2024.h5 (142,125 persons = ASEC 2025; 162 columns; all 18 NOW_* fields). The 2022/2023 inputs match the archived policyengine-us-data extractor's column list before 410f63a7 ("Add CPS current health coverage anchors", 2026-03-20, which added the broader block); the 2024 input was extracted with it. The input-coverage manifest already documents this vintage asymmetry for other fields ("The 2022 and 2023 inputs also omit PECOHAB, A_EXPRRP, and A_FAMREL; only 2024 carries those alternatives" — is_unmarried_partner_of_household_head exclusion; same pattern in the employer_sponsored_insurance_premiums exclusion, Track SPM-specific input gaps: housing, WIC, school meals, child support, workers comp, and expense deductions #32).
The 2024-vintage slice is survey-plausible; selection and reweighting push the other way. Within the 2024 vintage the flag carries 24.6M of 105.7M under-65 = 23.3%, versus 21.1% in full ASEC 2023 (57.5M of 272.7M). Joining the 2022-vintage rows back to pppub23.csv by PERIDNUM (100% match, zero age mismatches), the under-65 Medicaid-at-interview rate moves from 21.1% in the full survey to 23.8% among the selected source persons, 24.5% with support clones, and 25.8% under final artifact weights — selection and calibration mildly enrich reporters, the opposite direction from the thinning. Counterfactual scale: restoring the raw codes on the artifact's existing rows and weights gives ≈ 70M under 65 (22.7M on the 2022 vintage, verified directly against pppub23; the 2023 slice extrapolated at the same enrichment; 24.6M already on 2024); at survey rates ≈ 0.211 × 278.9M ≈ 59M. A rebuild reselects and reweights, so neither is a guaranteed post-fix value — the point is the scale, ~2.5–3× today's 24.6M.
The Medicaid take-up stage consumes the already-thinned anchor.medicaid_take_up.py anchors on the flag (eligible reporters always take up) and hard-fails only if the column is absent (L173-L177) — there is no guard on per-vintage coverage. The CMS state-count fill compensates in enrollment terms, so enrollment-side calibration passes while the reported-coverage denominator stays thinned; the thinned anchor also shifts enrollment composition from reported toward filled and overstates saturation pressure (Add Medicaid and CHIP eligibility-to-enrollment diagnostics #170's diagnostic direction).
Scorecard follow-up: once a fixed artifact certifies, the kff-medicaid-reported-denominator-sanity annotation and the reported-uninsured rows in policyengine-scorecard PR Target latest eligible Ledger fiscal facts #69 can be revisited.
Numbers computed 2026-08-18 on the locally cached certified snapshot (26dcad668676…, sha256 48b9d479fb4f…) and asecpub23csv with policyengine-us 1.764.6 (the build pin).
Summary
On the certified default artifact (
hf://policyengine/populace-us/populace_us_2024.h5@populace-us-2024-buildp-sparse-rmloss100-cae8640-20260728T011454Z), the reported-coverage person inputhas_medicaid_health_coverage_at_interviewsums to 24.6M weighted under-65 persons versus ~57.5M survey-reported (CPS ASEC 2023NOW_MCAID, MARSUPWT). Root cause: the pooled support spine stacks three ASEC vintages keyed by income year (source_year2022/2023/2024 = the ASEC 2023/2024/2025 survey files), and the income-year-2022 and -2023 raw H5 inputs carry only 2 of the 18NOW_*at-interview coverage recodes (NOW_GRPandNOW_MRK). The CPS-carried derivation maps missing/NaN source values toFalse, so roughly two-thirds of the weighted population — every 2022- and 2023-vintage person, 173.2M weighted under 65 — is structurally unable to report Medicaid (or TRICARE, VA, CHAMPVA, IHS, other-means-tested, or non-marketplace direct-purchase) coverage.has_esiandhas_marketplace_health_coverage_at_interviewescape only becauseNOW_GRPandNOW_MRKhappen to be the twoNOW_*columns the archived raw-lane converter carried for all vintages.Downstream consequence (policyengine-scorecard PR #69, annotation
kff-medicaid-reported-denominator-sanity): the "no reported coverage" construct identifies 80.9M under-65 persons versus 25.9M survey uninsured-at-interview (NOW_COV==2, ASEC 2023) and ~27M ACS nonelderly uninsured, so uninsured-population constructs on the certified artifact are not survey-faithful. Modeled enrollment is separately CMS-calibrated and does not backfill the reported flag.No artifacts were published or promoted as part of this investigation.
Reproduction
Weighted person counts on the certified artifact (person-table columns × household weight; the columns are physically present in the h5 and the engine surface reads them as-is), against full-file CPS ASEC 2023 (MARSUPWT/100):
has_esiNOW_GRPhas_marketplace_health_coverage_at_interviewNOW_MRKhas_non_marketplace_direct_purchase_…_at_interviewNOW_NONMhas_medicaid_health_coverage_at_interviewNOW_MCAIDhas_champva_health_coverage_at_interviewNOW_CHAMPVAhas_tricare_health_coverage_at_interviewNOW_MILhas_va_health_coverage_at_interviewNOW_VACAREhas_other_means_tested_…_at_interviewNOW_OTHMThas_indian_health_service_coverage_at_interviewNOW_IHSFLGNOW_COV==2The marketplace flag tracks
NOW_MRKone-to-one on all vintages, so its level above the ASEC 2023 survey reflects vintage composition and calibration-era weighting, not the missing-column mechanism (out of scope here).Artifact totals: 340.1M persons, 278.9M under 65 (57,240 households, 166,321 person rows; pe-us pin 1.764.6 per the build manifest).
Compact repro (certified snapshot cached locally)
Root cause
The pooled spine stacks three ASEC vintages keyed by income year.
source_yearon the certified person table: 2022 = ASEC 2023 survey (54,464 rows, 106.8M weighted), 2023 = ASEC 2024 (54,654 rows, 105.7M), 2024 = ASEC 2025 (57,203 rows, 127.6M). Pooling unions per-year columns viapd.concat(asec_pool.py#L141), leaving NaN where a vintage lacks a column.The 2022/2023 raw H5 inputs carry only 2 of the 18
NOW_*fields. On the certified frame,NOW_MCAID,NOW_CAID,NOW_COV,NOW_MRKS,NOW_MRKUN,NOW_PCHIP,NOW_CHAMPVA,NOW_VACARE,NOW_MIL,NOW_IHSFLG,NOW_NONM,NOW_OTHMT,NOW_PUB,NOW_PRIV,NOW_DIRare populated on exactly the 57,203 2024-vintage rows and NaN on all 109,118 rows from 2022/2023. OnlyNOW_GRPandNOW_MRKare populated for all vintages. This is a property of the SHA-locked inputs themselves:policyengine_us_data/storage/census_cps_2022.h5(146,133 persons =pppub23, 100% PERIDNUM match; 137 person columns;NOW_*= {NOW_GRP,NOW_MRK}),census_cps_2023.h5(144,265 persons = ASEC 2024; 138 columns; the same two),census_cps_2024.h5(142,125 persons = ASEC 2025; 162 columns; all 18NOW_*fields). The 2022/2023 inputs match the archivedpolicyengine-us-dataextractor's column list before410f63a7("Add CPS current health coverage anchors", 2026-03-20, which added the broader block); the 2024 input was extracted with it. The input-coverage manifest already documents this vintage asymmetry for other fields ("The 2022 and 2023 inputs also omit PECOHAB, A_EXPRRP, and A_FAMREL; only 2024 carries those alternatives" —is_unmarried_partner_of_household_headexclusion; same pattern in theemployer_sponsored_insurance_premiumsexclusion, Track SPM-specific input gaps: housing, WIC, school meals, child support, workers comp, and expense deductions #32).The CPS-carried derivation silently maps missing to False.
_fill_health_coverage_inputsmapshas_medicaid_health_coverage_at_interview ← NOW_MCAID(L272) through_yes_code, where_sourcereturns zeros for an absent column andfillna(0.0)for NaN. The certified flag equalsNOW_MCAID == 1exactly (weighted crosstab: 24.6M both-true, 0.0M in either disagreement cell) — no later stage rewrites it, and the export carries it (this is not the Sparse-57k export drops 94 no-formula input columns from the dense parent (tips, overtime, disability flags, ESI premiums, rent, QBI basis) #361 export-drop class; the column is present).The 2024-vintage slice is survey-plausible; selection and reweighting push the other way. Within the 2024 vintage the flag carries 24.6M of 105.7M under-65 = 23.3%, versus 21.1% in full ASEC 2023 (57.5M of 272.7M). Joining the 2022-vintage rows back to
pppub23.csvby PERIDNUM (100% match, zero age mismatches), the under-65 Medicaid-at-interview rate moves from 21.1% in the full survey to 23.8% among the selected source persons, 24.5% with support clones, and 25.8% under final artifact weights — selection and calibration mildly enrich reporters, the opposite direction from the thinning. Counterfactual scale: restoring the raw codes on the artifact's existing rows and weights gives ≈ 70M under 65 (22.7M on the 2022 vintage, verified directly againstpppub23; the 2023 slice extrapolated at the same enrichment; 24.6M already on 2024); at survey rates ≈ 0.211 × 278.9M ≈ 59M. A rebuild reselects and reweights, so neither is a guaranteed post-fix value — the point is the scale, ~2.5–3× today's 24.6M.The Medicaid take-up stage consumes the already-thinned anchor.
medicaid_take_up.pyanchors on the flag (eligible reporters always take up) and hard-fails only if the column is absent (L173-L177) — there is no guard on per-vintage coverage. The CMS state-count fill compensates in enrollment terms, so enrollment-side calibration passes while the reported-coverage denominator stays thinned; the thinned anchor also shifts enrollment composition from reported toward filled and overstates saturation pressure (Add Medicaid and CHIP eligibility-to-enrollment diagnostics #170's diagnostic direction).Why certification passed
release_input_coveragerequires the column to be present with non-default signal ("Column mass parity is not column coverage" — the gate closes the absence class, Build J: full eCPS-exported-column coverage as a HARD release gate + asset-column restoration (SSI reforms score $0) #368); 24.6M true satisfies it.degenerate_input_signal(175 columns) passes any column that is neither all-default nor constant.health_input_signalchecks 2 columns (selected_marketplace_plan_benchmark_ratio,takes_up_aca_if_eligible) — no reported-coverage flags.ecps_parityis a populated-layer presence check (158 layers, 0 gaps).Nothing measures per-vintage signal or survey-mass fidelity for the reported-coverage family, so a flag populated for one of three vintages certifies.
Relationship to existing issues
receives_medicaidis never emitted whilehas_medicaid_health_coverage_at_interview"is emitted"; this issue sharpens that: it is emitted for the 2024 vintage only. Partial-vintage holes are invisible to presence-style checks.NOW_*coverage block for every vintage.Proposed fix
NOW_*-only patch, so the next missing field (Track SPM-specific input gaps: housing, WIC, school meals, child support, workers comp, and expense deductions #32'sNOW_OWNGRP/NOW_HIPAID/NOW_GRPFTYP, Populate remaining US tax-input and reported-observation layers #38'sPERRP/A_EXPRRP/PECOHAB) does not repeat this cycle, while any new derivations stay in separate PRs — and rebuild the pooled source base. Do it as one schema migration with Ingest ASEC 2024 and 2025 into the US support pool (spine is two vintages behind) #296 (whose body predates the ASEC 2025 ingest: Build P already consumes income years 2022–2024) after reconciling survey-year vs income-year naming. The raw CSVs carry the data — verified for ASEC 2023 (pppub23.csvhasNOW_MCAID, column 547). This runs in the gated data lane outside PR CI; no artifact publication is part of this issue.source_year, every reported-coverage input must carry non-default signal (the crisp invariant violated today: 2022/2023 vintages have exactly zero true mass for seven of the nine flags). Ships red against current bases by design, like the Build J: full eCPS-exported-column coverage as a HARD release gate + asset-column restoration (SSI reforms score $0) #368 asset gates, and turns green with the re-extraction.kff-medicaid-reported-denominator-sanityannotation and the reported-uninsured rows in policyengine-scorecard PR Target latest eligible Ledger fiscal facts #69 can be revisited.Numbers computed 2026-08-18 on the locally cached certified snapshot (
26dcad668676…, sha25648b9d479fb4f…) andasecpub23csvwith policyengine-us 1.764.6 (the build pin).