Skip to content

perf(ensapi): index-accelerate registration-ordered domain queries#2259

Merged
shrugs merged 7 commits into
mainfrom
perf/registration-ordered-domains
Jun 5, 2026
Merged

perf(ensapi): index-accelerate registration-ordered domain queries#2259
shrugs merged 7 commits into
mainfrom
perf/registration-ordered-domains

Conversation

@shrugs
Copy link
Copy Markdown
Member

@shrugs shrugs commented Jun 4, 2026

Reviewer Focus (Read This First)

  • the keyset + null handling in find-domains-resolver-helpers.ts (cursorFilter / orderFindDomains) — the trickiest part. registration sort columns are now NOT NULL with a +∞ sentinel, which is what lets a single plain composite serve both directions with no null special-casing.
  • the sentinel materialization across all 5 latest-registration expiry-mutation handler sites — correctness depends on always writing the latest registration's value.
  • whether hydrating find-domains results directly via a relational findMany (skipping the Domain dataloader) is acceptable.

Problem & Motivation

  • Domain.subdomains(order: { by: REGISTRATION_TIMESTAMP }) on .eth ran ~55s vs ~0.3s for the default NAME order.
  • root cause: the order column lives in registrations (reached via join through latest_registration_indexes) while the filter (registry_id) is on domains — no index can serve both, so the planner fetched all ~3M .eth subdomains, joined, sorted, and took 10.
  • affects both REGISTRATION_TIMESTAMP and REGISTRATION_EXPIRY, across Query.domains, Account.domains, Registry.domains, Domain.subdomains.

What Changed (Concrete)

  1. materialize the latest registration's start/expiry onto Domain as __latestRegistrationStart / __latestRegistrationExpiry, NOT NULL with a +∞ sentinel (REGISTRATION_SORT_SENTINEL = 2^256-1) for absent values (no registration / never expires).
  2. add composites (registry_id, __latestRegistrationStart, id) and (registry_id, __latestRegistrationExpiry, id).
  3. maintain the columns in the indexer: insertLatestRegistration + a new updateLatestRegistrationExpiry helper wired through all 5 latest-registration expiry-mutation sites (BaseRegistrar, unigraph NameWrapper ×2, ENSv2Registry ×2).
  4. resolver orders by the materialized columns (no join) and omits the NULLS clause for registration so the plain composite serves both ASC and DESC.
  5. hydrate find-domains results directly via a relational findMany (with label), dropping the dataloader round-trip; remove the now-unused context param from resolveFindDomains and its 4 call sites.
  6. cast registration cursor values to ::numeric(78,0) (ponder bigint is numeric, not int8 — ::bigint overflowed the uint64-max "never expires" sentinel).
  7. document ordering / null semantics on the DomainsOrderBy enum values and each find-domains field.
  8. add a "Recently Registered Subdomains" Omnigraph example (+ snapshot / response refresh).

Design & Planning

  • lightweight, iterative; no upfront design doc.

  • alternatives considered and rejected: (a) 4 indexes (separate ASC + DESC-NULLS-LAST per column) — keeps nullable columns but doubles index cost on the largest table; (b) default NULL placement on nullable columns — breaks index-efficient keyset pagination over the null tail (O(offset) scans + forward/backward inconsistency); (c) exclude no-registration domains — simplest but changes the result set. landed on the NOT-NULL sentinel as the cleanest: same set, index-seekable both directions, no null special-casing.

  • Planning artifacts: none

  • Reviewed / approved by: n/a (solo)

Self-Review

  • Bugs caught: ::bigint cursor cast overflowed on the uint64-max never-expires expiry (→ ::numeric(78,0)); a debug console.log(JSON.stringify(toSQL())) threw on BigInt params and masked the real error behind yoga's "Unexpected error" (removed); forward/backward keyset inconsistency over the null tail (resolved by the sentinel).
  • Logic simplified: the sentinel made the columns non-null, letting me delete all the null-placement / cursor special-casing I'd briefly added.
  • Naming / terminology improved: usesDefaultNullPlacementisRegistrationOrdering.
  • Dead or unnecessary code removed: dropped the join machinery (needsRegistrationJoin, the two leftJoins, registrationValueById) plus the orphaned context param and DomainInterfaceRef / rejectAnyErrors imports.

Cross-Codebase Alignment

Downstream & Consumer Impact

  • Public APIs affected: REGISTRATION_TIMESTAMP / REGISTRATION_EXPIRY ordering on Query.domains, Account.domains, Registry.domains, Domain.subdomains is now fast. result set is unchanged — no-registration domains are still included, sorted last for ASC and first for DESC via the sentinel.
  • Docs updated: DomainsOrderBy enum value descriptions, find-domains field descriptions, new Omnigraph example.
  • Naming decisions worth calling out: __latestRegistration* (double-underscore marks an internal materialized mirror, not protocol surface; the canonical value stays on the Registration entity).
  • Requires a re-index (schema change).

Testing Evidence

  • Testing performed: standalone EXPLAIN on 200k / 2M-row repros confirming index(-only) scans in both directions including keyset pages and the uint64-max sentinel; full integration CI (pnpm test:integration:ci) green — 351 passed, 0 failures, including every REGISTRATION pagination permutation across the 4 fields; ensapi (288) + ensindexer (224) unit; root typecheck + lint.
  • Known gaps: live perf is only confirmable post-deploy/reindex (the columns/indexes don't exist on currently-deployed instances); devnet tables are too small for EXPLAIN to be meaningful, hence the standalone repro.
  • What reviewers have to reason about manually: the 5-site expiry materialization invariant (callers must pass the latest registration — every renewal/expiry handler already operates on getLatestRegistration).

Scope Reductions

Risk Analysis

  • Risk areas: a missed expiry-mutation site would leave a stale sort key; the relational findMany skipping the dataloader loses request-scoped cache priming for these connection nodes.
  • Mitigations or rollback options: a re-index rebuilds the materialized columns from scratch; reverting the branch restores the join-based resolver.
  • Named owner if this causes problems: @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)

Materialize the latest registration's start/expiry onto Domain as NOT NULL,
sentinel-backed sort columns with (registry_id, col, id) composites, turning
REGISTRATION_TIMESTAMP / REGISTRATION_EXPIRY ordering from a join + full-sort
(~55s on .eth subdomains) into an index-ordered scan. Hydrate find-domains
results directly via a relational query (skip the dataloader round-trip), and
add a "most recently registered subdomains" Omnigraph example.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 4, 2026 19:48
@shrugs shrugs requested a review from a team as a code owner June 4, 2026 19:48
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Jun 4, 2026

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

Project Deployment Actions Updated (UTC)
admin.ensnode.io Ready Ready Preview, Comment Jun 5, 2026 3:36pm
enskit-react-example.ensnode.io Ready Ready Preview, Comment Jun 5, 2026 3:36pm
ensnode.io Ready Ready Preview, Comment Jun 5, 2026 3:36pm
ensrainbow.io Ready Ready Preview, Comment Jun 5, 2026 3:36pm

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 4, 2026

🦋 Changeset detected

Latest commit: aae4cd9

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

This PR includes changesets to release 24 packages
Name Type
@ensnode/ensdb-sdk Patch
ensindexer Patch
ensapi Patch
@ensnode/integration-test-env Patch
@ensnode/ensnode-sdk Patch
ensadmin Patch
ensrainbow Patch
fallback-ensapi Patch
enssdk Patch
enscli Patch
enskit Patch
ensskills Patch
@ensnode/datasources Patch
@ensnode/ensrainbow-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
@ensnode/enskit-react-example Patch
@ensnode/enssdk-example 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 Jun 4, 2026

Review Change Stack

Warning

Review limit reached

@shrugs, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 49 minutes and 30 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 07a84ee0-efaf-4380-b54b-2886f8bfd063

📥 Commits

Reviewing files that changed from the base of the PR and between b120ef0 and aae4cd9.

⛔ Files ignored due to path filters (1)
  • packages/enssdk/src/omnigraph/generated/schema.graphql is excluded by !**/generated/**
📒 Files selected for processing (6)
  • 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/domain-inputs.ts
  • docs/ensnode.io/src/content/docs/docs/integrate/unigraph/schema-reference.mdx
  • packages/ensdb-sdk/src/ensindexer-abstract/unigraph.schema.ts
  • packages/ensskills/skills/omnigraph/SKILL.md
📝 Walkthrough

Walkthrough

Adds sentinel-backed mirrored registration start/expiry on Domain with composite indexes, maintains mirrors from registration events, refactors find-domains to use mirrored columns (adjusting NULLs behavior), extends GraphQL schema/types/examples, and updates pagination tests and docs.

Changes

Registration Timestamp/Expiry Ordering Optimization

Layer / File(s) Summary
Database Schema Foundation
packages/ensdb-sdk/src/ensindexer-abstract/unigraph.schema.ts
Introduces REGISTRATION_SORT_SENTINEL constant and adds NOT NULL mirror columns __latestRegistrationStart and __latestRegistrationExpiry with composite indexes for efficient keyset ordering by (registryId, __latestRegistration*, id).
Registration Data Maintenance
apps/ensindexer/src/lib/ensv2/registration-db-helpers.ts, apps/ensindexer/src/plugins/unigraph/handlers/ensv1/BaseRegistrar.ts, apps/ensindexer/src/plugins/unigraph/handlers/ensv1/NameWrapper.ts, apps/ensindexer/src/plugins/unigraph/handlers/ensv2/ENSv2Registry.ts, apps/ensindexer/src/plugins/unigraph/handlers/ensv1/ENSv1Registry.ts
Adds materializeDomainLatestRegistration and exported updateLatestRegistrationExpiry, maps null expiries to the sentinel, and replaces inline registration expiry updates in multiple handlers with the shared helper to keep Domain mirrors consistent.
Query Ordering & Cursor Logic
apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts
Adds shouldUseNullsLast(orderBy) and updates cursor docs and orderFindDomains so registration orderings omit NULLS LAST (sentinel-backed NOT NULL) while NAME/DEPTH continue to use NULLS LAST.
Resolver Refactoring
apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver.ts
resolveFindDomains now takes args-only (uses di.context), replaces conditional join+dataloader hydration with a single ensDb.query.domain.findMany applying filters, decoded cursors, orderClauses, limit, and eager label join; __orderValue reads from __latestRegistrationStart/__latestRegistrationExpiry.
GraphQL Schema Wiring
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, apps/ensapi/src/omnigraph-api/schema/account.ts
Adds DOMAINS_ORDERING_DESCRIPTION and per-value descriptions on DomainsOrderBy; stops threading context into resolveFindDomains at schema call sites and appends canonical ordering guidance to connection field descriptions.
Pagination Test Updates
apps/ensapi/src/test/integration/find-domains/test-domain-pagination.ts
Tests import shouldUseNullsLast and adjust NULL-placement assertions per ordering field and direction (registration orderings follow SQL-default NULL placement with sentinel mapping).
GraphQL Schema Expansion
docs/ensnode.io/src/data/omnigraph-examples/schema.graphql
Adds AccelerationStatus, ForwardResolve/ReverseResolve, DomainProfile and Profile* types, resolved-record types, new scalars (Email, JSON, InterfaceId, multiple address scalars), and extends DomainsOrderBy (adds REGISTRATION_TIMESTAMP) with doc updates.
Examples & Documentation
docs/ensnode.io/src/data/omnigraph-examples/examples.json, docs/ensnode.io/src/data/omnigraph-examples/meta.ts, docs/ensnode.io/src/data/omnigraph-examples/responses.json, docs/ensnode.io/src/data/omnigraph-examples/snapshot.json, packages/ensnode-sdk/src/omnigraph-api/example-queries.ts, packages/ensskills/skills/omnigraph/SKILL.md, .changeset/recently-registered-subdomains-index.md
Adds new examples including domain-subdomains-recently-registered, response fixtures, SDK example entry, skill docs, snapshot update, and a changeset describing the denormalization + sentinel indexing approach.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

  • namehash/ensnode#2155: Refactors resolveFindDomains and ordering/cursor SQL helpers in the same code paths.
  • namehash/ensnode#2174: Related resolver refactoring to use di.context and DI-provided resources.
  • namehash/ensnode#2125: Prior changes to find-domains ordering and defaultOrder that intersect with this PR's ordering logic.

Poem

🐰 I hop through rows of domains so wide,
Mirrored times and sentinels by my side,
Queries leap quicker, cursors align,
Subdomains ordered, tidy and fine,
A little rabbit cheers the index tide.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly summarizes the main change: performance optimization for registration-ordered domain queries via indexing.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering problem, solution, testing, and risks. It addresses the required template sections with detailed explanations.
Docstring Coverage ✅ Passed Docstring coverage is 81.82% 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 perf/registration-ordered-domains

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.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 4, 2026

Greptile Summary

This PR eliminates a ~55 s sort-and-join query on REGISTRATION_TIMESTAMP/REGISTRATION_EXPIRY-ordered domain connections by materializing __latestRegistrationStart / __latestRegistrationExpiry directly onto the domains table as NOT NULL columns (absent value → uint256-max sentinel), then adding (registry_id, col, id) composites that let the planner use an index-ordered scan in both directions with a plain keyset tuple.

  • Schema + index changes: two new NOT NULL numeric(78,0) columns on domains with DEFAULT REGISTRATION_SORT_SENTINEL, backed by two composite indexes; sentinel defined once in unigraph.schema.ts and shared with all writers.
  • Indexer maintenance: insertLatestRegistration now materializes both columns; a new updateLatestRegistrationExpiry helper updates the expiry mirror and replaces all five direct registration.expiry write sites (BaseRegistrar, NameWrapper ×2, ENSv2Registry ×2); preminted-name domains (BaseRegistrar registerOnly) are handled by a find-guard in materializeDomainLatestRegistration.
  • Resolver changes: join machinery and context param removed from resolveFindDomains; query switched to a relational findMany with label relation; shouldUseNullsLast replaces uniform NULLS LAST to match the NOT NULL sentinel; cursor cast hardened to ::numeric(78,0) to avoid uint64-max overflow.

Confidence Score: 5/5

Safe to merge after the required re-index; the sentinel design is sound, all five expiry-mutation sites are correctly wired to the new helper, and the preminted-name domain-absent guard is in place.

All five expiry-mutation sites (BaseRegistrar NameRenewed, NameWrapper NameUnwrapped/ExpiryExtended, ENSv2Registry LabelUnregistered/ExpiryUpdated) now route through updateLatestRegistrationExpiry, keeping the domain mirror consistent. The materializeDomainLatestRegistration find-guard correctly handles preminted names whose Domain row does not exist at BaseRegistrar registration time. The sentinel value fits in numeric(78,0), the cursor cast is hardened to that type to avoid the previous bigint overflow, and the relational findMany returns all scalar fields needed by the GraphQL resolvers. Integration tests cover every REGISTRATION pagination permutation in both directions.

No files require special attention; the five expiry-mutation handlers in the indexer and the resolver helper are the most logic-dense, but all verified correct.

Important Files Changed

Filename Overview
apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts Replaces registration join columns with __latestRegistration* column references; adds shouldUseNullsLast to omit NULLS LAST for sentinel-backed columns; correct ::numeric(78,0) cast for large bigints; null cursor path correctly gated to NAME/DEPTH only.
apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver.ts Removes join machinery and unused context/DomainInterfaceRef/rejectAnyErrors; switches to ensDb.query.domain.findMany with label relation; __orderValue now always a non-null bigint for registration orderings (sentinel for unregistered domains).
apps/ensindexer/src/lib/ensv2/registration-db-helpers.ts New materializeDomainLatestRegistration helper guards against absent Domain rows (preminted names); insertLatestRegistration materializes both start+expiry; updateLatestRegistrationExpiry materializes expiry mirror at all renewal/deactivation sites.
packages/ensdb-sdk/src/ensindexer-abstract/unigraph.schema.ts Adds REGISTRATION_SORT_SENTINEL = 2^256-1, two NOT NULL bigint columns with default sentinel, and two composite indexes on domains table; schema is well-documented.
apps/ensindexer/src/plugins/unigraph/handlers/ensv1/ENSv1Registry.ts Correctly seeds __latestRegistration* on domain insert for preminted names; onConflictDoUpdate intentionally excludes those columns so owner-transfers do not clobber existing materialized values.
apps/ensindexer/src/plugins/unigraph/handlers/ensv2/ENSv2Registry.ts LabelUnregistered now splits the previous single-update into updateLatestRegistrationExpiry plus a separate set of unregistrantId; both writes occur within the same Ponder event transaction so atomicity is preserved.
apps/ensindexer/src/plugins/unigraph/handlers/ensv1/BaseRegistrar.ts NameRenewed switches to updateLatestRegistrationExpiry; correctly passes domainId and the latest registration.id.
apps/ensindexer/src/plugins/unigraph/handlers/ensv1/NameWrapper.ts Both NameUnwrapped (non-BaseRegistrar path) and ExpiryExtended switch to updateLatestRegistrationExpiry; BaseRegistrar-wrapped path correctly leaves expiry untouched (BaseRegistrar governs it).
apps/ensapi/src/test/integration/find-domains/test-domain-pagination.ts Updated assertOrdering to mirror the new null-placement semantics: nulls-first for REGISTRATION_* DESC, nulls-last for all other cases; logic is correct.
apps/ensapi/src/omnigraph-api/schema/domain-inputs.ts Added per-value descriptions to DomainsOrderBy and a shared DOMAINS_ORDERING_DESCRIPTION constant; sentinel/null-placement behavior is documented accurately.

Reviews (8): Last reviewed commit: "docs(ensapi): clarify REGISTRATION_TIMES..." | Re-trigger Greptile

Comment thread apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver.ts Outdated
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 accelerates find-domains-backed GraphQL connections when ordering by latest registration start/expiry by materializing those values onto the domains row (sentinel-backed NOT NULL) and switching the resolver to order/paginate directly on those columns (avoiding the latest_registration_indexes → registrations join + sort for registry-scoped queries like .eth subdomains).

Changes:

  • Materialize latest registration start/expiry onto Domain (__latestRegistrationStart / __latestRegistrationExpiry) using a +∞ sentinel and add composite indexes to support ordered scans.
  • Update ensindexer registration helpers + relevant expiry-mutation handlers to keep the materialized columns correct.
  • Update ensapi find-domains resolver/helpers/tests and refresh Omnigraph schema docs + examples (including a “recently registered subdomains” example).

Reviewed changes

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

Show a summary per file
File Description
packages/ensskills/skills/omnigraph/SKILL.md Adds a skill example query for “recently registered subdomains”.
packages/enssdk/src/omnigraph/generated/schema.graphql Updates schema descriptions for ordering semantics and enum value docs.
packages/ensnode-sdk/src/omnigraph-api/example-queries.ts Adds an example query for registration-timestamp-ordered subdomains.
packages/ensdb-sdk/src/ensindexer-abstract/unigraph.schema.ts Adds sentinel constant, materialized domain columns, and registry+registration composites.
docs/ensnode.io/src/data/omnigraph-examples/snapshot.json Refreshes snapshot metadata (commit/date).
docs/ensnode.io/src/data/omnigraph-examples/schema.graphql Refreshes the vendored schema snapshot.
docs/ensnode.io/src/data/omnigraph-examples/responses.json Adds response fixture for the new example query.
docs/ensnode.io/src/data/omnigraph-examples/meta.ts Adds curated meta entry for the new example.
docs/ensnode.io/src/data/omnigraph-examples/examples.json Adds the new example to the vendored examples snapshot.
apps/ensindexer/src/plugins/unigraph/handlers/ensv2/ENSv2Registry.ts Routes expiry updates through helper to maintain domain materialization.
apps/ensindexer/src/plugins/unigraph/handlers/ensv1/NameWrapper.ts Routes expiry updates through helper to maintain domain materialization.
apps/ensindexer/src/plugins/unigraph/handlers/ensv1/BaseRegistrar.ts Routes renewal expiry updates through helper to maintain domain materialization.
apps/ensindexer/src/lib/ensv2/registration-db-helpers.ts Materializes latest registration values onto Domain + adds expiry-update helper.
apps/ensapi/src/test/integration/find-domains/test-domain-pagination.ts Updates ordering assertions for registration-ordering null placement semantics.
apps/ensapi/src/omnigraph-api/schema/registry.ts Appends shared ordering semantics to connection description; removes context param usage.
apps/ensapi/src/omnigraph-api/schema/query.ts Appends shared ordering semantics to connection description; removes context param usage.
apps/ensapi/src/omnigraph-api/schema/domain.ts Appends shared ordering semantics to connection description; removes context param usage.
apps/ensapi/src/omnigraph-api/schema/domain-inputs.ts Adds enum value descriptions and introduces shared ordering description constant.
apps/ensapi/src/omnigraph-api/schema/account.ts Appends shared ordering semantics to connection description; removes context param usage.
apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver.ts Switches to relational hydration + orders by materialized registration columns.
apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts Updates order/cursor logic to use materialized columns and numeric casting.
.changeset/recently-registered-subdomains-index.md Changeset describing the perf improvements and sentinel design.

💡 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.ts Outdated
Copy link
Copy Markdown
Member Author

@shrugs shrugs left a comment

Choose a reason for hiding this comment

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

also update the ensdb schema documentation in the docs/ensnode.io project for these new fields and discuss how to query them in an example for the unigraph sql documentation in that same project

Comment thread .changeset/recently-registered-subdomains-index.md Outdated
Comment thread apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver-helpers.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver.ts Outdated
Comment thread apps/ensapi/src/test/integration/find-domains/test-domain-pagination.ts Outdated
Comment thread apps/ensindexer/src/lib/ensv2/registration-db-helpers.ts Outdated
Comment thread apps/ensindexer/src/lib/ensv2/registration-db-helpers.ts Outdated
Comment thread apps/ensindexer/src/plugins/unigraph/handlers/ensv2/ENSv2Registry.ts Outdated
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: 1

🤖 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 `@docs/ensnode.io/src/data/omnigraph-examples/examples.json`:
- Around line 34-40: The examples.json contains example IDs
(account-primary-names, domain-profile, domain-records, domain-registration,
hello-world, namegraph, resolver-by-address, subdomains-pagination) that are not
present in meta.ts and responses.json; update the fixtures to match by adding
corresponding entries for each of these IDs in meta.ts and responses.json (use
the same id strings as in examples.json and populate minimal matching metadata
and mock response objects), or alternatively modify the loader function that
reads meta.ts/responses.json to tolerate missing IDs by skipping or logging them
instead of throwing—ensure the chosen approach keeps id parity between
examples.json and the metadata/response sources and reference the IDs above when
making changes.
🪄 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: b7e8a4f6-deec-46b9-8675-a1fa5bae8c07

📥 Commits

Reviewing files that changed from the base of the PR and between 25d1fc8 and 212e91c.

⛔ Files ignored due to path filters (1)
  • packages/enssdk/src/omnigraph/generated/schema.graphql is excluded by !**/generated/**
📒 Files selected for processing (21)
  • .changeset/recently-registered-subdomains-index.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/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
  • apps/ensapi/src/test/integration/find-domains/test-domain-pagination.ts
  • apps/ensindexer/src/lib/ensv2/registration-db-helpers.ts
  • apps/ensindexer/src/plugins/unigraph/handlers/ensv1/BaseRegistrar.ts
  • apps/ensindexer/src/plugins/unigraph/handlers/ensv1/NameWrapper.ts
  • apps/ensindexer/src/plugins/unigraph/handlers/ensv2/ENSv2Registry.ts
  • docs/ensnode.io/src/data/omnigraph-examples/examples.json
  • docs/ensnode.io/src/data/omnigraph-examples/meta.ts
  • docs/ensnode.io/src/data/omnigraph-examples/responses.json
  • docs/ensnode.io/src/data/omnigraph-examples/schema.graphql
  • docs/ensnode.io/src/data/omnigraph-examples/snapshot.json
  • packages/ensdb-sdk/src/ensindexer-abstract/unigraph.schema.ts
  • packages/ensnode-sdk/src/omnigraph-api/example-queries.ts
  • packages/ensskills/skills/omnigraph/SKILL.md

Comment thread docs/ensnode.io/src/data/omnigraph-examples/examples.json
- rename isRegistrationOrdering -> shouldUseNullsLast (inverted), shared with the
  pagination integration test
- drop the eager toSQL() debug log on the find-domains hot path
- use query.execute() in the connection span callback (matches codebase convention)
- trim resolver/helper comments and rename finalQuery/loadedDomains -> query/domains
- drop ensapi from the changeset

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shrugs
Copy link
Copy Markdown
Member Author

shrugs commented Jun 4, 2026

@greptile review

Comment thread apps/ensindexer/src/lib/ensv2/registration-db-helpers.ts Outdated
…preminted names

A preminted name (BaseRegistrar registerOnly on Basenames/Lineanames) has a
Registration before its Domain row exists, so the unconditional Domain update in
insertLatestRegistration/updateLatestRegistrationExpiry would throw. Guard the
update behind a find, and materialize the sort keys from the latest Registration
when the preminted name's Domain is created (ENSv1Registry NewOwner).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 4, 2026 22:15
@vercel vercel Bot temporarily deployed to Preview – ensnode.io June 4, 2026 22:15 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io June 4, 2026 22:15 Inactive
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io June 4, 2026 22:15 Inactive
@shrugs
Copy link
Copy Markdown
Member Author

shrugs commented Jun 4, 2026

@greptile review

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 22 out of 23 changed files in this pull request and generated 1 comment.

Copy link
Copy Markdown
Member

@tk-o tk-o left a comment

Choose a reason for hiding this comment

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

I've tested the update on my local ENSNode instance. The improvement is massive!

Comment thread packages/ensdb-sdk/src/ensindexer-abstract/unigraph.schema.ts Outdated
Comment thread packages/ensdb-sdk/src/ensindexer-abstract/unigraph.schema.ts Outdated
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 23 out of 24 changed files in this pull request and generated 2 comments.

Comment thread apps/ensapi/src/omnigraph-api/schema/domain-inputs.ts
Comment thread apps/ensapi/src/omnigraph-api/schema/domain-inputs.ts Outdated
@shrugs
Copy link
Copy Markdown
Member Author

shrugs commented Jun 5, 2026

@greptile review

@shrugs shrugs merged commit 5f929d8 into main Jun 5, 2026
20 checks passed
@shrugs shrugs deleted the perf/registration-ordered-domains branch June 5, 2026 15:37
@github-actions github-actions Bot mentioned this pull request Jun 5, 2026
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