From 34375fe6d1858657046b0f5304066623b5b47586 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 09:02:56 +0200 Subject: [PATCH 01/17] Document gate-failed release lane kickoff --- PROGRESS.md | 70 ++++++++++++----------------------------------------- 1 file changed, 16 insertions(+), 54 deletions(-) diff --git a/PROGRESS.md b/PROGRESS.md index 3036d509..7b82fba0 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -1,63 +1,25 @@ -# Progress: stacked-pool to release CD-vintage provenance +# Gate-failed base-pool release lane ## State -Implementation and validation are complete. The stacked -producer now authenticates and applies household geography after source -assembly, carries its authority through checkpoint and publication identities, -publishes verified CD-vintage H5 attributes, and reaches the unchanged release -guard through the shared fixed/table-aware reader -(`tools/build_us_multispine_pool.py:814-928,1300-1469,1857-1930,5290-5334`; -`packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py:1032-1193,1463-1699`; -`tools/build_us_fiscal_refresh_release.py:2565-2677`). - -No pool/release build, push, guard weakening, operator-boundary weakening, or -`logbook-pending-chain.txt` access has occurred. +Implementation has started from `origin/main` at `2263df36`. Repository and +agent instructions have been read. The working tree was clean at kickoff. ## Done -- Reconciled the worktree with salvage commit `ca26ea21`: its tracked tree was - already exactly present, so the best salvage was retained and audited rather - than reimplemented. -- Completed the required all-package US environment sync from the exact lock - using the writable offline uv cache after the managed sandbox refused the - default cache. -- Added the two required pinned geography authority pairs, the ledgered seeded - PUMA-overlap assignment, schema-12 checkpoint identity, assignment receipts, - schema-9 terminal manifest validation, and schema-3 H5 materializer binding. -- Added atomic nullable-H5 root-attribute write/verification and authenticated - manifest-to-H5 geography/clone-lineage validation. -- Made release preflight read root attributes and fixed household frames in one - `HDFStore` handle while retaining all existing SHA, target-vintage, and - positive-support checks. -- Added a real tiny stacked-pool publication to release-preflight integration - test plus negative attr, digest, missing-lineage, and divergent-clone tests - (`packages/microcosm-build/tests/test_us_multispine_pool_tool.py:2279-2335`; - `packages/microcosm-build/tests/test_us_multispine_pool_h5_io.py:1357-1440`). -- Regenerated and checked the US anti-rot chain: spec SHA - `5378bb9189aec96f50da22aac71e5bd2c3d919e9795f6ef2147e0bc9c739dd8e`, - 42,120/42,120 configuration fields, 49 claims, and 41/41 inventory checks. -- Passed the complete accepted workspace suite: 7,241 passed, 77 skipped, and - 0 failed. The two memory-bounded build partitions were 4,155 passed / 36 - skipped and 2,177 passed / 3 skipped; calibrate, data, fit, and frame account - for the remaining 909 passed / 38 skipped. -- Passed repository-wide Ruff, bundle freshness, coverage freshness, smoke - script syntax, and `git diff --check`. -- Recorded the exact candidate Stage-1 path/SHA additions and the checkpoint - invalidation verdict in `_LANE-NOTES.md` and `FINAL_REPORT.md`. +- Confirmed the assigned branch and worktree. +- Recorded the v2 charter: close the legacy bare-H5 multispine bypass, add an + explicit release-build opt-in, carry the authenticated red verdict, and + surface it in publication preflight without making it an automatic + publication failure. +- Confirmed that no network, artifact builds, publishing, or pushes are in + scope. ## Next -1. Candidate Stage 1 adds both authenticated geography authority pairs and - rebuilds under checkpoint materializer 12. -2. Candidate Stage 2 consumes the new schema-9 manifest/materializer-3 H5 and - passes the unchanged release preflight. -3. Do not reuse pre-fix Stage-1 checkpoints or pool publications; immutable - source artifacts remain reusable. - -## Historical prior lane - -The PolicyEngine-US 1.819.0 lock-bump journal previously in this file is -historical: that lane merged into `origin/main` at `7b90bb18` on 2026-08-24. -Its final state remains available at commit `05d254aa` and its detailed -receipts remain in the historical section of `_LANE-NOTES.md`. +- Trace the current release builder, H5 loader seam, pool stamping, preflight, + and relevant tests. +- Review the untrusted salvage branch line by line as a design reference. +- Implement and test the containment and opt-in behavior. +- Audit other pool-manifest and `simulation_ready` consumers. +- Run Ruff and every pytest shard in its own process, then write `out.md`. From 5be9e49a8961732d2af0c652162f7c5367597afa Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 09:03:15 +0200 Subject: [PATCH 02/17] Preserve prior progress journal history --- PROGRESS.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/PROGRESS.md b/PROGRESS.md index 7b82fba0..32fa7cec 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -23,3 +23,19 @@ agent instructions have been read. The working tree was clean at kickoff. - Implement and test the containment and opt-in behavior. - Audit other pool-manifest and `simulation_ready` consumers. - Run Ruff and every pytest shard in its own process, then write `out.md`. + +## Historical prior lane + +The stacked-pool-to-release CD-vintage provenance lane previously maintained +this journal and completed before this work began. It authenticated and +applied household geography after source assembly, carried that authority +through checkpoint and publication identities, published verified CD-vintage +H5 attributes, and reached the unchanged release guard through the shared +fixed/table-aware reader. Its final verification was 7,241 passed, 77 skipped, +with repository-wide Ruff and anti-rot checks green. Full details remain at +commit `2263df36` (the parent of this lane's first journal commit). + +The still-earlier PolicyEngine-US 1.819.0 lock-bump lane merged into +`origin/main` at `7b90bb18` on 2026-08-24; its final state remains at commit +`05d254aa` and its detailed receipts remain in the historical section of +`_LANE-NOTES.md`. From c5a24c0fd69898adf10b23f26134119fa066bb15 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 09:12:38 +0200 Subject: [PATCH 03/17] Record release containment design review --- PROGRESS.md | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/PROGRESS.md b/PROGRESS.md index 32fa7cec..58dc2e89 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,8 +2,11 @@ ## State -Implementation has started from `origin/main` at `2263df36`. Repository and -agent instructions have been read. The working tree was clean at kickoff. +Design and consumer review are complete. The final salvage tree is a useful +implementation base, but it needs two additional fail-closed checks before it +is trustworthy: reject a redundant gate-failure opt-in on a green pool, and +bind mixed preflight inputs so a release manifest cannot display one pool's +red verdict while static checks authenticate another pool. ## Done @@ -14,14 +17,29 @@ agent instructions have been read. The working tree was clean at kickoff. publication failure. - Confirmed that no network, artifact builds, publishing, or pushes are in scope. +- Traced the strict manifest loader, current stacked-only terminal-failure + exception, H5 identity stamp, pool sidecar naming, legacy release arm, + release manifests, and both preflight output modes. +- Reviewed the salvage branch's final source and test diff line by line. Its + shared classifier/path-binding/receipt approach closes the bypass without + changing either loader's contract and is suitable to retain with the two + coherence corrections above. +- Completed the `simulation_ready` / `gate_failed` / loader consumer audit. + Exact-k remains deliberately strict and head-to-head scoring remains the + existing authenticated evidence exception. +- Identified report-only downstream caveats: stacked producer metadata still + names only the k-ladder readiness consumer; red pool publication returns + status 1 and stops shell chains; ACS-local derivatives keep a donor revision + but do not project the nested red verdict; generic release consumers tolerate + and ignore the additive receipt. ## Next -- Trace the current release builder, H5 loader seam, pool stamping, preflight, - and relevant tests. -- Review the untrusted salvage branch line by line as a design reference. -- Implement and test the containment and opt-in behavior. -- Audit other pool-manifest and `simulation_ready` consumers. +- Import the re-reviewed salvage implementation as coherent local commits. +- Add redundant-opt-in and mixed-preflight receipt-binding regressions and + enforce both contracts. +- Run the focused containment, carriage, preflight, exact-k, and data-contract + suites. - Run Ruff and every pytest shard in its own process, then write `out.md`. ## Historical prior lane From 7227491009cd8966542c9730ffa4bafacacb0b8c Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 07:54:48 +0200 Subject: [PATCH 04/17] feat: allow explicit gate-failed pool release inputs --- .../tests/test_us_fiscal_refresh_builder.py | 216 ++++++++++++++++++ tools/build_us_fiscal_refresh_release.py | 108 +++++++-- 2 files changed, 307 insertions(+), 17 deletions(-) diff --git a/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py b/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py index 48486968..5756585a 100644 --- a/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py +++ b/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py @@ -1547,6 +1547,30 @@ def test_builder_exact_k_parser_enforces_charter_and_explicit_seed(capsys) -> No assert parsed.no_staging is True +def test_builder_gate_failed_base_pool_override_is_explicit(capsys) -> None: + builder = _load_builder_module() + + parsed = builder._parse_args(_exact_k_builder_argv("20000")) + assert parsed.allow_gate_failed_base_pool is False + + parsed = builder._parse_args( + [*_exact_k_builder_argv("20000"), "--allow-gate-failed-base-pool"] + ) + assert parsed.allow_gate_failed_base_pool is True + + with pytest.raises(SystemExit): + builder._parse_args( + [ + "--ledger-facts", + "facts.jsonl", + "--out", + "release", + "--allow-gate-failed-base-pool", + ] + ) + assert "requires --pool-manifest" in capsys.readouterr().err + + def test_builder_exact_k_requires_pointer_suppression(capsys) -> None: builder = _load_builder_module() argv = _exact_k_builder_argv("20000") @@ -1643,6 +1667,55 @@ def fake_load_pool(path, *, expected_manifest_sha256): assert not out.exists() +@pytest.mark.parametrize( + ("allow_gate_failed", "selected_loader", "unselected_loader"), + ( + ( + False, + "load_simulation_ready_us_multispine_pool", + "load_authenticated_us_multispine_pool_for_scoring", + ), + ( + True, + "load_authenticated_us_multispine_pool_for_scoring", + "load_simulation_ready_us_multispine_pool", + ), + ), +) +def test_builder_selects_pool_loader_only_from_explicit_gate_failed_opt_in( + monkeypatch, + tmp_path, + allow_gate_failed, + selected_loader, + unselected_loader, +) -> None: + builder = _load_builder_module() + argv = _exact_k_builder_argv("20000") + argv[argv.index("out")] = str(tmp_path / "out") + if allow_gate_failed: + argv.append("--allow-gate-failed-base-pool") + + monkeypatch.setattr(builder, "_git_dirty", lambda: False) + monkeypatch.setattr(builder, "_refuse_certified_release_dir_reuse", lambda path: None) + monkeypatch.setattr( + builder, + "_load_verified_incumbent_diagnostics_payload", + lambda path, *, expected_sha256: ({}, expected_sha256), + ) + + def selected(*args, **kwargs): + raise RuntimeError("selected pool loader") + + def unselected(*args, **kwargs): + pytest.fail("the unselected pool loader ran") + + monkeypatch.setattr(builder, selected_loader, selected) + monkeypatch.setattr(builder, unselected_loader, unselected) + + with pytest.raises(RuntimeError, match="selected pool loader"): + builder.main(argv) + + def test_authenticated_pool_h5_consumers_use_one_returned_identity() -> None: import ast import inspect @@ -8717,6 +8790,149 @@ def __len__(self): ) +def _gate_failed_exact_k_receipt(builder, *, allow_gate_failed_base_pool: bool): + class FakeFrame: + @staticmethod + def n(entity): + assert entity == "household" + return 20_000 + + outcome = SimpleNamespace( + result=SimpleNamespace(frame=FakeFrame()), + selection_receipt={ + "k": 20_000, + "pi_hi": 0.95, + "seed": 17, + "certainty_count": 3, + "boundary_pool_size": 100, + "design": "sampford", + }, + refit_baseline_diagnostics={"method": "fixture"}, + ) + args = SimpleNamespace( + exact_k=20_000, + seed=17, + pool_release_id="fixture-publication", + allow_gate_failed_base_pool=allow_gate_failed_base_pool, + ) + failures = ["asec incidence differs", "puf_tax_detail incidence differs"] + pool_manifest = { + "status": "gate_failed", + "simulation_ready": False, + "agreement_diagnostics": {"sha256": "2" * 64}, + "agreement_gate": { + "passed": False, + "gates": { + "us_by_origin_battery": { + "passed": False, + "failures": failures, + "details": {"fixture": True}, + } + }, + }, + } + authenticated_pool_h5 = builder.AuthenticatedPoolH5( + path=Path("pool.h5"), + sha256="1" * 64, + size_bytes=123, + publication_run_id="fixture-publication", + manifest_sha256="a" * 64, + ) + receipt = builder._exact_k_ladder_manifest_payload( + args=args, + outcome=outcome, + pool_manifest=pool_manifest, + authenticated_pool_h5=authenticated_pool_h5, + ledger_artifact={"facts_sha256": "3" * 64}, + target_surface={"sha256": "4" * 64}, + target_loss_basis={"method": "fixture"}, + incumbent_diagnostics_sha256="5" * 64, + incumbent_fit_gate=builder.GateResult("incumbent_fit", True), + puf_tail_gate=builder.GateResult("puf_tail", True), + ) + return receipt, failures + + +def test_builder_refuses_gate_failed_pool_without_explicit_opt_in() -> None: + builder = _load_builder_module() + + with pytest.raises(RuntimeError, match="lost its passing agreement gate"): + _gate_failed_exact_k_receipt( + builder, + allow_gate_failed_base_pool=False, + ) + + +def test_gate_failed_pool_verdict_is_carried_into_release_manifest( + monkeypatch, tmp_path +) -> None: + builder = _load_builder_module() + ladder, failures = _gate_failed_exact_k_receipt( + builder, + allow_gate_failed_base_pool=True, + ) + release_id = "populace-us-2024-k20000-gate-failed-fixture" + release_dir = tmp_path / "release" / release_id + release_dir.mkdir(parents=True) + artifact_root = tmp_path / "artifacts" + artifact_root.mkdir() + (artifact_root / builder.DATASET_FILENAME).write_bytes(b"h5") + (artifact_root / builder.CALIBRATION_FILENAME).write_bytes(b"npz") + (release_dir / "calibration_diagnostics.json").write_text("{}") + (release_dir / "us_source_coverage.json").write_text("{}") + (release_dir / "us_ssi_take_up.json").write_text("{}") + monkeypatch.setattr( + builder, + "_runtime_versions", + lambda: { + "python": "3.14.0", + "microcosm-data": "0.1.0", + "policyengine-core": "3.26.11", + "policyengine-us": "1.752.2", + }, + ) + monkeypatch.setattr(builder, "_git_output", lambda *args: "a" * 40) + monkeypatch.setattr( + builder, + "diagnostics_payload", + lambda result, target_registry: { + "initial_loss": 2.0, + "final_loss": 1.0, + "fraction_within_10pct": 1.0, + "target_surface": {"sha256": "b" * 64, "n_targets": 1}, + }, + ) + + builder._build_manifests( + exact_k_ladder=ladder, + **_minimal_manifest_kwargs(builder, release_id, release_dir, artifact_root), + ) + + release_manifest = json.loads((release_dir / "release_manifest.json").read_text()) + carried = release_manifest["build"]["exact_k_ladder"] + assert carried["pool"] == { + "release_id": "fixture-publication", + "release_id_source": "pool_manifest.publication_run_id", + "manifest_sha256": "a" * 64, + "publication_run_id": "fixture-publication", + "pool_h5_sha256": "1" * 64, + "pool_h5_size_bytes": 123, + "agreement_diagnostics_sha256": "2" * 64, + "status": "gate_failed", + "simulation_ready": False, + "allow_gate_failed_base_pool": True, + } + verdict = carried["agreement_gate_reference"] + assert verdict["passed"] is False + assert verdict["battery_status"] == "red" + assert verdict["gates_json_sha256"] == "2" * 64 + assert verdict["failure_count"] == 2 + assert verdict["failures"] == failures + assert verdict["verdict"]["gates"]["us_by_origin_battery"]["failures"] == ( + failures + ) + + def test_build_manifests_uses_loadable_paths_and_round_trips_exact_count_receipt( monkeypatch, tmp_path ) -> None: diff --git a/tools/build_us_fiscal_refresh_release.py b/tools/build_us_fiscal_refresh_release.py index b00c5189..bb72ac56 100644 --- a/tools/build_us_fiscal_refresh_release.py +++ b/tools/build_us_fiscal_refresh_release.py @@ -228,6 +228,7 @@ ) from microcosm.build.us_runtime.h5_io import ( AuthenticatedPoolH5, + load_authenticated_us_multispine_pool_for_scoring, load_simulation_ready_us_multispine_pool, ) from microcosm.build.us_runtime.input_mass import us_input_mass_totals @@ -848,6 +849,17 @@ def _parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace: "Mutually exclusive with --base-h5." ), ) + parser.add_argument( + "--allow-gate-failed-base-pool", + action="store_true", + help=( + "Explicitly allow an authenticated current stacked base-pool " + "manifest with status=gate_failed and simulation_ready=false. " + "The red agreement-gate verdict is carried into the release " + "manifest for a separate human publication decision. Without " + "this flag --pool-manifest remains fail-closed." + ), + ) parser.add_argument( "--pool-manifest-sha256", help=( @@ -1537,6 +1549,8 @@ def _parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace: ) if args.evidence_failure_owners is not None and not args.evidence_release: parser.error("--evidence-failure-owners requires --evidence-release.") + if args.allow_gate_failed_base_pool and args.pool_manifest is None: + parser.error("--allow-gate-failed-base-pool requires --pool-manifest.") if args.evidence_release and args.exact_k is not None: parser.error( "--evidence-release is incompatible with --exact-k: ladder " @@ -8224,31 +8238,86 @@ def _exact_k_ladder_manifest_payload( isinstance(value, Mapping) for value in (agreement_diagnostics, agreement_gate) ): raise RuntimeError("Validated pool manifest lost a required receipt block.") - if agreement_gate.get("passed") is not True: + agreement_gate_passed = agreement_gate.get("passed") + gate_passed = agreement_gate_passed is True + is_gate_failed_pool = ( + pool_manifest.get("status") == "gate_failed" + and pool_manifest.get("simulation_ready") is False + ) + if is_gate_failed_pool and agreement_gate_passed is not False: + raise RuntimeError( + "Validated gate-failed pool manifest does not carry an explicitly " + "failed agreement gate." + ) + if not gate_passed and not ( + args.allow_gate_failed_base_pool and is_gate_failed_pool + ): raise RuntimeError("Validated pool manifest lost its passing agreement gate.") pool_release_id = _assert_pool_release_id_value( args.pool_release_id, authenticated_pool_h5.publication_run_id, ) + pool_reference = { + "release_id": pool_release_id, + "release_id_source": "pool_manifest.publication_run_id", + "manifest_sha256": authenticated_pool_h5.manifest_sha256, + "publication_run_id": authenticated_pool_h5.publication_run_id, + "pool_h5_sha256": authenticated_pool_h5.sha256, + "pool_h5_size_bytes": authenticated_pool_h5.size_bytes, + "agreement_diagnostics_sha256": agreement_diagnostics.get("sha256"), + } + agreement_gate_reference = { + "passed": True, + "publication_run_id": authenticated_pool_h5.publication_run_id, + "diagnostics_sha256": agreement_diagnostics.get("sha256"), + "verdict": dict(agreement_gate), + } + if args.allow_gate_failed_base_pool: + pool_reference.update( + { + "status": pool_manifest.get("status"), + "simulation_ready": pool_manifest.get("simulation_ready"), + "allow_gate_failed_base_pool": True, + } + ) + if is_gate_failed_pool: + failures: list[str] = [] + gates = agreement_gate.get("gates") + if not isinstance(gates, Mapping): + raise RuntimeError( + "Validated gate-failed pool manifest lost its agreement-gate " + "results." + ) + for gate_name, gate_verdict in gates.items(): + if not isinstance(gate_verdict, Mapping): + raise RuntimeError( + "Validated gate-failed pool manifest has a malformed " + f"agreement-gate result for {gate_name!r}." + ) + gate_failures = gate_verdict.get("failures", ()) + if not isinstance(gate_failures, list) or not all( + isinstance(failure, str) for failure in gate_failures + ): + raise RuntimeError( + "Validated gate-failed pool manifest has a malformed " + f"failure list for {gate_name!r}." + ) + failures.extend(gate_failures) + agreement_gate_reference.update( + { + "passed": False, + "battery_status": "red", + "gates_json_sha256": agreement_diagnostics.get("sha256"), + "failure_count": len(failures), + "failures": failures, + } + ) payload = exact_k_ladder_manifest_payload( outcome, k=int(args.exact_k), seed=int(args.seed), - pool={ - "release_id": pool_release_id, - "release_id_source": "pool_manifest.publication_run_id", - "manifest_sha256": authenticated_pool_h5.manifest_sha256, - "publication_run_id": authenticated_pool_h5.publication_run_id, - "pool_h5_sha256": authenticated_pool_h5.sha256, - "pool_h5_size_bytes": authenticated_pool_h5.size_bytes, - "agreement_diagnostics_sha256": agreement_diagnostics.get("sha256"), - }, - agreement_gate_reference={ - "passed": True, - "publication_run_id": authenticated_pool_h5.publication_run_id, - "diagnostics_sha256": agreement_diagnostics.get("sha256"), - "verdict": dict(agreement_gate), - }, + pool=pool_reference, + agreement_gate_reference=agreement_gate_reference, frozen_target_register={ "ledger_artifact": dict(ledger_artifact), "target_surface_sha256": target_surface.get("sha256"), @@ -8534,8 +8603,13 @@ def _main(argv: Sequence[str] | None = None) -> None: pool_manifest_payload: dict[str, object] | None = None authenticated_pool_h5: AuthenticatedPoolH5 | None = None if args.pool_manifest is not None: + pool_loader = ( + load_authenticated_us_multispine_pool_for_scoring + if args.allow_gate_failed_base_pool + else load_simulation_ready_us_multispine_pool + ) pool_frame, pool_manifest_payload, authenticated_pool_h5 = ( - load_simulation_ready_us_multispine_pool( + pool_loader( args.pool_manifest, expected_manifest_sha256=args.pool_manifest_sha256, ) From e3d847d642d17d481fe203c482ed97f6d21658e0 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 08:00:59 +0200 Subject: [PATCH 05/17] feat: surface carried red pool verdict in preflight --- changelog.d/gate-failed-pool-release.added.md | 1 + .../tests/test_us_release_gate_preflight.py | 156 ++++++++++++- tools/preflight_us_release_gates.py | 220 ++++++++++++++++-- 3 files changed, 353 insertions(+), 24 deletions(-) create mode 100644 changelog.d/gate-failed-pool-release.added.md diff --git a/changelog.d/gate-failed-pool-release.added.md b/changelog.d/gate-failed-pool-release.added.md new file mode 100644 index 00000000..3a1b460a --- /dev/null +++ b/changelog.d/gate-failed-pool-release.added.md @@ -0,0 +1 @@ +Allow an exact-k US fiscal release to opt in explicitly to an authenticated current stacked pool whose terminal agreement battery is red via ``--allow-gate-failed-base-pool``. The release carries the pool status, readiness, opt-in, gates-JSON digest, complete verdict, and failure summary, while publication preflight presents the red battery as prominent evidence for a separate human decision without changing its automated exit code. diff --git a/packages/microcosm-build/tests/test_us_release_gate_preflight.py b/packages/microcosm-build/tests/test_us_release_gate_preflight.py index c9647f73..bf9700f3 100644 --- a/packages/microcosm-build/tests/test_us_release_gate_preflight.py +++ b/packages/microcosm-build/tests/test_us_release_gate_preflight.py @@ -16,8 +16,13 @@ from __future__ import annotations +import importlib.util +import json +from pathlib import Path + import numpy as np import pandas as pd +import pytest from microcosm.build.us_runtime.release_gate_preflight import ( PreflightReport, @@ -36,6 +41,58 @@ from microcosm.frame import US_SCHEMA, Frame, WeightKind, Weights +def _load_preflight_cli(): + root = Path(__file__).resolve().parents[3] + path = root / "tools" / "preflight_us_release_gates.py" + spec = importlib.util.spec_from_file_location("preflight_us_release_gates", path) + module = importlib.util.module_from_spec(spec) + assert spec.loader is not None + spec.loader.exec_module(module) + return module + + +def _write_gate_failed_release_manifest(path: Path) -> tuple[list[str], str]: + failures = ["asec incidence differs", "puf_tax_detail incidence differs"] + gates_sha256 = "2" * 64 + verdict = { + "passed": False, + "gates": { + "us_by_origin_battery": { + "passed": False, + "failures": failures, + "details": {"fixture": True}, + } + }, + } + path.write_text( + json.dumps( + { + "schema_version": 1, + "build": { + "exact_k_ladder": { + "pool": { + "status": "gate_failed", + "simulation_ready": False, + "allow_gate_failed_base_pool": True, + "agreement_diagnostics_sha256": gates_sha256, + }, + "agreement_gate_reference": { + "passed": False, + "battery_status": "red", + "diagnostics_sha256": gates_sha256, + "gates_json_sha256": gates_sha256, + "failure_count": len(failures), + "failures": failures, + "verdict": verdict, + }, + } + }, + } + ) + ) + return failures, gates_sha256 + + def _frame(households: list[dict[str, object]]) -> Frame: """A minimal US frame from household specs (one person per household).""" prows, hrows, spm_rows, mu_rows = [], [], [], [] @@ -639,8 +696,6 @@ def test__report__exit_code_and_status_precedence() -> None: def test__report__to_dict_is_json_ready() -> None: - import json - from microcosm.build.us_runtime.release_gate_preflight import CheckResult report = PreflightReport( @@ -660,6 +715,103 @@ def test__report__to_dict_is_json_ready() -> None: assert payload["checks"][0]["rows"] == [{"k": 1}] +def test__cli__manifest_only_surfaces_carried_red_battery_without_failing( + monkeypatch, tmp_path, capsys +) -> None: + cli = _load_preflight_cli() + release_manifest = tmp_path / "release_manifest.json" + failures, gates_sha256 = _write_gate_failed_release_manifest(release_manifest) + json_out = tmp_path / "preflight.json" + monkeypatch.setattr( + cli, + "run_preflight", + lambda **kwargs: pytest.fail("manifest-only review ran static checks"), + ) + + exit_code = cli.main( + [ + "--release-manifest", + str(release_manifest), + "--json-out", + str(json_out), + ] + ) + + output = capsys.readouterr().out + assert exit_code == 0 + assert output.startswith("=" * 72) + assert "CARRIED BASE-POOL AGREEMENT BATTERY: RED — 2 FAILURES" in output + assert "Build opt-in used: --allow-gate-failed-base-pool" in output + assert f"Pool gates JSON SHA-256: {gates_sha256}" in output + assert "Publication decision: HUMAN REVIEW REQUIRED" in output + assert "does not alter the preflight exit code" in output + assert "Static base/selection checks: NOT RUN" in output + assert all(f"FAILURE: {failure}" in output for failure in failures) + assert output.rstrip().endswith( + "CARRIED RED BATTERY: HUMAN REVIEW REQUIRED; automated preflight exit " + "remains 0." + ) + + payload = json.loads(json_out.read_text()) + carried = payload["carried_base_pool_agreement_battery"] + assert payload["exit_code"] == 0 + assert payload["static_checks_run"] is False + assert carried["battery_status"] == "red" + assert carried["failure_count"] == 2 + assert carried["failures"] == failures + assert carried["gates_json_sha256"] == gates_sha256 + assert carried["affects_exit_code"] is False + assert carried["agreement_gate_reference"]["verdict"]["passed"] is False + + +def test__cli__carried_red_battery_does_not_change_existing_preflight_exit( + monkeypatch, tmp_path, capsys +) -> None: + from microcosm.build.us_runtime.release_gate_preflight import CheckResult + + cli = _load_preflight_cli() + release_manifest = tmp_path / "release_manifest.json" + _write_gate_failed_release_manifest(release_manifest) + json_out = tmp_path / "preflight.json" + report = PreflightReport( + checks=( + CheckResult( + name="existing_risk", + status="AT_RISK", + summary="existing check controls the exit", + at_risks=("fixture risk",), + ), + ) + ) + monkeypatch.setattr(cli, "run_preflight", lambda **kwargs: report) + + exit_code = cli.main( + [ + "--base-h5", + str(tmp_path / "base.h5"), + "--selection-source-manifest", + str(tmp_path / "selection.json"), + "--release-manifest", + str(release_manifest), + "--json-out", + str(json_out), + ] + ) + + output = capsys.readouterr().out + payload = json.loads(json_out.read_text()) + assert exit_code == report.exit_code == 2 + assert "[AT-RISK] existing_risk" in output + assert output.rstrip().endswith( + "CARRIED RED BATTERY: HUMAN REVIEW REQUIRED; automated preflight exit " + "remains 2." + ) + assert payload["exit_code"] == 2 + assert payload["carried_base_pool_agreement_battery"][ + "affects_exit_code" + ] is False + + def test__load_ledger_target_specs__hands_fact_rows_to_the_compiler( monkeypatch, tmp_path ) -> None: diff --git a/tools/preflight_us_release_gates.py b/tools/preflight_us_release_gates.py index 0ca5ec8c..0cfeadf7 100644 --- a/tools/preflight_us_release_gates.py +++ b/tools/preflight_us_release_gates.py @@ -17,7 +17,10 @@ --selection-source-manifest inputs/buildm_keogh_swap_selection_source.json \ --export-input-mass-reference-h5 forensics/populace_us_2024.h5 -Exit code: 1 on any FAIL, 2 on AT-RISK only, 0 clean. +Exit code: 1 on any static-check FAIL, 2 on static AT-RISK only, 0 clean. A +carried red base-pool battery is human-review evidence and does not by itself +change that exit code; ``--release-manifest`` also supports a manifest-only +publication review when those static inputs do not apply. """ from __future__ import annotations @@ -34,10 +37,122 @@ 0, str(Path(__file__).resolve().parents[1] / "packages" / "microcosm-build" / "src") ) -from microcosm.build.us_runtime.release_gate_preflight import ( # noqa: E402 - run_preflight, +from microcosm.build.us_runtime.release_gate_preflight import ( + run_preflight, # noqa: E402 ) +_ALLOW_GATE_FAILED_BASE_POOL_FLAG = "--allow-gate-failed-base-pool" +_CARRIED_BATTERY_PAYLOAD_KEY = "carried_base_pool_agreement_battery" + + +def _json_object(value: object, *, label: str) -> dict[str, object]: + if not isinstance(value, dict): + raise ValueError(f"{label} must be a JSON object.") + return value + + +def _load_carried_base_pool_battery( + path: Path, +) -> dict[str, object] | None: + """Read the non-blocking red pool verdict carried by a release manifest.""" + + release_manifest = _json_object( + json.loads(path.read_text()), + label=f"release manifest {path}", + ) + build = release_manifest.get("build") + if not isinstance(build, dict): + return None + exact_k_ladder = build.get("exact_k_ladder") + if not isinstance(exact_k_ladder, dict): + return None + pool = exact_k_ladder.get("pool") + agreement_gate_reference = exact_k_ladder.get("agreement_gate_reference") + if not isinstance(pool, dict): + return None + carries_gate_failed_override = ( + pool.get("allow_gate_failed_base_pool") is True + or pool.get("status") == "gate_failed" + or ( + isinstance(agreement_gate_reference, dict) + and agreement_gate_reference.get("battery_status") == "red" + ) + ) + if not carries_gate_failed_override: + return None + if ( + pool.get("status") != "gate_failed" + or pool.get("simulation_ready") is not False + or pool.get("allow_gate_failed_base_pool") is not True + ): + raise ValueError( + f"Release manifest {path} has an incoherent gate-failed base-pool " + "carriage receipt." + ) + gate_reference = _json_object( + agreement_gate_reference, + label=( + f"release manifest {path} build.exact_k_ladder." + "agreement_gate_reference" + ), + ) + failures = gate_reference.get("failures") + failure_count = gate_reference.get("failure_count") + gates_json_sha256 = gate_reference.get("gates_json_sha256") + verdict = gate_reference.get("verdict") + if ( + gate_reference.get("passed") is not False + or gate_reference.get("battery_status") != "red" + or not isinstance(failures, list) + or not all(isinstance(failure, str) for failure in failures) + or type(failure_count) is not int + or failure_count != len(failures) + or not isinstance(gates_json_sha256, str) + or len(gates_json_sha256) != 64 + or any( + character not in "0123456789abcdef" + for character in gates_json_sha256 + ) + or not isinstance(verdict, dict) + or verdict.get("passed") is not False + or gate_reference.get("diagnostics_sha256") != gates_json_sha256 + or pool.get("agreement_diagnostics_sha256") != gates_json_sha256 + ): + raise ValueError( + f"Release manifest {path} has an incomplete or inconsistent " + "carried red agreement-battery verdict." + ) + return { + "battery_status": "red", + "pool_status": "gate_failed", + "simulation_ready": False, + "allow_gate_failed_base_pool": True, + "flag": _ALLOW_GATE_FAILED_BASE_POOL_FLAG, + "gates_json_sha256": gates_json_sha256, + "failure_count": failure_count, + "failures": list(failures), + "agreement_gate_reference": dict(gate_reference), + "publication_decision": "human_review_required", + "affects_exit_code": False, + } + + +def _carried_battery_banner(carried: dict[str, object]) -> str: + count = int(carried["failure_count"]) + noun = "FAILURE" if count == 1 else "FAILURES" + lines = [ + "=" * 72, + f"CARRIED BASE-POOL AGREEMENT BATTERY: RED — {count} {noun}", + "Pool status: gate_failed; simulation_ready: false", + f"Build opt-in used: {carried['flag']}", + f"Pool gates JSON SHA-256: {carried['gates_json_sha256']}", + "Publication decision: HUMAN REVIEW REQUIRED", + "This carried verdict does not alter the preflight exit code.", + ] + lines.extend(f" FAILURE: {failure}" for failure in carried["failures"]) + lines.append("=" * 72) + return "\n".join(lines) + def _parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( @@ -49,15 +164,31 @@ def _parser() -> argparse.ArgumentParser: ) parser.add_argument( "--base-h5", - required=True, type=Path, - help="Base pool H5 (read-only).", + help=( + "Base pool H5 (read-only). Required with " + "--selection-source-manifest unless --release-manifest is used " + "for a manifest-only publication review." + ), ) parser.add_argument( "--selection-source-manifest", - required=True, type=Path, - help="Frozen selection-source manifest JSON.", + help=( + "Frozen selection-source manifest JSON. Required with --base-h5 " + "for the existing static preflight checks." + ), + ) + parser.add_argument( + "--release-manifest", + type=Path, + help=( + "Optional built release_manifest.json. A carried gate-failed " + "base-pool battery is displayed as prominent, non-blocking " + "evidence for the human publication decision. It may be used " + "alone for publication review or alongside the existing static " + "preflight inputs." + ), ) parser.add_argument( "--export-input-mass-reference-h5", @@ -118,33 +249,78 @@ def _parser() -> argparse.ArgumentParser: def main(argv: list[str] | None = None) -> int: - args = _parser().parse_args(argv) + parser = _parser() + args = parser.parse_args(argv) + has_base_h5 = args.base_h5 is not None + has_selection_manifest = args.selection_source_manifest is not None + if has_base_h5 != has_selection_manifest: + parser.error( + "--base-h5 and --selection-source-manifest must be provided together." + ) + if not has_base_h5 and args.release_manifest is None: + parser.error( + "provide --base-h5 with --selection-source-manifest, or provide " + "--release-manifest for publication review." + ) + carried = ( + _load_carried_base_pool_battery(args.release_manifest) + if args.release_manifest is not None + else None + ) + if not has_base_h5 and carried is None: + parser.error( + "manifest-only publication review requires a release manifest " + "carrying an explicit gate-failed base-pool verdict." + ) + if carried is not None: + print(_carried_battery_banner(carried)) + try: target_period: int | str = int(args.target_period) except (TypeError, ValueError): target_period = args.target_period - report = run_preflight( - base_h5=args.base_h5, - selection_source_manifest=args.selection_source_manifest, - export_input_mass_reference_h5=args.export_input_mass_reference_h5, - ledger_facts=args.ledger_facts, - ledger_facts_sha256=args.ledger_facts_sha256, - target_period=target_period, - relative_tolerance=args.relative_tolerance, - minimum_reference_total=args.minimum_reference_total, - ) - - print(report.human_table()) - payload = report.to_dict() + if has_base_h5: + report = run_preflight( + base_h5=args.base_h5, + selection_source_manifest=args.selection_source_manifest, + export_input_mass_reference_h5=args.export_input_mass_reference_h5, + ledger_facts=args.ledger_facts, + ledger_facts_sha256=args.ledger_facts_sha256, + target_period=target_period, + relative_tolerance=args.relative_tolerance, + minimum_reference_total=args.minimum_reference_total, + ) + print(report.human_table()) + payload = report.to_dict() + exit_code = report.exit_code + else: + print("US release-gate preflight (manifest-only publication review)") + print("Static base/selection checks: NOT RUN") + print("Automated exit: 0 (carried evidence requires human review)") + payload = { + "status": "PASS", + "exit_code": 0, + "inputs": {"release_manifest": str(args.release_manifest)}, + "checks": [], + "static_checks_run": False, + } + exit_code = 0 + if carried is not None: + payload[_CARRIED_BATTERY_PAYLOAD_KEY] = carried if args.json_out is not None: args.json_out.write_text(json.dumps(payload, indent=2, sort_keys=False)) print(f"\nWrote machine-readable report to {args.json_out}") else: print("\n--- machine-readable report ---") print(json.dumps(payload, indent=2, sort_keys=False)) + if carried is not None: + print( + "\nCARRIED RED BATTERY: HUMAN REVIEW REQUIRED; " + f"automated preflight exit remains {exit_code}." + ) - return report.exit_code + return exit_code if __name__ == "__main__": From 46811fdb79c4ba8cbf8952ce142e2a12fc758ac0 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 08:04:34 +0200 Subject: [PATCH 06/17] fix: preserve default exact-k receipt fixtures --- tools/build_us_fiscal_refresh_release.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/build_us_fiscal_refresh_release.py b/tools/build_us_fiscal_refresh_release.py index bb72ac56..19f22e91 100644 --- a/tools/build_us_fiscal_refresh_release.py +++ b/tools/build_us_fiscal_refresh_release.py @@ -8240,6 +8240,11 @@ def _exact_k_ladder_manifest_payload( raise RuntimeError("Validated pool manifest lost a required receipt block.") agreement_gate_passed = agreement_gate.get("passed") gate_passed = agreement_gate_passed is True + allow_gate_failed_base_pool = getattr( + args, + "allow_gate_failed_base_pool", + False, + ) is_gate_failed_pool = ( pool_manifest.get("status") == "gate_failed" and pool_manifest.get("simulation_ready") is False @@ -8250,7 +8255,7 @@ def _exact_k_ladder_manifest_payload( "failed agreement gate." ) if not gate_passed and not ( - args.allow_gate_failed_base_pool and is_gate_failed_pool + allow_gate_failed_base_pool and is_gate_failed_pool ): raise RuntimeError("Validated pool manifest lost its passing agreement gate.") pool_release_id = _assert_pool_release_id_value( @@ -8272,7 +8277,7 @@ def _exact_k_ladder_manifest_payload( "diagnostics_sha256": agreement_diagnostics.get("sha256"), "verdict": dict(agreement_gate), } - if args.allow_gate_failed_base_pool: + if allow_gate_failed_base_pool: pool_reference.update( { "status": pool_manifest.get("status"), From dd1ad19ac4156ebe8fd3c0523339c3affbb1adfc Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 08:06:54 +0200 Subject: [PATCH 07/17] Add shared multispine base-pool authentication seam --- .../src/microcosm/build/us_runtime/h5_io.py | 164 ++++++++++++++++++ .../tests/test_us_multispine_pool_h5_io.py | 90 ++++++++++ 2 files changed, 254 insertions(+) diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py b/packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py index c63fac0b..256b046f 100644 --- a/packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py @@ -58,11 +58,14 @@ "US_MULTISPINE_POOL_MANIFEST_ARTIFACT_KIND", "US_MULTISPINE_POOL_MANIFEST_SCHEMA_VERSION", "US_STACKED_POOL_OPERATOR_ORDER", + "identify_us_multispine_pool_manifest", "load_authenticated_us_multispine_pool_for_scoring", "load_legacy_calibrated_us_h5", "load_simulation_ready_us_multispine_pool", "load_simulation_ready_us_multispine_pool_manifest", "read_nullable_us_h5_metadata", + "require_authenticated_us_multispine_pool_h5", + "us_multispine_pool_release_receipt", "write_nullable_us_h5", ] @@ -328,6 +331,167 @@ def _raise_mismatch( ) +def identify_us_multispine_pool_manifest(path: str | Path) -> Path | None: + """Return the required sidecar when an H5 positively identifies as a pool. + + A successful pool publication writes ``.manifest.json`` beside the + H5 and stamps the H5's artifact-metadata row. Either identity is enough to + require the manifest. The caller must still authenticate that manifest; + this classifier deliberately does not turn sidecar existence into trust. + """ + + h5_path = Path(path) + manifest_path = h5_path.with_suffix(".manifest.json") + manifest_identifies_pool = False + if manifest_path.is_file(): + try: + sibling_manifest = _read_json_object( + manifest_path, + label="candidate US multispine pool manifest", + ) + except (OSError, ValueError): + sibling_manifest = None + manifest_identifies_pool = ( + isinstance(sibling_manifest, Mapping) + and sibling_manifest.get("artifact_kind") + == US_MULTISPINE_POOL_MANIFEST_ARTIFACT_KIND + ) + + # A generic PolicyEngine H5 has no Microcosm artifact-metadata table. Open + # the key inventory first so an unreadable non-pool fixture stays on the + # generic path, while a present-but-malformed identity row remains a hard + # error instead of becoming a receipt bypass. + try: + with pd.HDFStore(h5_path, mode="r") as store: + has_artifact_metadata = _METADATA_KEY in { + key.lstrip("/") for key in store.keys() + } + except Exception: + has_artifact_metadata = False + + h5_identifies_pool = False + if has_artifact_metadata: + metadata = read_nullable_us_h5_metadata(h5_path) + h5_identifies_pool = ( + metadata.get("artifact_kind") == US_MULTISPINE_POOL_H5_ARTIFACT_KIND + ) + if manifest_identifies_pool or h5_identifies_pool: + return manifest_path + return None + + +def require_authenticated_us_multispine_pool_h5( + requested_path: str | Path, + authenticated_pool_h5: AuthenticatedPoolH5, + *, + consumer: str, +) -> Path: + """Require one sidecar to authorize the exact H5 supplied by a consumer.""" + + requested = Path(requested_path).resolve() + authenticated = authenticated_pool_h5.path.resolve() + if authenticated != requested: + raise ValueError( + f"{consumer} supplied US multispine pool H5 {requested}, but its " + f"sibling manifest authenticates a different H5 {authenticated}." + ) + return authenticated + + +def us_multispine_pool_release_receipt( + manifest: Mapping[str, object], + authenticated_pool_h5: AuthenticatedPoolH5, + *, + allow_gate_failed_base_pool: bool, +) -> dict[str, object]: + """Build self-contained release evidence from an authenticated pool.""" + + status = manifest.get("status") + simulation_ready = manifest.get("simulation_ready") + is_ready = status == "simulation_ready" and simulation_ready is True + is_gate_failed = status == "gate_failed" and simulation_ready is False + if not is_ready and not is_gate_failed: + raise ValueError( + "Authenticated US multispine pool has an unsupported release status " + f"pair: status={status!r}, simulation_ready={simulation_ready!r}." + ) + if is_gate_failed and not allow_gate_failed_base_pool: + raise ValueError( + "Authenticated gate-failed US multispine pool requires the explicit " + "--allow-gate-failed-base-pool opt-in." + ) + + agreement_gate = _mapping( + manifest.get("agreement_gate"), + label="authenticated US multispine pool agreement_gate", + ) + expected_passed = is_ready + if agreement_gate.get("passed") is not expected_passed: + raise ValueError( + "Authenticated US multispine pool status disagrees with its " + "agreement-gate verdict." + ) + gates = _mapping( + agreement_gate.get("gates"), + label="authenticated US multispine pool agreement_gate.gates", + ) + failures: list[dict[str, str]] = [] + for gate_name, gate_payload in gates.items(): + if not isinstance(gate_name, str) or not gate_name: + raise ValueError( + "Authenticated US multispine pool agreement gate has an invalid " + "gate name." + ) + gate = _mapping( + gate_payload, + label=f"authenticated US multispine pool gate {gate_name!r}", + ) + gate_failures = gate.get("failures") + if not isinstance(gate_failures, list) or not all( + isinstance(failure, str) for failure in gate_failures + ): + raise ValueError( + f"Authenticated US multispine pool gate {gate_name!r} has an " + "invalid failure list." + ) + failures.extend( + {"gate": gate_name, "message": failure} for failure in gate_failures + ) + + diagnostics = _mapping( + manifest.get("agreement_diagnostics"), + label="authenticated US multispine pool agreement_diagnostics", + ) + gates_json_sha256 = diagnostics.get("sha256") + if ( + not isinstance(gates_json_sha256, str) + or _LOWERCASE_SHA256.fullmatch(gates_json_sha256) is None + ): + raise ValueError( + "Authenticated US multispine pool agreement diagnostics have no " + "valid SHA-256." + ) + + return { + "artifact_kind": US_MULTISPINE_POOL_H5_ARTIFACT_KIND, + "status": status, + "simulation_ready": simulation_ready, + "manifest_sha256": authenticated_pool_h5.manifest_sha256, + "publication_run_id": authenticated_pool_h5.publication_run_id, + "pool_h5_sha256": authenticated_pool_h5.sha256, + "pool_h5_size_bytes": authenticated_pool_h5.size_bytes, + "allow_gate_failed_base_pool": bool(allow_gate_failed_base_pool), + "agreement_gate_reference": { + "battery_status": "green" if is_ready else "red", + "passed": expected_passed, + "gates_json_sha256": gates_json_sha256, + "failure_count": len(failures), + "failures": failures, + "verdict": dict(agreement_gate), + }, + } + + def load_legacy_calibrated_us_h5(path: str | Path) -> Frame: """Load a legacy US single-year H5 as a calibrated-weight frame. diff --git a/packages/microcosm-build/tests/test_us_multispine_pool_h5_io.py b/packages/microcosm-build/tests/test_us_multispine_pool_h5_io.py index 54a7fe18..5074245a 100644 --- a/packages/microcosm-build/tests/test_us_multispine_pool_h5_io.py +++ b/packages/microcosm-build/tests/test_us_multispine_pool_h5_io.py @@ -26,15 +26,20 @@ CURRENT_CONGRESSIONAL_DISTRICT_VINTAGE, ) from microcosm.build.us_runtime.h5_io import ( + LEGACY_NULLABLE_STAGING_ARTIFACT_KIND, US_MULTISPINE_AGREEMENT_DIAGNOSTICS_ARTIFACT_KIND, US_MULTISPINE_POOL_H5_ARTIFACT_KIND, US_MULTISPINE_POOL_H5_MATERIALIZER_VERSION, US_MULTISPINE_POOL_MANIFEST_ARTIFACT_KIND, US_MULTISPINE_POOL_MANIFEST_SCHEMA_VERSION, US_STACKED_POOL_OPERATOR_ORDER, + AuthenticatedPoolH5, AuthenticatedPoolH5MismatchError, + identify_us_multispine_pool_manifest, load_authenticated_us_multispine_pool_for_scoring, load_simulation_ready_us_multispine_pool, + require_authenticated_us_multispine_pool_h5, + us_multispine_pool_release_receipt, write_nullable_us_h5, ) from microcosm.build.us_runtime.support_provenance import ( @@ -1490,6 +1495,91 @@ def test_scoring_pool_loader_authenticates_failed_stacked_terminal_receipt( assert loaded_manifest["terminal_gates"]["passed"] is False assert authenticated_h5.sha256 == loaded_manifest["pool_h5"]["sha256"] + receipt = us_multispine_pool_release_receipt( + loaded_manifest, + authenticated_h5, + allow_gate_failed_base_pool=True, + ) + assert receipt["status"] == "gate_failed" + assert receipt["simulation_ready"] is False + assert receipt["allow_gate_failed_base_pool"] is True + assert receipt["agreement_gate_reference"] == { + "battery_status": "red", + "passed": False, + "gates_json_sha256": loaded_manifest["agreement_diagnostics"]["sha256"], + "failure_count": 1, + "failures": [ + { + "gate": "us_spine_agreement", + "message": "fixture terminal failure", + } + ], + "verdict": failed_gate, + } + + +def test_pool_h5_identity_requires_its_missing_manifest_sidecar( + tmp_path: Path, +) -> None: + pytest.importorskip("tables") + manifest_path = _write_ready_pool(tmp_path, stacked=True) + pool_path = tmp_path / "pool.h5" + manifest_path.unlink() + + assert identify_us_multispine_pool_manifest(pool_path) == manifest_path + + +def test_pool_sidecar_identity_requires_authentication_even_without_h5_stamp( + tmp_path: Path, +) -> None: + pytest.importorskip("tables") + pool_path = tmp_path / "pool.h5" + write_nullable_us_h5( + _pool_frame(), + pool_path, + period=2024, + artifact_kind=LEGACY_NULLABLE_STAGING_ARTIFACT_KIND, + ) + manifest_path = pool_path.with_suffix(".manifest.json") + manifest_path.write_text( + json.dumps({"artifact_kind": US_MULTISPINE_POOL_MANIFEST_ARTIFACT_KIND}), + encoding="utf-8", + ) + + assert identify_us_multispine_pool_manifest(pool_path) == manifest_path + + +def test_non_pool_h5_has_no_required_pool_manifest(tmp_path: Path) -> None: + pytest.importorskip("tables") + h5_path = tmp_path / "staging.h5" + write_nullable_us_h5( + _pool_frame(), + h5_path, + period=2024, + artifact_kind=LEGACY_NULLABLE_STAGING_ARTIFACT_KIND, + ) + + assert identify_us_multispine_pool_manifest(h5_path) is None + + +def test_pool_sidecar_must_authenticate_the_requested_h5(tmp_path: Path) -> None: + requested = tmp_path / "requested.h5" + authenticated = tmp_path / "authenticated.h5" + identity = AuthenticatedPoolH5( + path=authenticated, + sha256="a" * 64, + size_bytes=1, + publication_run_id="fixture-publication", + manifest_sha256="b" * 64, + ) + + with pytest.raises(ValueError, match="authenticates a different H5"): + require_authenticated_us_multispine_pool_h5( + requested, + identity, + consumer="fixture consumer", + ) + @pytest.mark.parametrize( ("status", "simulation_ready"), From 271ee1fefaf5bdb5613eb7db8259bb568cbf832c Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 08:12:46 +0200 Subject: [PATCH 08/17] Close legacy base-H5 pool receipt bypass --- .../tests/test_us_fiscal_refresh_builder.py | 311 +++++++++++++----- tools/build_us_fiscal_refresh_release.py | 167 +++++----- 2 files changed, 301 insertions(+), 177 deletions(-) diff --git a/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py b/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py index 5756585a..a09ee0b4 100644 --- a/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py +++ b/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py @@ -1550,25 +1550,26 @@ def test_builder_exact_k_parser_enforces_charter_and_explicit_seed(capsys) -> No def test_builder_gate_failed_base_pool_override_is_explicit(capsys) -> None: builder = _load_builder_module() - parsed = builder._parse_args(_exact_k_builder_argv("20000")) + base_argv = [ + "--base-h5", + "pool.h5", + "--ledger-facts", + "facts.jsonl", + "--out", + "release", + "--no-staging", + ] + parsed = builder._parse_args(base_argv) assert parsed.allow_gate_failed_base_pool is False - parsed = builder._parse_args( - [*_exact_k_builder_argv("20000"), "--allow-gate-failed-base-pool"] - ) + parsed = builder._parse_args([*base_argv, "--allow-gate-failed-base-pool"]) assert parsed.allow_gate_failed_base_pool is True with pytest.raises(SystemExit): builder._parse_args( - [ - "--ledger-facts", - "facts.jsonl", - "--out", - "release", - "--allow-gate-failed-base-pool", - ] + [*_exact_k_builder_argv("20000"), "--allow-gate-failed-base-pool"] ) - assert "requires --pool-manifest" in capsys.readouterr().err + assert "requires --base-h5" in capsys.readouterr().err def test_builder_exact_k_requires_pointer_suppression(capsys) -> None: @@ -1668,52 +1669,170 @@ def fake_load_pool(path, *, expected_manifest_sha256): @pytest.mark.parametrize( - ("allow_gate_failed", "selected_loader", "unselected_loader"), + ("allow_gate_failed", "status", "simulation_ready", "passed"), ( - ( - False, - "load_simulation_ready_us_multispine_pool", - "load_authenticated_us_multispine_pool_for_scoring", - ), - ( - True, - "load_authenticated_us_multispine_pool_for_scoring", - "load_simulation_ready_us_multispine_pool", - ), + (False, "simulation_ready", True, True), + (True, "gate_failed", False, False), ), ) -def test_builder_selects_pool_loader_only_from_explicit_gate_failed_opt_in( +def test_builder_base_h5_pool_loader_is_selected_only_by_explicit_opt_in( monkeypatch, tmp_path, allow_gate_failed, - selected_loader, - unselected_loader, + status, + simulation_ready, + passed, ) -> None: builder = _load_builder_module() - argv = _exact_k_builder_argv("20000") - argv[argv.index("out")] = str(tmp_path / "out") + pool_h5 = tmp_path / "pool.h5" + pool_h5.write_bytes(b"authenticated pool") + manifest_path = pool_h5.with_suffix(".manifest.json") + gate_failures = [] if passed else ["fixture battery failure"] + manifest = { + "status": status, + "simulation_ready": simulation_ready, + "agreement_gate": { + "passed": passed, + "gates": { + "us_by_origin_battery": { + "passed": passed, + "failures": gate_failures, + } + }, + }, + "agreement_diagnostics": {"sha256": "2" * 64}, + } + authenticated = builder.AuthenticatedPoolH5( + path=pool_h5.resolve(), + sha256=hashlib.sha256(pool_h5.read_bytes()).hexdigest(), + size_bytes=pool_h5.stat().st_size, + publication_run_id="fixture-publication", + manifest_sha256="a" * 64, + ) + frame = SimpleNamespace() + monkeypatch.setattr( + builder, + "identify_us_multispine_pool_manifest", + lambda path: manifest_path, + ) + + def selected(path): + assert path == manifest_path + return frame, manifest, authenticated + if allow_gate_failed: - argv.append("--allow-gate-failed-base-pool") + monkeypatch.setattr( + builder, + "load_authenticated_us_multispine_pool_for_scoring", + selected, + ) + monkeypatch.setattr( + builder, + "load_simulation_ready_us_multispine_pool", + lambda path: pytest.fail("strict loader ran after explicit opt-in"), + ) + else: + monkeypatch.setattr( + builder, + "load_simulation_ready_us_multispine_pool", + selected, + ) + monkeypatch.setattr( + builder, + "load_authenticated_us_multispine_pool_for_scoring", + lambda path: pytest.fail("scoring loader ran without explicit opt-in"), + ) - monkeypatch.setattr(builder, "_git_dirty", lambda: False) - monkeypatch.setattr(builder, "_refuse_certified_release_dir_reuse", lambda path: None) + loaded_frame, receipt, loaded_identity = builder._load_base_pool_if_identified( + pool_h5, + allow_gate_failed_base_pool=allow_gate_failed, + ) + + assert loaded_frame is frame + assert loaded_identity is authenticated + assert receipt["status"] == status + assert receipt["allow_gate_failed_base_pool"] is allow_gate_failed + assert receipt["agreement_gate_reference"]["failure_count"] == len( + gate_failures + ) + + +def test_builder_refuses_red_base_h5_pool_without_opt_in( + monkeypatch, tmp_path +) -> None: + builder = _load_builder_module() + pool_h5 = tmp_path / "pool.h5" + manifest_path = pool_h5.with_suffix(".manifest.json") monkeypatch.setattr( builder, - "_load_verified_incumbent_diagnostics_payload", - lambda path, *, expected_sha256: ({}, expected_sha256), + "identify_us_multispine_pool_manifest", + lambda path: manifest_path, + ) + monkeypatch.setattr( + builder, + "load_authenticated_us_multispine_pool_for_scoring", + lambda path: pytest.fail("scoring loader ran without explicit opt-in"), ) - def selected(*args, **kwargs): - raise RuntimeError("selected pool loader") + def refuse(path): + raise ValueError("US multispine pool manifest is not simulation-ready") - def unselected(*args, **kwargs): - pytest.fail("the unselected pool loader ran") + monkeypatch.setattr(builder, "load_simulation_ready_us_multispine_pool", refuse) - monkeypatch.setattr(builder, selected_loader, selected) - monkeypatch.setattr(builder, unselected_loader, unselected) + with pytest.raises(ValueError, match="not simulation-ready"): + builder._load_base_pool_if_identified( + pool_h5, + allow_gate_failed_base_pool=False, + ) - with pytest.raises(RuntimeError, match="selected pool loader"): - builder.main(argv) + +def test_builder_refuses_bare_stamped_pool_h5_before_generic_load( + monkeypatch, tmp_path +) -> None: + pytest.importorskip("tables", exc_type=ModuleNotFoundError) + builder = _load_builder_module() + base_h5 = tmp_path / "pool.h5" + with pd.HDFStore(base_h5, mode="w") as store: + store.put( + "_populace_staging_metadata", + pd.Series( + [ + json.dumps( + { + "artifact_kind": "populace_us_multispine_input_pool", + "household_weight_kind": "importance", + "publication_run_id": "fixture-publication", + } + ) + ] + ), + format="table", + ) + out = tmp_path / "out" + monkeypatch.setattr(builder, "_git_dirty", lambda: False) + monkeypatch.setattr(builder, "_refuse_certified_release_dir_reuse", lambda path: None) + monkeypatch.setattr( + builder, + "_load_frame", + lambda path: pytest.fail("bare pool reached the generic H5 loader"), + ) + + with pytest.raises(ValueError, match="pool.manifest.json is not readable"): + builder.main( + [ + "--base-h5", + str(base_h5), + "--ledger-facts", + str(tmp_path / "facts.jsonl"), + "--out", + str(out), + "--release-id", + "populace-us-2024-bare-pool-fixture", + "--no-staging", + ] + ) + + assert not out.exists() def test_authenticated_pool_h5_consumers_use_one_returned_identity() -> None: @@ -8790,7 +8909,7 @@ def __len__(self): ) -def _gate_failed_exact_k_receipt(builder, *, allow_gate_failed_base_pool: bool): +def _gate_failed_exact_k_inputs(builder): class FakeFrame: @staticmethod def n(entity): @@ -8813,7 +8932,7 @@ def n(entity): exact_k=20_000, seed=17, pool_release_id="fixture-publication", - allow_gate_failed_base_pool=allow_gate_failed_base_pool, + allow_gate_failed_base_pool=True, ) failures = ["asec incidence differs", "puf_tax_detail incidence differs"] pool_manifest = { @@ -8838,40 +8957,73 @@ def n(entity): publication_run_id="fixture-publication", manifest_sha256="a" * 64, ) - receipt = builder._exact_k_ladder_manifest_payload( - args=args, - outcome=outcome, - pool_manifest=pool_manifest, - authenticated_pool_h5=authenticated_pool_h5, - ledger_artifact={"facts_sha256": "3" * 64}, - target_surface={"sha256": "4" * 64}, - target_loss_basis={"method": "fixture"}, - incumbent_diagnostics_sha256="5" * 64, - incumbent_fit_gate=builder.GateResult("incumbent_fit", True), - puf_tail_gate=builder.GateResult("puf_tail", True), - ) - return receipt, failures + return { + "args": args, + "outcome": outcome, + "pool_manifest": pool_manifest, + "authenticated_pool_h5": authenticated_pool_h5, + "ledger_artifact": {"facts_sha256": "3" * 64}, + "target_surface": {"sha256": "4" * 64}, + "target_loss_basis": {"method": "fixture"}, + "incumbent_diagnostics_sha256": "5" * 64, + "incumbent_fit_gate": builder.GateResult("incumbent_fit", True), + "puf_tail_gate": builder.GateResult("puf_tail", True), + } -def test_builder_refuses_gate_failed_pool_without_explicit_opt_in() -> None: +def test_exact_k_receipt_stays_strict_even_when_base_h5_opt_in_is_present() -> None: builder = _load_builder_module() with pytest.raises(RuntimeError, match="lost its passing agreement gate"): - _gate_failed_exact_k_receipt( - builder, - allow_gate_failed_base_pool=False, + builder._exact_k_ladder_manifest_payload( + **_gate_failed_exact_k_inputs(builder) ) -def test_gate_failed_pool_verdict_is_carried_into_release_manifest( +def _gate_failed_base_pool_receipt() -> dict[str, object]: + failures = [ + {"gate": "us_by_origin_battery", "message": "asec incidence differs"}, + { + "gate": "us_by_origin_battery", + "message": "puf_tax_detail incidence differs", + }, + ] + verdict = { + "passed": False, + "gates": { + "us_by_origin_battery": { + "passed": False, + "failures": [entry["message"] for entry in failures], + "details": {"fixture": True}, + } + }, + } + return { + "artifact_kind": "populace_us_multispine_input_pool", + "status": "gate_failed", + "simulation_ready": False, + "manifest_sha256": "a" * 64, + "publication_run_id": "fixture-publication", + "pool_h5_sha256": "1" * 64, + "pool_h5_size_bytes": 123, + "allow_gate_failed_base_pool": True, + "agreement_gate_reference": { + "battery_status": "red", + "passed": False, + "gates_json_sha256": "2" * 64, + "failure_count": len(failures), + "failures": failures, + "verdict": verdict, + }, + } + + +def test_gate_failed_base_pool_verdict_is_carried_into_release_manifest( monkeypatch, tmp_path ) -> None: builder = _load_builder_module() - ladder, failures = _gate_failed_exact_k_receipt( - builder, - allow_gate_failed_base_pool=True, - ) - release_id = "populace-us-2024-k20000-gate-failed-fixture" + receipt = _gate_failed_base_pool_receipt() + release_id = "populace-us-2024-gate-failed-fixture" release_dir = tmp_path / "release" / release_id release_dir.mkdir(parents=True) artifact_root = tmp_path / "artifacts" @@ -8904,33 +9056,14 @@ def test_gate_failed_pool_verdict_is_carried_into_release_manifest( ) builder._build_manifests( - exact_k_ladder=ladder, + base_pool=receipt, **_minimal_manifest_kwargs(builder, release_id, release_dir, artifact_root), ) + build_manifest = json.loads((release_dir / "build_manifest.json").read_text()) release_manifest = json.loads((release_dir / "release_manifest.json").read_text()) - carried = release_manifest["build"]["exact_k_ladder"] - assert carried["pool"] == { - "release_id": "fixture-publication", - "release_id_source": "pool_manifest.publication_run_id", - "manifest_sha256": "a" * 64, - "publication_run_id": "fixture-publication", - "pool_h5_sha256": "1" * 64, - "pool_h5_size_bytes": 123, - "agreement_diagnostics_sha256": "2" * 64, - "status": "gate_failed", - "simulation_ready": False, - "allow_gate_failed_base_pool": True, - } - verdict = carried["agreement_gate_reference"] - assert verdict["passed"] is False - assert verdict["battery_status"] == "red" - assert verdict["gates_json_sha256"] == "2" * 64 - assert verdict["failure_count"] == 2 - assert verdict["failures"] == failures - assert verdict["verdict"]["gates"]["us_by_origin_battery"]["failures"] == ( - failures - ) + assert build_manifest["base_pool"] == receipt + assert release_manifest["build"]["base_pool"] == receipt def test_build_manifests_uses_loadable_paths_and_round_trips_exact_count_receipt( diff --git a/tools/build_us_fiscal_refresh_release.py b/tools/build_us_fiscal_refresh_release.py index 19f22e91..d1343404 100644 --- a/tools/build_us_fiscal_refresh_release.py +++ b/tools/build_us_fiscal_refresh_release.py @@ -228,8 +228,11 @@ ) from microcosm.build.us_runtime.h5_io import ( AuthenticatedPoolH5, + identify_us_multispine_pool_manifest, load_authenticated_us_multispine_pool_for_scoring, load_simulation_ready_us_multispine_pool, + require_authenticated_us_multispine_pool_h5, + us_multispine_pool_release_receipt, ) from microcosm.build.us_runtime.input_mass import us_input_mass_totals from microcosm.build.us_runtime.l0_refit_export import ( @@ -853,11 +856,12 @@ def _parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace: "--allow-gate-failed-base-pool", action="store_true", help=( - "Explicitly allow an authenticated current stacked base-pool " - "manifest with status=gate_failed and simulation_ready=false. " + "Explicitly allow --base-h5 to consume an authenticated current " + "stacked pool with status=gate_failed and simulation_ready=false. " "The red agreement-gate verdict is carried into the release " "manifest for a separate human publication decision. Without " - "this flag --pool-manifest remains fail-closed." + "this flag an identified pool H5 remains fail-closed. The exact-k " + "--pool-manifest arm is always simulation-ready-only." ), ) parser.add_argument( @@ -1549,8 +1553,8 @@ def _parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace: ) if args.evidence_failure_owners is not None and not args.evidence_release: parser.error("--evidence-failure-owners requires --evidence-release.") - if args.allow_gate_failed_base_pool and args.pool_manifest is None: - parser.error("--allow-gate-failed-base-pool requires --pool-manifest.") + if args.allow_gate_failed_base_pool and args.base_h5 is None: + parser.error("--allow-gate-failed-base-pool requires --base-h5.") if args.evidence_release and args.exact_k is not None: parser.error( "--evidence-release is incompatible with --exact-k: ladder " @@ -1689,6 +1693,41 @@ def _legacy_base_h5_sha256(path: Path) -> str: return _sha256(path) +def _load_base_pool_if_identified( + path: Path, + *, + allow_gate_failed_base_pool: bool, +) -> tuple[Frame | None, dict[str, object] | None, AuthenticatedPoolH5 | None]: + """Authenticate a pool supplied through legacy ``--base-h5`` if present.""" + + manifest_path = identify_us_multispine_pool_manifest(path) + if manifest_path is None: + if allow_gate_failed_base_pool: + raise ValueError( + "--allow-gate-failed-base-pool was set, but --base-h5 does not " + "identify as a US multispine pool." + ) + return None, None, None + + loader = ( + load_authenticated_us_multispine_pool_for_scoring + if allow_gate_failed_base_pool + else load_simulation_ready_us_multispine_pool + ) + frame, manifest, authenticated_pool_h5 = loader(manifest_path) + require_authenticated_us_multispine_pool_h5( + path, + authenticated_pool_h5, + consumer="US fiscal refresh release builder --base-h5", + ) + receipt = us_multispine_pool_release_receipt( + manifest, + authenticated_pool_h5, + allow_gate_failed_base_pool=allow_gate_failed_base_pool, + ) + return frame, receipt, authenticated_pool_h5 + + def _copy_base_h5_for_local_audit( source: Path, destination: Path, @@ -7474,6 +7513,7 @@ def _build_manifests( calibration_key: str = "populace_us_2024_calibration", calibration_filename: str = CALIBRATION_FILENAME, exact_k_ladder: Mapping[str, object] | None = None, + base_pool: Mapping[str, object] | None = None, evidence_known_failures: Sequence[Mapping[str, str]] | None = None, ) -> None: dataset_path = artifact_root / dataset_filename @@ -7540,6 +7580,7 @@ def _build_manifests( if exact_k_ladder is not None else {} ), + **({"base_pool": dict(base_pool)} if base_pool is not None else {}), "dataset": { "filename": dataset_filename, "sha256": dataset_sha, @@ -7763,6 +7804,7 @@ def _build_manifests( if exact_k_ladder is not None else {} ), + **({"base_pool": dict(base_pool)} if base_pool is not None else {}), "warm_start_calibration": warm_start_payload, "selection_source": selection_source_payload, "default_dataset": default_dataset_payload, @@ -8238,91 +8280,31 @@ def _exact_k_ladder_manifest_payload( isinstance(value, Mapping) for value in (agreement_diagnostics, agreement_gate) ): raise RuntimeError("Validated pool manifest lost a required receipt block.") - agreement_gate_passed = agreement_gate.get("passed") - gate_passed = agreement_gate_passed is True - allow_gate_failed_base_pool = getattr( - args, - "allow_gate_failed_base_pool", - False, - ) - is_gate_failed_pool = ( - pool_manifest.get("status") == "gate_failed" - and pool_manifest.get("simulation_ready") is False - ) - if is_gate_failed_pool and agreement_gate_passed is not False: - raise RuntimeError( - "Validated gate-failed pool manifest does not carry an explicitly " - "failed agreement gate." - ) - if not gate_passed and not ( - allow_gate_failed_base_pool and is_gate_failed_pool - ): + if agreement_gate.get("passed") is not True: raise RuntimeError("Validated pool manifest lost its passing agreement gate.") pool_release_id = _assert_pool_release_id_value( args.pool_release_id, authenticated_pool_h5.publication_run_id, ) - pool_reference = { - "release_id": pool_release_id, - "release_id_source": "pool_manifest.publication_run_id", - "manifest_sha256": authenticated_pool_h5.manifest_sha256, - "publication_run_id": authenticated_pool_h5.publication_run_id, - "pool_h5_sha256": authenticated_pool_h5.sha256, - "pool_h5_size_bytes": authenticated_pool_h5.size_bytes, - "agreement_diagnostics_sha256": agreement_diagnostics.get("sha256"), - } - agreement_gate_reference = { - "passed": True, - "publication_run_id": authenticated_pool_h5.publication_run_id, - "diagnostics_sha256": agreement_diagnostics.get("sha256"), - "verdict": dict(agreement_gate), - } - if allow_gate_failed_base_pool: - pool_reference.update( - { - "status": pool_manifest.get("status"), - "simulation_ready": pool_manifest.get("simulation_ready"), - "allow_gate_failed_base_pool": True, - } - ) - if is_gate_failed_pool: - failures: list[str] = [] - gates = agreement_gate.get("gates") - if not isinstance(gates, Mapping): - raise RuntimeError( - "Validated gate-failed pool manifest lost its agreement-gate " - "results." - ) - for gate_name, gate_verdict in gates.items(): - if not isinstance(gate_verdict, Mapping): - raise RuntimeError( - "Validated gate-failed pool manifest has a malformed " - f"agreement-gate result for {gate_name!r}." - ) - gate_failures = gate_verdict.get("failures", ()) - if not isinstance(gate_failures, list) or not all( - isinstance(failure, str) for failure in gate_failures - ): - raise RuntimeError( - "Validated gate-failed pool manifest has a malformed " - f"failure list for {gate_name!r}." - ) - failures.extend(gate_failures) - agreement_gate_reference.update( - { - "passed": False, - "battery_status": "red", - "gates_json_sha256": agreement_diagnostics.get("sha256"), - "failure_count": len(failures), - "failures": failures, - } - ) payload = exact_k_ladder_manifest_payload( outcome, k=int(args.exact_k), seed=int(args.seed), - pool=pool_reference, - agreement_gate_reference=agreement_gate_reference, + pool={ + "release_id": pool_release_id, + "release_id_source": "pool_manifest.publication_run_id", + "manifest_sha256": authenticated_pool_h5.manifest_sha256, + "publication_run_id": authenticated_pool_h5.publication_run_id, + "pool_h5_sha256": authenticated_pool_h5.sha256, + "pool_h5_size_bytes": authenticated_pool_h5.size_bytes, + "agreement_diagnostics_sha256": agreement_diagnostics.get("sha256"), + }, + agreement_gate_reference={ + "passed": True, + "publication_run_id": authenticated_pool_h5.publication_run_id, + "diagnostics_sha256": agreement_diagnostics.get("sha256"), + "verdict": dict(agreement_gate), + }, frozen_target_register={ "ledger_artifact": dict(ledger_artifact), "target_surface_sha256": target_surface.get("sha256"), @@ -8606,15 +8588,11 @@ def _main(argv: Sequence[str] | None = None) -> None: pool_original_household_ids: np.ndarray | None = None pool_original_household_weights: np.ndarray | None = None pool_manifest_payload: dict[str, object] | None = None + base_pool_receipt: dict[str, object] | None = None authenticated_pool_h5: AuthenticatedPoolH5 | None = None if args.pool_manifest is not None: - pool_loader = ( - load_authenticated_us_multispine_pool_for_scoring - if args.allow_gate_failed_base_pool - else load_simulation_ready_us_multispine_pool - ) pool_frame, pool_manifest_payload, authenticated_pool_h5 = ( - pool_loader( + load_simulation_ready_us_multispine_pool( args.pool_manifest, expected_manifest_sha256=args.pool_manifest_sha256, ) @@ -8643,7 +8621,19 @@ def _main(argv: Sequence[str] | None = None) -> None: base_h5 = authenticated_pool_h5.path else: base_h5 = args.base_h5 or _download_base_h5() - base_dataset_sha256 = _legacy_base_h5_sha256(base_h5) + pool_frame, base_pool_receipt, authenticated_pool_h5 = ( + _load_base_pool_if_identified( + base_h5, + allow_gate_failed_base_pool=args.allow_gate_failed_base_pool, + ) + ) + if authenticated_pool_h5 is None: + base_dataset_sha256 = _legacy_base_h5_sha256(base_h5) + else: + base_dataset_sha256 = authenticated_pool_h5.verified_digest( + consumer="builder base dataset identity" + ) + base_h5 = authenticated_pool_h5.path digest = base_dataset_sha256[:7] build_timestamp = datetime.now(UTC) full_commit = _git_output("rev-parse", "HEAD") @@ -11800,6 +11790,7 @@ def _main(argv: Sequence[str] | None = None) -> None: calibration_key=calibration_key, calibration_filename=calibration_filename, exact_k_ladder=exact_k_ladder_provenance, + base_pool=base_pool_receipt, evidence_known_failures=evidence_known_failures, ) if telemetry is not None: From 921343222fd117f1bbc3307265535378a1d16a15 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 08:18:31 +0200 Subject: [PATCH 09/17] Authenticate and surface gate-failed pools in preflight --- changelog.d/gate-failed-pool-release.added.md | 1 - changelog.d/gate-failed-pool-release.fixed.md | 1 + .../us_runtime/release_gate_preflight.py | 93 +++++++- .../tests/test_us_release_gate_preflight.py | 221 ++++++++++++++++-- tools/preflight_us_release_gates.py | 85 +++++-- 5 files changed, 364 insertions(+), 37 deletions(-) delete mode 100644 changelog.d/gate-failed-pool-release.added.md create mode 100644 changelog.d/gate-failed-pool-release.fixed.md diff --git a/changelog.d/gate-failed-pool-release.added.md b/changelog.d/gate-failed-pool-release.added.md deleted file mode 100644 index 3a1b460a..00000000 --- a/changelog.d/gate-failed-pool-release.added.md +++ /dev/null @@ -1 +0,0 @@ -Allow an exact-k US fiscal release to opt in explicitly to an authenticated current stacked pool whose terminal agreement battery is red via ``--allow-gate-failed-base-pool``. The release carries the pool status, readiness, opt-in, gates-JSON digest, complete verdict, and failure summary, while publication preflight presents the red battery as prominent evidence for a separate human decision without changing its automated exit code. diff --git a/changelog.d/gate-failed-pool-release.fixed.md b/changelog.d/gate-failed-pool-release.fixed.md new file mode 100644 index 00000000..bda525e2 --- /dev/null +++ b/changelog.d/gate-failed-pool-release.fixed.md @@ -0,0 +1 @@ +Close the US fiscal release and release-gate preflight bypass that treated a bare multispine ``--base-h5`` as a generic H5 without authenticating its terminal manifest. ``--allow-gate-failed-base-pool`` now explicitly admits only an authenticated current stacked ``gate_failed`` pool, carries its full red battery receipt under ``build.base_pool``, and surfaces that evidence prominently for a separate human publication decision without changing other preflight exits. diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/release_gate_preflight.py b/packages/microcosm-build/src/microcosm/build/us_runtime/release_gate_preflight.py index 2c203fa4..efe74535 100644 --- a/packages/microcosm-build/src/microcosm/build/us_runtime/release_gate_preflight.py +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/release_gate_preflight.py @@ -64,6 +64,13 @@ import pandas as pd from microcosm.build.gates import input_mass_parity_gate +from microcosm.build.us_runtime.h5_io import ( + identify_us_multispine_pool_manifest, + load_authenticated_us_multispine_pool_for_scoring, + load_simulation_ready_us_multispine_pool, + require_authenticated_us_multispine_pool_h5, + us_multispine_pool_release_receipt, +) from microcosm.build.us_runtime.input_mass import us_input_mass_totals from microcosm.build.us_runtime.puf_capital_gains_tail import ( assert_puf_capital_gains_tail_survives_selection, @@ -159,6 +166,7 @@ class PreflightReport: checks: tuple[CheckResult, ...] inputs: Mapping[str, Any] = field(default_factory=dict) + base_pool: Mapping[str, Any] | None = None @property def status(self) -> PreflightStatus: @@ -179,16 +187,46 @@ def exit_code(self) -> int: return 0 def to_dict(self) -> dict[str, Any]: - return { + payload = { "status": self.status, "exit_code": self.exit_code, "inputs": dict(self.inputs), "checks": [check.to_dict() for check in self.checks], } + if self.base_pool is not None: + payload["base_pool"] = dict(self.base_pool) + return payload def human_table(self) -> str: """A compact, terminal-friendly rendering of every check.""" lines: list[str] = [] + if self.base_pool is not None: + agreement = self.base_pool.get("agreement_gate_reference") + if isinstance(agreement, Mapping) and agreement.get( + "battery_status" + ) == "red": + failure_count = agreement.get("failure_count") + lines.extend( + [ + "!" * 72, + "BASE POOL BATTERY: RED — " + f"{failure_count} FAILURES", + "Authenticated opt-in: --allow-gate-failed-base-pool", + "Gates JSON SHA-256: " + f"{agreement.get('gates_json_sha256')}", + "Human publication decision required; this evidence " + "does not determine the preflight exit code.", + ] + ) + failures = agreement.get("failures") + if isinstance(failures, list): + for failure in failures: + if isinstance(failure, Mapping): + lines.append( + f" [{failure.get('gate')}] " + f"{failure.get('message')}" + ) + lines.append("!" * 72) badge = { "PASS": "PASS ", "FAIL": "FAIL ", @@ -808,6 +846,7 @@ def run_preflight( probes: Iterable[ReformCoverageProbe] | None = None, engine_input_variables: Sequence[str] | None = None, export_mass_reviewed_exclusions: Mapping[str, str] | None = None, + allow_gate_failed_base_pool: bool = False, ) -> PreflightReport: """Load the real artifacts and run every preflight check (no solve). @@ -818,7 +857,10 @@ def run_preflight( from microcosm.build.us_runtime.l0_refit_export import load_us_frame base_h5 = Path(base_h5) - base_frame = load_us_frame(base_h5) + base_frame, base_pool, base_pool_manifest = _load_preflight_base( + base_h5, + allow_gate_failed_base_pool=allow_gate_failed_base_pool, + ) selection_source = load_selection_source_from_manifest(selection_source_manifest) checks: list[CheckResult] = [] @@ -908,6 +950,10 @@ def run_preflight( inputs = { "base_h5": str(base_h5), + "base_pool_manifest": ( + str(base_pool_manifest) if base_pool_manifest is not None else None + ), + "allow_gate_failed_base_pool": bool(allow_gate_failed_base_pool), "selection_source_manifest": str(selection_source_manifest), "export_input_mass_reference_h5": ( str(export_input_mass_reference_h5) @@ -919,7 +965,48 @@ def run_preflight( "relative_tolerance": float(relative_tolerance), "minimum_reference_total": float(minimum_reference_total), } - return PreflightReport(checks=tuple(checks), inputs=inputs) + return PreflightReport( + checks=tuple(checks), + inputs=inputs, + base_pool=base_pool, + ) + + +def _load_preflight_base( + base_h5: Path, + *, + allow_gate_failed_base_pool: bool, +) -> tuple[Frame, dict[str, object] | None, Path | None]: + """Load a generic base or authenticate a positively identified pool.""" + + from microcosm.build.us_runtime.l0_refit_export import load_us_frame + + manifest_path = identify_us_multispine_pool_manifest(base_h5) + if manifest_path is None: + if allow_gate_failed_base_pool: + raise ValueError( + "--allow-gate-failed-base-pool was set, but --base-h5 does not " + "identify as a US multispine pool." + ) + return load_us_frame(base_h5), None, None + + loader = ( + load_authenticated_us_multispine_pool_for_scoring + if allow_gate_failed_base_pool + else load_simulation_ready_us_multispine_pool + ) + frame, manifest, authenticated_pool_h5 = loader(manifest_path) + require_authenticated_us_multispine_pool_h5( + base_h5, + authenticated_pool_h5, + consumer="US release-gate preflight --base-h5", + ) + receipt = us_multispine_pool_release_receipt( + manifest, + authenticated_pool_h5, + allow_gate_failed_base_pool=allow_gate_failed_base_pool, + ) + return frame, receipt, manifest_path def _household_person_mask(base_frame: Frame, household_mask: np.ndarray) -> np.ndarray: diff --git a/packages/microcosm-build/tests/test_us_release_gate_preflight.py b/packages/microcosm-build/tests/test_us_release_gate_preflight.py index bf9700f3..194cae29 100644 --- a/packages/microcosm-build/tests/test_us_release_gate_preflight.py +++ b/packages/microcosm-build/tests/test_us_release_gate_preflight.py @@ -24,6 +24,8 @@ import pandas as pd import pytest +import microcosm.build.us_runtime.release_gate_preflight as preflight_module +from microcosm.build.us_runtime.h5_io import AuthenticatedPoolH5 from microcosm.build.us_runtime.release_gate_preflight import ( PreflightReport, check_export_mass_parity_risk, @@ -51,15 +53,24 @@ def _load_preflight_cli(): return module -def _write_gate_failed_release_manifest(path: Path) -> tuple[list[str], str]: - failures = ["asec incidence differs", "puf_tax_detail incidence differs"] +def _write_gate_failed_release_manifest( + path: Path, +) -> tuple[list[dict[str, str]], str]: + failure_messages = [ + "asec incidence differs", + "puf_tax_detail incidence differs", + ] + failures = [ + {"gate": "us_by_origin_battery", "message": message} + for message in failure_messages + ] gates_sha256 = "2" * 64 verdict = { "passed": False, "gates": { "us_by_origin_battery": { "passed": False, - "failures": failures, + "failures": failure_messages, "details": {"fixture": True}, } }, @@ -69,17 +80,18 @@ def _write_gate_failed_release_manifest(path: Path) -> tuple[list[str], str]: { "schema_version": 1, "build": { - "exact_k_ladder": { - "pool": { - "status": "gate_failed", - "simulation_ready": False, - "allow_gate_failed_base_pool": True, - "agreement_diagnostics_sha256": gates_sha256, - }, + "base_pool": { + "artifact_kind": "populace_us_multispine_input_pool", + "status": "gate_failed", + "simulation_ready": False, + "manifest_sha256": "a" * 64, + "publication_run_id": "fixture-publication", + "pool_h5_sha256": "1" * 64, + "pool_h5_size_bytes": 123, + "allow_gate_failed_base_pool": True, "agreement_gate_reference": { "passed": False, "battery_status": "red", - "diagnostics_sha256": gates_sha256, "gates_json_sha256": gates_sha256, "failure_count": len(failures), "failures": failures, @@ -715,6 +727,178 @@ def test__report__to_dict_is_json_ready() -> None: assert payload["checks"][0]["rows"] == [{"k": 1}] +def test__report__carried_red_pool_is_prominent_but_non_blocking(tmp_path) -> None: + release_manifest = tmp_path / "release_manifest.json" + failures, gates_sha256 = _write_gate_failed_release_manifest(release_manifest) + base_pool = json.loads(release_manifest.read_text())["build"]["base_pool"] + report = PreflightReport(checks=(), base_pool=base_pool) + + rendered = report.human_table() + assert report.status == "PASS" + assert report.exit_code == 0 + assert "BASE POOL BATTERY: RED — 2 FAILURES" in rendered + assert "Human publication decision required" in rendered + assert f"Gates JSON SHA-256: {gates_sha256}" in rendered + assert all( + f"[{failure['gate']}] {failure['message']}" in rendered + for failure in failures + ) + assert report.to_dict()["base_pool"] == base_pool + + +@pytest.mark.parametrize( + ("allow_gate_failed", "status", "simulation_ready", "passed"), + ( + (False, "simulation_ready", True, True), + (True, "gate_failed", False, False), + ), +) +def test__preflight_base__authenticates_pool_with_loader_selected_by_opt_in( + monkeypatch, + tmp_path, + allow_gate_failed, + status, + simulation_ready, + passed, +) -> None: + base_h5 = tmp_path / "pool.h5" + base_h5.write_bytes(b"authenticated pool") + manifest_path = base_h5.with_suffix(".manifest.json") + failures = [] if passed else ["fixture battery failure"] + manifest = { + "status": status, + "simulation_ready": simulation_ready, + "agreement_gate": { + "passed": passed, + "gates": { + "us_by_origin_battery": { + "passed": passed, + "failures": failures, + } + }, + }, + "agreement_diagnostics": {"sha256": "2" * 64}, + } + identity = AuthenticatedPoolH5( + path=base_h5.resolve(), + sha256="1" * 64, + size_bytes=base_h5.stat().st_size, + publication_run_id="fixture-publication", + manifest_sha256="a" * 64, + ) + frame = _frame(_POOL) + monkeypatch.setattr( + preflight_module, + "identify_us_multispine_pool_manifest", + lambda path: manifest_path, + ) + + def selected(path): + assert path == manifest_path + return frame, manifest, identity + + if allow_gate_failed: + monkeypatch.setattr( + preflight_module, + "load_authenticated_us_multispine_pool_for_scoring", + selected, + ) + monkeypatch.setattr( + preflight_module, + "load_simulation_ready_us_multispine_pool", + lambda path: pytest.fail("strict loader ran after explicit opt-in"), + ) + else: + monkeypatch.setattr( + preflight_module, + "load_simulation_ready_us_multispine_pool", + selected, + ) + monkeypatch.setattr( + preflight_module, + "load_authenticated_us_multispine_pool_for_scoring", + lambda path: pytest.fail("scoring loader ran without explicit opt-in"), + ) + + loaded, receipt, loaded_manifest_path = preflight_module._load_preflight_base( + base_h5, + allow_gate_failed_base_pool=allow_gate_failed, + ) + + assert loaded is frame + assert loaded_manifest_path == manifest_path + assert receipt["status"] == status + assert receipt["agreement_gate_reference"]["failure_count"] == len(failures) + + +def test__preflight_base__refuses_red_pool_without_opt_in( + monkeypatch, tmp_path +) -> None: + base_h5 = tmp_path / "pool.h5" + manifest_path = base_h5.with_suffix(".manifest.json") + monkeypatch.setattr( + preflight_module, + "identify_us_multispine_pool_manifest", + lambda path: manifest_path, + ) + monkeypatch.setattr( + preflight_module, + "load_authenticated_us_multispine_pool_for_scoring", + lambda path: pytest.fail("scoring loader ran without explicit opt-in"), + ) + + def refuse(path): + raise ValueError("US multispine pool manifest is not simulation-ready") + + monkeypatch.setattr( + preflight_module, + "load_simulation_ready_us_multispine_pool", + refuse, + ) + + with pytest.raises(ValueError, match="not simulation-ready"): + preflight_module._load_preflight_base( + base_h5, + allow_gate_failed_base_pool=False, + ) + + +def test__preflight_base__refuses_bare_stamped_pool_before_generic_load( + monkeypatch, tmp_path +) -> None: + pytest.importorskip("tables", exc_type=ModuleNotFoundError) + import microcosm.build.us_runtime.l0_refit_export as l0_refit_export + + base_h5 = tmp_path / "pool.h5" + with pd.HDFStore(base_h5, mode="w") as store: + store.put( + "_populace_staging_metadata", + pd.Series( + [ + json.dumps( + { + "artifact_kind": "populace_us_multispine_input_pool", + "household_weight_kind": "importance", + "publication_run_id": "fixture-publication", + } + ) + ] + ), + format="table", + ) + monkeypatch.setattr( + l0_refit_export, + "load_us_frame", + lambda path: pytest.fail("bare pool reached the generic H5 loader"), + ) + + with pytest.raises(ValueError, match="pool.manifest.json is not readable"): + preflight_module._load_preflight_base( + base_h5, + allow_gate_failed_base_pool=False, + ) + + def test__cli__manifest_only_surfaces_carried_red_battery_without_failing( monkeypatch, tmp_path, capsys ) -> None: @@ -746,7 +930,10 @@ def test__cli__manifest_only_surfaces_carried_red_battery_without_failing( assert "Publication decision: HUMAN REVIEW REQUIRED" in output assert "does not alter the preflight exit code" in output assert "Static base/selection checks: NOT RUN" in output - assert all(f"FAILURE: {failure}" in output for failure in failures) + assert all( + f"FAILURE [{failure['gate']}]: {failure['message']}" in output + for failure in failures + ) assert output.rstrip().endswith( "CARRIED RED BATTERY: HUMAN REVIEW REQUIRED; automated preflight exit " "remains 0." @@ -783,7 +970,13 @@ def test__cli__carried_red_battery_does_not_change_existing_preflight_exit( ), ) ) - monkeypatch.setattr(cli, "run_preflight", lambda **kwargs: report) + captured: dict[str, object] = {} + + def fake_run_preflight(**kwargs): + captured.update(kwargs) + return report + + monkeypatch.setattr(cli, "run_preflight", fake_run_preflight) exit_code = cli.main( [ @@ -791,6 +984,7 @@ def test__cli__carried_red_battery_does_not_change_existing_preflight_exit( str(tmp_path / "base.h5"), "--selection-source-manifest", str(tmp_path / "selection.json"), + "--allow-gate-failed-base-pool", "--release-manifest", str(release_manifest), "--json-out", @@ -810,6 +1004,7 @@ def test__cli__carried_red_battery_does_not_change_existing_preflight_exit( assert payload["carried_base_pool_agreement_battery"][ "affects_exit_code" ] is False + assert captured["allow_gate_failed_base_pool"] is True def test__load_ledger_target_specs__hands_fact_rows_to_the_compiler( diff --git a/tools/preflight_us_release_gates.py b/tools/preflight_us_release_gates.py index 0cfeadf7..a0fae0e2 100644 --- a/tools/preflight_us_release_gates.py +++ b/tools/preflight_us_release_gates.py @@ -37,8 +37,11 @@ 0, str(Path(__file__).resolve().parents[1] / "packages" / "microcosm-build" / "src") ) -from microcosm.build.us_runtime.release_gate_preflight import ( - run_preflight, # noqa: E402 +from microcosm.build.us_runtime.h5_io import ( # noqa: E402 + US_MULTISPINE_POOL_H5_ARTIFACT_KIND, +) +from microcosm.build.us_runtime.release_gate_preflight import ( # noqa: E402 + run_preflight, ) _ALLOW_GATE_FAILED_BASE_POOL_FLAG = "--allow-gate-failed-base-pool" @@ -63,16 +66,13 @@ def _load_carried_base_pool_battery( build = release_manifest.get("build") if not isinstance(build, dict): return None - exact_k_ladder = build.get("exact_k_ladder") - if not isinstance(exact_k_ladder, dict): - return None - pool = exact_k_ladder.get("pool") - agreement_gate_reference = exact_k_ladder.get("agreement_gate_reference") - if not isinstance(pool, dict): + base_pool = build.get("base_pool") + if not isinstance(base_pool, dict): return None + agreement_gate_reference = base_pool.get("agreement_gate_reference") carries_gate_failed_override = ( - pool.get("allow_gate_failed_base_pool") is True - or pool.get("status") == "gate_failed" + base_pool.get("allow_gate_failed_base_pool") is True + or base_pool.get("status") == "gate_failed" or ( isinstance(agreement_gate_reference, dict) and agreement_gate_reference.get("battery_status") == "red" @@ -81,9 +81,10 @@ def _load_carried_base_pool_battery( if not carries_gate_failed_override: return None if ( - pool.get("status") != "gate_failed" - or pool.get("simulation_ready") is not False - or pool.get("allow_gate_failed_base_pool") is not True + base_pool.get("artifact_kind") != US_MULTISPINE_POOL_H5_ARTIFACT_KIND + or base_pool.get("status") != "gate_failed" + or base_pool.get("simulation_ready") is not False + or base_pool.get("allow_gate_failed_base_pool") is not True ): raise ValueError( f"Release manifest {path} has an incoherent gate-failed base-pool " @@ -92,8 +93,7 @@ def _load_carried_base_pool_battery( gate_reference = _json_object( agreement_gate_reference, label=( - f"release manifest {path} build.exact_k_ladder." - "agreement_gate_reference" + f"release manifest {path} build.base_pool.agreement_gate_reference" ), ) failures = gate_reference.get("failures") @@ -104,7 +104,13 @@ def _load_carried_base_pool_battery( gate_reference.get("passed") is not False or gate_reference.get("battery_status") != "red" or not isinstance(failures, list) - or not all(isinstance(failure, str) for failure in failures) + or not all( + isinstance(failure, dict) + and isinstance(failure.get("gate"), str) + and bool(failure.get("gate")) + and isinstance(failure.get("message"), str) + for failure in failures + ) or type(failure_count) is not int or failure_count != len(failures) or not isinstance(gates_json_sha256, str) @@ -115,13 +121,37 @@ def _load_carried_base_pool_battery( ) or not isinstance(verdict, dict) or verdict.get("passed") is not False - or gate_reference.get("diagnostics_sha256") != gates_json_sha256 - or pool.get("agreement_diagnostics_sha256") != gates_json_sha256 ): raise ValueError( f"Release manifest {path} has an incomplete or inconsistent " "carried red agreement-battery verdict." ) + verdict_gates = verdict.get("gates") + if not isinstance(verdict_gates, dict): + raise ValueError( + f"Release manifest {path} has no full carried gate verdict." + ) + verdict_failures: list[dict[str, str]] = [] + for gate_name, gate_payload in verdict_gates.items(): + if not isinstance(gate_name, str) or not isinstance(gate_payload, dict): + raise ValueError( + f"Release manifest {path} has a malformed carried gate verdict." + ) + gate_failures = gate_payload.get("failures") + if not isinstance(gate_failures, list) or not all( + isinstance(failure, str) for failure in gate_failures + ): + raise ValueError( + f"Release manifest {path} has a malformed carried failure list." + ) + verdict_failures.extend( + {"gate": gate_name, "message": failure} for failure in gate_failures + ) + if verdict_failures != failures: + raise ValueError( + f"Release manifest {path} failure summary does not match its full " + "carried gate verdict." + ) return { "battery_status": "red", "pool_status": "gate_failed", @@ -130,7 +160,7 @@ def _load_carried_base_pool_battery( "flag": _ALLOW_GATE_FAILED_BASE_POOL_FLAG, "gates_json_sha256": gates_json_sha256, "failure_count": failure_count, - "failures": list(failures), + "failures": [dict(failure) for failure in failures], "agreement_gate_reference": dict(gate_reference), "publication_decision": "human_review_required", "affects_exit_code": False, @@ -149,7 +179,10 @@ def _carried_battery_banner(carried: dict[str, object]) -> str: "Publication decision: HUMAN REVIEW REQUIRED", "This carried verdict does not alter the preflight exit code.", ] - lines.extend(f" FAILURE: {failure}" for failure in carried["failures"]) + lines.extend( + f" FAILURE [{failure['gate']}]: {failure['message']}" + for failure in carried["failures"] + ) lines.append("=" * 72) return "\n".join(lines) @@ -171,6 +204,15 @@ def _parser() -> argparse.ArgumentParser: "for a manifest-only publication review." ), ) + parser.add_argument( + "--allow-gate-failed-base-pool", + action="store_true", + help=( + "Allow an authenticated current stacked --base-h5 pool whose " + "terminal battery is red. The verdict is displayed prominently " + "but does not itself determine the preflight exit code." + ), + ) parser.add_argument( "--selection-source-manifest", type=Path, @@ -257,6 +299,8 @@ def main(argv: list[str] | None = None) -> int: parser.error( "--base-h5 and --selection-source-manifest must be provided together." ) + if args.allow_gate_failed_base_pool and not has_base_h5: + parser.error("--allow-gate-failed-base-pool requires --base-h5.") if not has_base_h5 and args.release_manifest is None: parser.error( "provide --base-h5 with --selection-source-manifest, or provide " @@ -290,6 +334,7 @@ def main(argv: list[str] | None = None) -> int: target_period=target_period, relative_tolerance=args.relative_tolerance, minimum_reference_total=args.minimum_reference_total, + allow_gate_failed_base_pool=args.allow_gate_failed_base_pool, ) print(report.human_table()) payload = report.to_dict() From cd39f756a5c06b4856bd8e67bc7a70fb014212dd Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 08:19:07 +0200 Subject: [PATCH 10/17] Document gate-failed base-pool release boundary --- CLAUDE.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 2857eb1f..2303d9a1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -80,6 +80,13 @@ build recorded staging telemetry that never reached its repo publishes without the flag. Never publish or promote artifacts as a side effect of another task. +A US release or release-gate preflight that receives a multispine pool through +`--base-h5` must authenticate its sibling terminal manifest. A current stacked +pool whose terminal battery is red remains fail-closed unless the operator +passes `--allow-gate-failed-base-pool`; that opt-in carries the full red verdict +into `release_manifest.json` for a separate human publication decision. It does +not weaken the exact-k manifest arm or authorize publication by itself. + ## Root journals are history, not state The root `PROGRESS*.md`, `FINAL_REPORT.md`, `*_COVERAGE_PROGRESS.md`, and From 9db4694a64b32244ebfa18ae869072c0eec8c791 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 09:21:57 +0200 Subject: [PATCH 11/17] Tighten the authenticated red-pool release opt-in --- .../src/microcosm/build/us_runtime/h5_io.py | 58 +++++++++- .../us_runtime/release_gate_preflight.py | 13 +-- .../tests/test_us_fiscal_refresh_builder.py | 106 ++++++++++-------- .../tests/test_us_multispine_pool_h5_io.py | 64 +++++++++++ .../tests/test_us_release_gate_preflight.py | 86 +++++++------- tools/build_us_fiscal_refresh_release.py | 17 +-- 6 files changed, 238 insertions(+), 106 deletions(-) diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py b/packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py index 256b046f..516dead3 100644 --- a/packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py @@ -59,6 +59,7 @@ "US_MULTISPINE_POOL_MANIFEST_SCHEMA_VERSION", "US_STACKED_POOL_OPERATOR_ORDER", "identify_us_multispine_pool_manifest", + "load_authenticated_us_multispine_pool_for_release", "load_authenticated_us_multispine_pool_for_scoring", "load_legacy_calibrated_us_h5", "load_simulation_ready_us_multispine_pool", @@ -420,6 +421,12 @@ def us_multispine_pool_release_receipt( "Authenticated gate-failed US multispine pool requires the explicit " "--allow-gate-failed-base-pool opt-in." ) + if is_ready and allow_gate_failed_base_pool: + raise ValueError( + "--allow-gate-failed-base-pool was set, but the authenticated US " + "multispine pool is simulation-ready; the override is valid only " + "for status=gate_failed and simulation_ready=false." + ) agreement_gate = _mapping( manifest.get("agreement_gate"), @@ -435,7 +442,13 @@ def us_multispine_pool_release_receipt( agreement_gate.get("gates"), label="authenticated US multispine pool agreement_gate.gates", ) + if not gates: + raise ValueError( + "Authenticated US multispine pool agreement gate has no nested " + "gate verdicts." + ) failures: list[dict[str, str]] = [] + nested_passed: list[bool] = [] for gate_name, gate_payload in gates.items(): if not isinstance(gate_name, str) or not gate_name: raise ValueError( @@ -446,17 +459,31 @@ def us_multispine_pool_release_receipt( gate_payload, label=f"authenticated US multispine pool gate {gate_name!r}", ) + gate_passed = gate.get("passed") gate_failures = gate.get("failures") - if not isinstance(gate_failures, list) or not all( + if type(gate_passed) is not bool or not isinstance( + gate_failures, list + ) or not all( isinstance(failure, str) for failure in gate_failures ): raise ValueError( f"Authenticated US multispine pool gate {gate_name!r} has an " - "invalid failure list." + "invalid passed verdict or failure list." + ) + if gate_passed is bool(gate_failures): + raise ValueError( + f"Authenticated US multispine pool gate {gate_name!r} has an " + "incoherent passed verdict and failure list." ) + nested_passed.append(gate_passed) failures.extend( {"gate": gate_name, "message": failure} for failure in gate_failures ) + if all(nested_passed) is not expected_passed: + raise ValueError( + "Authenticated US multispine pool aggregate agreement verdict " + "disagrees with its nested gate verdicts." + ) diagnostics = _mapping( manifest.get("agreement_diagnostics"), @@ -1449,6 +1476,33 @@ def load_authenticated_us_multispine_pool_for_scoring( ) +def load_authenticated_us_multispine_pool_for_release( + path: str | Path, + *, + allow_terminal_gate_failure: bool, + expected_manifest_sha256: str | None = None, +) -> tuple[Frame, dict[str, object], AuthenticatedPoolH5]: + """Load an authenticated pool for release build or release preflight. + + The default release boundary remains the public simulation-ready loader. + An explicit caller opt-in may instead admit the same current stacked + ``gate_failed`` status pair accepted for evidence scoring. Both branches + authenticate the complete manifest/H5/diagnostics publication; neither + changes the contract of the strict or scoring-only public loaders. + """ + + if not allow_terminal_gate_failure: + return load_simulation_ready_us_multispine_pool( + path, + expected_manifest_sha256=expected_manifest_sha256, + ) + return _load_us_multispine_pool( + path, + expected_manifest_sha256=expected_manifest_sha256, + require_simulation_ready=False, + ) + + def _load_us_multispine_pool( path: str | Path, *, diff --git a/packages/microcosm-build/src/microcosm/build/us_runtime/release_gate_preflight.py b/packages/microcosm-build/src/microcosm/build/us_runtime/release_gate_preflight.py index efe74535..4978ea94 100644 --- a/packages/microcosm-build/src/microcosm/build/us_runtime/release_gate_preflight.py +++ b/packages/microcosm-build/src/microcosm/build/us_runtime/release_gate_preflight.py @@ -66,8 +66,7 @@ from microcosm.build.gates import input_mass_parity_gate from microcosm.build.us_runtime.h5_io import ( identify_us_multispine_pool_manifest, - load_authenticated_us_multispine_pool_for_scoring, - load_simulation_ready_us_multispine_pool, + load_authenticated_us_multispine_pool_for_release, require_authenticated_us_multispine_pool_h5, us_multispine_pool_release_receipt, ) @@ -990,12 +989,12 @@ def _load_preflight_base( ) return load_us_frame(base_h5), None, None - loader = ( - load_authenticated_us_multispine_pool_for_scoring - if allow_gate_failed_base_pool - else load_simulation_ready_us_multispine_pool + frame, manifest, authenticated_pool_h5 = ( + load_authenticated_us_multispine_pool_for_release( + manifest_path, + allow_terminal_gate_failure=allow_gate_failed_base_pool, + ) ) - frame, manifest, authenticated_pool_h5 = loader(manifest_path) require_authenticated_us_multispine_pool_h5( base_h5, authenticated_pool_h5, diff --git a/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py b/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py index a09ee0b4..2b75abb6 100644 --- a/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py +++ b/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py @@ -1669,19 +1669,27 @@ def fake_load_pool(path, *, expected_manifest_sha256): @pytest.mark.parametrize( - ("allow_gate_failed", "status", "simulation_ready", "passed"), ( - (False, "simulation_ready", True, True), - (True, "gate_failed", False, False), + "allow_gate_failed", + "status", + "simulation_ready", + "passed", + "rejected", + ), + ( + (False, "simulation_ready", True, True, False), + (True, "gate_failed", False, False, False), + (True, "simulation_ready", True, True, True), ), ) -def test_builder_base_h5_pool_loader_is_selected_only_by_explicit_opt_in( +def test_builder_base_h5_pool_loader_receives_explicit_terminal_gate_policy( monkeypatch, tmp_path, allow_gate_failed, status, simulation_ready, passed, + rejected, ) -> None: builder = _load_builder_module() pool_h5 = tmp_path / "pool.h5" @@ -1716,36 +1724,30 @@ def test_builder_base_h5_pool_loader_is_selected_only_by_explicit_opt_in( lambda path: manifest_path, ) - def selected(path): + def selected(path, *, allow_terminal_gate_failure): assert path == manifest_path + assert allow_terminal_gate_failure is allow_gate_failed return frame, manifest, authenticated - if allow_gate_failed: - monkeypatch.setattr( - builder, - "load_authenticated_us_multispine_pool_for_scoring", - selected, - ) - monkeypatch.setattr( - builder, - "load_simulation_ready_us_multispine_pool", - lambda path: pytest.fail("strict loader ran after explicit opt-in"), - ) - else: - monkeypatch.setattr( - builder, - "load_simulation_ready_us_multispine_pool", - selected, - ) - monkeypatch.setattr( - builder, - "load_authenticated_us_multispine_pool_for_scoring", - lambda path: pytest.fail("scoring loader ran without explicit opt-in"), - ) + monkeypatch.setattr( + builder, + "load_authenticated_us_multispine_pool_for_release", + selected, + ) - loaded_frame, receipt, loaded_identity = builder._load_base_pool_if_identified( - pool_h5, - allow_gate_failed_base_pool=allow_gate_failed, + if rejected: + with pytest.raises(ValueError, match="override is valid only"): + builder._load_base_pool_if_identified( + pool_h5, + allow_gate_failed_base_pool=allow_gate_failed, + ) + return + + loaded_frame, receipt, loaded_identity = ( + builder._load_base_pool_if_identified( + pool_h5, + allow_gate_failed_base_pool=allow_gate_failed, + ) ) assert loaded_frame is frame @@ -1757,34 +1759,48 @@ def selected(path): ) -def test_builder_refuses_red_base_h5_pool_without_opt_in( +def test_builder_refuses_actual_red_base_h5_pool_sidecar_without_opt_in( monkeypatch, tmp_path ) -> None: builder = _load_builder_module() pool_h5 = tmp_path / "pool.h5" + pool_h5.write_bytes(b"pool identity comes from its sibling manifest") manifest_path = pool_h5.with_suffix(".manifest.json") - monkeypatch.setattr( - builder, - "identify_us_multispine_pool_manifest", - lambda path: manifest_path, + manifest_path.write_text( + json.dumps( + { + "artifact_kind": "populace_us_multispine_pool_manifest", + "status": "gate_failed", + "simulation_ready": False, + } + ) ) + out = tmp_path / "out" + monkeypatch.setattr(builder, "_git_dirty", lambda: False) + monkeypatch.setattr(builder, "_refuse_certified_release_dir_reuse", lambda path: None) monkeypatch.setattr( builder, - "load_authenticated_us_multispine_pool_for_scoring", - lambda path: pytest.fail("scoring loader ran without explicit opt-in"), + "_load_frame", + lambda path: pytest.fail("red pool reached the generic H5 loader"), ) - def refuse(path): - raise ValueError("US multispine pool manifest is not simulation-ready") - - monkeypatch.setattr(builder, "load_simulation_ready_us_multispine_pool", refuse) - with pytest.raises(ValueError, match="not simulation-ready"): - builder._load_base_pool_if_identified( - pool_h5, - allow_gate_failed_base_pool=False, + builder.main( + [ + "--base-h5", + str(pool_h5), + "--ledger-facts", + str(tmp_path / "facts.jsonl"), + "--out", + str(out), + "--release-id", + "populace-us-2024-red-pool-fixture", + "--no-staging", + ] ) + assert not out.exists() + def test_builder_refuses_bare_stamped_pool_h5_before_generic_load( monkeypatch, tmp_path diff --git a/packages/microcosm-build/tests/test_us_multispine_pool_h5_io.py b/packages/microcosm-build/tests/test_us_multispine_pool_h5_io.py index 5074245a..5544e92a 100644 --- a/packages/microcosm-build/tests/test_us_multispine_pool_h5_io.py +++ b/packages/microcosm-build/tests/test_us_multispine_pool_h5_io.py @@ -36,6 +36,7 @@ AuthenticatedPoolH5, AuthenticatedPoolH5MismatchError, identify_us_multispine_pool_manifest, + load_authenticated_us_multispine_pool_for_release, load_authenticated_us_multispine_pool_for_scoring, load_simulation_ready_us_multispine_pool, require_authenticated_us_multispine_pool_h5, @@ -1484,16 +1485,30 @@ def test_scoring_pool_loader_authenticates_failed_stacked_terminal_receipt( with pytest.raises(ValueError, match="not simulation-ready"): load_simulation_ready_us_multispine_pool(manifest_path) + with pytest.raises(ValueError, match="not simulation-ready"): + load_authenticated_us_multispine_pool_for_release( + manifest_path, + allow_terminal_gate_failure=False, + ) frame, loaded_manifest, authenticated_h5 = ( load_authenticated_us_multispine_pool_for_scoring(manifest_path) ) + release_frame, release_manifest, release_h5 = ( + load_authenticated_us_multispine_pool_for_release( + manifest_path, + allow_terminal_gate_failure=True, + ) + ) assert frame.n("household") == 3 assert loaded_manifest["status"] == "gate_failed" assert loaded_manifest["simulation_ready"] is False assert loaded_manifest["terminal_gates"]["passed"] is False assert authenticated_h5.sha256 == loaded_manifest["pool_h5"]["sha256"] + assert release_frame.n("household") == frame.n("household") + assert release_manifest == loaded_manifest + assert release_h5 == authenticated_h5 receipt = us_multispine_pool_release_receipt( loaded_manifest, @@ -1518,6 +1533,55 @@ def test_scoring_pool_loader_authenticates_failed_stacked_terminal_receipt( } +def test_gate_failed_release_opt_in_is_rejected_for_a_ready_pool( + tmp_path: Path, +) -> None: + pytest.importorskip("tables") + manifest_path = _write_ready_pool(tmp_path, stacked=True) + _frame, manifest, authenticated_h5 = ( + load_authenticated_us_multispine_pool_for_release( + manifest_path, + allow_terminal_gate_failure=False, + ) + ) + + with pytest.raises(ValueError, match="override is valid only"): + us_multispine_pool_release_receipt( + manifest, + authenticated_h5, + allow_gate_failed_base_pool=True, + ) + + +@pytest.mark.parametrize( + ("nested_passed", "failures"), + ((False, []), (True, ["contradictory failure"])), +) +def test_release_receipt_rejects_incoherent_nested_gate_verdict( + tmp_path: Path, + nested_passed: bool, + failures: list[str], +) -> None: + pytest.importorskip("tables") + manifest_path = _write_ready_pool(tmp_path, stacked=True) + _frame, manifest, authenticated_h5 = ( + load_authenticated_us_multispine_pool_for_release( + manifest_path, + allow_terminal_gate_failure=False, + ) + ) + first_gate = next(iter(manifest["agreement_gate"]["gates"].values())) + first_gate["passed"] = nested_passed + first_gate["failures"] = failures + + with pytest.raises(ValueError, match="incoherent passed verdict"): + us_multispine_pool_release_receipt( + manifest, + authenticated_h5, + allow_gate_failed_base_pool=False, + ) + + def test_pool_h5_identity_requires_its_missing_manifest_sidecar( tmp_path: Path, ) -> None: diff --git a/packages/microcosm-build/tests/test_us_release_gate_preflight.py b/packages/microcosm-build/tests/test_us_release_gate_preflight.py index 194cae29..ef1a3e21 100644 --- a/packages/microcosm-build/tests/test_us_release_gate_preflight.py +++ b/packages/microcosm-build/tests/test_us_release_gate_preflight.py @@ -747,19 +747,27 @@ def test__report__carried_red_pool_is_prominent_but_non_blocking(tmp_path) -> No @pytest.mark.parametrize( - ("allow_gate_failed", "status", "simulation_ready", "passed"), ( - (False, "simulation_ready", True, True), - (True, "gate_failed", False, False), + "allow_gate_failed", + "status", + "simulation_ready", + "passed", + "rejected", + ), + ( + (False, "simulation_ready", True, True, False), + (True, "gate_failed", False, False, False), + (True, "simulation_ready", True, True, True), ), ) -def test__preflight_base__authenticates_pool_with_loader_selected_by_opt_in( +def test__preflight_base__passes_explicit_terminal_gate_policy_to_release_loader( monkeypatch, tmp_path, allow_gate_failed, status, simulation_ready, passed, + rejected, ) -> None: base_h5 = tmp_path / "pool.h5" base_h5.write_bytes(b"authenticated pool") @@ -793,32 +801,24 @@ def test__preflight_base__authenticates_pool_with_loader_selected_by_opt_in( lambda path: manifest_path, ) - def selected(path): + def selected(path, *, allow_terminal_gate_failure): assert path == manifest_path + assert allow_terminal_gate_failure is allow_gate_failed return frame, manifest, identity - if allow_gate_failed: - monkeypatch.setattr( - preflight_module, - "load_authenticated_us_multispine_pool_for_scoring", - selected, - ) - monkeypatch.setattr( - preflight_module, - "load_simulation_ready_us_multispine_pool", - lambda path: pytest.fail("strict loader ran after explicit opt-in"), - ) - else: - monkeypatch.setattr( - preflight_module, - "load_simulation_ready_us_multispine_pool", - selected, - ) - monkeypatch.setattr( - preflight_module, - "load_authenticated_us_multispine_pool_for_scoring", - lambda path: pytest.fail("scoring loader ran without explicit opt-in"), - ) + monkeypatch.setattr( + preflight_module, + "load_authenticated_us_multispine_pool_for_release", + selected, + ) + + if rejected: + with pytest.raises(ValueError, match="override is valid only"): + preflight_module._load_preflight_base( + base_h5, + allow_gate_failed_base_pool=allow_gate_failed, + ) + return loaded, receipt, loaded_manifest_path = preflight_module._load_preflight_base( base_h5, @@ -831,29 +831,27 @@ def selected(path): assert receipt["agreement_gate_reference"]["failure_count"] == len(failures) -def test__preflight_base__refuses_red_pool_without_opt_in( +def test__preflight_base__refuses_actual_red_sidecar_without_opt_in( monkeypatch, tmp_path ) -> None: + import microcosm.build.us_runtime.l0_refit_export as l0_refit_export + base_h5 = tmp_path / "pool.h5" + base_h5.write_bytes(b"pool identity comes from its sibling manifest") manifest_path = base_h5.with_suffix(".manifest.json") - monkeypatch.setattr( - preflight_module, - "identify_us_multispine_pool_manifest", - lambda path: manifest_path, - ) - monkeypatch.setattr( - preflight_module, - "load_authenticated_us_multispine_pool_for_scoring", - lambda path: pytest.fail("scoring loader ran without explicit opt-in"), + manifest_path.write_text( + json.dumps( + { + "artifact_kind": "populace_us_multispine_pool_manifest", + "status": "gate_failed", + "simulation_ready": False, + } + ) ) - - def refuse(path): - raise ValueError("US multispine pool manifest is not simulation-ready") - monkeypatch.setattr( - preflight_module, - "load_simulation_ready_us_multispine_pool", - refuse, + l0_refit_export, + "load_us_frame", + lambda path: pytest.fail("red pool reached the generic H5 loader"), ) with pytest.raises(ValueError, match="not simulation-ready"): diff --git a/tools/build_us_fiscal_refresh_release.py b/tools/build_us_fiscal_refresh_release.py index d1343404..df0634b2 100644 --- a/tools/build_us_fiscal_refresh_release.py +++ b/tools/build_us_fiscal_refresh_release.py @@ -229,7 +229,7 @@ from microcosm.build.us_runtime.h5_io import ( AuthenticatedPoolH5, identify_us_multispine_pool_manifest, - load_authenticated_us_multispine_pool_for_scoring, + load_authenticated_us_multispine_pool_for_release, load_simulation_ready_us_multispine_pool, require_authenticated_us_multispine_pool_h5, us_multispine_pool_release_receipt, @@ -1709,12 +1709,12 @@ def _load_base_pool_if_identified( ) return None, None, None - loader = ( - load_authenticated_us_multispine_pool_for_scoring - if allow_gate_failed_base_pool - else load_simulation_ready_us_multispine_pool + frame, manifest, authenticated_pool_h5 = ( + load_authenticated_us_multispine_pool_for_release( + manifest_path, + allow_terminal_gate_failure=allow_gate_failed_base_pool, + ) ) - frame, manifest, authenticated_pool_h5 = loader(manifest_path) require_authenticated_us_multispine_pool_h5( path, authenticated_pool_h5, @@ -8981,8 +8981,9 @@ def _main(argv: Sequence[str] | None = None) -> None: "method": "preserve_validated_multispine_pool_weights", "applied": False, "reason": ( - "Exact-k selection and HT-with-q refit retain the validated " - "pool artifact's original importance-weight baseline." + "The authenticated multispine input retains the published " + "pool artifact's original importance-weight baseline; " + "pool-owned preparation stages are not replayed." ), "initial_population": pool_population, "benchmark": US_BASE_PERSON_POPULATION_BENCHMARK, From 72c4c7a15b1a26c50f5fe8858fb6f1cddd6a2d39 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 09:25:14 +0200 Subject: [PATCH 12/17] Bind carried pool verdicts to preflight inputs --- .../tests/test_us_release_gate_preflight.py | 145 +++++++++++------ tools/preflight_us_release_gates.py | 150 ++++++++++-------- 2 files changed, 176 insertions(+), 119 deletions(-) diff --git a/packages/microcosm-build/tests/test_us_release_gate_preflight.py b/packages/microcosm-build/tests/test_us_release_gate_preflight.py index ef1a3e21..269cb615 100644 --- a/packages/microcosm-build/tests/test_us_release_gate_preflight.py +++ b/packages/microcosm-build/tests/test_us_release_gate_preflight.py @@ -897,76 +897,56 @@ def test__preflight_base__refuses_bare_stamped_pool_before_generic_load( ) -def test__cli__manifest_only_surfaces_carried_red_battery_without_failing( +def test__cli__release_manifest_does_not_replace_required_static_inputs( monkeypatch, tmp_path, capsys ) -> None: cli = _load_preflight_cli() release_manifest = tmp_path / "release_manifest.json" - failures, gates_sha256 = _write_gate_failed_release_manifest(release_manifest) - json_out = tmp_path / "preflight.json" + _write_gate_failed_release_manifest(release_manifest) monkeypatch.setattr( cli, "run_preflight", - lambda **kwargs: pytest.fail("manifest-only review ran static checks"), + lambda **kwargs: pytest.fail("argument validation reached static checks"), ) - exit_code = cli.main( - [ - "--release-manifest", - str(release_manifest), - "--json-out", - str(json_out), - ] - ) + with pytest.raises(SystemExit) as error: + cli.main(["--release-manifest", str(release_manifest)]) - output = capsys.readouterr().out - assert exit_code == 0 - assert output.startswith("=" * 72) - assert "CARRIED BASE-POOL AGREEMENT BATTERY: RED — 2 FAILURES" in output - assert "Build opt-in used: --allow-gate-failed-base-pool" in output - assert f"Pool gates JSON SHA-256: {gates_sha256}" in output - assert "Publication decision: HUMAN REVIEW REQUIRED" in output - assert "does not alter the preflight exit code" in output - assert "Static base/selection checks: NOT RUN" in output - assert all( - f"FAILURE [{failure['gate']}]: {failure['message']}" in output - for failure in failures - ) - assert output.rstrip().endswith( - "CARRIED RED BATTERY: HUMAN REVIEW REQUIRED; automated preflight exit " - "remains 0." - ) - - payload = json.loads(json_out.read_text()) - carried = payload["carried_base_pool_agreement_battery"] - assert payload["exit_code"] == 0 - assert payload["static_checks_run"] is False - assert carried["battery_status"] == "red" - assert carried["failure_count"] == 2 - assert carried["failures"] == failures - assert carried["gates_json_sha256"] == gates_sha256 - assert carried["affects_exit_code"] is False - assert carried["agreement_gate_reference"]["verdict"]["passed"] is False + assert error.value.code == 2 + stderr = capsys.readouterr().err + assert "--base-h5" in stderr + assert "--selection-source-manifest" in stderr +@pytest.mark.parametrize( + ("static_status", "expected_exit"), + (("PASS", 0), ("AT_RISK", 2), ("FAIL", 1)), +) def test__cli__carried_red_battery_does_not_change_existing_preflight_exit( - monkeypatch, tmp_path, capsys + monkeypatch, + tmp_path, + capsys, + static_status, + expected_exit, ) -> None: from microcosm.build.us_runtime.release_gate_preflight import CheckResult cli = _load_preflight_cli() release_manifest = tmp_path / "release_manifest.json" - _write_gate_failed_release_manifest(release_manifest) + failures, gates_sha256 = _write_gate_failed_release_manifest(release_manifest) + base_pool = json.loads(release_manifest.read_text())["build"]["base_pool"] json_out = tmp_path / "preflight.json" report = PreflightReport( checks=( CheckResult( - name="existing_risk", - status="AT_RISK", + name="existing_check", + status=static_status, summary="existing check controls the exit", - at_risks=("fixture risk",), + failures=("fixture failure",) if static_status == "FAIL" else (), + at_risks=("fixture risk",) if static_status == "AT_RISK" else (), ), - ) + ), + base_pool=base_pool, ) captured: dict[str, object] = {} @@ -992,19 +972,84 @@ def fake_run_preflight(**kwargs): output = capsys.readouterr().out payload = json.loads(json_out.read_text()) - assert exit_code == report.exit_code == 2 - assert "[AT-RISK] existing_risk" in output + assert exit_code == report.exit_code == expected_exit + assert output.startswith("=" * 72) + assert "CARRIED BASE-POOL AGREEMENT BATTERY: RED — 2 FAILURES" in output + assert "Build opt-in used: --allow-gate-failed-base-pool" in output + assert f"Pool gates JSON SHA-256: {gates_sha256}" in output + assert "Publication decision: HUMAN REVIEW REQUIRED" in output + assert "does not alter the preflight exit code" in output + assert all( + f"FAILURE [{failure['gate']}]: {failure['message']}" in output + for failure in failures + ) assert output.rstrip().endswith( "CARRIED RED BATTERY: HUMAN REVIEW REQUIRED; automated preflight exit " - "remains 2." + f"remains {expected_exit}." ) - assert payload["exit_code"] == 2 + assert payload["exit_code"] == expected_exit assert payload["carried_base_pool_agreement_battery"][ "affects_exit_code" ] is False + assert payload["carried_base_pool_agreement_battery"]["failures"] == failures + assert payload["carried_base_pool_agreement_battery"][ + "agreement_gate_reference" + ]["verdict"]["passed"] is False assert captured["allow_gate_failed_base_pool"] is True +@pytest.mark.parametrize( + "mismatch", + ( + "generic_base", + "manifest_sha256", + "pool_h5_sha256", + "pool_h5_size_bytes", + "publication_run_id", + "gates_json_sha256", + "verdict", + ), +) +def test__cli__release_manifest_must_match_authenticated_base_pool( + monkeypatch, + tmp_path, + mismatch, +) -> None: + cli = _load_preflight_cli() + release_manifest = tmp_path / "release_manifest.json" + _write_gate_failed_release_manifest(release_manifest) + authenticated = json.loads( + json.dumps(json.loads(release_manifest.read_text())["build"]["base_pool"]) + ) + if mismatch == "generic_base": + authenticated = None + elif mismatch == "pool_h5_size_bytes": + authenticated[mismatch] += 1 + elif mismatch == "gates_json_sha256": + authenticated["agreement_gate_reference"][mismatch] = "3" * 64 + elif mismatch == "verdict": + authenticated["agreement_gate_reference"]["verdict"]["gates"][ + "us_by_origin_battery" + ]["details"] = {"fixture": "different"} + else: + authenticated[mismatch] = "different-authenticated-value" + report = PreflightReport(checks=(), base_pool=authenticated) + monkeypatch.setattr(cli, "run_preflight", lambda **kwargs: report) + + with pytest.raises(ValueError, match="does not exactly match"): + cli.main( + [ + "--base-h5", + str(tmp_path / "base.h5"), + "--selection-source-manifest", + str(tmp_path / "selection.json"), + "--allow-gate-failed-base-pool", + "--release-manifest", + str(release_manifest), + ] + ) + + def test__load_ledger_target_specs__hands_fact_rows_to_the_compiler( monkeypatch, tmp_path ) -> None: diff --git a/tools/preflight_us_release_gates.py b/tools/preflight_us_release_gates.py index a0fae0e2..1cb2b2ce 100644 --- a/tools/preflight_us_release_gates.py +++ b/tools/preflight_us_release_gates.py @@ -19,8 +19,8 @@ Exit code: 1 on any static-check FAIL, 2 on static AT-RISK only, 0 clean. A carried red base-pool battery is human-review evidence and does not by itself -change that exit code; ``--release-manifest`` also supports a manifest-only -publication review when those static inputs do not apply. +change that exit code. When ``--release-manifest`` is supplied, its base-pool +receipt must exactly match the pool authenticated by this preflight. """ from __future__ import annotations @@ -54,10 +54,8 @@ def _json_object(value: object, *, label: str) -> dict[str, object]: return value -def _load_carried_base_pool_battery( - path: Path, -) -> dict[str, object] | None: - """Read the non-blocking red pool verdict carried by a release manifest.""" +def _load_release_base_pool_receipt(path: Path) -> dict[str, object] | None: + """Read one optional base-pool receipt from a built release manifest.""" release_manifest = _json_object( json.loads(path.read_text()), @@ -65,9 +63,25 @@ def _load_carried_base_pool_battery( ) build = release_manifest.get("build") if not isinstance(build, dict): + raise ValueError(f"Release manifest {path} has no build object.") + if "base_pool" not in build: return None base_pool = build.get("base_pool") if not isinstance(base_pool, dict): + raise ValueError( + f"Release manifest {path} build.base_pool must be a JSON object." + ) + return base_pool + + +def _carried_base_pool_battery( + base_pool: dict[str, object] | None, + *, + path: Path, +) -> dict[str, object] | None: + """Validate the non-blocking red verdict carried by one pool receipt.""" + + if base_pool is None: return None agreement_gate_reference = base_pool.get("agreement_gate_reference") carries_gate_failed_override = ( @@ -138,16 +152,23 @@ def _load_carried_base_pool_battery( f"Release manifest {path} has a malformed carried gate verdict." ) gate_failures = gate_payload.get("failures") - if not isinstance(gate_failures, list) or not all( + gate_passed = gate_payload.get("passed") + if type(gate_passed) is not bool or not isinstance( + gate_failures, list + ) or not all( isinstance(failure, str) for failure in gate_failures ): raise ValueError( f"Release manifest {path} has a malformed carried failure list." ) + if gate_passed is bool(gate_failures): + raise ValueError( + f"Release manifest {path} has an incoherent nested gate verdict." + ) verdict_failures.extend( {"gate": gate_name, "message": failure} for failure in gate_failures ) - if verdict_failures != failures: + if not verdict_failures or verdict_failures != failures: raise ValueError( f"Release manifest {path} failure summary does not match its full " "carried gate verdict." @@ -167,6 +188,21 @@ def _load_carried_base_pool_battery( } +def _require_matching_release_base_pool( + authenticated: dict[str, object] | None, + carried: dict[str, object] | None, + *, + path: Path, +) -> None: + """Bind a release manifest to the exact pool preflight authenticated.""" + + if authenticated != carried: + raise ValueError( + f"Release manifest {path} build.base_pool does not exactly match " + "the base-pool receipt authenticated by this preflight." + ) + + def _carried_battery_banner(carried: dict[str, object]) -> str: count = int(carried["failure_count"]) noun = "FAILURE" if count == 1 else "FAILURES" @@ -197,12 +233,9 @@ def _parser() -> argparse.ArgumentParser: ) parser.add_argument( "--base-h5", + required=True, type=Path, - help=( - "Base pool H5 (read-only). Required with " - "--selection-source-manifest unless --release-manifest is used " - "for a manifest-only publication review." - ), + help="Base pool H5 (read-only).", ) parser.add_argument( "--allow-gate-failed-base-pool", @@ -215,11 +248,9 @@ def _parser() -> argparse.ArgumentParser: ) parser.add_argument( "--selection-source-manifest", + required=True, type=Path, - help=( - "Frozen selection-source manifest JSON. Required with --base-h5 " - "for the existing static preflight checks." - ), + help="Frozen selection-source manifest JSON.", ) parser.add_argument( "--release-manifest", @@ -227,9 +258,8 @@ def _parser() -> argparse.ArgumentParser: help=( "Optional built release_manifest.json. A carried gate-failed " "base-pool battery is displayed as prominent, non-blocking " - "evidence for the human publication decision. It may be used " - "alone for publication review or alongside the existing static " - "preflight inputs." + "evidence for the human publication decision after its receipt " + "is matched to the authenticated --base-h5 pool." ), ) parser.add_argument( @@ -291,66 +321,48 @@ def _parser() -> argparse.ArgumentParser: def main(argv: list[str] | None = None) -> int: - parser = _parser() - args = parser.parse_args(argv) - has_base_h5 = args.base_h5 is not None - has_selection_manifest = args.selection_source_manifest is not None - if has_base_h5 != has_selection_manifest: - parser.error( - "--base-h5 and --selection-source-manifest must be provided together." - ) - if args.allow_gate_failed_base_pool and not has_base_h5: - parser.error("--allow-gate-failed-base-pool requires --base-h5.") - if not has_base_h5 and args.release_manifest is None: - parser.error( - "provide --base-h5 with --selection-source-manifest, or provide " - "--release-manifest for publication review." - ) - carried = ( - _load_carried_base_pool_battery(args.release_manifest) + args = _parser().parse_args(argv) + release_base_pool = ( + _load_release_base_pool_receipt(args.release_manifest) if args.release_manifest is not None else None ) - if not has_base_h5 and carried is None: - parser.error( - "manifest-only publication review requires a release manifest " - "carrying an explicit gate-failed base-pool verdict." + carried = ( + _carried_base_pool_battery( + release_base_pool, + path=args.release_manifest, ) - if carried is not None: - print(_carried_battery_banner(carried)) + if args.release_manifest is not None + else None + ) try: target_period: int | str = int(args.target_period) except (TypeError, ValueError): target_period = args.target_period - if has_base_h5: - report = run_preflight( - base_h5=args.base_h5, - selection_source_manifest=args.selection_source_manifest, - export_input_mass_reference_h5=args.export_input_mass_reference_h5, - ledger_facts=args.ledger_facts, - ledger_facts_sha256=args.ledger_facts_sha256, - target_period=target_period, - relative_tolerance=args.relative_tolerance, - minimum_reference_total=args.minimum_reference_total, - allow_gate_failed_base_pool=args.allow_gate_failed_base_pool, + report = run_preflight( + base_h5=args.base_h5, + selection_source_manifest=args.selection_source_manifest, + export_input_mass_reference_h5=args.export_input_mass_reference_h5, + ledger_facts=args.ledger_facts, + ledger_facts_sha256=args.ledger_facts_sha256, + target_period=target_period, + relative_tolerance=args.relative_tolerance, + minimum_reference_total=args.minimum_reference_total, + allow_gate_failed_base_pool=args.allow_gate_failed_base_pool, + ) + if args.release_manifest is not None: + _require_matching_release_base_pool( + report.base_pool, + release_base_pool, + path=args.release_manifest, ) - print(report.human_table()) - payload = report.to_dict() - exit_code = report.exit_code - else: - print("US release-gate preflight (manifest-only publication review)") - print("Static base/selection checks: NOT RUN") - print("Automated exit: 0 (carried evidence requires human review)") - payload = { - "status": "PASS", - "exit_code": 0, - "inputs": {"release_manifest": str(args.release_manifest)}, - "checks": [], - "static_checks_run": False, - } - exit_code = 0 + if carried is not None: + print(_carried_battery_banner(carried)) + print(report.human_table()) + payload = report.to_dict() + exit_code = report.exit_code if carried is not None: payload[_CARRIED_BATTERY_PAYLOAD_KEY] = carried if args.json_out is not None: From 59c5759d1a9e81c280c28af698ffebe7cd10d31e Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 09:25:43 +0200 Subject: [PATCH 13/17] Record completed release containment work --- PROGRESS.md | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/PROGRESS.md b/PROGRESS.md index 58dc2e89..f2bc0568 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,11 +2,11 @@ ## State -Design and consumer review are complete. The final salvage tree is a useful -implementation base, but it needs two additional fail-closed checks before it -is trustworthy: reject a redundant gate-failure opt-in on a green pool, and -bind mixed preflight inputs so a release manifest cannot display one pool's -red verdict while static checks authenticate another pool. +Containment, opt-in carriage, and preflight surfacing are implemented. Focused +builder, authenticated-H5, and preflight tests pass. The implementation now +rejects both redundant green-pool waivers and any release-manifest receipt that +does not exactly match the pool authenticated by preflight; the preflight's +historically required base/selection inputs and exit semantics are unchanged. ## Done @@ -32,14 +32,31 @@ red verdict while static checks authenticate another pool. status 1 and stops shell chains; ACS-local derivatives keep a donor revision but do not project the nested red verdict; generic release consumers tolerate and ignore the additive receipt. +- Added a release/preflight-specific authenticated pool loader over the shared + `require_simulation_ready` seam. The strict simulation-ready and existing + scoring-only loader contracts remain unchanged. +- Closed the bare-H5 path by detecting either the canonical sibling manifest + or the H5's stamped pool identity, requiring the sidecar, authenticating the + publication triple, and binding it to the exact requested H5 path. +- Added `--allow-gate-failed-base-pool` only to the legacy `--base-h5` arm. + It admits only a current authenticated stacked `gate_failed` pool, rejects a + green or non-pool use, and never affects the exact-k arm. +- Added the self-contained `base_pool` receipt to both manifests, including + status/readiness, immutable pool identities, flag use, gates JSON SHA-256, + failure count/list, and the complete terminal verdict. +- Kept the static preflight inputs mandatory, authenticated its base identically, + displayed red evidence prominently without changing its exit calculation, + and required optional release-manifest carriage to match the authenticated + receipt exactly. +- Hardened carried verdict normalization so nested pass/failure pairs and the + aggregate verdict must be coherent and a red battery cannot report zero + failures. +- Passed focused Ruff and the complete builder/H5/preflight test files after + the containment changes. ## Next -- Import the re-reviewed salvage implementation as coherent local commits. -- Add redundant-opt-in and mixed-preflight receipt-binding regressions and - enforce both contracts. -- Run the focused containment, carriage, preflight, exact-k, and data-contract - suites. +- Run the broader affected exact-k, launcher, and data-contract suites. - Run Ruff and every pytest shard in its own process, then write `out.md`. ## Historical prior lane From af20d3f53c737dfe3e2d1a62ab34cd39f417f118 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 09:27:00 +0200 Subject: [PATCH 14/17] Lock ordinary base-pool release wiring in tests --- .../tests/test_us_fiscal_refresh_builder.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py b/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py index 2b75abb6..3c76b462 100644 --- a/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py +++ b/packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py @@ -1877,10 +1877,41 @@ def test_authenticated_pool_h5_consumers_use_one_returned_identity() -> None: builder._write_release_calibration_diagnostics ) receipt_source = inspect.getsource(builder._exact_k_ladder_manifest_payload) + main_tree = ast.parse(main_source) + base_pool_assignments = [ + node + for node in ast.walk(main_tree) + if isinstance(node, ast.Assign) + and isinstance(node.value, ast.Call) + and isinstance(node.value.func, ast.Name) + and node.value.func.id == "_load_base_pool_if_identified" + ] + assert len(base_pool_assignments) == 1 + assert [ + element.id + for element in base_pool_assignments[0].targets[0].elts + if isinstance(element, ast.Name) + ] == ["pool_frame", "base_pool_receipt", "authenticated_pool_h5"] + manifest_calls = [ + node + for node in ast.walk(main_tree) + if isinstance(node, ast.Call) + and isinstance(node.func, ast.Name) + and node.func.id == "_build_manifests" + ] + assert len(manifest_calls) == 1 + base_pool_keyword = next( + keyword for keyword in manifest_calls[0].keywords if keyword.arg == "base_pool" + ) + assert isinstance(base_pool_keyword.value, ast.Name) + assert base_pool_keyword.value.id == "base_pool_receipt" assert ( "authenticated_pool_h5.verified_digest(\n" ' consumer="builder base dataset identity"' ) in main_source + assert "if pool_frame is None:\n base_frame = _load_frame(base_h5)" in ( + main_source + ) assert "base_dataset_sha256=base_dataset_sha256" in main_source assert '"base_dataset_sha256": base_dataset_sha256' in diagnostics_source assert '"manifest_sha256": authenticated_pool_h5.manifest_sha256' in receipt_source From 010a9576626d748c0e88fd3d51b750ed4c3a64fa Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 10:28:49 +0200 Subject: [PATCH 15/17] Finalize gate-failed release lane report --- PROGRESS.md | 31 +++++-- out.md | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+), 9 deletions(-) create mode 100644 out.md diff --git a/PROGRESS.md b/PROGRESS.md index f2bc0568..a0394ddf 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,11 +2,12 @@ ## State -Containment, opt-in carriage, and preflight surfacing are implemented. Focused -builder, authenticated-H5, and preflight tests pass. The implementation now -rejects both redundant green-pool waivers and any release-manifest receipt that -does not exactly match the pool authenticated by preflight; the preflight's -historically required base/selection inputs and exit semantics are unchanged. +Complete on 2026-08-26. Containment, opt-in carriage, and preflight surfacing +are implemented and fully verified. The implementation rejects both redundant +green-pool waivers and any release-manifest receipt that does not exactly match +the pool authenticated by preflight; the preflight's historically required +base/selection inputs and exit semantics are unchanged. No pool or release was +built, no artifact was published, and nothing was pushed. ## Done @@ -22,8 +23,8 @@ historically required base/selection inputs and exit semantics are unchanged. release manifests, and both preflight output modes. - Reviewed the salvage branch's final source and test diff line by line. Its shared classifier/path-binding/receipt approach closes the bypass without - changing either loader's contract and is suitable to retain with the two - coherence corrections above. + changing either loader's contract and was retained with the subsequent + coherence corrections recorded below. - Completed the `simulation_ready` / `gate_failed` / loader consumer audit. Exact-k remains deliberately strict and head-to-head scoring remains the existing authenticated evidence exception. @@ -53,11 +54,23 @@ historically required base/selection inputs and exit semantics are unchanged. failures. - Passed focused Ruff and the complete builder/H5/preflight test files after the containment changes. +- Passed the broader exact-k, launcher, release-contract, and publish-guard + regression suites. +- Passed repository-wide Ruff and the CI test-group inventory verifier. +- Passed every pytest shard in its own process: build 6,545 passed / 45 + skipped; calibrate 203 passed; data 318 passed / 2 skipped; fit 93 passed; + frame 295 passed / 36 skipped. Aggregate: 7,454 passed, 83 skipped. +- Confirmed `git diff --check` is clean and that no battery bounds, + tolerances, plans, or terminal gate logic changed. +- Wrote the complete handoff, consumer audit, manifest schema, verification + receipts, and commit inventory to `out.md`. ## Next -- Run the broader affected exact-k, launcher, and data-contract suites. -- Run Ruff and every pytest shard in its own process, then write `out.md`. +- Human review and merge of `release-from-gate-failed-pool`. +- Any later artifact operation remains separate: an operator must deliberately + choose the red-pool flag, then run publication preflight and make the human + publication decision. This lane performed none of those operations. ## Historical prior lane diff --git a/out.md b/out.md new file mode 100644 index 00000000..d6bb8bb9 --- /dev/null +++ b/out.md @@ -0,0 +1,230 @@ +# Gate-failed base-pool release lane: final report + +Date: 2026-08-26 +Branch: `release-from-gate-failed-pool` +Base: `origin/main` at `2263df36` + +## Outcome + +The legacy `--base-h5` release and preflight paths now fail closed when the H5 +identifies as a US multispine pool. They require and authenticate the canonical +sibling pool manifest, bind it to the exact requested H5, and reject a red +terminal agreement battery by default. The new explicit opt-in is: + +`--allow-gate-failed-base-pool` + +The flag is valid only with `--base-h5` and only for an authenticated current +stacked pool with `status=gate_failed` and `simulation_ready=false`. It is +rejected for generic H5 inputs, green pools, and the exact-k manifest arm. A +release built with the flag carries the full authenticated red verdict so a +reader can see `battery: red, N failures` without fetching the pool. + +Publication preflight authenticates the same pool and displays the red receipt +as prominent human-review evidence. The red battery alone does not change the +existing preflight PASS/AT_RISK/FAIL calculation or exit code. Publication +remains a separate human-gated operation. + +No network access, pool build, release build, publication, push, battery +threshold change, or gate-logic change was performed. + +## Diff summary and rationale + +- `CLAUDE.md`: documents the authenticated `--base-h5` boundary, explicit red + opt-in, verdict carriage, strict exact-k arm, and separate publication step. +- `PROGRESS.md`: maintains the required state/done/next journal from kickoff + through the final verified handoff while preserving the prior lane history. +- `changelog.d/gate-failed-pool-release.fixed.md`: records the closed receipt + bypass and explicit opt-in under the repository changelog convention. +- `packages/microcosm-build/src/microcosm/build/us_runtime/h5_io.py`: adds the + shared pool classifier, exact-H5 binding check, release-specific authenticated + loader, and normalized self-contained release receipt. The existing strict + simulation-ready and scoring loader contracts were not weakened. +- `packages/microcosm-build/src/microcosm/build/us_runtime/release_gate_preflight.py`: + authenticates identified base pools through the shared seam, records their + receipt in `PreflightReport`, and renders authenticated red evidence before + the ordinary check table without including it in exit-code calculation. +- `tools/build_us_fiscal_refresh_release.py`: adds + `--allow-gate-failed-base-pool`, authenticates pool-like legacy base H5s before + the generic loader can run, uses the authenticated frame/H5 identity, and + passes the receipt into both generated manifests. The exact-k arm remains + simulation-ready-only. +- `tools/preflight_us_release_gates.py`: adds the same explicit opt-in and an + optional `--release-manifest`; validates the carried full verdict, requires + its receipt to exactly equal the pool authenticated from `--base-h5`, emits a + large red/human-review banner, and adds machine-readable carried evidence. + Existing required `--base-h5` and `--selection-source-manifest` arguments and + all other preflight behavior remain intact. +- `packages/microcosm-build/tests/test_us_multispine_pool_h5_io.py`: exercises + real stamped H5 classification, strict/default refusal, explicit red + acceptance, redundant-green refusal, receipt contents, identity binding, and + malformed aggregate/nested verdict refusal. PyTables-dependent cases use the + sibling-test `importorskip` idiom. +- `packages/microcosm-build/tests/test_us_fiscal_refresh_builder.py`: covers the + old bare-H5 bypass directly, red-manifest default refusal, flag routing, + generic/non-pool refusal when the flag is present, both-manifest carriage, + exact-k isolation, and AST-level ordinary base-pool wiring guards. +- `packages/microcosm-build/tests/test_us_release_gate_preflight.py`: covers + bare/missing/red receipt authentication, prominent text and JSON carriage, + nonblocking PASS/AT_RISK/FAIL exit semantics, required static inputs, and + exact mismatch refusal across manifest/H5/publication/gates/full-verdict + identities. +- `out.md`: this final implementation, audit, verification, and handoff report. + +## Flag and manifest contract + +The exact flag is `--allow-gate-failed-base-pool`. The release builder permits +it only on its legacy `--base-h5` arm. Publication preflight uses the same flag +to authenticate and inspect the same red pool; neither invocation is an +authorization to publish. + +The build manifest stores the receipt at top-level `base_pool`. The release +manifest stores the same receipt at `build.base_pool`: + +- `artifact_kind` +- `status` +- `simulation_ready` +- `manifest_sha256` +- `publication_run_id` +- `pool_h5_sha256` +- `pool_h5_size_bytes` +- `allow_gate_failed_base_pool` +- `agreement_gate_reference.battery_status` +- `agreement_gate_reference.passed` +- `agreement_gate_reference.gates_json_sha256` +- `agreement_gate_reference.failure_count` +- `agreement_gate_reference.failures`, a flattened list of `{gate, message}` +- `agreement_gate_reference.verdict`, the complete agreement-gate verdict + +The receipt accepts only coherent pairs: simulation-ready/green/passed or +gate-failed/red/failed. Every nested gate must carry a boolean `passed` and a +coherent failure list; the nested aggregate must match the terminal status. +For a red pool the failure list must be nonempty. SHA-256, publication run ID, +H5 size, full verdict, and all other receipt fields are bound through exact +preflight equality. + +The preflight report also exposes the authenticated receipt as `base_pool`. +When `--release-manifest` supplies a red carried receipt, JSON adds +`carried_base_pool_agreement_battery`, including `battery_status=red`, the +failure count/list, gates digest, full agreement reference, +`publication_decision=human_review_required`, and `affects_exit_code=false`. + +## §4 consumer audit + +The requested exhaustive source audit used +`simulation_ready|gate_failed|load_simulation_ready` across `tools/` and +`packages/`, followed by source tracing of every non-test match. + +- `h5_io.py` owns the authentication boundary. The new release wrapper selects + the unchanged strict loader by default and the existing private terminal + loader only when its required explicit boolean is true. The public scoring + and strict simulation-ready contracts remain unchanged. +- `tools/build_us_exact_k_ladder_release.py` remains deliberately strict: it + uses the simulation-ready loader, validates config/release identities, checks + `agreement_gate.passed`, and never forwards the new flag. +- `tools/score_us_release_head_to_head.py` retains its existing authenticated + terminal-evidence exception. It requires a pool manifest and terminal gates; + it cannot authorize a release or accept a naked pool H5. +- `tools/build_us_multispine_pool.py` and + `us_runtime/multispine_pool.py` are producers of the status, readiness, H5 + stamp, manifest, diagnostics, and terminal verdict rather than downstream + release consumers. +- `tools/_legacy/build_us_acs_multispine_base.py` writes its own pre-calibration + `simulation_ready=false` state; it is not a current terminal-pool consumer. +- `tools/build_us_acs_local_release.py` uses its own calibrated-release + readiness summary. A derivative keeps donor release/revision provenance but + does not project the nested `build.base_pool` verdict into its own manifest. +- The microcosm-data release contract, loader, TRACE conversion, and publisher + tolerate but otherwise ignore the additive `build.base_pool` object. The + designated publication preflight is therefore the prominent human-facing + red-verdict surface. + +Report-only interactions left unchanged, as directed: + +1. `tools/build_us_multispine_pool.py::_stacked_manifest_payload` still labels + `calibration.consumer` as `k-ladder` and says + `requires_manifest_simulation_ready=true`. That metadata is now incomplete + for the explicit legacy base-H5 red-pool route, but it is informational and + unenforced. +2. A red pool producer writes its H5, manifest, gates evidence, and failed + Logbook row, then returns status 1. Existing `set -e` candidate chains stop + there, so an operator must deliberately start the separate release command + to use the new opt-in. +3. ACS-local derivative manifests retain fetchable donor provenance but do not + self-contain the nested red receipt. +4. Generic data/release consumers accept the additive receipt but do not + surface it. This is not a publication bypass because the publication tool's + designated preflight now authenticates and displays it. + +No audit-only consumer was modified. + +## Judgment calls + +- Pool detection uses either a canonical sibling manifest whose artifact kind + is the pool kind or the H5's own artifact-metadata stamp. Either positive + identity requires the sidecar; sidecar existence alone is never trusted. +- A dedicated release loader with a required + `allow_terminal_gate_failure` argument keeps the strict and scoring APIs + semantically stable. +- The opt-in is rejected for a green pool rather than silently accepted, so + every recorded flag use has one unambiguous meaning. +- Preflight requires exact equality between the release-carried receipt and the + freshly authenticated base receipt. This prevents displaying release A's red + evidence while checking release B's pool. +- The earlier salvage branch was used as a reference and selected commits were + replayed only after line-by-line review. The final tree corrected its + manifest-only preflight expansion, loader naming/contract ambiguity, + redundant-green behavior, receipt binding, nested-verdict coherence, and an + inaccurate exact-k diagnostic. Full verification ran on the corrected tree. + +## Verification evidence + +All commands ran offline against the pre-built environment with +`uv run --no-sync` (and a task-local UV cache where required). Each pytest +shard ran in one independent process. + +- `uv run --no-sync ruff check .`: PASS, `All checks passed!` +- `uv run --no-sync pytest -q packages/microcosm-build/tests`: PASS, 6,545 + passed, 45 skipped, 2,351 warnings in 3,326.74 seconds. +- `uv run --no-sync pytest -q packages/microcosm-calibrate/tests`: PASS, 203 + passed, 2 warnings in 11.39 seconds. +- `uv run --no-sync pytest -q packages/microcosm-data/tests`: PASS, 318 passed, + 2 skipped in 9.11 seconds. +- `uv run --no-sync pytest -q packages/microcosm-fit/tests`: PASS, 93 passed, + 1 warning in 30.27 seconds. +- `uv run --no-sync pytest -q packages/microcosm-frame/tests`: PASS, 295 + passed, 36 skipped, 1 warning in 89.30 seconds. +- Full aggregate: 7,454 passed, 83 skipped. +- `.venv/bin/python tools/ci_test_groups.py --verify`: PASS, + `tracked_test_files=309`, `verification=ok`. +- Focused changed-file suites plus exact-k E2E/launcher and data + contract/release/publish-guard regressions: PASS; the full shard runs above + subsequently covered the same tests on the final code tree. +- `git diff --check origin/main...HEAD`: PASS. + +The build-shard warnings are expected numerical, pandas chained-assignment, +PolicyEngine division, and intentionally fragmented-frame test warnings; no +warning is a test failure and none originates in the new receipt path. + +## Commit inventory + +Implementation and journal commits before this final report carrier: + +1. `34375fe6` Document gate-failed release lane kickoff +2. `5be9e49a` Preserve prior progress journal history +3. `c5a24c0f` Record release containment design review +4. `72274910` feat: allow explicit gate-failed pool release inputs +5. `e3d847d6` feat: surface carried red pool verdict in preflight +6. `46811fdb` fix: preserve default exact-k receipt fixtures +7. `dd1ad19a` Add shared multispine base-pool authentication seam +8. `271ee1fe` Close legacy base-H5 pool receipt bypass +9. `92134322` Authenticate and surface gate-failed pools in preflight +10. `cd39f756` Document gate-failed base-pool release boundary +11. `9db4694a` Tighten the authenticated red-pool release opt-in +12. `72c4c7a1` Bind carried pool verdicts to preflight inputs +13. `59c5759d` Record completed release containment work +14. `af20d3f5` Lock ordinary base-pool release wiring in tests + +The next/HEAD commit carries this report and the final `PROGRESS.md` state; its +hash is available from `git log --oneline origin/main..HEAD`. Final handoff +checks require no uncommitted paths and list that carrier with the commits +above. From d984ccb62bd10396f0afb2d03266d4c6ef4ee41a Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 10:29:21 +0200 Subject: [PATCH 16/17] Remove final report whitespace --- out.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/out.md b/out.md index d6bb8bb9..04cc7848 100644 --- a/out.md +++ b/out.md @@ -1,7 +1,9 @@ # Gate-failed base-pool release lane: final report -Date: 2026-08-26 -Branch: `release-from-gate-failed-pool` +Date: 2026-08-26 + +Branch: `release-from-gate-failed-pool` + Base: `origin/main` at `2263df36` ## Outcome From c5bf8683b0a0b797f9568419862d6bdb4993208a Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 26 Aug 2026 10:29:56 +0200 Subject: [PATCH 17/17] Clarify final commit inventory --- out.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/out.md b/out.md index 04cc7848..df65be15 100644 --- a/out.md +++ b/out.md @@ -226,7 +226,8 @@ Implementation and journal commits before this final report carrier: 13. `59c5759d` Record completed release containment work 14. `af20d3f5` Lock ordinary base-pool release wiring in tests -The next/HEAD commit carries this report and the final `PROGRESS.md` state; its -hash is available from `git log --oneline origin/main..HEAD`. Final handoff -checks require no uncommitted paths and list that carrier with the commits -above. +Commits after the list carry this report, the final `PROGRESS.md` state, and +their handoff cleanup. A report cannot embed the hash of the commit containing +its own final bytes, so `git log --oneline origin/main..HEAD` is the +authoritative complete inventory. At final handoff the branch is 17 commits +ahead of `origin/main` with no uncommitted paths.