Skip to content

Fix/indexing behavior dependencies#1909

Closed
tk-o wants to merge 2 commits intomainfrom
fix/indexing-behavior-dependencies
Closed

Fix/indexing behavior dependencies#1909
tk-o wants to merge 2 commits intomainfrom
fix/indexing-behavior-dependencies

Conversation

@tk-o
Copy link
Copy Markdown
Contributor

@tk-o tk-o commented Apr 10, 2026

Lite PR

Tip: Review docs on the ENSNode PR process

Summary

  • What changed (1-3 bullets, no essays).

Why

  • Why this change exists. Link to related GitHub issues where relevant.

Testing

  • How this was tested.
  • If you didn't test it, say why.

Notes for Reviewer (Optional)

  • Anything non-obvious or worth a heads-up.

Pre-Review Checklist (Blocking)

  • This PR does not introduce significant changes and is low-risk to review quickly.
  • Relevant changesets are included (or are not required)

Copilot AI review requested due to automatic review settings April 10, 2026 09:48
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 10, 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 Apr 10, 2026 9:48am
ensnode.io Skipped Skipped Apr 10, 2026 9:48am
ensrainbow.io Skipped Skipped Apr 10, 2026 9:48am

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 10, 2026

⚠️ No Changeset found

Latest commit: 233df59

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 10, 2026

📝 Walkthrough

Walkthrough

The PR refactors how indexing behavior dependencies feed into Ponder's build-id generation. Instead of directly modifying a config object property, it establishes a contracts-based injection mechanism that consolidates configuration parameters and database schema checksums into a deterministic input for Ponder's build process.

Changes

Cohort / File(s) Summary
Indexing Behavior Injection Mechanism
apps/ensindexer/src/ponder/config.ts, apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts
Replaced manual property injection with a structured contracts-based mechanism. New function buildIndexingBehaviorInjectionContracts() packages configuration and schema inputs into a contracts-compatible object for Ponder build-id variability.
Schema Checksum Infrastructure
packages/ensdb-sdk/src/client/ensdb-reader.ts, packages/ensdb-sdk/src/lib/drizzle.ts
Added public getter ensDbSchemaChecksum on EnsDbReader and new utility function getDrizzleSchemaChecksum() that computes a deterministic SHA-256-based checksum of merged Drizzle schema definitions with circular-reference-safe serialization.

Sequence Diagram

sequenceDiagram
    participant Ponder Config
    participant buildInjectionContracts as buildIndexingBehaviorInjectionContracts()
    participant EnsDbReader
    participant Drizzle
    
    Ponder Config->>buildInjectionContracts: Call with config & ensDbClient
    buildInjectionContracts->>EnsDbReader: Read ensDbSchemaChecksum
    EnsDbReader->>Drizzle: getDrizzleSchemaChecksum(merged schema)
    Drizzle->>Drizzle: Safely stringify schema<br/>(handle circular refs)
    Drizzle->>Drizzle: SHA-256 hash & truncate
    Drizzle-->>EnsDbReader: Return checksum
    EnsDbReader-->>buildInjectionContracts: Checksum value
    buildInjectionContracts->>buildInjectionContracts: Embed checksum into<br/>indexingBehaviorDependencies
    buildInjectionContracts-->>Ponder Config: Return contracts-like mapping
    Ponder Config->>Ponder Config: Merge into ponderConfig.contracts
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly Related PRs

Poem

🐰 A checksum hops through schemas deep,
Where circular trails no longer creep,
With SHA-256's steady hand,
Ponder's build now firmly stands,
Config flows through contracts true,
Fresh injection paths break through! 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is a template skeleton with no substantive content filled in any of the required sections (Summary, Why, Testing, Notes for Reviewer, checklist unchecked). Complete all template sections: add 1-3 bullets summarizing changes, explain why the refactoring was needed, describe testing performed, and check the blocking checklist items.
Title check ❓ Inconclusive The title 'Fix/indexing behavior dependencies' is vague and generic, using a 'Fix/' prefix without clearly specifying what the actual problem is or what was fixed. Clarify the title to be more specific about the actual change, e.g., 'Refactor indexing behavior dependencies injection' or 'Use contracts-based injection for indexing behavior dependencies'.
✅ Passed checks (1 passed)
Check name Status Explanation
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 fix/indexing-behavior-dependencies

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 updates how ENSIndexer influences Ponder’s build ID by introducing a schema checksum for the ENSDb Drizzle schema and injecting indexing-behavior dependencies into the Ponder contracts config.

Changes:

  • Add a Drizzle schema checksum utility (getDrizzleSchemaChecksum) to the ENSDb SDK.
  • Expose the checksum via EnsDbReader.ensDbSchemaChecksum.
  • Replace the previous top-level indexingBehaviorDependencies injection with a special “injection contract” added to ponderConfig.contracts.

Reviewed changes

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

File Description
packages/ensdb-sdk/src/lib/drizzle.ts Adds schema-safe stringification + schema checksum hashing utility.
packages/ensdb-sdk/src/client/ensdb-reader.ts Exposes the schema checksum via a new getter on EnsDbReader.
apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts Introduces a synthetic contract config containing indexing-behavior dependencies (including schema checksum).
apps/ensindexer/src/ponder/config.ts Injects the synthetic contract into ponderConfig.contracts so it affects Ponder build ID generation.

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

Comment on lines +53 to +58
export function buildIndexingBehaviorInjectionContracts() {
return {
IndexingBehaviorInjectionContract: {
chain: `${rootChainId}`,
indexingBehaviorDependencies,
},
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

buildIndexingBehaviorInjectionContracts() adds an entry under ponderConfig.contracts, but the returned object doesn’t match the contract config shape used throughout the codebase (e.g. plugins always provide abi and a chain object keyed by chainId via chainConfigForContract(...)). With the current { chain: "${rootChainId}", indexingBehaviorDependencies }, Ponder config validation/typechecking is likely to fail at runtime or silently ignore the entry for build-id purposes.

Suggestion: make this a valid minimal contract config (include abi and use a chain mapping like { [rootChainId.toString()]: { address, startBlock, endBlock } }), and ensure the chosen blockrange/address won’t cause unnecessary indexing work.

Copilot uses AI. Check for mistakes.
Comment on lines +108 to +113
get ensDbSchemaChecksum(): string {
return getDrizzleSchemaChecksum({
...this._concreteEnsIndexerSchema,
...this._ensNodeSchema,
});
}
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

ensDbSchemaChecksum recomputes a full schema stringify + SHA-256 hash on every access. This can be relatively expensive given the size of the Drizzle schema objects.

Suggestion: compute once (e.g., in the constructor) or memoize the getter in a private field so repeated accesses don’t repeatedly hash the same data.

Copilot uses AI. Check for mistakes.
Comment on lines +206 to +210
export function getDrizzleSchemaChecksum(schema: Record<string, unknown>): string {
const stringifiedSchema = safeStringifyDrizzleSchema(schema);

return createHash("sha256").update(stringifiedSchema).digest("hex").slice(0, 10);
}
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

getDrizzleSchemaChecksum() is new exported behavior that will influence indexing build IDs, but there are no tests covering checksum determinism and that schema objects with circular references won’t throw.

Suggestion: add Vitest coverage in packages/ensdb-sdk/src/lib/drizzle.test.ts to assert (1) stable checksum for the same schema input and (2) no throw + stable output when circular references exist (and ideally that a meaningful schema change alters the checksum).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts`:
- Around line 53-60: The current code uses module-level constants
indexingBehaviorDependencies and rootChainId which are evaluated at import time,
so change buildIndexingBehaviorInjectionContracts() to compute or fetch those
values inside the function instead of relying on the module-level variables:
move the logic that derives indexingBehaviorDependencies and rootChainId into
the body of buildIndexingBehaviorInjectionContracts (or call the functions that
return them) so the values are evaluated at call time; update references inside
the function to use the locally computed variables and leave the exported
function signature (buildIndexingBehaviorInjectionContracts) unchanged.

In `@packages/ensdb-sdk/src/lib/drizzle.ts`:
- Around line 188-199: The safeStringifyDrizzleSchema function can produce
non-deterministic output because JSON.stringify uses native key enumeration
order; modify safeStringifyDrizzleSchema to produce deterministic serialization
by sorting object keys before serializing while preserving arrays and the
existing circular-reference handling: in the replacer used by JSON.stringify
(inside safeStringifyDrizzleSchema) detect plain objects (not arrays), collect
and sort Object.keys(value) and build a new object with keys in sorted order (or
return a sorted-key representation) so the same schema yields identical strings
across environments; keep the WeakSet circular detection logic unchanged so
circular references still produce "[circular]".
🪄 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: 7315e0d0-5fd1-45ad-a7fc-6a473166ec0d

📥 Commits

Reviewing files that changed from the base of the PR and between b781245 and 233df59.

📒 Files selected for processing (4)
  • apps/ensindexer/src/ponder/config.ts
  • apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts
  • packages/ensdb-sdk/src/client/ensdb-reader.ts
  • packages/ensdb-sdk/src/lib/drizzle.ts

Comment on lines +53 to +60
export function buildIndexingBehaviorInjectionContracts() {
return {
IndexingBehaviorInjectionContract: {
chain: `${rootChainId}`,
indexingBehaviorDependencies,
},
} as const;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Module-level initialization occurs at import time.

The indexingBehaviorDependencies and rootChainId constants are evaluated when this module is first imported, not when buildIndexingBehaviorInjectionContracts() is called. This is fine for the current use case where config and ensDbClient are singleton modules that initialize synchronously. Just be aware that any import-time failures in those dependencies would surface here.

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

In `@apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts` around
lines 53 - 60, The current code uses module-level constants
indexingBehaviorDependencies and rootChainId which are evaluated at import time,
so change buildIndexingBehaviorInjectionContracts() to compute or fetch those
values inside the function instead of relying on the module-level variables:
move the logic that derives indexingBehaviorDependencies and rootChainId into
the body of buildIndexingBehaviorInjectionContracts (or call the functions that
return them) so the values are evaluated at call time; update references inside
the function to use the locally computed variables and leave the exported
function signature (buildIndexingBehaviorInjectionContracts) unchanged.

Comment on lines +188 to +199
function safeStringifyDrizzleSchema(schema: Record<string, unknown>): string {
const seen = new WeakSet();

return JSON.stringify(schema, (_key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) return "[circular]";
seen.add(value);
}

return value;
});
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Non-deterministic key ordering may cause inconsistent checksums.

JSON.stringify does not guarantee consistent key ordering across different object instantiation orders or JavaScript engines. If the schema object's keys are enumerated in a different order (e.g., due to how Drizzle constructs the schema internally), the resulting checksum could differ for semantically identical schemas, potentially causing unexpected Ponder build-id changes.

Consider sorting keys during serialization for deterministic output:

🔧 Proposed fix for deterministic serialization
 function safeStringifyDrizzleSchema(schema: Record<string, unknown>): string {
   const seen = new WeakSet();

-  return JSON.stringify(schema, (_key, value) => {
+  return JSON.stringify(schema, (_key, value) => {
     if (typeof value === "object" && value !== null) {
       if (seen.has(value)) return "[circular]";
       seen.add(value);
+      // Sort object keys for deterministic output
+      if (!Array.isArray(value)) {
+        const sorted: Record<string, unknown> = {};
+        for (const k of Object.keys(value).sort()) {
+          sorted[k] = (value as Record<string, unknown>)[k];
+        }
+        return sorted;
+      }
     }

     return value;
   });
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ensdb-sdk/src/lib/drizzle.ts` around lines 188 - 199, The
safeStringifyDrizzleSchema function can produce non-deterministic output because
JSON.stringify uses native key enumeration order; modify
safeStringifyDrizzleSchema to produce deterministic serialization by sorting
object keys before serializing while preserving arrays and the existing
circular-reference handling: in the replacer used by JSON.stringify (inside
safeStringifyDrizzleSchema) detect plain objects (not arrays), collect and sort
Object.keys(value) and build a new object with keys in sorted order (or return a
sorted-key representation) so the same schema yields identical strings across
environments; keep the WeakSet circular detection logic unchanged so circular
references still produce "[circular]".

export function buildIndexingBehaviorInjectionContracts() {
return {
IndexingBehaviorInjectionContract: {
chain: `${rootChainId}`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
chain: `${rootChainId}`,
chain: {
[rootChainId.toString()]: {
address: "0x0000000000000000000000000000000000000000",
startBlock: 0,
endBlock: 0,
},
},

The IndexingBehaviorInjectionContract has an invalid chain property structure - it's a string instead of an object mapping chain IDs to configuration objects

Fix on Vercel

@tk-o tk-o closed this Apr 10, 2026
@tk-o tk-o deleted the fix/indexing-behavior-dependencies branch April 10, 2026 14:56
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.

2 participants