Skip to content

Comments

feat: implement canonical filter for findDomains#1654

Open
shrugs wants to merge 11 commits intomainfrom
feat/find-canonical-domains
Open

feat: implement canonical filter for findDomains#1654
shrugs wants to merge 11 commits intomainfrom
feat/find-canonical-domains

Conversation

@shrugs
Copy link
Collaborator

@shrugs shrugs commented Feb 19, 2026

Summary

  • added optional canonical: boolean to DomainsWhereInput GraphQL input
  • when canonical: true, v2 domains are filtered to those whose registry is reachable from the ENSv2 root registry via a recursive CTE over registry_canonical_domains
  • v1 domains are unfiltered (all are canonical)

Why

  • findDomains should support this

Testing

  • no integration test — this is query-building code that requires a running database with v2 data

Notes for Reviewer

  • the recursive CTE uses IN (WITH RECURSIVE ...) was generated by claude
  • no performance testing yet with all of these CTEs

Checklist

  • This PR is low-risk and safe to review quickly

…ter in Queyr.domains and Account.domains. When specified, the resulting set of Domains is composed exclusively of Canonical Domains.
@shrugs shrugs requested a review from a team as a code owner February 19, 2026 21:46
Copilot AI review requested due to automatic review settings February 19, 2026 21:46
@vercel
Copy link
Contributor

vercel bot commented Feb 19, 2026

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

3 Skipped Deployments
Project Deployment Actions Updated (UTC)
admin.ensnode.io Skipped Skipped Feb 20, 2026 10:22pm
ensnode.io Skipped Skipped Feb 20, 2026 10:22pm
ensrainbow.io Skipped Skipped Feb 20, 2026 10:22pm

@changeset-bot
Copy link

changeset-bot bot commented Feb 19, 2026

🦋 Changeset detected

Latest commit: 5682d37

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

This PR includes changesets to release 19 packages
Name Type
ensapi Major
ensindexer Major
ensadmin Major
ensrainbow Major
fallback-ensapi Major
@ensnode/datasources Major
@ensnode/ensrainbow-sdk Major
@ensnode/ponder-metadata Major
@ensnode/ensnode-schema Major
@ensnode/ensnode-react Major
@ensnode/ensnode-sdk Major
@ensnode/ponder-sdk Major
@ensnode/ponder-subgraph Major
@ensnode/shared-configs Major
@docs/ensnode Major
@docs/ensrainbow Major
@docs/mintlify Major
@namehash/ens-referrals Major
@namehash/namehash-ui Major

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

coderabbitai bot commented Feb 19, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

A new optional boolean canonical filter was added to domain queries. When true, the API seeds a recursive CTE from the ENSv2 root registry to restrict v2 results to Canonical Domains; v1 domains remain canonical by default. Account.domains was removed in favor of Query.domains.

Changes

Cohort / File(s) Summary
Changesets
\.changeset/wide-trains-camp.md, \.changeset/dull-rabbits-take.md, \.changeset/eight-beans-behave.md, \.changeset/whole-ways-grin.md
Adds changeset entries documenting the ensapi minor bump, the new canonical?: boolean filter, and related GraphQL surface changes (Account.domains → Query.domains).
GraphQL API — Types & Schema
apps/ensapi/src/graphql-api/lib/find-domains/types.ts, apps/ensapi/src/graphql-api/schema/domain.ts
Introduces optional canonical?: boolean on FindDomainsWhereArg, DomainsWhereInput, and AccountDomainsWhereInput with descriptions; updates field descriptions.
GraphQL API — Find Domains Implementation
apps/ensapi/src/graphql-api/lib/find-domains/find-domains.ts, apps/ensapi/src/graphql-api/lib/find-domains/find-domains-resolver.ts
Extends findDomains signature to accept canonical; coerces input to onlyCanonical and, when true, joins a new canonical_registries CTE to filter v2 domains by canonical reachability; minor resolver comment update.
Canonical CTE & Path Logic
apps/ensapi/src/graphql-api/lib/canonical-registries-cte.ts, apps/ensapi/src/graphql-api/lib/get-canonical-path.ts, apps/ensapi/src/graphql-api/lib/find-domains/find-domains-by-labelhash-path.ts
Adds getCanonicalRegistriesCTE() (recursive CTE capped at depth 16) and tightens/extends joins in v2 path traversal to align subregistry traversal and include parent joins for canonical path calculations.
Schema — v2 Domain Index
packages/ensnode-schema/src/schemas/ensv2.schema.ts
Adds bySubregistry index on v2Domain for non-null subregistryId.
Indexer — ENSv2 Registry Handler
apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ENSv2Registry.ts
Introduces ETH_LABELHASH constant and uses it for bridged domainId computation (replaces inline labelhash call).
Tests / Mocks
apps/ensapi/src/graphql-api/lib/find-domains/find-domains.test.ts
Adds a mock for config.namespace (forces mainnet) in test setup.
GraphQL API — Account Type
apps/ensapi/src/graphql-api/schema/account.ts
Removes the domains connection field from Account (and related imports/resolver).

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant API as GraphQL API
    participant DB as Postgres DB

    Client->>API: Query Query.domains(where: {..., canonical: true})
    API->>API: coerce input -> onlyCanonical
    API->>DB: Execute SQL with canonical_registries CTE (seed = ENSv2 root registry id)
    DB->>DB: Recursive CTE traverses registries and filters reachable v2 domains
    DB-->>API: Return canonical domain rows (plus v1 rows)
    API-->>Client: Return filtered domain results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped from root registry to leaf,
Tracing v2 reach while v1 stayed brief,
Through recursive CTE tunnels I wind,
Filtering names the network can find,
A tiny hop — canonical and kind. 🌿

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: implementing a canonical filter for the findDomains function, which is the core feature across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description check ✅ Passed The PR description follows the required template with clear Summary, Why, Testing, and Notes sections addressing key aspects of the change.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/find-canonical-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
Contributor

greptile-apps bot commented Feb 19, 2026

Greptile Summary

This PR adds a canonical boolean filter to the findDomains query, allowing users to filter for domains that are connected to either the ENSv1 or ENSv2 root registries.

Key changes:

  • Added canonical?: boolean field to DomainsWhereInput and AccountDomainsWhereInput GraphQL input types
  • Implemented filtering logic: when canonical: true, v2 domains are filtered using a recursive CTE that walks from the ENSv2 root registry through registry_canonical_domains to identify all canonical registries
  • All v1 domains remain unfiltered (they are all canonical by definition)

Issues found:

  • Typo in changeset file: "Queyr" should be "Query"
  • The recursive CTE lacks infinite loop protection (no depth limit), unlike similar CTEs in the codebase

Confidence Score: 4/5

  • Safe to merge with minor improvements recommended
  • The implementation is logically sound and follows established patterns in the codebase. The recursive CTE correctly identifies canonical registries by walking from the root. However, missing infinite loop protection could cause issues if circular references exist in the data, though this is unlikely given the domain structure. The typo in the changeset is cosmetic.
  • The recursive CTE in find-domains.ts should have a depth limit added for safety, similar to other recursive queries in the codebase

Important Files Changed

Filename Overview
.changeset/wide-trains-camp.md Changeset file documenting the new canonical filter feature - contains a typo "Queyr" instead of "Query"
apps/ensapi/src/graphql-api/lib/find-domains/find-domains.ts Implements canonical filter with recursive CTE - missing infinite loop protection and has a potential SQL injection concern with namespace config

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[findDomains called with canonical filter] --> B{canonical === true?}
    B -->|No| C[Return all domains]
    B -->|Yes| D[Build recursive CTE]
    D --> E[Base case: Start with ENSv2 Root Registry]
    E --> F[Recursive: Find domains in canonical registries]
    F --> G[Get subregistries of those domains via registry_canonical_domains]
    G --> H{More registries found?}
    H -->|Yes| F
    H -->|No| I[Return set of canonical registries]
    I --> J[Filter v2Domains by registry IN canonical set]
    J --> K[Union with all v1Domains]
    K --> L[Return filtered domains]
Loading

Last reviewed commit: d6a57fa

Copy link
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

Adds a canonical filter to findDomains and the GraphQL where inputs, enabling callers to restrict ENSv2 results to registries reachable from the ENSv2 root via a recursive CTE.

Changes:

  • Added optional canonical: boolean to DomainsWhereInput and AccountDomainsWhereInput.
  • Extended findDomains to accept canonical and apply an ENSv2 canonical-registry recursive CTE filter.
  • Added a changeset documenting the new filter.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
apps/ensapi/src/graphql-api/schema/domain.ts Exposes canonical in GraphQL inputs for domain filtering.
apps/ensapi/src/graphql-api/lib/find-domains/types.ts Adds canonical to the TypeScript where-arg type with doc comment.
apps/ensapi/src/graphql-api/lib/find-domains/find-domains.ts Implements canonical filtering for ENSv2 domains via a recursive CTE.
.changeset/wide-trains-camp.md Documents the API change in release notes.

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

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

4 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Copy link

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/ensapi/src/graphql-api/lib/find-domains/find-domains.ts (2)

136-164: 🧹 Nitpick | 🔵 Trivial

Performance: unbenchmarked recursive CTE on hot query path

The recursive canonical_registries CTE walks registry_canonical_domain + v2Domain on every findDomains call where onlyCanonical: true. Without:

  • An index on registry_canonical_domain(registry_id) (the JOIN predicate cr.registry_id = parent.registry_id)
  • An index on v2Domain(registry_id) for the outer IN (...) filter
  • Knowledge of how deep the registry tree can grow

…this could become a sequential-scan-heavy query at production scale. The PR explicitly acknowledges "No performance testing has been performed."

Ensure relevant columns are indexed to speed up join operations in recursive queries.

Before shipping to production, consider:

  1. Confirming indexes exist on registry_canonical_domain.registry_id and v2_domain.registry_id.
  2. Running EXPLAIN ANALYZE with a realistic dataset to check whether PostgreSQL materializes the CTE once or re-evaluates it.
  3. Optionally adding a depth-counter column and WHERE depth < N guard in the recursive term (though UNION deduplication already prevents cycles, it doesn't bound traversal depth on an unexpectedly deep tree).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ensapi/src/graphql-api/lib/find-domains/find-domains.ts` around lines
136 - 164, The recursive CTE canonical_registries in the onlyCanonical path can
cause sequential scans at scale; ensure you add a b-tree index on
registry_canonical_domain(registry_id) and on v2_domain(registry_id) (referenced
by schema.registryCanonicalDomain and schema.v2Domain in the
canonicalRegistryFilter), re-run EXPLAIN ANALYZE against a realistic dataset to
confirm the CTE is materialized and performant, and optionally add a depth guard
in the recursive term of canonical_registries (or other cycle/size protection)
to bound traversal if the registry tree can be deep (see getENSv2RootRegistryId
usage and canonicalRegistryFilter in find-domains.ts).

136-164: 🧹 Nitpick | 🔵 Trivial

Refactor CTE to use schema-based column references instead of hardcoded SQL names for maintainability

The hardcoded column names in the CTE (rcd.registry_id, rcd.domain_id, parent.id, parent.registry_id) currently match the schema's default camelCase-to-snake_case conversion, so the query works as intended. However, this approach is fragile: if anyone adds explicit SQL column name overrides (e.g., text('registry_table_id')) to the registryCanonicalDomain or v2Domain schema definitions, the CTE would silently produce wrong results or fail at runtime without compile-time detection.

Consider refactoring to use schema-based column references (similar to how the table names are already interpolated via ${schema.registryCanonicalDomain}) to ensure type safety and maintainability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ensapi/src/graphql-api/lib/find-domains/find-domains.ts` around lines
136 - 164, The CTE in canonicalRegistryFilter uses hardcoded column names
(rcd.registry_id, rcd.domain_id, parent.id, parent.registry_id); change it to
interpolate schema-based column references so column renames are respected—use
${schema.registryCanonicalDomain.<column>} and ${schema.v2Domain.<column>}
(e.g., ${schema.registryCanonicalDomain.registryId},
${schema.registryCanonicalDomain.domainId}, ${schema.v2Domain.id},
${schema.v2Domain.registryId}) inside the sql template for
canonicalRegistryFilter and retain the existing
getENSv2RootRegistryId(config.namespace)::text cast; update
canonicalRegistryFilter (and any alias refs like rcd/parent) to reference those
interpolated symbols instead of hardcoded names.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/wide-trains-camp.md:
- Line 5: Typo in the changelog: change "Queyr.domains" to "Query.domains" in
the .changeset description so it correctly references the Query.domains filter;
ensure the text mentions the added canonical?: boolean filter and
Account.domains consistently.

In `@apps/ensapi/src/graphql-api/lib/find-domains/find-domains.ts`:
- Around line 138-150: Add tests in find-domains.test.ts that exercise the
onlyCanonical=true path: create test fixtures for schema.registryCanonicalDomain
and schema.v2Domain (including a root registry id from
getENSv2RootRegistryId(config.namespace)), insert parent/child registry
relationships that require the WITH RECURSIVE CTE to traverse, then call the
findDomains resolver (the code that builds canonicalRegistryFilter in
find-domains.ts) with onlyCanonical enabled and assert only domains from the
recursive canonical registry set are returned; ensure the test uses the
project's DB test helpers/transaction rollback so it runs as an integration test
and validates the IN( WITH RECURSIVE ... ) behavior end-to-end.

---

Outside diff comments:
In `@apps/ensapi/src/graphql-api/lib/find-domains/find-domains.ts`:
- Around line 136-164: The recursive CTE canonical_registries in the
onlyCanonical path can cause sequential scans at scale; ensure you add a b-tree
index on registry_canonical_domain(registry_id) and on v2_domain(registry_id)
(referenced by schema.registryCanonicalDomain and schema.v2Domain in the
canonicalRegistryFilter), re-run EXPLAIN ANALYZE against a realistic dataset to
confirm the CTE is materialized and performant, and optionally add a depth guard
in the recursive term of canonical_registries (or other cycle/size protection)
to bound traversal if the registry tree can be deep (see getENSv2RootRegistryId
usage and canonicalRegistryFilter in find-domains.ts).
- Around line 136-164: The CTE in canonicalRegistryFilter uses hardcoded column
names (rcd.registry_id, rcd.domain_id, parent.id, parent.registry_id); change it
to interpolate schema-based column references so column renames are
respected—use ${schema.registryCanonicalDomain.<column>} and
${schema.v2Domain.<column>} (e.g., ${schema.registryCanonicalDomain.registryId},
${schema.registryCanonicalDomain.domainId}, ${schema.v2Domain.id},
${schema.v2Domain.registryId}) inside the sql template for
canonicalRegistryFilter and retain the existing
getENSv2RootRegistryId(config.namespace)::text cast; update
canonicalRegistryFilter (and any alias refs like rcd/parent) to reference those
interpolated symbols instead of hardcoded names.

Copilot AI review requested due to automatic review settings February 20, 2026 00:18
@vercel vercel bot temporarily deployed to Preview – ensnode.io February 20, 2026 00:18 Inactive
@vercel vercel bot temporarily deployed to Preview – ensrainbow.io February 20, 2026 00:18 Inactive
@vercel vercel bot temporarily deployed to Preview – admin.ensnode.io February 20, 2026 00:18 Inactive
Copy link

@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 the current code and only fix it if needed.

Inline comments:
In
`@apps/ensapi/src/graphql-api/lib/find-domains/find-domains-by-labelhash-path.ts`:
- Around line 140-141: The v2Domain schema is missing an index on subregistryId
causing sequential scans during the recursive JOINs; update the v2Domain index
block in ensv2.schema.ts (the schema that defines v2Domain) to add an index
entry named like bySubregistry that indexes t.subregistryId (e.g., add
bySubregistry: index().on(t.subregistryId) to the v2Domain indexes), then run
migrations/seed as appropriate so queries using v2Domain.subregistry_id use the
new index.

In `@apps/ensapi/src/graphql-api/lib/find-domains/find-domains.ts`:
- Around line 136-156: The CTE built in the canonicalRegistries query uses UNION
which already deduplicates, so remove the redundant DISTINCT in the final
SELECT; update the SQL in the canonicalRegistries construction (the SELECT
DISTINCT registry_id FROM canonical_registries part) to just SELECT registry_id,
keeping the rest of the CTE and joins in the canonicalRegistries variable and
preserving getENSv2RootRegistryId(config.namespace) and schema references.

Copy link

@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 the current code and only fix it if needed.

Inline comments:
In `@apps/ensapi/src/graphql-api/lib/find-domains/find-domains.test.ts`:
- Around line 3-5: Remove the unused import ENSNamespaceIds and the
vi.mock("@/config", ...) call from find-domains.test.ts because isEffectiveDesc
only depends on its parameters (orderDir, inverted) and does not read config;
update the test file by deleting the line importing ENSNamespaceIds and the
vi.mock(...) line so only the relevant test code and imports for isEffectiveDesc
remain.

Copy link
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 8 out of 8 changed files in this pull request and generated 2 comments.


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

@vercel vercel bot temporarily deployed to Preview – ensrainbow.io February 20, 2026 20:52 Inactive
Copy link

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ensapi/src/graphql-api/lib/find-domains/find-domains.test.ts`:
- Around line 3-5: The current test mocks "@/config" using the imported
ENSNamespaceIds inside the vi.mock factory which violates Vitest hoisting rules;
update the mock in find-domains.test.ts to avoid referencing imported bindings
inside vi.mock: either inline the namespace string value (remove the
ENSNamespaceIds import) or use vi.hoisted to require ENSNamespaceIds before
calling vi.mock so the factory can safely reference ENSNamespaceIds.Mainnet;
ensure the mock still returns { default: { namespace: ... } } to satisfy
find-domains.ts module-level import.

In `@apps/ensapi/src/graphql-api/lib/find-domains/find-domains.ts`:
- Around line 136-156: Add a depth guard to the recursive CTE that builds
canonicalRegistries: modify the CTE in find-domains.ts (the SQL block used to
create canonicalRegistries) to include a depth column (start depth = 0 for the
root row, increment depth + 1 in the recursive SELECT) and add a WHERE clause
like "WHERE depth < FIND_DOMAINS_MAX_DEPTH" on the recursive branch (or on the
final selection) using the existing FIND_DOMAINS_MAX_DEPTH constant referenced
earlier; ensure the outer Drizzle select still projects only registry_id (drop
or ignore the depth column there) so
canonicalRegistries.as("canonical_registries") returns the same shape while
preventing unbounded recursion.

In `@packages/ensnode-schema/src/schemas/ensv2.schema.ts`:
- Line 224: The current index definition bySubregistry indexes nullable
subregistryId leading to many NULL entries; change it to a partial index that
only includes non-NULL values by using a WHERE clause (e.g., use
sql`${t.subregistryId} IS NOT NULL`) on the index definition for bySubregistry
and import sql from drizzle-orm; update the index declaration in ensv2.schema.ts
(reference: bySubregistry and subregistryId) to use the .where(...)
partial-index approach so NULL subregistryId rows are excluded.

Copy link
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 10 out of 10 changed files in this pull request and generated 3 comments.


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

Copy link

@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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/dull-rabbits-take.md:
- Line 2: The changeset currently labels "ensapi" as minor while the body states
a BREAKING change (removal of Account.domains); update the bump to major or
explicitly confirm rationale if this package is pre-1.0.0: either change the
changeset entry from "ensapi": minor to "ensapi": major to reflect the breaking
API change (removal of Account.domains) or add a clear justification in the
changeset body stating that ensapi is <1.0.0 and you intend to use minor for
breaking changes; ensure the change references the removed symbol
Account.domains and that the final changeset accurately matches semver intent.

In `@apps/ensapi/src/graphql-api/lib/canonical-registries-cte.ts`:
- Around line 30-40: The CTE currently selects (registry_id, depth) so UNION
dedupes on the pair and does not provide true cycle protection; change the
recursive CTE canonical_registries to only track registry_id: define
canonical_registries(registry_id) and have both the initial SELECT (use
getENSv2RootRegistryId(config.namespace)::text) and the recursive SELECT from
schema.registryCanonicalDomain JOIN schema.v2Domain return only rcd.registry_id,
and remove references to depth and the WHERE cr.depth <
CANONICAL_REGISTRIES_MAX_DEPTH clause so UNION can terminate on registry_id
alone (alternatively, if you want to keep depth as a cap, replace UNION with
UNION ALL and apply DISTINCT on the final SELECT).

In `@apps/ensapi/src/graphql-api/lib/find-domains/find-domains.ts`:
- Around line 147-154: getCanonicalRegistriesCTE() is being called
unconditionally which causes getENSv2RootRegistryId(...) to run even when
onlyCanonical is false; change the code so the CTE is only created when needed
by moving the call into the conditional branch (i.e., call
getCanonicalRegistriesCTE() inside the true branch where v2DomainsBaseQuery is
innerJoined) or lazily assign canonicalRegistries = onlyCanonical ?
getCanonicalRegistriesCTE() : undefined and then use it in the ternary for
v2DomainsBase, referencing the existing symbols getCanonicalRegistriesCTE,
onlyCanonical, v2DomainsBaseQuery, and v2DomainsBase.

In `@apps/ensapi/src/graphql-api/schema/domain.ts`:
- Around line 332-335: The schema's `canonical` field in domain.ts documents
"defaults to false" but is nullable with no default; update the GraphQL input
field `canonical` (in the domain.ts Pothos object) to include defaultValue:
false so the schema matches the description and callers receive false when
omitted; alternatively, if you prefer nullable behavior, change the field
description to remove "defaults to false" to match current semantics (note: the
find-domains logic that uses `canonical === true` already handles nulls).

---

Duplicate comments:
In `@apps/ensapi/src/graphql-api/lib/find-domains/find-domains.ts`:
- Around line 82-84: Tests do not cover the findDomains({ canonical: true })
path (the onlyCanonical branch), so add a test that calls findDomains with
canonical set to true and asserts the returned query/result respects the
canonical-only filter; locate the logic in findDomains (variable onlyCanonical)
and either mock the underlying data layer or provide a fixture with both
canonical and non-canonical domains, then verify only canonical entries are
returned, ensuring the XOR tests remain unchanged while exercising the
canonical=true path.

In `@packages/ensnode-schema/src/schemas/ensv2.schema.ts`:
- Line 224: The partial index definition using bySubregistry with
index().on(t.subregistryId).where(sql`${t.subregistryId} IS NOT NULL`) is
correct and requires no change; keep the current line (bySubregistry:
index().on(t.subregistryId).where(sql`${t.subregistryId} IS NOT NULL`)) as it
properly excludes rows with NULL subregistryId.

Copilot AI review requested due to automatic review settings February 20, 2026 21:51
@vercel vercel bot temporarily deployed to Preview – ensrainbow.io February 20, 2026 21:51 Inactive
@vercel vercel bot temporarily deployed to Preview – admin.ensnode.io February 20, 2026 21:51 Inactive
@vercel vercel bot temporarily deployed to Preview – ensnode.io February 20, 2026 21:51 Inactive
Copy link
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 15 out of 15 changed files in this pull request and generated 4 comments.


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

@vercel vercel bot temporarily deployed to Preview – ensrainbow.io February 20, 2026 22:22 Inactive
@vercel vercel bot temporarily deployed to Preview – ensnode.io February 20, 2026 22:22 Inactive
@vercel vercel bot temporarily deployed to Preview – admin.ensnode.io February 20, 2026 22:22 Inactive
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.

1 participant