Repository navigation
Module-qualified resolution: remove std.types base-injection leak (fixes v1↔v2 FreeMonoid collision) - #5422
Conversation
e8f2f55 to
51bccfb
Compare
|
CI red on The failing job is
These tests are deterministic pure-compiler tests; a CI-only failure with healthy-local + green-discovery-corpus points to a corrupt sccache build on the runner (needs — sent from merry-bee-526 |
… (fixes v1↔v2 FreeMonoid collision) The type/constructor environment keyed names by bare interned string and an implicit bootstrap bridge injected v1 `std.types`' whole transitive env as a base into every module that didn't import it. Together these let v1's `std.algebra` FreeMonoid (a record) and v2's `v2.std.algebra` FreeMonoid (`Empty | Cons` sum) collide — the winner decided by the topological typecheck order, which the std.types implicit edges coupled across the v1 and v2 trees into one global sort. Adding import edges (e.g. #5418's 44 extdeps anchors) perturbed that order, so `v2.std.node_query` bound FreeMonoid to the leaked v1 record and produced `undefined variable 'Empty'` / `variant 'Empty' not found in type 'FreeMonoid'` across the v2 tree. A §3 single-authority violation. Fix (authority in src/v1/*.dag, mirrored in the stage0 seed .rs): - 03_resolve.dag `topological_sort`: drop the implicit `std.types -> *` edges and the implicit in-degree term. Ordering is now import-driven only, so the two trees decouple and a module is always typechecked after the modules it actually imports — no order-sensitivity to re-tune. - 04_infer.dag `build_type_env` / `build_type_env_unresolved`: drop the `std.types` base-injection. Import bindings start empty and are seeded only by the module's explicit imports; kernel primitives still come from the kernel env. No second, implicit authority for names. Witness (src/v1/tests/src/module_authority_resolution_test.rs): a module that never imports `std.types` no longer inherits a type `std.types` declares — the reference is a hard UnresolvedType (RED without the fix, where the leak silently resolved it). Plus two §3 invariant guards for same-named types across modules. Verified by execution: the #5418-anchored discovery-corpus repro (wet_hermetic_scaffold_roster_filter_uses_dag_prefix_authority) goes green; regen_stage0 self-compiles the v1 tree clean without the leak; full `cargo test --workspace` green except the pre-existing regen receipt-hash red (#5420); clippy + fmt clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6b206f1 to
b7cb1bb
Compare
|
Correction — that CI red was NOT an sccache flake. It was a real I was wrong above. The Fixed with — sent from merry-bee-526 |
…nalAuthorityGate #5418 added ExtdepsExternalAuthorityGate to the Gate enum and to every match over it EXCEPT gate_is_heavy_resolve (ci_floor_plan.dag:154), so once the v1↔v2 FreeMonoid collision cleared (#5422 now in this branch) the plan resolve reached this fn and fail-closed on a non-exhaustive match: ci_floor_plan.dag:154:3: error: non-exhaustive match: missing variant(s) ExtdepsExternalAuthorityGate The extdeps external-authority gate is a focused lens witness (filesystem_read over dsl/extdeps/**), not a whole-tree heavy resolve like SourceRootIngest / DslCompileClean — so it joins the other lens gates (Layering/ResolvedImports) at `false`. Plan-data only; resolved at runtime by claim_executor, no stage0 seed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…key-completeness lens #5418's external-authority gate scans the LIVE extdeps tree and fail-closes on any module lacking an anchor. Once #5422 cleared the FreeMonoid collision and the missing gate_is_heavy_resolve arm let the plan resolve, the gate correctly flagged 5 modules that landed on main AFTER #5418 authored its roster and were neither anchored nor backfilled: missing: extdeps.access.{aws_iam,posix,rbac,zanzibar} (#5415 access model) missing: extdeps.cache.key_completeness (#5423 cache lens) The 4 access modules already carry their real upstream citation in a `// Source:` comment (AWS IAM grammar, POSIX.1-2017/opengroup, ANSI/NIST RBAC, the Zanzibar USENIX paper) — promoted each to the structured `extdeps_external_authority_anchor` carrier the gate gates on (DESIGN §3: the mark on the carrier is the authority). No access sibling is backfilled, so anchoring (not backfilling) is the consistent treatment. extdeps.cache.key_completeness is an internal §5 cache-soundness LENS (a pure reader over the cache catalog), not a cited external-system model — so it joins its 8 extdeps.cache.* siblings on the backfill_pending roster as tracked debt, not a fake external anchor. Verified by execution: the floor's discovery-corpus (587 witnesses) and extdeps_external_authority_gate_passes both go GREEN with this change (live violation set empty, roster count > 150). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ive #5297) (#5418) * extdeps: external-authority anchor carrier + fail-closed CI lens (revive #5297) Land the never-merged #5297 mechanism onto current main: a structured, lens-checkable external-authority citation on every dsl/extdeps module, enforced fail-closed on the CI floor. Carriers - extdeps.uri: Uri { scheme: UriScheme, locator } with closed-sum UriScheme = Http | Https | File | Ftp (RFC 3986 / 7595 grounded). - extdeps.external_authority: ExternalAuthority { uri }, FactAuthorityOverride, and the canonical `data extdeps_external_authority_anchor` row. Lens (v2.lens.extdeps_external_authority) - Fail-closed live policy per module: machinery-exempt -> backfill-pending -> else require a present external Http/Https anchor. Scheme decoded by exhaustive constructor identity (decode_uri_scheme), never a URL-prefix string. - Violations: MissingFormalAnchor / UnrecognizedAnchorScheme / NonExternalAnchorScheme. Host projection (extdeps_shape_transport_policy_project.rs) - Structural read of the anchor record; live roster derived from the module-path index (declared module name, not directory); backfill + machinery-exempt facts. - 9 builtins wired through 04_method.dag / v1_interpreter.rs / v1_compiler_infer_method.rs. CI - ExtdepsExternalAuthorityGate enrolled in gunbc_ci_spec and scheduled on the floor; runs uri witnesses + live-corpus clean-tree + RED perturb receipts. 44 extdeps modules carry external anchors; 125 remain in the shrinking backfill_pending snapshot. Reconciliation onto current main: the snapshot keys on declared module name, so the post-#5391 directory reorganizations (rust/, package_managers/, ...) need no rename. The only stale entry, extdeps.diagnostic.redfish, was dropped (redfish moved to extdeps.bmc.redfish, separately covered). Verified by execution: 18 projection unit tests; 14 floor-enrolled .dag witnesses (GREEN clean-tree + machinery-exempt fold + 3 RED perturbs + live anchor-drop RED); live-tree discrimination on a real cited module (Https->File and anchor-drop both flip the gate RED, revert restores GREEN); ci_spec/ci_floor_plan enrollment witnesses; gate main -> ExitSuccess via real shell; cargo fmt + clippy -D warnings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Mi3t2wX7UPzgqLyYAE1kS * ci_floor_plan: add missing gate_is_heavy_resolve arm for ExtdepsExternalAuthorityGate #5418 added ExtdepsExternalAuthorityGate to the Gate enum and to every match over it EXCEPT gate_is_heavy_resolve (ci_floor_plan.dag:154), so once the v1↔v2 FreeMonoid collision cleared (#5422 now in this branch) the plan resolve reached this fn and fail-closed on a non-exhaustive match: ci_floor_plan.dag:154:3: error: non-exhaustive match: missing variant(s) ExtdepsExternalAuthorityGate The extdeps external-authority gate is a focused lens witness (filesystem_read over dsl/extdeps/**), not a whole-tree heavy resolve like SourceRootIngest / DslCompileClean — so it joins the other lens gates (Layering/ResolvedImports) at `false`. Plan-data only; resolved at runtime by claim_executor, no stage0 seed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * extdeps live-clean: anchor the 4 access modules + backfill the cache key-completeness lens #5418's external-authority gate scans the LIVE extdeps tree and fail-closes on any module lacking an anchor. Once #5422 cleared the FreeMonoid collision and the missing gate_is_heavy_resolve arm let the plan resolve, the gate correctly flagged 5 modules that landed on main AFTER #5418 authored its roster and were neither anchored nor backfilled: missing: extdeps.access.{aws_iam,posix,rbac,zanzibar} (#5415 access model) missing: extdeps.cache.key_completeness (#5423 cache lens) The 4 access modules already carry their real upstream citation in a `// Source:` comment (AWS IAM grammar, POSIX.1-2017/opengroup, ANSI/NIST RBAC, the Zanzibar USENIX paper) — promoted each to the structured `extdeps_external_authority_anchor` carrier the gate gates on (DESIGN §3: the mark on the carrier is the authority). No access sibling is backfilled, so anchoring (not backfilling) is the consistent treatment. extdeps.cache.key_completeness is an internal §5 cache-soundness LENS (a pure reader over the cache catalog), not a cited external-system model — so it joins its 8 extdeps.cache.* siblings on the backfill_pending roster as tracked debt, not a fake external anchor. Verified by execution: the floor's discovery-corpus (587 witnesses) and extdeps_external_authority_gate_passes both go GREEN with this change (live violation set empty, roster count > 150). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
Problem (§3 single-authority violation in the resolver)
Type/constructor resolution keyed names by bare interned string, and an implicit bootstrap bridge injected v1
std.types' whole transitive env as a base into every module that didn't import it. Together these let two live authorities for one name collide:dsl/std/algebra.dag→type FreeMonoid<T> { … }(a v1 record, no variants)src/v2/std/algebra.dag→type FreeMonoid = Empty | Cons(the v2 sum)The winner was decided by the topological typecheck order, which the
std.typesimplicit edges coupled across the v1 and v2 trees into one global sort. Adding import edges (e.g. #5418's 44dsl/extdepsanchors) perturbed that order, sov2.std.node_queryboundFreeMonoidto the leaked v1 record and producedundefined variable 'Empty'/variant 'Empty' not found in type 'FreeMonoid'cascading across the v2 tree during combined[dsl, src/v2]discovery resolution.Fix (authority in
src/v1/*.dag, mirrored in the stage0 seed.rs)03_resolve.dagtopological_sort— drop the implicitstd.types -> *edges and the implicit in-degree term. Ordering is import-driven only, so the two trees decouple and a module is always typechecked after the modules it actually imports. This removes the order-sensitivity rather than re-tuning it.04_infer.dagbuild_type_env/build_type_env_unresolved— drop thestd.typesbase-injection. Import bindings start empty and are seeded only by the module's explicit imports; kernel primitives still resolve from the kernel env. No second, implicit authority for names.Not a band-aid: no rename, no "v2 wins", no special-casing
std.types/FreeMonoidin the merge, no touchingkahn_drain's (vestigial) fuel.Verified by execution (§5)
module_authority_resolution_test.rs— discriminating witness: a module that never importsstd.typesno longer inherits a typestd.typesdeclares (hardUnresolvedType). Proven RED without the fix (the leak silently resolved it,diagnostics == []), GREEN with it. Plus two §3 invariant guards for same-named types across modules.wet_hermetic_scaffold_roster_filter_uses_dag_prefix_authority→ green (was the reported panic).regen_stage0self-compiles the v1 tree clean without the leak (bootstrap holds).cargo test --workspacegreen except the pre-existingcargo_invalidation_receipt_hashes…red (fail-closed cross-representation==(numeric model↔realization fork) #5420, unrelated);clippy --all-targets -D warnings+fmt --checkclean.Once this lands, #5418 rebases on top with zero content changes — its anchors are already correct.