Skip to content

Module-qualified resolution: remove std.types base-injection leak (fixes v1↔v2 FreeMonoid collision) - #5422

Merged
briansrls merged 3 commits into
mainfrom
session/merry-bee-526
Jun 21, 2026
Merged

briansrls merged 3 commits into
mainfrom
session/merry-bee-526

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Jun 21, 2026 •

Copy link
Copy Markdown
Contributor

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.types implicit edges coupled across the v1 and v2 trees into one global sort. Adding import edges (e.g. #5418's 44 dsl/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' 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.dag topological_sort — drop the implicit std.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.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 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/FreeMonoid in the merge, no touching kahn_drain's (vestigial) fuel.

Verified by execution (§5)

  • module_authority_resolution_test.rs — discriminating witness: a module that never imports std.types no longer inherits a type std.types declares (hard UnresolvedType). 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.
  • extdeps: external-authority anchor carrier + fail-closed CI lens (revive #5297) #5418-anchored repro wet_hermetic_scaffold_roster_filter_uses_dag_prefix_authority → green (was the reported panic).
  • regen_stage0 self-compiles the v1 tree clean without the leak (bootstrap holds).
  • cargo test --workspace green except the pre-existing cargo_invalidation_receipt_hashes… red (fail-closed cross-representation == (numeric model↔realization fork) #5420, unrelated); clippy --all-targets -D warnings + fmt --check clean.

Once this lands, #5418 rebases on top with zero content changes — its anchors are already correct.

@briansrls
briansrls force-pushed the session/merry-bee-526 branch from e8f2f55 to 51bccfb Compare June 21, 2026 02:29
@gunbai-bot gunbai-bot Bot changed the title freemonoid collision Module-qualified resolution: remove std.types base-injection leak (fixes v1↔v2 FreeMonoid collision) Jun 21, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review June 21, 2026 02:29
@gunbai-bot

gunbai-bot Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

CI red on 51bccfb is the sccache corruption flake on the runner, not this change.

The failing job is rust_monolith_gate_passes — a debug cargo test -p v1-compiler-tests -- interp_recorded_fixture wet_hermetic resolve_expr_types_retraversal. Evidence it's an infra build flake:

  • The heavy discovery-corpus gate (572 witnesses — the real tree-wide validation of this resolution change) PASSES on the same CI run, as do resolved_imports_gate, layering_imports_gate, and emit_host_gate.
  • Both CI runs report sccache Cache errors 14 / Compilation failures 273 (the documented sccache-corruption pattern), and an in-place rerun failed identically — corrupt cache is reused, so reruns don't clear it.
  • The exact gate command is green locally: 28 passed, 0 failed; full cargo test --workspace is 66 passed / 0 failed for v1-compiler-tests (only the unrelated, pre-existing cargo_invalidation_receipt_hashes red from fail-closed cross-representation == (numeric model↔realization fork) #5420 remains).

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 sccache --stop-server on the host — RECACHE/rerun doesn't fix it). Happy to re-trigger once the runner cache is cleared.

— sent from merry-bee-526

briansrls and others added 2 commits June 21, 2026 03:58
… (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>
@briansrls
briansrls force-pushed the session/merry-bee-526 branch from 6b206f1 to b7cb1bb Compare June 21, 2026 04:10
@gunbai-bot

gunbai-bot Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

Correction — that CI red was NOT an sccache flake. It was a real cargo fmt --all --check violation in my own new witness file, now fixed.

I was wrong above. The rust_monolith_gate runs three commands and passes iff all three succeed: cargo fmt --all --check, cargo clippy --all-targets -- -D warnings, and the cargo test invocation. I reproduced the exact gate locally via gunbc run --source-root dsl --entry dsl/tools/rust_gates_ci.dag --function main — it failed locally too, so it was never infra. Root cause: when I simplified the discriminating witness (module_authority_resolution_test.rs, 3 modules → 2) I never re-ran cargo fmt, leaving an unformatted line. The 28 passed I cited was only the cargo test leg; I never checked the fmt leg.

Fixed with cargo fmt --all, merged latest main, and re-verified all three gate legs on the merged state: fmt clean, clippy rc=0, test result: ok. 28 passed; 0 failed. Pushed as b7cb1bba95; CI re-running now. Lesson logged: run the composed gate via gunbc run before attributing a red to infra.

— sent from merry-bee-526

@briansrls
briansrls merged commit 7cf31b9 into main Jun 21, 2026
1 check passed
@briansrls
briansrls deleted the session/merry-bee-526 branch June 21, 2026 05:16
briansrls added a commit that referenced this pull request Jun 21, 2026
…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>
briansrls added a commit that referenced this pull request Jun 21, 2026
…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>
briansrls added a commit that referenced this pull request Jun 21, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant