Skip to content

feat(ensapi): resolvable-but-unindexed Domains & Accounts (UnindexedDomain)#2271

Merged
shrugs merged 10 commits into
mainfrom
feat/virtualize-unindexed-domains
Jun 8, 2026
Merged

feat(ensapi): resolvable-but-unindexed Domains & Accounts (UnindexedDomain)#2271
shrugs merged 10 commits into
mainfrom
feat/virtualize-unindexed-domains

Conversation

@shrugs
Copy link
Copy Markdown
Member

@shrugs shrugs commented Jun 7, 2026

Summary

Resolvable-but-unindexed ENS names and addresses are now resolvable through the Omnigraph API, instead of returning null. Today resolve (forward) and primaryNames/resolve (reverse) are protocol operations keyed on a name/address — they work for any valid name/address and the index only accelerates them — but modeling them as fields on indexed entities makes them unreachable whenever no Domain/Account row exists (off-chain / CCIP-Read names, unindexed 3DNS/.box, wildcard subnames, unobserved addresses). This is a correctness gap, not just DX.

Query.domain(by: { name }) and Query.account(by: { address }) now return a resolvable entity for these inputs.

Design (summary of the spec for discussion)

Full spec/discussion doc: Resolving Unindexed Names & Addresses in the Omnigraph API. Key decisions:

  • Constraint: the clean fix (top-level Query.resolve/Query.reverse decoupled from entities) was rejected — resolution must stay reachable through the existing domain(by:{name}) / account(by:{address}) DX so the address → primary name → forward resolve composition keeps working in one query. The backend does more work to preserve correctness + DX.
  • Account: always virtualized from the address (AccountRef is now a plain objectRef<NormalizedAddress> — there's nothing to load), so reverse resolution works regardless of indexing; indexed relations (domains/events/permissions) return empty for an unobserved address.
  • Domain: a new UnindexedDomain concrete type implementing the Domain interface (Domain = IndexedDomain | UnindexedDomain), returned by domain(by:{name}) when there is no indexed leaf but the name is resolvable.
  • Predicate ( the whole game): an unindexed name is resolvable iff the namegraph walk finds no exact leaf but its deepest ancestor Resolver is an ENSIP-10 wildcard (IExtendedResolver) Resolver. A static ancestor Resolver cannot resolve a descendant, so e.g. doesnotexist.eth and ordinary sub.vitalik.eth (PublicResolver, non-wildcard) correctly stay null — only genuinely wildcard-capable ancestors (cb.id, uni.eth, …) yield a result. The walk already follows Bridged/ENSv1/ENSv2 hops, so the ENSv2 .eth→ENSv1 bridge false-positive is handled for free.
  • extended is index-resident (Optimize Resolution API by upserting resolvers in SetResolver/ResolverUpdated #1991): resolver.extended is captured via a single cached supportsInterface RPC the first time a Resolver is observed, so the predicate runs fully from the index with no query-time RPC. upsertResolver now runs wherever a Resolver is referenced (every Domain-Resolver Relation), not only where it self-emits.
  • UnindexedDomain is Canonical (it's named, via the queried name). DomainCanonical.path is built lazily, label-by-label: the deepest indexed ancestor's materialized canonical path + a virtual UnindexedDomain per label below it (passed through as resolved values, since virtual nodes can't be loaded by id). registry virtualizes to the registry that manages the wildcard-Resolver's Domain. id is unindexed-{registryId}-{node} (prefixed to disambiguate from ENSv1DomainId).
  • ResolvableName: a name is only virtualized as an UnindexedDomain if it is a ResolvableName — normalized, no Encoded-LabelHash segment, every label < 256 bytes (DNS-encodable). New enssdk type with isResolvableName / asResolvableName.

Notable deviations from the original spec

  • findResolver (index path) is not gated on extended. The ENS UniversalResolver.findResolver returns the deepest resolver + offset without an IExtendedResolver check (that gate lives in _checkResolver/resolve), so to stay 1:1 with the UR the index path also leaves the ENSIP-10 check to the consumer. extended is consumed by the UnindexedDomain predicate (which mirrors _checkResolver).
  • Name evolved MaybeUnindexedDomainUnindexedDomain.

What changed

  • Indexer / schema: resolver.extended column; upsertResolver (cached supportsInterface) wired into ensureDomainResolverRelation (covers ENSv1/ENSv2/3DNS) and ensureResolverAndRecords.
  • Walk: forwardWalkDisjointNamegraph returns registryId + extended + the node's canonicalPath; forwardWalkNamegraph returns { rows, exact }.
  • enssdk: UnindexedDomainId (a DomainId) + makeUnindexedDomainId; ResolvableName + isResolvableName/asResolvableName.
  • Omnigraph API: UnindexedDomain type; omnigraph-api/lib/unindexed-domain.ts (makeUnindexedDomain(name, rows) + lazy computeUnindexedDomainCanonicalPath); Query.domain/Query.account updated; DomainCanonical.path handles virtual nodes.
  • enskit: client cache support for UnindexedDomain.
  • docs: ensdb resolvers table documents extended.

Closes / supersedes

Testing

pnpm typecheck, pnpm lint, pnpm generate clean. pnpm test — 1847 passing. pnpm test:integration:ci — 360 passing, incl. new coverage: canonical UnindexedDomain (name/depth/path), label-by-label path with intermediate virtual nodes (a.b.parent.eth), null for a resolver-less subname, null for an Encoded-LabelHash leaf under a wildcard resolver, and Account virtualization for an unindexed address; plus ResolvableName unit tests.

@shrugs shrugs requested a review from a team as a code owner June 7, 2026 20:10
Copilot AI review requested due to automatic review settings June 7, 2026 20:10
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 7, 2026

🦋 Changeset detected

Latest commit: 944ba53

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

This PR includes changesets to release 24 packages
Name Type
@ensnode/ensnode-sdk Patch
ensindexer Patch
enssdk Patch
@ensnode/ensdb-sdk Patch
ensapi Patch
ensadmin Patch
ensrainbow Patch
fallback-ensapi Patch
@docs/ensnode Patch
@namehash/ens-referrals Patch
enscli Patch
@ensnode/ensrainbow-sdk Patch
ensskills Patch
@ensnode/integration-test-env Patch
@namehash/namehash-ui Patch
@ensnode/enskit-react-example Patch
@ensnode/enssdk-example Patch
@ensnode/datasources Patch
enskit Patch
@docs/ensrainbow Patch
@ensnode/ponder-sdk Patch
@ensnode/ponder-subgraph Patch
@ensnode/shared-configs 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

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Jun 7, 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 8, 2026 2:30am
enskit-react-example.ensnode.io Ready Ready Preview, Comment Jun 8, 2026 2:30am
ensnode.io Ready Ready Preview, Comment Jun 8, 2026 2:30am
ensrainbow.io Ready Ready Preview, Comment Jun 8, 2026 2:30am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 7, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b2f453b6-638a-4b46-97a1-b6034397c7bb

📥 Commits

Reviewing files that changed from the base of the PR and between 6d0f695 and 944ba53.

⛔ Files ignored due to path filters (2)
  • packages/enssdk/src/omnigraph/generated/introspection.ts is excluded by !**/generated/**
  • packages/enssdk/src/omnigraph/generated/schema.graphql is excluded by !**/generated/**
📒 Files selected for processing (8)
  • .changeset/enssdk-resolvable-name.md
  • .changeset/resolver-is-extended.md
  • apps/ensapi/src/lib/protocol-acceleration/forward-walk-disjoint-namegraph.ts
  • apps/ensapi/src/omnigraph-api/schema/resolver.ts
  • apps/ensindexer/src/lib/protocol-acceleration/resolver-db-helpers.ts
  • docs/ensnode.io/src/content/docs/docs/services/ensdb/concepts/database-schemas.mdx
  • packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts
  • packages/ensskills/skills/omnigraph/SKILL.md

📝 Walkthrough

Walkthrough

The PR adds support for resolvable-but-unindexed ENS domains and accounts by introducing ResolvableName validation, returning structured namegraph walk results with resolver extended metadata, synthesizing UnindexedDomain/Account objects from walk rows, and persisting resolver ENSIP-10 capability at index time.

Changes

Unindexed Domain and Account Resolution

Layer / File(s) Summary
SDK types: ResolvableName and UnindexedDomainId
packages/enssdk/src/lib/resolvable-name.ts, packages/enssdk/src/lib/resolvable-name.test.ts, packages/enssdk/src/lib/ids.ts, packages/enssdk/src/lib/types/ensv2.ts, packages/enssdk/src/lib/index.ts
Adds branded ResolvableName and validators, a UnindexedDomainId type and makeUnindexedDomainId, and re-exports resolvable-name utilities.
Forward/reverse resolution enforces ResolvableName
apps/ensapi/src/lib/resolution/forward-resolution.ts, apps/ensapi/src/lib/resolution/reverse-resolution.ts, apps/ensapi/src/omnigraph-api/schema/domain.ts, apps/ensapi/src/omnigraph-api/schema/primary-name-record.ts
Resolution paths convert/validate inputs to ResolvableName and replace prior normalization checks with resolvable-name guards.
WalkResultRow extended with registry, extended, and canonical path
apps/ensapi/src/lib/protocol-acceleration/forward-walk-disjoint-namegraph.ts, apps/ensapi/src/lib/protocol-acceleration/find-resolver.ts
WalkResultRow gains registryId, extended, and canonicalPath; SQL CTEs propagate these; resolver type guard renamed to walkResultRowHasResolver.
Namegraph walk returns NamegraphWalkResult
apps/ensapi/src/omnigraph-api/lib/get-domain-by-interpreted-name.ts
Replaces getDomainIdByInterpretedName with forwardWalkNamegraph returning { rows, exact }; refactors recursive walk helper to return structured results for all branches.
UnindexedDomain construction
apps/ensapi/src/omnigraph-api/lib/unindexed-domain.ts
Adds UnindexedDomain interface, isUnindexedDomain, makeUnindexedDomain, and computeUnindexedDomainCanonicalPath to mint virtual domains from walk rows.
Domain schema unifies indexed and unindexed
apps/ensapi/src/omnigraph-api/schema/domain.ts, apps/ensapi/src/omnigraph-api/schema/domain-canonical.ts, apps/ensapi/src/omnigraph-api/schema/domain-resolver.ts
Domain becomes `IndexedDomain
Query.domain resolves by walk result shape
apps/ensapi/src/omnigraph-api/schema/query.ts
Query.domain now calls forwardWalkNamegraph and returns null for no rows, an indexed domain id when exact, or an UnindexedDomain constructed from walk rows otherwise.
Account model for unindexed address synthesis
apps/ensapi/src/omnigraph-api/schema/account.ts, apps/ensapi/src/omnigraph-api/schema/account.integration.test.ts
AccountRef changed to objectRef<NormalizedAddress>; Account.resolve synthesizes address-keyed account objects for unseen addresses and tests validate empty-domain responses.
Indexer resolver upsert with extended metadata
packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts, apps/ensindexer/src/lib/protocol-acceleration/resolver-db-helpers.ts, apps/ensindexer/src/lib/protocol-acceleration/domain-resolver-relationship-db-helpers.ts, docs/ensnode.io/src/content/docs/docs/services/ensdb/concepts/database-schemas.mdx
Adds isExtended resolver column (default false); upsertResolver ensures resolver rows exist and computes isExtended via a one-time supportsInterface RPC; domain-resolver upsert calls upsertResolver first.
EIP-165 optimization and integration tests
packages/ensnode-sdk/src/rpc/eip-165.ts, packages/enskit/src/react/omnigraph/_lib/by-id-lookup-resolvers.ts, apps/ensapi/src/omnigraph-api/schema/query.integration.test.ts, packages/ensskills/skills/omnigraph/SKILL.md, .changeset/*
EIP-165 helper opts out of empty-response retries (retryEmptyResponse:false) for indexer probes; Query.domain by-id lookup checks UnindexedDomain cache; integration tests and docs/changesets updated for unindexed behavior and resolver extended metadata.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • namehash/ensnode#2268: Modifies forward-resolution control flow and resolveViaUniversalResolver, overlapping resolution-path changes in this PR.
  • namehash/ensnode#1983: Refactors namegraph traversal; related to this PR's replacement of getDomainIdByInterpretedName with forwardWalkNamegraph.
  • namehash/ensnode#1576: Alters resolver-selection logic used by findResolverWithIndexENSv2, overlapping resolver predicate changes here.

Poem

"I’m a rabbit with a tiny key,
Hopping wild through wildcards free,
I stitch the walk rows into a chain,
Minting domains from off the plain,
Extended flags make resolvers sing — hop, hop! 🐇"

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the primary change: introducing UnindexedDomain support for resolvable-but-unindexed ENS names and Accounts in the Omnigraph API.
Description check ✅ Passed The PR description comprehensively covers all template sections: a clear summary of changes, detailed reasoning with linked issues, design decisions with tradeoffs, comprehensive testing coverage, and checklist completion.
Linked Issues check ✅ Passed Code changes fully address both linked issues: #1991 (upsertResolver with cached supportsInterface check wired into domain-resolver relations) and #1920 (ResolvableName type with isResolvableName/asResolvableName guards enforcing DNS-encodability and preventing label-hash resolution).
Out of Scope Changes check ✅ Passed All changes directly support the PR objectives of enabling unindexed domain/account resolution via UnindexedDomain and ResolvableName constraints; no unrelated refactoring or scope creep detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/virtualize-unindexed-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.

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 extends the ENSApi Omnigraph “entity-shaped” resolution experience so Query.domain(by:{name}) and Query.account(by:{address}) can return resolvable entities even when no indexed Domain/Account row exists (via a new UnindexedDomain concrete type and Account virtualization), while also enriching the index with resolver.extended (ENSIP-10 wildcard support).

Changes:

  • Add UnindexedDomain (implements Domain) and update Query.domain to return it when a name is resolvable-but-unindexed.
  • Virtualize Account to be address-backed (reverse resolution works regardless of indexing) and constrain resolution inputs via new ResolvableName.
  • Capture and persist resolver.extended in the indexer and expose it for query-time predicates without RPC.

Reviewed changes

Copilot reviewed 26 out of 28 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/ensskills/skills/omnigraph/SKILL.md Update Omnigraph skill docs to include UnindexedDomain and clarify resolver semantics.
packages/enssdk/src/omnigraph/generated/schema.graphql Add UnindexedDomain GraphQL type to the generated schema.
packages/enssdk/src/omnigraph/generated/introspection.ts Regenerate introspection to include UnindexedDomain.
packages/enssdk/src/lib/types/ensv2.ts Add UnindexedDomainId and include it in DomainId.
packages/enssdk/src/lib/resolvable-name.ts Introduce ResolvableName (+ validators) to constrain resolvable inputs.
packages/enssdk/src/lib/resolvable-name.test.ts Unit tests for ResolvableName constraints.
packages/enssdk/src/lib/index.ts Export resolvable-name from the SDK public surface.
packages/enssdk/src/lib/ids.ts Add makeUnindexedDomainId helper.
packages/enskit/src/react/omnigraph/_lib/by-id-lookup-resolvers.ts Teach client cache lookup to resolve UnindexedDomain by id.
packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts Add resolver.extended column to protocol acceleration schema.
docs/ensnode.io/src/content/docs/docs/services/ensdb/concepts/database-schemas.mdx Document resolver observation semantics and new extended column.
apps/ensindexer/src/lib/protocol-acceleration/resolver-db-helpers.ts Add upsertResolver to capture extended via cached supportsInterface.
apps/ensindexer/src/lib/protocol-acceleration/domain-resolver-relationship-db-helpers.ts Ensure resolver entities exist when writing domain-resolver relations.
apps/ensapi/src/omnigraph-api/schema/query.ts Update Query.domain to return indexed leaf or UnindexedDomain based on namegraph walk.
apps/ensapi/src/omnigraph-api/schema/query.integration.test.ts Add integration tests covering UnindexedDomain behaviors and edge cases.
apps/ensapi/src/omnigraph-api/schema/primary-name-record.ts Gate forward resolution of primary name record on isResolvableName.
apps/ensapi/src/omnigraph-api/schema/domain.ts Extend Domain interface shape to include UnindexedDomain and add UnindexedDomain concrete GraphQL type.
apps/ensapi/src/omnigraph-api/schema/domain-canonical.ts Build canonical path for UnindexedDomain via resolved values rather than id-loading.
apps/ensapi/src/omnigraph-api/schema/account.ts Virtualize Account as NormalizedAddress (no DB load) to support unindexed accounts.
apps/ensapi/src/omnigraph-api/schema/account.integration.test.ts Add integration test ensuring Query.account returns a virtual account for unindexed addresses.
apps/ensapi/src/omnigraph-api/lib/unindexed-domain.ts Implement UnindexedDomain construction + lazy canonical path computation.
apps/ensapi/src/omnigraph-api/lib/get-domain-by-interpreted-name.ts Refactor namegraph walking to return { rows, exact } for indexed vs unindexed decisions.
apps/ensapi/src/lib/resolution/reverse-resolution.ts Constrain reverse resolution internal names/records to ResolvableName.
apps/ensapi/src/lib/resolution/forward-resolution.ts Require ResolvableName for forward resolution and tighten input validation.
apps/ensapi/src/lib/protocol-acceleration/forward-walk-disjoint-namegraph.ts Extend walk rows to include registryId, extended, and canonicalPath.
apps/ensapi/src/lib/protocol-acceleration/find-resolver.ts Update resolver-finding logic to use the new walkResultRowHasResolver helper.
.changeset/unindexed-domain-resolution.md Add changeset describing new resolvable-but-unindexed Domain/Account behavior.

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

Comment thread apps/ensapi/src/omnigraph-api/lib/unindexed-domain.ts
Comment thread apps/ensapi/src/omnigraph-api/lib/unindexed-domain.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/lib/unindexed-domain.ts
Comment thread apps/ensapi/src/omnigraph-api/lib/unindexed-domain.ts
Comment thread apps/ensapi/src/lib/protocol-acceleration/forward-walk-disjoint-namegraph.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/lib/unindexed-domain.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/lib/unindexed-domain.ts
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 7, 2026

Greptile Summary

This PR corrects a protocol-correctness gap in the Omnigraph API: Query.domain(by:{name}) and Query.account(by:{address}) now return resolvable entities for names and addresses that have no indexed row, rather than silently returning null. The fix touches the indexer schema (new resolver.isExtended column), the namegraph walk (extended with registryId, extended, and canonicalPath columns), a new UnindexedDomain concrete type implementing the Domain interface, and a simplified Account virtualization.

  • UnindexedDomain: minted when forwardWalkNamegraph finds no exact leaf but the deepest ancestor Resolver carries ENSIP-10 wildcard support (extended); its canonical path is built label-by-label from the deepest indexed ancestor's materialized canonicalPath plus one virtual node per unindexed label below it, using the retained walk rows to avoid re-walking.
  • resolver.isExtended: captured once via a cached supportsInterface RPC in the new upsertResolver helper, called both from ensureDomainResolverRelation (DRR creation) and ensureResolverAndRecords (record events); retryEmptyResponse: false prevents Ponder's 9× backoff on empty responses.
  • Account virtualization: AccountRef is now a plain objectRef<NormalizedAddress> — no DB load needed since the account table carries only an id — enabling reverse resolution for any address regardless of whether it has been observed by the indexer.

Confidence Score: 5/5

Safe to merge — the core namegraph walk logic is correct, the wildcard-resolver predicate faithfully mirrors UniversalResolver's _checkResolver, and all bridged/ENSv1/ENSv2 hop cases preserve existing forward-resolution semantics.

The walk correctness was carefully verified: canonicalPath.length (not the walk-frame depth) determines the indexed prefix for bridged names, upsertResolver with onConflictDoNothing handles concurrent indexing races cleanly, and the Account virtualization is a straightforward collapse of a no-op dataloader. Integration tests cover the canonical UnindexedDomain path, multi-level virtual nodes, null for resolver-less names, null for encoded-labelhash leaves under wildcard resolvers, and unindexed account virtualization. Only two documentation/style observations were found.

No files require special attention.

Important Files Changed

Filename Overview
apps/ensapi/src/omnigraph-api/lib/unindexed-domain.ts New file introducing UnindexedDomain struct and its factory/canonical-path builder; logic for wildcard-resolver predicate and label-by-label path construction is sound, rows correctly threaded through to avoid re-walking.
apps/ensapi/src/lib/protocol-acceleration/forward-walk-disjoint-namegraph.ts SQL walk extended with registryId, extended (via LEFT JOIN on resolver), and canonicalPath columns; walkResultRowHasResolver guard updated to require all three non-null, with clear invariant documented.
apps/ensapi/src/omnigraph-api/lib/get-domain-by-interpreted-name.ts Refactored from returning DomainId
apps/ensapi/src/omnigraph-api/schema/domain.ts Domain union extended to IndexedDomain
apps/ensapi/src/omnigraph-api/schema/account.ts AccountRef simplified from loadableObjectRef to objectRef; accounts are now always virtualized, enabling unindexed reverse resolution.
apps/ensindexer/src/lib/protocol-acceleration/resolver-db-helpers.ts New upsertResolver captures isExtended via supportsInterface RPC with onConflictDoNothing for races.
packages/enssdk/src/lib/resolvable-name.ts New ResolvableName branded type; @dev comment misleadingly implies the function enforces normalization when InterpretedName already guarantees it.
apps/ensapi/src/omnigraph-api/schema/domain-canonical.ts DomainCanonical.path branches on isUnindexedDomain, calling computeUnindexedDomainCanonicalPath to build the virtual path from retained rows.
apps/ensapi/src/omnigraph-api/schema/domain-resolver.ts DomainResolverRef carries Domain; assigned is null for virtual domains; effective returns effectiveResolverId for virtual domains.
packages/ensnode-sdk/src/rpc/eip-165.ts Adds retryEmptyResponse: false to short-circuit Ponder's 9x retry for empty responses.
apps/ensindexer/src/lib/protocol-acceleration/domain-resolver-relationship-db-helpers.ts ensureDomainResolverRelation now calls upsertResolver, ensuring every referenced resolver has isExtended populated at DRR creation time.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Query.domain(by: { name })"] --> B{forwardWalkNamegraph}
    B --> C{rows.length === 0?}
    C -- yes --> D["return null"]
    C -- no --> E{exact match?}
    E -- yes --> F["return rows[0].domainId\n(IndexedDomain via loader)"]
    E -- no --> G["makeUnindexedDomain(name, rows)"]
    G --> H{isResolvableName?}
    H -- no --> I["return null"]
    H -- yes --> J{deepest ancestor has\nextended Resolver?}
    J -- no --> K["return null"]
    J -- yes --> L["return UnindexedDomain"]
    L --> M["DomainCanonical.path requested?"]
    M --> N["computeUnindexedDomainCanonicalPath"]
    N --> O["indexedPrefix = rows[0].canonicalPath"]
    O --> P["slice suffix hierarchy past indexed prefix"]
    P --> Q["return [...indexedPrefix, ...virtualNodes]"]
Loading

Reviews (11): Last reviewed commit: "fix: generate" | Re-trigger Greptile

Comment thread apps/ensapi/src/omnigraph-api/lib/unindexed-domain.ts Outdated
Comment thread apps/ensapi/src/lib/protocol-acceleration/forward-walk-disjoint-namegraph.ts Outdated
Comment thread apps/ensapi/src/lib/resolution/reverse-resolution.ts Outdated
Thread the namegraph walk rows onto UnindexedDomain so canonical.path no
longer re-walks; reuse getNameHierarchy/labelhashInterpretedLabel; flatten
reverse-resolution name narrowing.
Copilot AI review requested due to automatic review settings June 7, 2026 20:27
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io June 7, 2026 20:27 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io June 7, 2026 20:27 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensnode.io June 7, 2026 20:27 Inactive
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 28 changed files in this pull request and generated 1 comment.

Slice the virtual-node suffix by the deepest indexed ancestor's canonical
path length rather than the walk-frame depth, which is relative to the
post-bridge sub-path and over-mints/duplicates ancestors for bridged names.

Also: document UnindexedDomain registry/parent semantics on the Domain
interface fields, drop a redundant asResolvableName call in reverse
resolution, and fix the resolver-walk extended-NULL docstring.
…lver.extended

Rename the resolvers table column extended -> is_extended (Drizzle property
isExtended) and surface it through the Omnigraph API as a new non-nullable
Resolver.extended Boolean field. Regenerated SDL/introspection and updated
the ENSDb schema docs.
Copilot AI review requested due to automatic review settings June 7, 2026 22:31
@shrugs
Copy link
Copy Markdown
Member Author

shrugs commented Jun 7, 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 31 out of 33 changed files in this pull request and generated 4 comments.

Comment thread .changeset/resolver-is-extended.md Outdated
Comment thread packages/enssdk/src/lib/index.ts
Comment thread packages/enskit/src/react/omnigraph/_lib/by-id-lookup-resolvers.ts
Comment thread packages/ensskills/skills/omnigraph/SKILL.md
Describe the resolvers.is_extended column as a net addition (it is new vs
the last release, not a rename), and add an enssdk changeset for the new
ResolvableName/UnindexedDomainId public API.
@shrugs
Copy link
Copy Markdown
Member Author

shrugs commented Jun 7, 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 32 out of 34 changed files in this pull request and generated 1 comment.

Comment on lines +128 to +134
// the deepest indexed ancestor (rows are ordered depth DESC) anchors the indexed canonical prefix.
// Its materialized canonicalPath is root→leaf inclusive, so its length is that ancestor's canonical
// depth — the count of leading labels already covered by indexed Domains. We slice by this length
// (NOT the walk-frame `depth`, which is relative to the post-bridge sub-path and undercounts for
// bridged names, over-minting and duplicating the indexed ancestors).
const indexedPrefix = rows[0]?.canonicalPath ?? [];

@shrugs shrugs merged commit 83ed372 into main Jun 8, 2026
21 checks passed
@shrugs shrugs deleted the feat/virtualize-unindexed-domains branch June 8, 2026 02:36
@github-actions github-actions Bot mentioned this pull request Jun 7, 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.

Optimize Resolution API by upserting resolvers in SetResolver/ResolverUpdated Resolution API: Further constrain the type of names used for resolution

3 participants