feat(derive): Haskell same-file REFS — intent-faithful single-target scope-walk .dl pack (retire native LocalRefs) — W23 - #436
Merged
Conversation
… scope-walk .dl pack (retire native LocalRefs; prelude via haskell-globals) — W23 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Disentinel
force-pushed
the
hbp/haskell-refs-dl-final
branch
from
June 16, 2026 16:48
768de22 to
147fd03
Compare
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.
Intent
Migrate Haskell same-file REFERENCE resolution (
READS_FROM) off the nativeHaskellLocalRefs.hsresolver onto an in-engine@stdlib/haskell_local_refs*Datalog pack, faithful to the legacy resolver's intent — exactly ONE target per source (the legacyMap.fromListlast-write-wins cardinality) — while fixing the cross-scope-collapse misroute the flat Map produced.The native resolver was a flat
(file, name)Map.fromList(last-write-wins). A naive multi-type union of that Map blew the edge count up ~×4.8 (spurious cross-namespace + foreign-scope-PARAMETER fan-out). This pack reproduces the legacy RETARGET-not-ADD cardinality via a nearest-binder scope-walk plus a single-target flat fallback.Rides on the stack
do-binds in their own scope. Gives the scope-walk its precise binder scoping (the REFS single-target residual was closed by DoScope).FilterReferences) — the prelude reference arm is re-homed out of the native LocalRefs into thehaskell-globalsruntime-globals pass. This fixes the oldlost_vs_intent = 423(prelude refs that the legacy resolver mapped but a pure same-file pack would drop). With the prelude arm dropped here and served by haskell-globals, those 423 are preserved.What this pack does
Q1 applied.
haskell_local_refs_nodesMINTS the virtualHASKELL_GLOBAL::<name>EXTERNAL_FUNCTIONprelude endpoints;haskell_local_refsjoins them as committed EDB (thejs_runtime_globalstwo-pack nodes→edges split — a@materializeedge endpoint must be a committed node-ID column).Resolution order in
haskell_local_refs:PARAMETER/VARIABLElocal hit (the analyzerCONTAINS-parents these at the ref's own scope id — the dominant legacy bug) wins.FUNCTION > VARIABLE > CONSTANT > CONSTRUCTOR > RECORD_FIELD, then the TYPE namespace LAST (DATA_TYPE > TYPE_SYNONYM). A(file,name)with binders in several namespaces emits ONE edge to the highest-priority namespace (RETARGET, not ADD). LocalFUNCTIONs are MODULE-flattened by the analyzer, so flat is the only recoverable resolution for them — no-worse than legacy.PARAMETERtarget routes a ref to a FOREIGN scope's parameter — exactly the misroute bug re-introduced as fan-out. The only soundPARAMETERhit is the same-scope local arm.Differential vs intent
false_added = 0— a value binder always wins when present, so no spurious type/foreign edge is added.lost_vs_intent = 0— the TYPE namespace is kept at LOWEST priority (not dropped), so a value REFERENCE whose only binder is aDATA_TYPE/TYPE_SYNONYMstill resolves; the prelude 423 are preserved by haskell-globals.max_edges_per_source = 1— pinned by the unit test (a ref to a 5-binder name + a foreign-scope PARAMETER emits ONE flat edge, to the FUNCTION).Retirement (scoped)
HaskellLocalRefs.hsremoved; dropped fromhaskell-resolve.cabalother-modules.haskell-local-refscommand (both resolve sites); same-fileREADS_FROMnow runs in-engine. The KEPT arms (haskell-imports/haskell-cross-module-calls/haskell-globals) are cross-file / stdlib and the packs do NOT replace them.haskell_local_callspack is already on this base (feat(derive): Haskell same-file CALLS → intent-faithful single-target .dl pack (retire native LocalCalls) — W23 #428) — NOT re-introduced here; only the REFS pack + its registration.Tests
haskell_local_refs_scope_walk_fixes_cross_scope_collapse— nearest-binder scope-walk.haskell_local_refs_flat_fallback_is_single_target— the ×4.8 fan-out guard: single-target ladder, NO flat PARAMETER, TYPE-namespace lowest-priority still resolves (lost_real≈0).haskell_local_refs_prelude_fall_through— nodes-pack minting + EDB join + exclusive (provenance-scoped) mint.stdlib_pack_registry_resolves_names_in_canonical_order— registration/ordering with the new refs packs.All green (
cargo test --release --lib stdlib::tests: 57 passed; the 3 refs tests + the pre-existing calls test pass underhaskell_local). rfdb-server + orchestrator build clean in release.See
_ai/research/haskell-resolve-intent-spec.mdfor the full intent spec.Stacking
STACKED on #434 + #435 — merge those first. This branch's base (
w23/haskell-refs-integration) already includes #434 (DoScope) and #435 (haskell-globals), so this branch contains them transitively.🤖 Generated with Claude Code
DO NOT MERGE — Vadim reviews; stacked on #434+#435.