From 3d8fd5b5eb500133d06f2e276484b631551384da Mon Sep 17 00:00:00 2001 From: Javier Sagredo Date: Fri, 19 Jun 2026 18:21:11 +0200 Subject: [PATCH] Fix equality constraints surfacing every fam-instance MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The instance-view equality edges (added in 9f81486) call addFamilyLinksFromArgs with predClassQn = null to surface type families mentioned inside an equality (e.g. `Norm` in `Norm a ~ Int`). But the relevance filter that keeps only the fam-instances whose LHS matches the use site was gated behind `if (predClassQn)`, so the null call skipped it and pulled in *every* instance of the family. Concretely: drilling into STS instances and filtering down to ShelleyUTXOW still showed the `State` of every rule, because ShelleyUTXOW's context has `State (EraRule "UTXO" era) ~ …` and the unfiltered call dumped all ~21 `State` instances. Apply the relevance filter (replaceFamilyApp unification) regardless of predClassQn; only the resolution-chain step stays gated on it. Now the filtered view shows just `State (ShelleyUTXOW era)` plus a placeholder for ShelleyUTXOW's own unresolved `State (EraRule "UTXO" era)` reference. Co-Authored-By: Claude Opus 4.8 (1M context) --- data/viewer.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/data/viewer.js b/data/viewer.js index d26d496..84fc084 100644 --- a/data/viewer.js +++ b/data/viewer.js @@ -759,11 +759,17 @@ // noise. Run the relevance check *before* creating the // fam-instance node so irrelevant rows are skipped entirely. for (const fi of (famInstsByFamily.get(famNodeId) || [])) { - let resolvedArgs = null; - if (predClassQn) { - resolvedArgs = args.map(a => replaceFamilyApp(a, fa, fi)); - if (resolvedArgs.some(a => a === null)) continue; - } + // Relevance filter — keep only fam-instances whose LHS can + // actually describe the family-application used here. + // replaceFamilyApp returns null for an arg that mentions `fa` + // but whose use-site args don't unify with this fi's LHS; an + // arg that doesn't mention `fa` comes back unchanged. This runs + // regardless of predClassQn: without it, an equality constraint + // like `State (EraRule "UTXO" era) ~ …` (predClassQn = null) + // would pull in *every* `State` instance instead of only the + // ones matching this use site. + const resolvedArgs = args.map(a => replaceFamilyApp(a, fa, fi)); + if (resolvedArgs.some(a => a === null)) continue; anyRelevant = true; const fiNodeId = ensureFamInstanceNode(fi); @@ -784,7 +790,7 @@ // also pull a class node into the graph alongside it — it // would just be a redundant box with a green arrow that says // the same thing. - if (predClassQn && resolvedArgs) { + if (predClassQn) { const reduced = resolvedArgs.map(reduceTypeArg); const matched = findMatchingInstances(predClassQn, reduced); if (matched.length > 0) { -- 2.54.0