// 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);
// 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) {