Follow-up on canonical Registry logic so the domains.canonical filter correctly reflects resolution semantics (including Bridged Resolvers), and does so performantly.
Context
filterByCanonical in the Omnigraph API joins domains against the set of Canonical Registries built by getCanonicalRegistriesCTE (apps/ensapi/src/omnigraph-api/lib/find-domains/canonical-registries-cte.ts). The CTE walks domain.subregistryId forward from every Root Registry — a Registry is canonical iff reachable via live forward pointers from a Root.
That captures the namegraph-by-construction definition of canonicality, but not resolution semantics. Resolution can cross Registry boundaries via Bridged Resolvers (see apps/ensapi/src/omnigraph-api/lib/get-domain-by-interpreted-name.ts), and from a resolution perspective the bridged-to Registry's domains are also canonical for the bridged path. The current CTE doesn't account for that.
Requirements
- The canonical set used by the
domains.canonical filter must reflect resolution semantics (forward subregistryId traversal plus Bridged Resolver edges).
- Reverse-walking the namegraph for every Domain result on a list query is not viable — the filter must be expressible as a join against a precomputed-or-trivially-computable set.
Approaches to consider
- Materialized view of canonical Registries refreshed on relevant indexer events (subregistry pointer changes, resolver changes, root config changes).
- Materialized
canonical field on the Registry entity, written by indexer handlers as the namegraph + bridged edges evolve. Cleanest at query time but hardest to maintain: Ponder's cache semantics are primary-key-lookup-only, so propagating canonicality through a Registry chain (e.g. when a mid-graph subregistry is unset, every descendant must be re-evaluated) is awkward and potentially expensive without secondary indexes / scans.
- Recursive CTE extended with bridged-resolver edges, kept runtime — preserves correctness but adds cost on every list query, and CTE complexity grows with each new resolution-semantic wrinkle.
Per #1423, prefer correctness first ("make it work then make it fast") — but the canonical filter is on a hot path, so we likely need (1) or (2) before this is production-acceptable for ENSv2.
Related
Follow-up on canonical Registry logic so the
domains.canonicalfilter correctly reflects resolution semantics (including Bridged Resolvers), and does so performantly.Context
filterByCanonicalin the Omnigraph API joinsdomainsagainst the set of Canonical Registries built bygetCanonicalRegistriesCTE(apps/ensapi/src/omnigraph-api/lib/find-domains/canonical-registries-cte.ts). The CTE walksdomain.subregistryIdforward from every Root Registry — a Registry is canonical iff reachable via live forward pointers from a Root.That captures the namegraph-by-construction definition of canonicality, but not resolution semantics. Resolution can cross Registry boundaries via Bridged Resolvers (see
apps/ensapi/src/omnigraph-api/lib/get-domain-by-interpreted-name.ts), and from a resolution perspective the bridged-to Registry's domains are also canonical for the bridged path. The current CTE doesn't account for that.Requirements
domains.canonicalfilter must reflect resolution semantics (forwardsubregistryIdtraversal plus Bridged Resolver edges).Approaches to consider
canonicalfield on the Registry entity, written by indexer handlers as the namegraph + bridged edges evolve. Cleanest at query time but hardest to maintain: Ponder's cache semantics are primary-key-lookup-only, so propagating canonicality through a Registry chain (e.g. when a mid-graph subregistry is unset, every descendant must be re-evaluated) is awkward and potentially expensive without secondary indexes / scans.Per #1423, prefer correctness first ("make it work then make it fast") — but the canonical filter is on a hot path, so we likely need (1) or (2) before this is production-acceptable for ENSv2.
Related
parentDomainId)