Deny the sealed candidate-26 pool in every readiness and release loader - #857
Merged
Conversation
…er (#856) The readiness loaders already refuse a gate_failed pool, but load_authenticated_us_multispine_pool_for_release(allow_terminal_gate_failure=True) admits the same status pair into a release build or preflight on an operator opt-in, and the preflight records that with affects_exit_code false. The exclusion of candidate-26 from the certifiable dense line is a decision (plan gate 20260902-220844-plan-532dab66), so it needs a mechanism: a sealed, source-coded deny-list checked centrally in the manifest authenticator every loader routes through, matching on the publication run id, the manifest digest, or the sealed pool H5 digest, so a renamed, re-serialized, or repackaged publication is still refused. The only exception is the scoring-only loader, which never labels a pool ready and which the diagnosis of #856 needs; a source-scan test keeps it unreachable from release paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A pool whose sidecar manifest and artifact-metadata row are stripped no longer identifies as a pool, so the release builder and the release-gate preflight fall through to generic H5 loading and never consult the deny-list. The bytes are the identity that survives repackaging: both generic paths now hash the file and refuse a denied pool's H5 digest before loading it (refuse_denied_pool_h5_digest), with a unit test for the helper and a preflight test on a stripped fixture. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ase-receipt boundary Sol's gate review of #857 found two laundering paths: release-producing generic ingresses (export_us_l0_refit_h5 through load_us_frame; the legacy calibrated loader) never consult the manifest loader, and the scoring-only result could be handed to us_multispine_pool_release_receipt with the gate-failed opt-in. The byte-identity check now lives in load_us_frame and load_legacy_calibrated_us_h5 themselves (so every caller inherits it, and preflight's explicit check is dropped as redundant), and the release-receipt builder rechecks the deny-list on the authenticated identity it is handed, so scoring evidence of a denied publication cannot become release evidence. Tests cover each ingress end to end and the scoring-to-receipt transition. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oundary for every generic ingress Sol's second review of #857 showed that the whole-file digest does not survive what it claimed to cover: dropping the artifact-metadata table or re-serializing the pool changes the SHA-256 and removes every pool marker, after which the generic loaders accept the file. The deny-list entry now also carries a content identity (SHA-256 of the household table's id, weight, channel, and clone-index columns sorted by id; 674b6e69... for candidate-26), and refuse_denied_pool_h5 checks both the bytes and that identity. Every generic ingress routes through it: load_us_frame, the legacy calibrated loader, the fiscal builder's and PUF support base's _load_frame, and the legacy ACS base's _load_base_frame, each verifying after its read that the file did not change under it. A regression rewrites a valid gate-failed fixture without its metadata table and without a sidecar and shows all five ingresses still refuse it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s to what it actually loaded Sol's third review of #857: the column-projection identity could be evaded by dropping optional provenance columns or renumbering ids; the authenticated paths never compared the content identity, so a reserialized publication with regenerated metadata passed the gate-failed opt-in; the selection-source manifest builder and loaders were an unguarded ingress; and every loader reopened the pathname between hashing and reading. - The content identity is now version 2: SHA-256 of the sorted multiset of household weights with the count (f5a5023b... for candidate-26, computed from the sealed pool). No ids, no optional columns, no order. - Authentication computes it, carries it on AuthenticatedPoolH5, refuses it on every non-scoring path, and the release-receipt boundary rechecks it; the authenticated loader also refuses by the identity of the frame it actually loaded. - Every generic ingress computes the identity from the loaded frame in memory after its read (refuse_denied_frame), so a file swapped between the on-disk checks and the read is caught by what was loaded (ABA regression on the legacy loader); the fiscal builder binds its late base load to the digest it recorded for the release id. - Selection-source manifests: the builder routes through the boundary and records byte and content provenance; consumers refuse a manifest with no source digest or with denied provenance. - The rewrite regression now also drops the provenance columns and relabels the ids; identity, selection-manifest, and digest-binding tests added. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… receipts, and version selection manifests The final review round of #857 found that the publisher never consulted the deny-list (publish_release validates the release directory without looking at base_pool), that the release receipt carried no content identity for a last check, and that the selection-manifest loader's new provenance requirement rejected existing schema-1 manifests while the public writer could emit unloadable ones. - The deny-list moves to microcosm-data (microcosm.data.denied_pools), which the publisher can import; h5_io re-exports it. The release contract refuses a build manifest whose base_pool matches a denied publication by any of its four identities. - us_multispine_pool_release_receipt persists content_identity_sha256. - Selection manifests are schema 2 with mandatory canonical provenance (lowercase sha256 and content identity); schema-1 manifests still load and are refused only when what they record is denied; the writer refuses to emit a schema-2 manifest without provenance. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Sep 3, 2026
Open
…test canonical provenance The engine-free CI lane failed because load_us_frame and its siblings imported policyengine_us before consulting the deny-list, so a denied file raised ModuleNotFoundError there instead of the refusal; the check now precedes the import in every generic loader. The selection-manifest round-trip test wrote a manifest with placeholder provenance, which the schema-2 writer rightly refuses; it now records a canonical digest and the frame's content identity. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
Author
This was referenced Sep 3, 2026
juaristi22
added a commit
that referenced
this pull request
Sep 3, 2026
…t UK gate-battery pins (#762 PR A) The rebase conflict on the data contract was resolved on this branch's side, which dropped main's newer content (#850's UC-deduction entries, #842's age_tail phase move, #857's denied-pool check, the certification part digests). This branch's only legitimate delta there is the three gate-battery digests re-cut on the merged gates spec; everything else is main's. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The readiness loaders already refuse a
gate_failedpool, butload_authenticated_us_multispine_pool_for_release(allow_terminal_gate_failure=True)admits the same status pair into a release build or release preflight on an operator opt-in (--allow-gate-failed-base-pool), and the preflight records that carried red verdict withaffects_exit_code: False. The exclusion of the sealed candidate-26 stacked pool from the certifiable dense line (#856; plan gate20260902-220844-plan-532dab66) is therefore a decision without a mechanism. This PR adds the mechanism.What it does
DENIED_POOL_PUBLICATIONS: a sealed, source-coded deny-list inus_runtime/h5_io.py, keyed bypublication_run_id, each entry carrying the manifest sha256, the sealed pool-H5 sha256, the release id, a reason, and a reference. Seeded with candidate-26 (2ab3f5a1…, manifest2a06fc2b…, H545f40173…)._load_authenticated_us_multispine_pool_manifest, which every loader routes through, on any of three identities: the publication run id, the manifest digest, or the pool-H5 digest. A renamed, re-serialized, or repackaged publication is still refused, regardless ofallow_terminal_gate_failure.load_authenticated_us_multispine_pool_for_scoring(scoring_only=True), which never labels a pool ready and which the diagnosis of c-26 stacked pool: emergent undocumented population 18.9M vs the 11.0M anchor (1.72x; gate band [0.5, 1.6]) #856 needs. A source-scan test asserts that no file outsideh5_io.pyand the head-to-head scorer references it, so the exception cannot become a release ingress.--allow-gate-failed-base-pool.CLAUDE.mdboundary paragraph and a towncrier fragment.Implemented by a sol build lane under a written brief; reviewed and extended (H5-digest rule, scoring-to-release scan test, reason text) by the dispatching session.
Refs #856.
🤖 Generated with Claude Code