Skip to content

Add per-vintage reported-coverage signal gate (#720) - #744

Merged
MaxGhenis merged 4 commits into
mainfrom
720-reported-coverage-vintage-gate
Aug 23, 2026
Merged

Add per-vintage reported-coverage signal gate (#720)#744
MaxGhenis merged 4 commits into
mainfrom
720-reported-coverage-vintage-gate

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Part of #720 (regression guard; the data-side re-extraction is tracked there and is not in this PR).

What

Adds us_reported_coverage_vintage_signal_gate (microcosm.build.us_runtime.cps_carried) and wires it into tools/build_us_fiscal_refresh_release.py: a base-frame hard gate (reported_coverage_vintage_gate, mirroring the pregnancy gate, with a persisted failure receipt before the early raise), an export-frame re-run under the #547 degraded-mode guard, and a reported_coverage_vintage_signal manifest entry.

The gate enforces the invariant the certified Build P artifact violated: every pooled source vintage — person_support_channel × source_year — must carry a fully populated, boolean column with at least one reporter for each of the nine reported-coverage person inputs (has_esi, has_marketplace_…, has_medicaid_…, has_non_marketplace_direct_purchase_…, has_champva_…, has_tricare_…, has_va_…, has_other_means_tested_…, has_indian_health_service_…_at_interview). On Build P the income-year 2022/2023 vintages had exactly zero reporters for seven of the nine (their SHA-locked inputs carry only NOW_GRP/NOW_MRK of the 18 NOW_* recodes) and _fill_health_coverage_inputs mapped NaN to False, thinning has_medicaid_health_coverage_at_interview to 24.6M under 65 against ~58M survey. Presence-style checks (release_input_coverage, degenerate_input_signal, ecps_parity) cannot see a partial-vintage hole; this gate can.

Behavior

Review

A cross-family adversarial review (sol) confirmed the root cause and hard-gate end state and raised five findings, all folded in here: source-family × vintage key, export-frame re-run, fail-closed provenance, completeness/dtype checks with observational failure text, and the persisted failure receipt. Its recompute also corrected two supporting claims in #720 (vintage labeling, selection direction) — see the issue comment.

Tests

  • packages/microcosm-build/tests/test_us_reported_coverage_vintage_gate.py (15): contract (the nine inputs are exactly the derived health-coverage flags), pass/fail shapes including the Build P 7×2 failure shape, ASEC/ACS channel separation, sub-threshold skip, fail-closed provenance (missing/null source_year), null-value and non-boolean-dtype failures, missing column, and a mechanism test running _fill_health_coverage_inputs on NaN NOW_* source rows.
  • test_us_fiscal_refresh_builder.py: _release_gate_failures includes the gate's failures with the Reported-coverage vintage signal failed: prefix; the failure receipt is written and does not make the directory look certified; the terminal-batch degraded-mode tests stub the gate like every other base-frame signal gate.

No artifacts are published or promoted by this PR.

🤖 Generated with Claude Code

Every pooled ASEC source_year must carry at least one reporter for each
of the nine reported-coverage person inputs. On the certified Build P
artifact the 2022/2023 vintage inputs lacked the NOW_* at-interview
recodes (except NOW_GRP/NOW_MRK), so seven of the nine flags were False
for two-thirds of the weighted population and reported Medicaid at
interview thinned to 24.6M under 65 against ~58M survey. Presence-style
checks cannot see a partial-vintage hole; this gate ships red against
current bases by design and turns green with the #720 re-extraction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MaxGhenis and others added 3 commits August 23, 2026 10:33
… test

The #547 degraded-mode test drives main() against a fake frame whose
table() only serves the household table; every base-frame signal gate
is monkeypatched there, and the new gate must be too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Key groups by person_support_channel x source_year so ACS-spine signal
  cannot mask a missing ASEC recode (both carry source_year).
- Fail closed on provenance: missing source_year column, null source
  years, or an empty person table fail instead of collapsing to one group.
- Require full population and boolean dtype per vintage, not just one
  truthy value; failure text is observational (zero reporters), with the
  #720 source-input reading as the documented cause.
- Re-run the gate on the export frame (sparse selection can drop a
  vintage's reporters) under the #547 degraded-mode guard.
- Persist a failure receipt in the release directory before the early
  raise so RED is durable without staging telemetry; the receipt does not
  mark the directory certified (#568).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
test_us_spine_blindness requires runtime population operators to stay
source-spine blind: only the reviewed provenance-owner modules may read
person_support_channel. The gate is origin-aware by charter (it keys
vintages by support channel so ACS signal cannot mask a missing ASEC
recode), so it lives in support_provenance.py; cps_carried.py keeps the
input list, the threshold, and the derivation. The inputs import is lazy
because cps_carried -> alimony -> support_provenance would otherwise cycle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Pushed 093daef3: the gate moved from cps_carried.py to support_provenance.py. test_us_spine_blindness requires runtime population operators to stay source-spine blind (only provenance-owner modules may read person_support_channel), and the hardened gate keys vintages by support channel — origin-aware by charter, so it belongs with the provenance owners. cps_carried.py keeps the input list, threshold, and derivation. Spine-blindness, gate, and builder suites pass locally.

Proof on real data (microcosm #720 fix, not in this PR): the source_construction stage rerun with the income-year 2022/2023 ASEC inputs augmented to the 2024 column set gives NOW_MCAID 0% null in all three vintages and the gate passes (Medicaid reporters 28,184 / 26,367 / 24,844 by vintage); the same stage on the SHA-locked inputs fails it (receipt in #720 shortly).

@MaxGhenis
MaxGhenis merged commit 31640b9 into main Aug 23, 2026
4 checks passed
@MaxGhenis
MaxGhenis deleted the 720-reported-coverage-vintage-gate branch August 23, 2026 13:46
MaxGhenis added a commit that referenced this pull request Aug 23, 2026
…he union

Main moved the same attested surfaces today (#744, #674, #754), so the
merge re-cuts them over the union tree in one reviewed step, the d70ea39
pattern: release_input_coverage_manifest.json regenerated (145 required /
0 exclusions unchanged), the UK spec_sha256 re-pinned, and the three
gate-battery digests recomputed into the microcosm-data contract and its
test mirror.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant