Skip to content

feat(derive): Haskell same-file REFS — intent-faithful single-target scope-walk .dl pack (retire native LocalRefs) — W23 - #436

Merged
Disentinel merged 1 commit into
mainfrom
hbp/haskell-refs-dl-final
Jun 16, 2026
Merged

feat(derive): Haskell same-file REFS — intent-faithful single-target scope-walk .dl pack (retire native LocalRefs) — W23#436
Disentinel merged 1 commit into
mainfrom
hbp/haskell-refs-dl-final

Conversation

@Disentinel

Copy link
Copy Markdown
Owner

Intent

Migrate Haskell same-file REFERENCE resolution (READS_FROM) off the native HaskellLocalRefs.hs resolver onto an in-engine @stdlib/haskell_local_refs* Datalog pack, faithful to the legacy resolver's intent — exactly ONE target per source (the legacy Map.fromList last-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

What this pack does

Q1 applied. haskell_local_refs_nodes MINTS the virtual HASKELL_GLOBAL::<name> EXTERNAL_FUNCTION prelude endpoints; haskell_local_refs joins them as committed EDB (the js_runtime_globals two-pack nodes→edges split — a @materialize edge endpoint must be a committed node-ID column).

Resolution order in haskell_local_refs:

  1. Nearest-binder scope-walk — a same-scope PARAMETER/VARIABLE local hit (the analyzer CONTAINS-parents these at the ref's own scope id — the dominant legacy bug) wins.
  2. Single-target flat fallback over the value decl types via a namespace-PRIORITY ladder: 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). Local FUNCTIONs are MODULE-flattened by the analyzer, so flat is the only recoverable resolution for them — no-worse than legacy.
    • PARAMETER is excluded from the flat arm: a flat PARAMETER target routes a ref to a FOREIGN scope's parameter — exactly the misroute bug re-introduced as fan-out. The only sound PARAMETER hit is the same-scope local arm.
  3. Prelude arm DROPPED — the prelude global fall-through is no longer minted/resolved here; it is served by feat(haskell-globals): resolve prelude REFERENCEs to HASKELL_GLOBAL (FilterReferences pass) — W23 #435 haskell-globals (re-homed). The flat hit still suppresses what would have been the prelude fall-through, so mutual exclusion holds.

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 a DATA_TYPE/TYPE_SYNONYM still resolves; the prelude 423 are preserved by haskell-globals.
  • single-target: 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)

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 under haskell_local). rfdb-server + orchestrator build clean in release.

See _ai/research/haskell-resolve-intent-spec.md for 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.

@Disentinel
Disentinel changed the base branch from w23/haskell-refs-integration to main June 16, 2026 16:47
… 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
Disentinel force-pushed the hbp/haskell-refs-dl-final branch from 768de22 to 147fd03 Compare June 16, 2026 16:48
@Disentinel
Disentinel merged commit 85438e1 into main Jun 16, 2026
13 checks passed
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