Repository navigation
The floor's kernel guard compares the kernel-name set, not the whole types.dag blob - #12087
Conversation
…types.dag blob kernel_set_serves_both answered a name-set question with a byte-identity proxy: any edit to dag/std/types.dag -- a function body, a comment -- made the base reconstruction refuse, so every PR touching that file lost its changed-witness observation. The guard now keeps the free blob-equality arm and, when the file differs, evaluates the base revision's own kernel_type_set (owned by that file, hermetic) and compares its names to this binary's. Distinct sets still refuse; an unreadable base set is a typed refusal (KernelSetNotReadable), never a substitution of the head's. The environment loader's evaluation, closure and scratch-root legs are shared with the new reader rather than copied. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
briansrls
left a comment
There was a problem hiding this comment.
SOURCE HOLD on exact head e6afc32254053130104de569cb209a98896398af. The central repair is right: the guard now compares the semantic kernel-name population, retains blob equality as a cheap arm, evaluates the base item hermetically with exact file ownership, and the body-edit / added-name pair discriminates the old byte-grain guard. I found three small but real source blockers before merge.
1. KernelSetNotReadable does not actually own the unreadable/undeclared paths
The new arm is constructed only around value_to_wire_json and serde_json::from_value. The earlier failures from the shared reader escape unchanged:
- missing declaring file ->
EnvironmentModuleMissing; - resolve or evaluation failure ->
ClosureNotEvaluable; - missing/renamed
kernel_type_set->EnvironmentItemNotOwned.
Those variants render as “parse environment” / “grammar authority.” That is exactly the subject conflation the new arm’s own comment says it exists to avoid. The undeclared-set test only asserts .is_err(), so it passes without establishing the promised KernelSetNotReadable arm—or even that the refusal came from the intended ownership distinction.
Please give the shared owned-item evaluator a subject-neutral internal refusal and map it at each caller, or wrap every kernel-item read failure into a kernel-specific typed refusal while retaining its exact cause. Then match the exact variant, revision and distinguishing cause in the undeclared control; add one evaluation/decode refusal control if needed to establish the other kernel-read arm.
2. The cheap arm can admit a missing head authority
blob_id_at returns Ok(None) whenever rev-parse --verify --quiet <rev>:dag/std/types.dag is non-zero. kernel_set_serves_both currently compares those Options directly, and after a non-equal pair evaluates only the base:
None == Nonereturnstrueimmediately;base = Some,head = Nonecan also returntruewhen the base names equal this binary’s generated set.
So absence of the head declaring file can be treated as equality or as an implicit binary substitution. The free arm is valid only for Some(base_blob) == Some(head_blob). A missing head authority must refuse; a missing base should reach the base reader and refuse. Please add the missing-file control as well.
3. The seed-growth authority now has false provenance
namespace_baseline_seed_growth_justification adds KERNEL_TYPES_ITEM, kernel_names_at, evaluate_owned_item_in, revision_scratch_root, and closure_paths_of, while its reason still says every declaration below existed in namespace_wave_admission.rs and moves unchanged. The first two are new kernel-guard surface; the latter three are extractions introduced here. Because this row is the authority admitting the hand-Rust declarations, the origin and dissolution story must distinguish the renamed carryovers, the new semantic guard, and the shared extractions. Please update the note/reason/current boundary and add the kernel-set reader’s actual dissolution trigger rather than enrolling new surface under the old rename claim.
The disclosed test-route ceiling is honest: clippy compiles this integration target but no required CI step executes it. I do not treat that already-declared rung drop as a fourth source blocker. Re-run the 4-test target after these repairs, preserve the exact test exit, and let the required jobs finish on the amended SHA.
…nt head refuses, roster states true provenance - Every failure reading the base or head kernel set is KernelSetNotReadable (as_kernel_set_refusal), keeping the inner refusal as its cause; the shared evaluator's refusal texts are subject-neutral rather than naming the grammar. - The free arm needs Some(base) == Some(head): a head with no dag/std/types.dag refuses instead of letting the compiled-in set stand in, and two absent files are not equality. - namespace_baseline_seed_growth distinguishes renamed carryover, the new kernel-set reader, and shared extractions, and names the reader's own dissolution trigger. - Tests match the exact variant, revision and located cause, and add the absent-head and both-absent controls. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
briansrls
left a comment
There was a problem hiding this comment.
APPROVE on exact head d7c3a89c8458842cba286cc930e6db4648933d12. All three source holds from review 5285273061 are discharged.
-
Kernel-read failures now have one subject-facing refusal. Blob lookup, revision materialization, resolution, ownership, evaluation, wire encoding and decoding are routed through
KernelSetNotReadable, retaining the underlying subject-neutral refusal text as the cause. The undeclared-set control now matches the exact variant, revision and ownership discriminator rather than accepting anyErr. -
The cheap arm is fail-closed on authority absence. It admits only
Some(base_blob) == Some(head_blob). An absent head refuses before the compiled-in set can stand in for it; an absent base reaches the versioned read and refuses; the added head-absent and both-absent controls discriminate both former fail-open shapes. -
The seed-growth authority now states true provenance and retirement. The row separates renamed carryover, the new kernel-set reader and shared helper extractions, enrolls
as_kernel_set_refusal, and gives the reader its own dissolution condition in versioned base/head kernel facts.
The central semantic repair remains correct: equality is decided at the kernel-name-set grain consumed by declaring_candidates, with whole-blob equality retained only as a free sufficient arm. The body-edit positive control and added-name negative control are the right discriminating pair.
CI classification. Clippy is green on this exact head. The required floor and compiler jobs are still executing as I submit this review. The standing emit-build failure is independently reproduced on main's merge-group SHA 7a9b29aeb0d5b47e87119027253c92319ec8879d: E0573, PointerWidth, src/std_integer.rs; that is the known non-required detector failure owned by #12070/#12076, not this four-file change. A matching red does not block this approval; a different error code or emitted file would be a new finding.
One non-blocking precision note: closure_paths_of(KERNEL_TYPES_PATH) is the live-tree closure-discovery premise and still returns its subject-neutral refusal directly before the versioned-read wrapper. That path is fail-closed and the production caller locates it as failure to compare the kernel declaration, so it does not recreate any prior harm. The phrase “every kernel-read failure” should be read as the versioned base/head read pipeline unless that live-tree acquisition premise is later given its own explicit subject carrier.
…te fleet-converge.yml from its authority Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Why
Since #11861 a refused phase fails the lane.
v1_compiler.namespace_baselinekernel_set_serves_bothcompared the Git blob ofdag/std/types.dagat base and head, so any byte change to that file, including a function body or a comment, refused the base reconstruction. Every PR touching that file was blocked (first seen on #11730). The fact the guard protects is narrower:declaring_candidatesconsults the running binary'skernel_type_set, so one map serves exactly when the base declares the same kernel names.What
kernel_names_atmaterializes that file's closure at the base revision. It then evaluates thekernel_type_setowned bydag/std/types.dag(hermetic, with the homonym check) and compares its names to this binary's set.false, so the lane still declines to plan. Threading separate base and head maps remains the general repair and is not this PR's subject.KernelSetNotReadableand never substitutes the head's set.evaluate_owned_item_in,closure_paths_of,revision_scratch_root), not copied.gunbc.namespace_baseline_seed_growth. This is v1 maintenance serving the v2 floor.gate_reported_success_on_a_phase_it_refused) is corrected: it described any change totypes.dagas unreconstructable.Evidence
the_kernel_guard_compares_names_not_bytesinsrc/v1/stage0/tests/parse_environment_decode_roundtrip.rsbuilds a scratch repository with three base revisions:true. This is the discriminating red: the old guard answersfalsehere by construction.false.kernel_type_set: requires a refusal.The run was 4/4 green on the remote runner (see the note below):
cargo test --release -p v1-compiler --test parse_environment_decode_roundtrip.Note: no CI step runs this test file (
rust_unit_tests_off_the_merge_path). The BuildBuddy runner also exposes no cgroup memory limit, so the file's existing tests refuse there withHostBudgetUnreadable. I ran it inside a child cgroup withmemory.max=24G.Not in this PR
This does not green #11730 by itself. Once the guard passes, #11730's census claim measures over budget on current main; that is the separate reader-cost change.
🤖 Generated with Claude Code