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 ASEC survey vintages 2022/2023/2024, and the 2022 and 2023 per-year raw H5 inputs never carried the NOW_* at-interview coverage recodes (except 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 survey vintages.source_year on the certified person table: 2022 (54,464 rows, 106.8M weighted), 2023 (54,654 rows, 105.7M), 2024 (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 lack the NOW_* coverage block. 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 matches the archived raw-lane converter: policyengine-us-data/datasets/cps/census_cps.py carries NOW_GRP and NOW_MRK in its person column list, and NOW_MCAID never appears anywhere in that file's git history (git log -S NOW_MCAID is empty); the 2024-vintage input was produced by a newer extraction that includes the full block. 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 are not the drivers. 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 frame's distinct retained ASEC-2023 source persons back to pppub23.csv by PERIDNUM: they capture 9.50% of full-survey under-65 population mass, 9.41% of NOW_MCAID mass, and 9.62% of NOW_GRP mass (original MARSUPWT) — household selection is coverage-neutral. If all three vintages carried the recodes at survey rates, the artifact would report ≈ 0.211 × 278.9M ≈ 59M under-65, consistent with the survey.
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).
Data side (the actual fix): re-extract the 2022 and 2023 per-year raw ASEC H5s with the full NOW_* at-interview coverage block and rebuild the pooled source base. The raw CSVs carry the data — verified for ASEC 2023 (pppub23.csv has NOW_MCAID, column 547); confirm ASEC 2022 at re-extraction. This runs in the gated data lane outside PR CI; no artifact publication is part of this issue.
Regression guard (small, PR-able now): a per-vintage reported-coverage signal gate — for each pooled 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.
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 ASEC survey vintages 2022/2023/2024, and the 2022 and 2023 per-year raw H5 inputs never carried theNOW_*at-interview coverage recodes (exceptNOW_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 survey vintages.
source_yearon the certified person table: 2022 (54,464 rows, 106.8M weighted), 2023 (54,654 rows, 105.7M), 2024 (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 lack the
NOW_*coverage block. 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 matches the archived raw-lane converter:policyengine-us-data/datasets/cps/census_cps.pycarriesNOW_GRPandNOW_MRKin its person column list, andNOW_MCAIDnever appears anywhere in that file's git history (git log -S NOW_MCAIDis empty); the 2024-vintage input was produced by a newer extraction that includes the full block. 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 are not the drivers. 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 frame's distinct retained ASEC-2023 source persons back to
pppub23.csvby PERIDNUM: they capture 9.50% of full-survey under-65 population mass, 9.41% ofNOW_MCAIDmass, and 9.62% ofNOW_GRPmass (original MARSUPWT) — household selection is coverage-neutral. If all three vintages carried the recodes at survey rates, the artifact would report ≈ 0.211 × 278.9M ≈ 59M under-65, consistent with the survey.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_*at-interview coverage block and rebuild the pooled source base. The raw CSVs carry the data — verified for ASEC 2023 (pppub23.csvhasNOW_MCAID, column 547); confirm ASEC 2022 at re-extraction. 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).