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) <[email protected]>
// noise. Run the relevance check *before* creating the
// fam-instance node so irrelevant rows are skipped entirely.
for (const fi of (famInstsByFamily.get(famNodeId) || [])) {
// 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);
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.
// 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) {
const reduced = resolvedArgs.map(reduceTypeArg);
const matched = findMatchingInstances(predClassQn, reduced);
if (matched.length > 0) {
const reduced = resolvedArgs.map(reduceTypeArg);
const matched = findMatchingInstances(predClassQn, reduced);
if (matched.length > 0) {