Skip to content

find-domains query perf fixes#2155

Merged
shrugs merged 15 commits into
mainfrom
fix/get-domain-index
May 19, 2026
Merged

find-domains query perf fixes#2155
shrugs merged 15 commits into
mainfrom
fix/get-domain-index

Conversation

@shrugs
Copy link
Copy Markdown
Member

@shrugs shrugs commented May 19, 2026

Also Included: Bridged-Resolver Canonicality Fix

scope creep against the original perf focus, but found while inspecting the perf-test index: only 4.9M of 13.5M Domains were canonical — all mainnet, with the entire ~8.6M Basenames + Lineanames subtree non-canonical. root cause: apps/ensindexer/src/plugins/unigraph/handlers/ensv1/ENSv1Registry.ts unconditionally called handleSubregistryUpdated and handleRegistryCanonicalDomainUpdated on every NewOwner, clobbering the two pointers that handleBridgedResolverChange owns (Domain.subregistryId on the L1 origin, Registry.canonicalDomainId on the L2 target). either side's first chain-local subname event broke the bidirectional agreement.

fix: guard both calls with two new SDK predicates isBridgeOriginDomain / isBridgedTargetRegistry (added to packages/ensnode-sdk/src/shared/protocol-acceleration/is-bridged-resolver.ts, reusing the cached config list). on bridge endpoints we leave the pointer alone; non-bridged subnames behave identically to before.

intended outcome (post-reindex): mainnet linea.eth/base.eth.subregistryId stays on the L2 bridged Registry, the L2 Registry's canonicalDomainId stays on the mainnet origin Domain, agreement holds, cascade canonicalizes all ~8.6M Lineanames + Basenames. mainnet-registered subnames directly under linea.eth/base.eth (bridge.linea.eth, devconnect.linea.eth, the handful that exist) drop out of canonicality — consistent with bridged-resolver semantics where resolution goes through L2.


Reviewer Focus (Read This First)

two things worth scrutiny:

  1. cursor format change. NAME-ordered cursors now store the 256-char prefix of canonical_name instead of the full name (see truncateNameForCursor). cursors minted by the prior deploy will not decode-compare correctly under the new code — clients with in-flight pagination state will need to restart from page 1.
  2. canonical filter semantics. DomainsWhere.canonical is now typeof === "boolean"-gated: both true and false produce an eq(canonical, ...) filter; only null/undefined is "no filter". AccountDomainsWhereInput.canonical lost its defaultValue: false — clients omitting that arg will now receive all domains regardless of canonicality (was: effectively no-op-then-everything, since false used to be a no-op). Query.domains no longer hardcodes canonical: true — the required name filter already implies it via canonical_name IS NOT NULL ⟺ canonical = true.

Problem & Motivation

three slow paths against the mainnet perf-test index (13.5M domains, 4.9M canonical):

  • get-domain-by-interpreted-name("eth"): 2.69s. namegraph walk's recursive CTE left-joined domain_resolver_relations on domain_id alone, but the PK leads with (chain_id, address) so the join had no usable index.
  • Domain.subdomains(.eth) (3.5M children): 15.26s+. registry-scoped browse had no composite index for WHERE registry_id = X ORDER BY canonical_name LIMIT N; planner fell back to filter + sort.
  • broad-prefix Query.domains typeahead (e.g. 'a%' ordered by NAME): planner was thrown by the hardcoded canonical = true predicate. removing it lets the planner use the GIN trigram path cleanly.

separately, find-domains had a layered "filter-by-X" abstraction (base-domain-set → filter-by-name → filter-by-canonical → ...) that materialized intermediate CTEs and made the SELECT shape opaque to the planner.

What Changed (Concrete)

  1. new indexes in packages/ensdb-sdk/src/ensindexer-abstract/:
    • domain_resolver_relations(domain_id) (secondary lookup off the PK)
    • domains(registry_id, left(canonical_name, 256), id) (composite for registry-scoped NAME browse)
  2. find-domains resolver rewrite (find-domains-resolver.ts and helpers): layered filter-by-X pattern collapsed into a single flat resolveFindDomains with a compound WHERE. SELECT projects only id + a single conditional registration_value column. NAME/DEPTH order values are read back from the dataloader-hydrated Domain instead of carried in a separate map. layer files deleted.
  3. Domain.subdomains now forward-walks via parent.subregistryId instead of reverse-walking via registry.canonicalDomainId. when subregistryId is null, short-circuits to a new EMPTY_CONNECTION helper (in connection-helpers.ts).
  4. cursor encoding: NAME-ordered cursors are truncated to CANONICAL_NAME_SORT_PREFIX (256) chars at encode time via truncateNameForCursor. the filter-side left(${cursor.value}::text, 256) re-application is gone; cursor value is compared directly against the index expression.
  5. canonical filter semantics: DomainsWhere.canonical is typeof === "boolean"-gated, so both true and false filter. AccountDomainsWhereInput.canonical drops defaultValue: false; description rewritten to clarify the three states. Query.domains drops the hardcoded canonical: true — the required name filter does the work.
  6. cursorFilter NULL branches collapsed 4 → 2 by hoisting op and idCmp.
  7. VERSION_TO_DOMAIN_TYPE value side typed against (typeof ensIndexerSchema.domainType.enumValues)[number] instead of a hand-rolled literal union.
  8. DomainsNameFilterValue replaced with typeof DomainsNameFilter.\$inferInput inline at point-of-use.
  9. schema.graphql regenerated to reflect AccountDomainsWhereInput.canonical no longer defaulting.

Design & Planning

no design doc. all work was done incrementally against a live perf-test index (ensindexer_perf_unigraph_pa, mainnet, unigraph + protocol-acceleration) with EXPLAIN ANALYZE driving each index decision.

an early version of this PR added two partial indexes WHERE canonical = true to support Query.domains's hardcoded canonical = true predicate. follow-up analysis showed that the NAME partial was harmful in the broad-prefix typeahead case (planner mis-selected it and scanned 4M rows; 11s actual). dropping the hardcoded predicate and the partials together is strictly better — the GIN trigram + existing hash indexes handle the remaining shapes, and the only regression ('a%' DEPTH-order: 5.5ms → 686ms) is a single-keystroke edge case.

alternative considered: enforce InterpretedLabel byte-length cap (255-byte DNS-encodable) and materialize a length-capped canonical name column, removing the need for the LEFT(...) expression index. documented in the CANONICAL_NAME_SORT_PREFIX JSDoc as the cleaner long-term shape; deferred because it requires changes to indexing-time semantics.

  • planning artifacts: none
  • reviewed / approved by: n/a (solo)

Self-Review

ran /simplify (three review agents: reuse, quality, efficiency) and applied findings.

  • bugs caught: SELECT projected canonicalName + canonicalDepth on every row regardless of orderBy; narrowed to id + conditional registration column. planner mis-selection on partial NAME index under broad-prefix ILIKE.
  • logic simplified: __orderValue map was redundant for NAME/DEPTH — those values live on the loaded Domain. getOrderValueFromResult deleted.
  • naming / terminology improved: truncateNameForCursor, EMPTY_CONNECTION, getDefaultOrder. DOMAINS_DEFAULT_ORDER constant extracted.
  • dead or unnecessary code removed: layered filter-by-X files (base-domain-set.ts, filter-by-*.ts, with-ordering-metadata.ts, layers/index.ts) deleted; getOrderValueFromResult deleted; verbose DomainsWhere JSDoc trimmed; narrating comments ("Compound WHERE…", "build order clauses…") removed; the two partial WHERE canonical = true indexes removed.

Cross-Codebase Alignment

  • search terms used: resolveFindDomains, DomainsWhereInput, canonical = true, setFilterCondition, paginateBy, byCanonicalDepth
  • reviewed but unchanged: find-events-resolver.ts (similar \$dynamic() + conditional join shape — left independent), Registry.parents (separate path), Account.domains callsite (now relies on the new semantics), Query.domains callsite (no longer needs the predicate)
  • deferred alignment: lift setFilterCondition from find-events-resolver.ts into a shared module so nameCondition can reuse its eq/in halves. cross-file refactor; out of scope here.

Downstream & Consumer Impact

  • public APIs affected:
    • AccountDomainsWhereInput.canonical no longer defaults — described in §Reviewer Focus
    • cursor format change — described in §Reviewer Focus
  • docs updated: AccountDomainsWhereInput.canonical GraphQL description rewritten; schema.graphql regenerated.
  • naming worth calling out: EMPTY_CONNECTION is a module-level singleton, not a factory. pothos relay reads edges/pageInfo without mutating, so the shared instance is safe — but if any future plugin starts mutating connection returns, this would leak across requests.

Testing Evidence

  • 98 ensapi unit tests pass; monorepo typecheck + pnpm lint:ci clean.
  • live EXPLAIN ANALYZE against perf-test mainnet (post-fix, cold/warm):
    • get-domain-by-interpreted-name("eth"): 2.69s → 0.836ms
    • Domain.subdomains(.eth) (3.5M children): 15.26s → 19-22ms warm / 140ms cold
    • Query.domains name.eq ordered NAME: 0.78ms (hash index)
    • Query.domains name.starts_with: "vitalik" ordered NAME: 16.6ms / DEPTH: 1.4ms (GIN trigram + bitmap)
    • Query.domains worst-case name.starts_with: "a" (815k matches) ordered NAME: 1.8s / DEPTH: 686ms — single-keystroke typeahead edge case, sub-second
  • known gaps: integration tests (pnpm test:integration:ci) not run for the post-merge state. cursor-encoding change has no dedicated unit test (existing helpers tests cover only isEffectiveDesc).
  • what reviewers reason about manually: that pothos relay's pageInfo/edges consumers don't mutate the returned object (relevant to EMPTY_CONNECTION singleton).

Scope Reductions

  • lift setFilterCondition into a shared helper for both find-events and find-domains — separate refactor PR
  • enforce InterpretedLabel byte-length cap to avoid the LEFT(...) expression index entirely — needs indexing-time changes; documented as future work in CANONICAL_NAME_SORT_PREFIX JSDoc
  • convert EMPTY_CONNECTION to a factory function — only matters if a future pothos plugin mutates connection results; trivial to switch later

Risk Analysis

  • risk: existing cursors won't pagination-compare correctly. mitigation: cursors are typically session/request-scoped; clients will restart pagination on the deploy boundary.
  • risk: Account.domains default behavior changes — clients that relied on canonical: false as a no-op now get a filter applied. mitigation: schema description rewritten; defaultValue removed so omitting the arg gives the most permissive answer (all domains). a client explicitly passing canonical: false is the only one affected, and the new behavior matches the field's name.
  • risk: single-keystroke typeahead (name.starts_with: "a") DEPTH-order is now ~700ms (was ~5ms with the dropped partial). worth mentioning to UI clients that they should debounce or require ≥2 chars; all narrower prefixes are sub-20ms.
  • named owner: @shrugs

Pre-Review Checklist (Blocking)

  • I reviewed every line of this diff and understand it end-to-end
  • I'm prepared to defend this PR line-by-line in review
  • I'm comfortable being the on-call owner for this change
  • Relevant changesets are included (or explicitly not required)

Copilot AI review requested due to automatic review settings May 19, 2026 20:20
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
enskit-react-example.ensnode.io Ready Ready Preview, Comment May 19, 2026 9:55pm
ensnode.io Ready Ready Preview, Comment May 19, 2026 9:55pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
admin.ensnode.io Skipped Skipped May 19, 2026 9:55pm
ensrainbow.io Skipped Skipped May 19, 2026 9:55pm

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 19, 2026

🦋 Changeset detected

Latest commit: 2b1b894

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
Name Type
ensapi Patch
@ensnode/ensdb-sdk Patch
ensindexer Patch
@ensnode/integration-test-env Patch
ensadmin Patch
ensrainbow Patch
fallback-ensapi Patch
enssdk Patch
enscli Patch
enskit Patch
ensskills Patch
@ensnode/datasources Patch
@ensnode/ensrainbow-sdk Patch
@ensnode/ensnode-sdk Patch
@ensnode/ponder-sdk Patch
@ensnode/ponder-subgraph Patch
@ensnode/shared-configs Patch
@docs/ensnode Patch
@docs/ensrainbow Patch
@namehash/ens-referrals Patch
@namehash/namehash-ui Patch
@ensnode/ensindexer-perf-testing Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

Review Change Stack

Warning

Rate limit exceeded

@shrugs has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 33 minutes and 16 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: db36cde1-bc19-4076-9862-857441ecacb9

📥 Commits

Reviewing files that changed from the base of the PR and between e6cf651 and 2b1b894.

⛔ Files ignored due to path filters (1)
  • packages/enssdk/src/omnigraph/generated/introspection.ts is excluded by !**/generated/**
📒 Files selected for processing (11)
  • .changeset/account-domains-canonical-semantics.md
  • .changeset/find-domains-perf-indexes.md
  • .changeset/sharp-towns-try.md
  • apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver.ts
  • apps/ensapi/src/omnigraph-api/schema/query.ts
  • apps/ensindexer/src/plugins/unigraph/handlers/ensv1/ENSv1Registry.ts
  • docs/ensnode.io/src/content/docs/docs/services/ensdb/concepts/database-schemas.mdx
  • packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts
  • packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts
  • packages/ensnode-sdk/src/shared/protocol-acceleration/is-bridged-resolver.ts
📝 Walkthrough

Walkthrough

This PR consolidates domain query construction by eliminating a multi-layer filtering pattern and moving all logic into a centralized resolveFindDomains resolver that builds SQL directly from the schema. It introduces DomainsWhere as the new filter input shape, refactors cursor/ordering helpers to work independently, and updates database indexes to support the new keyset pagination strategy.

Changes

Find-Domains Query Architecture

Layer / File(s) Summary
Empty Connection Helper
apps/ensapi/src/omnigraph-api/lib/connection-helpers.ts
Introduces EMPTY_CONNECTION constant—an async Relay connection that short-circuits with zero results, used by domain subdomain resolvers when a parent registry is missing.
Find-Domains Resolver Core Refactor
apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts, apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver.ts
Replaces the CTE-based pattern with direct schema querying: exports new DomainsWhere filter interface, adds CANONICAL_NAME_SORT_PREFIX and truncateNameForCursor helpers, and refactors cursorFilter and orderFindDomains to compute order/filter expressions independently using ensIndexerSchema instead of relying on pre-built ordering metadata CTEs.
GraphQL Schema Resolver Integration
apps/ensapi/src/omnigraph-api/schema/account.ts, apps/ensapi/src/omnigraph-api/schema/domain.ts, apps/ensapi/src/omnigraph-api/schema/query.ts, apps/ensapi/src/omnigraph-api/schema/registry.ts
Updates Account.domains, Domain.subdomains (using EMPTY_CONNECTION), Query.domains, and Registry.domains resolvers to delegate directly to resolveFindDomains, passing contextual where filters instead of building filtering layers inline.
Input Type Updates
apps/ensapi/src/omnigraph-api/schema/domain-inputs.ts
Introduces DomainsOrderValue type for order pairs, changes canonical field to tri-state (unconstrained when omitted), and removes default-order constants DOMAINS_DEFAULT_ORDER_BY and DOMAINS_DEFAULT_ORDER_DIR.
Removed Filter Layer Modules
apps/ensapi/src/omnigraph-api/lib/find-domains/layers/*, apps/ensapi/src/omnigraph-api/lib/find-domains/layers/index.ts
Deletes all legacy layered filtering helper modules (base-domain-set.ts, filter-by-canonical.ts, filter-by-name*.ts, filter-by-owner.ts, filter-by-parent.ts, filter-by-registry.ts, filter-by-version.ts, with-ordering-metadata.ts) and their barrel export, consolidating their functionality into the centralized resolver.
Database Index Optimization
packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts, packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts
Restructures domain table indexes: replaces byRegistry with composite byRegistryAndLabelHash and byRegistryAndCanonicalNameLeft indexes, adds partial indexes for canonical-only queries, and introduces byDomain index on domainResolverRelation for resolution joins.
Tracing Span Wrapping and Dependency Updates
apps/ensapi/src/omnigraph-api/lib/get-domain-by-interpreted-name.ts, apps/ensadmin/package.json
Wraps forwardWalkDisjointNamegraph SQL execution in withSpanAsync instrumentation and updates ensadmin SDK dependencies from pinned preview SHA to workspace:* resolution.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • namehash/ensnode#2125: Refactors find-domains query stack around materialized canonical fields, touching the same find-domains-resolver.ts/find-domains-resolver-helpers.ts modules and cursor/order/canonicalName-based filtering.
  • namehash/ensnode#2061: Overlaps at the module level by changing the same canonical/base filtering layer modules (base-domain-set.ts, filter-by-canonical.ts, filter-by-name*) that this PR removes.
  • namehash/ensnode#2145: Updates apps/ensadmin/package.json dependency versions for @ensnode/ensnode-sdk and enssdk to workspace:*, the same change made in this PR's dependency layer.

Poem

🐰 Layers once nested, now consolidated tight,
Domain queries dance in a single resolver's light,
Schema speaks direct, no middleware in sight,
Cursors skip keyset while indexes shine bright,
Find-domains flows smooth—ah, what a delight! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is completely empty, lacking all required sections from the template including Summary, Why, Testing, and Pre-Review Checklist. Add a complete PR description following the Lite PR template with Summary (changes in 1-3 bullets), Why (motivation/related issues), Testing (how it was tested), and the Pre-Review Checklist.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'find-domains query perf fixes' directly reflects the main changes in the changeset, which refactor the find-domains resolver and add database indexes for query optimization.
Docstring Coverage ✅ Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/get-domain-index

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

# Conflicts:
#	apps/ensadmin/package.json
#	pnpm-lock.yaml
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the Omnigraph find-domains query path to improve performance by pushing filtering/ordering into a single flat domains query (with conditional joins), and adds supporting DB indexes to make common ORDER BY/LIMIT patterns index-friendly.

Changes:

  • Refactor resolveFindDomains call sites (Query/Account/Registry/Domain) to pass a compound where object into a centralized resolver instead of composing layered CTEs.
  • Rework resolveFindDomains to query domains directly (conditionally joining registration tables only when needed for ordering), and update cursor ordering helpers to align with new DB indexes.
  • Add/adjust DB indexes (including composite/prefix and partial canonical indexes) to support ordered scans for NAME/DEPTH queries.

Reviewed changes

Copilot reviewed 22 out of 23 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pnpm-lock.yaml Switch some app deps from preview versions to workspace:* links; lockfile snapshot adjustments.
packages/enssdk/src/omnigraph/generated/schema.graphql Update AccountDomainsWhereInput.canonical semantics (remove default, clarify meaning).
packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts Add secondary index to speed domain-resolver relation lookups by domainId.
packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts Add composite/prefix and partial indexes to accelerate NAME/DEPTH ordered scans and registry/label lookups.
apps/ensapi/src/omnigraph-api/schema/registry.ts Simplify Registry.domains resolver to delegate filtering to resolveFindDomains via where.registryId.
apps/ensapi/src/omnigraph-api/schema/query.ts Simplify Query.domains resolver to delegate to resolveFindDomains and enforce canonical filtering centrally.
apps/ensapi/src/omnigraph-api/schema/domain.ts Update Domain.subdomains to short-circuit empty connections and delegate via where.registryId = subregistryId.
apps/ensapi/src/omnigraph-api/schema/domain-inputs.ts Remove default for AccountDomainsWhereInput.canonical; replace old default-order constants with a new order-value type.
apps/ensapi/src/omnigraph-api/schema/account.ts Simplify Account.domains resolver to delegate filtering to resolveFindDomains via where.ownerId.
apps/ensapi/src/omnigraph-api/lib/get-domain-by-interpreted-name.ts Add span around forward-walk query for tracing/observability.
apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver.ts Major refactor: build flat domain query with conditional joins, compound filters, and keyset pagination aligned to new indexes.
apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts Update ordering + cursor filters to use index-aligned expressions (notably left(canonical_name, N)).
apps/ensapi/src/omnigraph-api/lib/connection-helpers.ts Add EMPTY_CONNECTION helper for short-circuiting connection resolvers.
apps/ensadmin/package.json Switch local deps to workspace:* for monorepo consistency.
apps/ensapi/src/omnigraph-api/lib/find-domains/layers/with-ordering-metadata.ts Removed: ordering metadata now handled directly in resolveFindDomains.
apps/ensapi/src/omnigraph-api/lib/find-domains/layers/index.ts Removed: layered find-domains composition no longer used.
apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-version.ts Removed: version filtering now handled in resolveFindDomains.
apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-registry.ts Removed: registry filtering now handled in resolveFindDomains.
apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-parent.ts Removed: subdomain filtering now handled via registryId/subregistryId.
apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-owner.ts Removed: owner filtering now handled in resolveFindDomains.
apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-name.ts Removed: name filtering now handled in resolveFindDomains.
apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-name-starts-with.ts Removed: prefix filtering now handled in resolveFindDomains.
apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-name-in.ts Removed: exact/in-set filtering now handled in resolveFindDomains.
apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-canonical.ts Removed: canonical filtering now handled in resolveFindDomains.
apps/ensapi/src/omnigraph-api/lib/find-domains/layers/base-domain-set.ts Removed: base CTE composition replaced by flat domains query approach.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts Outdated
Comment thread packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts`:
- Around line 22-31: The current approach truncates canonical names to
CANONICAL_NAME_SORT_PREFIX (256) in truncateNameForCursor and in the ORDER BY
expression, which breaks true lexicographic ordering for long names; change the
logic so ordering uses the full canonical_name for comparison (keep the
tie-breaker id as needed) and stop truncating the value used for ORDER BY, while
still keeping cursor payloads compact by either encoding the full name into the
cursor (e.g., base64) or using a stable hash of the full name plus id for the
cursor; update truncateNameForCursor (and the other similar spots referenced
around the file, including the other occurrences of left(..., 256) at the places
noted) to return/encode the non-truncated value used for ordering or to produce
a hash-based cursor, and ensure cursorFilter comparisons use the same full-name
ordering semantics and tie-breaker (id) as the query.

In `@apps/ensapi/src/omnigraph-api/schema/domain.ts`:
- Around line 227-234: The Domain.subdomains resolver currently only filters by
registryId: parent.subregistryId which returns all domains under that registry;
update the resolver that calls resolveFindDomains to also scope by the current
domain as parent (e.g., add parentId: parent.id or equivalent parent reference)
so only direct descendants are returned—modify the where clause passed to
resolveFindDomains in the Domain.subdomains resolver to include both registryId:
parent.subregistryId and the parent identifier (parent.id or the appropriate
parent key) while preserving existing order and connectionArgs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bec51ee5-6f97-4c5c-b9ee-812cf3fe2fbf

📥 Commits

Reviewing files that changed from the base of the PR and between 7d0d378 and e6cf651.

⛔ Files ignored due to path filters (2)
  • packages/enssdk/src/omnigraph/generated/schema.graphql is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (23)
  • apps/ensadmin/package.json
  • apps/ensapi/src/omnigraph-api/lib/connection-helpers.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/base-domain-set.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-canonical.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-name-in.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-name-starts-with.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-name.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-owner.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-parent.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-registry.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-version.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/index.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/with-ordering-metadata.ts
  • apps/ensapi/src/omnigraph-api/lib/get-domain-by-interpreted-name.ts
  • apps/ensapi/src/omnigraph-api/schema/account.ts
  • apps/ensapi/src/omnigraph-api/schema/domain-inputs.ts
  • apps/ensapi/src/omnigraph-api/schema/domain.ts
  • apps/ensapi/src/omnigraph-api/schema/query.ts
  • apps/ensapi/src/omnigraph-api/schema/registry.ts
  • packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts
  • packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts
💤 Files with no reviewable changes (11)
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/with-ordering-metadata.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-canonical.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-name.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-parent.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-registry.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-owner.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-name-starts-with.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-name-in.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/index.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/filter-by-version.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/layers/base-domain-set.ts

Comment thread apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/domain.ts
@vercel vercel Bot temporarily deployed to Preview – ensnode.io May 19, 2026 20:40 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io May 19, 2026 20:40 Inactive
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io May 19, 2026 20:40 Inactive
@shrugs shrugs marked this pull request as ready for review May 19, 2026 20:44
@shrugs shrugs requested a review from a team as a code owner May 19, 2026 20:44
Copilot AI review requested due to automatic review settings May 19, 2026 20:44
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated 1 comment.

Comment thread apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts Outdated
Copy link
Copy Markdown
Member

@lightwalker-eth lightwalker-eth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shrugs Great to see these enhancements 👍 Reviewed and shared feedback. Please feel welcome to merge when ready!

Comment thread packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts
Comment thread apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/domain.ts
Comment thread apps/ensapi/src/omnigraph-api/schema/domain.ts
- truncateNameForCursor uses code-point iteration to match Postgres LEFT()
- registrationValueById: drop unreachable optional chain, explicit invariant
- CANONICAL_NAME_SORT_PREFIX JSDoc typo fixes
- add @ensnode/ensdb-sdk changeset for the new perf indexes
@shrugs
Copy link
Copy Markdown
Member Author

shrugs commented May 19, 2026

@greptile review

Copilot AI review requested due to automatic review settings May 19, 2026 21:54
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io May 19, 2026 21:54 Inactive
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io May 19, 2026 21:54 Inactive
@shrugs
Copy link
Copy Markdown
Member Author

shrugs commented May 19, 2026

@greptile review

@shrugs shrugs merged commit addfba6 into main May 19, 2026
19 of 20 checks passed
@shrugs shrugs deleted the fix/get-domain-index branch May 19, 2026 21:56
@github-actions github-actions Bot mentioned this pull request May 19, 2026
@shrugs shrugs review requested due to automatic review settings May 19, 2026 22:15
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.

3 participants