Skip to content

Full eCPS input-column coverage as a HARD release gate + reform-coverage smoke (#368 Deliverable 1)#369

Merged
MaxGhenis merged 7 commits into
mainfrom
buildj-coverage-gate
Jul 9, 2026
Merged

Full eCPS input-column coverage as a HARD release gate + reform-coverage smoke (#368 Deliverable 1)#369
MaxGhenis merged 7 commits into
mainfrom
buildj-coverage-gate

Conversation

@MaxGhenis

Copy link
Copy Markdown
Contributor

Deliverable 1 of #368 — the HARD coverage gate

Closes Deliverable 1 of #368. This makes full eCPS input-column coverage a hard
release gate and wires the reform-coverage smoke into the release tool.

This gate is RED on today's artifacts by design — that is the deliverable, not
a regression.
Per Max's order, the three SSI countable-resource asset inputs
(bank_account_assets, stock_assets, bond_assets) ship as hard requirements
with no reviewed exclusion. They are currently absent from the export, so
both the column gate and the SSI reform probe fail on the current dense and
sparse defaults. Deliverable 2 (porting the SCF asset stage) restores them and
turns the gate green. A gate that fails the current default is the point: it is
exactly the check that would have blocked the certification where an SSI
asset-limit reform ($10k/$20k) scored $0.

What this adds

  • Column-coverage contract. A versioned in-repo manifest declares every
    input column the pinned reference eCPS populates (158 layers): 58 required
  • Release-tool wiring. tools/build_us_fiscal_refresh_release.py runs the
    manifest anti-rot preflight before calibration, the column gate on the
    calibrated export before write_dataset, and the reform-coverage smoke on the
    written H5 — on both the dense and sparse default paths, aborting the
    release like the export-mass parity gate. Each writes a JSON artifact
    (input_coverage.json, reform_coverage_smoke.json).
  • Reform-coverage smoke. A pinned bound reform that scores ~$0 fails the
    release. First probe: SSI asset limits $10k/$20k (dense-native reference
    +$1.6B; no-limit ≈ +$16.1B, Sparse-57k certified release drops SSI asset input columns; SSI resource-test reforms score $0 on bundle 4.18.8 #356). It binds only through the SSI asset leaves,
    so it is $0 while they are absent.
  • Manifest anti-rot. assert_release_input_coverage_manifest_current proves
    the declared surface equals the reference eCPS populated layers, keeps the SSI
    assets as hard requirements, and (against the live engine, when available)
    checks every declared column is a real PE-US input leaf.

Tests

test_release_input_coverage.py covers the five brief cases (full-set pass,
missing-column fail, degenerate-without-exclusion fail, stale-exclusion fail,
$0-bound-reform smoke fail) plus red-by-design guards (SSI assets stay required;
demoting one is rejected) and a generator/​manifest sync guard — all isolated
from policyengine-us via a real Frame, a stub engine, an injected simulate,
and a monkeypatched reform builder.

CI safety

CI runs the test suite (uv run pytest) and lint (uv run ruff check .), not
releases — so this gate does not block CI; it blocks the release build. The
tests validate the gate logic without policyengine-us. This PR also fixes a
live-tree-guard break the prior manifest commit introduced (its reference
field named the retired data package).

Refs: #340, #356, #361, #278, #350 (mechanism), #286 (cannot-rot), #323, #359,
policyengine.py#463.

🤖 Generated with Claude Code

MaxGhenis and others added 7 commits July 9, 2026 09:11
…anifest (#368)

Generalizes the #350 required-source-columns mechanism to the full reference
eCPS input surface. input_column_coverage_gate() fails a required column that is
absent OR present-but-degenerate, with #286 cannot-rot reviewed exclusions.

Manifest derived from the pinned eCPS parity reference + known-gaps register:
58 required (incl. the 3 SSI countable-resource assets with NO exclusion per
#368) + 100 reviewed exclusions = the 158 populated eCPS input layers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
#368)

release_input_coverage.py: manifest loader, us_release_input_coverage_gate over
an export frame, and assert_release_input_coverage_manifest_current anti-rot
(manifest must equal the pinned eCPS surface; SSI assets must stay required;
every declared column a live PE-US input leaf).

reform_coverage_smoke.py: us_reform_coverage_smoke_gate — a pinned bound reform
scoring ~$0 fails the release. First probe: SSI $10k/$20k asset limits.

Registered in us_runtime __init__ and country_package.json resources.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ease tool (#368)

Complete Deliverable 1's release wiring: the coverage gate and reform-coverage
smoke now run in tools/build_us_fiscal_refresh_release.py on BOTH the dense and
sparse default paths, aborting the release exactly like the export-mass parity
gate.

- Preflight: assert_release_input_coverage_manifest_current() runs before the
  expensive calibration, so a manifest that has drifted from the pinned eCPS
  surface (or quietly demoted the SSI assets) fails fast.
- After the calibrated export frame is built and before write_dataset:
  us_release_input_coverage_gate scores every required eCPS input column for
  presence + non-degenerate signal, writes input_coverage.json, and raises on
  failure (--allow-input-coverage-gaps is a diagnostic-only escape hatch;
  release builds leave it unset).
- After write_dataset: us_reform_coverage_smoke_gate scores the pinned bound
  reforms on the written H5 (first probe: SSI asset limits $10k/$20k), writes
  reform_coverage_smoke.json, and raises on a ~$0 bound reform.

The SSI countable-resource assets ship as hard requirements with no reviewed
exclusion, so both gates are RED on today's asset-less artifacts by design;
Deliverable 2 (asset-stage restoration) turns them green.

Also re-export input_column_coverage_gate from populace.build to match every
sibling gate, and drop an unused import the loader carried.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The generated coverage manifest copied the eCPS parity reference's full source
block into its own "reference" field, which carried the retired data package's
repo id. The manifest is not on the incumbent-reference allow-list, so that
tripped the live-tree guard (test_us_plan.test_no_incumbent_data_package_
references_in_live_tree) and would have failed CI.

Nothing reads the manifest's reference field — the gate and the anti-rot check
derive the column surface from ecps_parity_reference.json directly — so the
generator now records only the sha-locked coordinates that do not name a package
(filename, content sha256, revision, vintage, period) plus a derived_from
pointer to that allow-listed parity reference. Column set is unchanged (58
required incl. the 3 SSI assets, 100 reviewed exclusions).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The five acceptance cases from the brief, plus red-by-design and anti-drift
guards, all isolated from policyengine-us (real Frame, a stub engine exposing
only default_values, an injected simulate, and a monkeypatched reform builder):

- full required set present with signal passes;
- a missing required column fails, named;
- a required column present but all-engine-default fails without an exclusion;
- a reviewed exclusion whose column has caught up (present with signal) is stale
  and fails (#286 cannot-rot);
- a bound reform scoring ~$0 fails the reform-coverage smoke (and a nonzero
  effect passes; a probe-less gate is refused).

Shipped-manifest guards: the SSI assets stay required with no exclusion, the SSI
probe binds through them, demoting an asset to a reviewed exclusion is rejected,
and the committed manifest matches regeneration and names no retired data
package — so neither the manifest nor the generator can silently rot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… register (65 required / 93 exclusions / 1 probe) (#368)

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