Skip to content

Skip ENSDb Writer Worker validation for ENSIndexer Public Config while in dev mode#1807

Merged
tk-o merged 8 commits intomainfrom
feat/ensdb-writer-worker-dev-mode-validation-skip
Mar 22, 2026
Merged

Skip ENSDb Writer Worker validation for ENSIndexer Public Config while in dev mode#1807
tk-o merged 8 commits intomainfrom
feat/ensdb-writer-worker-dev-mode-validation-skip

Conversation

@tk-o
Copy link
Contributor

@tk-o tk-o commented Mar 22, 2026

Lite PR

Tip: Review docs on the ENSNode PR process

Summary

  • Ponder SDK has a new PonderAppContext data model to capture relevant context from the local Ponder app
    • the context is source from globalThis.PONDER_COMMON const, that is injected by Ponder into ENSIndexer runtime.
    • see packages/ponder-sdk/src/deserialize/ponder-app-context.ts
  • LocalPonderClient now receives the PonderAppContext object with constructor params
  • LocalPonderClient defines isInDevMode(): boolean getter to enable ENSIndexer app modules to include conditional logic based on the local Ponder app mode.
    • see packages/ponder-sdk/src/local-ponder-client.ts
  • EnsDbWriterWorker now uses localPonderClient instance to skip the ENSIndexer Public Config validation when the local Ponder app is in the dev mode.
    • see apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.ts

Why

Problem

During ENSIndexer development, developers frequently change configuration (e.g., active plugins, ENS Namespace) between runs. The ENSDb Writer Worker validates that the in-memory config matches the previously stored config in ENSDb. This caused crashes on subsequent runs because the stored config from the previous run was incompatible with the new in-memory config, forcing developers to manually clear the database between runs.

Solution

Skip config compatibility validation when Ponder is running in dev mode, allowing developers to iterate without database resets.


Testing

  • Ran all static code checks (lint, typecheck).
  • Updated testing suite accordingly to the introduced updates. All tests pass.
  • Ran ENSIndexer locally multiple times, with different active plugins, and different ENSNamespace.

Notes for Reviewer (Optional)

  • Please review commit-by-commit.
  • The problem and solution to it was discussed and agreed to in this Slack thread.

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)

tk-o added 4 commits March 22, 2026 08:50
This data model allows to capture the internal context object of the local Ponder app
This getter will allow the consumers of the local Ponder client to decide business logic based on the Ponder app context.
Skip ENSIndexer Pulic Config validation in dev mode.
@tk-o tk-o requested a review from a team as a code owner March 22, 2026 08:01
Copilot AI review requested due to automatic review settings March 22, 2026 08:01
@changeset-bot
Copy link

changeset-bot bot commented Mar 22, 2026

🦋 Changeset detected

Latest commit: 2ad57bd

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

This PR includes changesets to release 19 packages
Name Type
ensindexer Major
@ensnode/ponder-sdk Major
ensadmin Major
ensrainbow Major
ensapi Major
fallback-ensapi Major
@ensnode/datasources Major
@ensnode/ensrainbow-sdk Major
@ensnode/ensdb-sdk Major
@ensnode/ensnode-react Major
@ensnode/ensnode-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
@ensnode/integration-test-env 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
Contributor

vercel bot commented Mar 22, 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 Mar 22, 2026 4:22pm
ensnode.io Skipped Skipped Mar 22, 2026 4:22pm
ensrainbow.io Skipped Skipped Mar 22, 2026 4:22pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 22, 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

Adds Ponder app context types and deserialization; LocalPonderClient now stores PonderAppContext and exposes isInDevMode; EnsDbWriterWorker accepts LocalPonderClient and skips public-config compatibility validation in dev mode; tests, mocks, and initialization wiring updated accordingly.

Changes

Cohort / File(s) Summary
Changeset metadata
\.changeset/better-bats-switch.md, \.changeset/old-seals-draw.md
New changeset files documenting minor version bumps and the Ponder app context / dev-mode changes.
Ponder app context types & deserializer
packages/ponder-sdk/src/ponder-app-context.ts, packages/ponder-sdk/src/deserialize/ponder-app-context.ts
Added PonderAppCommands, PonderAppCommand type, PonderAppContext interface, Zod schemas, and deserializePonderAppContext.
SDK exports & indexing-metrics adjustments
packages/ponder-sdk/src/index.ts, packages/ponder-sdk/src/indexing-metrics.ts, packages/ponder-sdk/src/deserialize/indexing-metrics.{ts,mock.ts}
Re-exported ponder-app-context and its deserializer; removed local PonderAppCommands from indexing-metrics and switched imports to new types.
LocalPonderClient implementation & tests/mocks
packages/ponder-sdk/src/local-ponder-client.ts, packages/ponder-sdk/src/local-ponder-client.mock.ts, packages/ponder-sdk/src/local-ponder-client.test.ts
LocalPonderClient ctor now accepts/stores PonderAppContext; added isInDevMode getter; mocks/tests updated to supply and assert ponderAppContext.
EnsDbWriterWorker integration, mocks & tests
apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.ts, .../ensdb-writer-worker.mock.ts, .../ensdb-writer-worker.test.ts, .../singleton.ts
Worker constructor extended to accept LocalPonderClient; getValidatedEnsIndexerPublicConfig() skips compatibility validation when isInDevMode is true; tests/mocks refactored to use new factories and assert dev-mode behavior.
Local Ponder client init & globals
apps/ensindexer/src/lib/local-ponder-client.ts, apps/ensindexer/types/env.d.ts
Deserialize globalThis.PONDER_COMMON into PonderAppContext (runtime guard added) and pass it to LocalPonderClient; added global PONDER_COMMON type declaration.
Mocks/deserializers minor tweaks
packages/ponder-sdk/src/deserialize/indexing-metrics.mock.ts, packages/ponder-sdk/src/deserialize/indexing-metrics.ts
Switched imports to use ponder-app-context exports and adapted schema imports; no logic changes beyond import sources.

Sequence Diagram

sequenceDiagram
    participant App as Application Start
    participant Deser as deserializePonderAppContext
    participant Init as LocalPonderClient Init
    participant LPC as LocalPonderClient
    participant WorkerInit as EnsDbWriterWorker Init
    participant Worker as EnsDbWriterWorker
    participant Validator as Compatibility Validator

    App->>Deser: read globalThis.PONDER_COMMON
    Deser-->>Init: return PonderAppContext
    Init->>LPC: construct(LocalPonderClient, ponderAppContext)
    LPC-->>App: expose isInDevMode

    App->>WorkerInit: construct EnsDbWriterWorker(..., localPonderClient)
    WorkerInit-->>Worker: store localPonderClient

    Worker->>Validator: getValidatedEnsIndexerPublicConfig(stored,inMemory)
    Validator->>LPC: query isInDevMode
    alt Dev mode (true)
        Validator-->>Worker: skip compatibility check, return inMemory config
    else Prod mode (false)
        Validator->>Validator: validateEnsIndexerPublicConfigCompatibility(...)
        Validator-->>Worker: return validated config or throw
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped into globals, found a tiny command,

Dev-mode whisper told me to lend a hand,
Mocks snugly wired, workers learn to defer,
Tests nod and smile as validations blur,
A rabbit cheers—code hops lighter on the land.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: skipping ENSDb Writer Worker validation for ENSIndexer Public Config in dev mode.
Description check ✅ Passed The PR description follows the Lite PR template with all required sections (Summary, Why, Testing, Notes) completed. The checklist is also marked as complete.

✏️ 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/ensdb-writer-worker-dev-mode-validation-skip

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 Mar 22, 2026

Greptile Summary

This PR improves the ENSIndexer development experience by skipping the ENSDb Writer Worker's config compatibility validation when Ponder is running in dev mode (ponder dev). It introduces a new PonderAppContext data model (sourced from Ponder's globalThis.PONDER_COMMON global) and threads it through LocalPonderClient so that any component can check isInDevMode without direct knowledge of Ponder internals.

Key changes:

  • New packages/ponder-sdk/src/ponder-app-context.ts defines PonderAppCommands, PonderAppCommand, and PonderAppContext. PonderAppCommands was extracted from indexing-metrics.ts where it didn't belong.
  • New packages/ponder-sdk/src/deserialize/ponder-app-context.ts deserialises and validates globalThis.PONDER_COMMON (a Zod pipeline: raw schema → transform → domain schema).
  • LocalPonderClient gains a ponderAppContext constructor param and an isInDevMode getter.
  • EnsDbWriterWorker receives localPonderClient and gates validateEnsIndexerPublicConfigCompatibility behind !this.localPonderClient.isInDevMode.
  • apps/ensindexer/types/env.d.ts now correctly types PONDER_COMMON as RawPonderAppContext | undefined, and a module-level guard in local-ponder-client.ts throws an explicit error if the global is absent at runtime.
  • Prior reviewer feedback has been addressed: PONDER_COMMON is typed as | undefined, and the concurrency assertion in the "fetches stored and in-memory configs concurrently" test has been restored.

Confidence Score: 5/5

  • Safe to merge — changes are dev-mode only and do not affect production indexing behaviour.
  • The feature is cleanly scoped: the validation bypass is strictly conditioned on isInDevMode, which is derived from Ponder's own injected PONDER_COMMON.options.command. Production runs (ponder start) are completely unaffected. Prior reviewer concerns (typing of PONDER_COMMON, restored concurrency assertions) have been addressed. Test coverage is thorough, including a dedicated "skips config validation when in dev mode" case. Only a minor JSDoc wording issue was found.
  • No files require special attention.

Important Files Changed

Filename Overview
packages/ponder-sdk/src/deserialize/ponder-app-context.ts New module that validates and deserialises globalThis.PONDER_COMMON into a typed PonderAppContext. Zod pipeline (schemaRawPonderAppContext → transform → schemaPonderAppContext) is clean; error reporting via prettifyError is appropriate. No issues found.
packages/ponder-sdk/src/local-ponder-client.ts Adds ponderAppContext constructor parameter and isInDevMode getter. Implementation is straightforward; PonderAppContext is stored privately and only surfaced through the getter. Clean.
apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.ts Adds localPonderClient as a constructor parameter and gates the config-compatibility validation on !this.localPonderClient.isInDevMode. Logic is correct; the upsert still runs in dev mode (intentionally overwriting the stored config). Minor JSDoc wording issue on the private field.
apps/ensindexer/src/lib/local-ponder-client.ts Module-level guard (if (!globalThis.PONDER_COMMON) { throw }) correctly prevents use outside the Ponder runtime and narrows the type before passing to deserializePonderAppContext. PONDER_COMMON is now typed `
apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.test.ts New "skips config validation when in dev mode" test is well-structured. The previously missing publicConfigBuilder.getPublicConfig assertion in the concurrency test (line 191) has been restored. All test cases use the new createMockEnsDbWriterWorker factory for cleaner setup.
apps/ensindexer/types/env.d.ts Correctly declares PONDER_COMMON as `RawPonderAppContext

Sequence Diagram

sequenceDiagram
    participant Ponder as Ponder Runtime
    participant LC as local-ponder-client.ts (module init)
    participant DPAC as deserializePonderAppContext
    participant LPC as LocalPonderClient
    participant Worker as EnsDbWriterWorker
    participant ENSDb as ENSDb

    Ponder->>LC: inject globalThis.PONDER_COMMON
    LC->>LC: guard: if (!PONDER_COMMON) throw
    LC->>DPAC: deserializePonderAppContext(PONDER_COMMON)
    DPAC-->>LC: PonderAppContext { command }
    LC->>LPC: new LocalPonderClient(..., ponderAppContext)
    Note over LPC: isInDevMode = command === "dev"

    Worker->>Worker: run()
    Worker->>Worker: getValidatedEnsIndexerPublicConfig()
    Worker->>ENSDb: getEnsIndexerPublicConfig() [concurrent]
    Worker->>Worker: publicConfigBuilder.getPublicConfig() [concurrent]
    alt storedConfig exists AND NOT isInDevMode
        Worker->>Worker: validateEnsIndexerPublicConfigCompatibility()
        Note over Worker: throws on incompatibility
    else isInDevMode OR no storedConfig
        Worker->>Worker: skip validation (dev mode)
    end
    Worker->>ENSDb: upsertEnsDbVersion(...)
    Worker->>ENSDb: upsertEnsIndexerPublicConfig(inMemoryConfig)
Loading

Comments Outside Diff (1)

  1. apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.ts, line 54-59 (link)

    Misleading field JSDoc comment

    The doc comment says "Used to get local Ponder app command." but the client is only ever consulted via isInDevMode, which reflects the mode rather than the raw command string. A more accurate description would keep readers from digging into the class to understand the actual usage.

Reviews (5): Last reviewed commit: "Apply AI PR feedback" | Re-trigger Greptile

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 Ponder “app context” model (incl. command) to allow ENSIndexer to detect dev mode and skip ENSDb Writer Worker public-config compatibility validation during development.

Changes:

  • Introduce PonderAppContext/PonderAppCommands plus Zod deserialization for Ponder’s injected runtime context.
  • Thread PonderAppContext into LocalPonderClient and expose isInDevMode.
  • Skip validateEnsIndexerPublicConfigCompatibility() in EnsDbWriterWorker when running in dev mode; update mocks/tests and add changesets.

Reviewed changes

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

Show a summary per file
File Description
packages/ponder-sdk/src/ponder-app-context.ts Adds PonderAppContext + command constants/types.
packages/ponder-sdk/src/local-ponder-client.ts Accepts app context and exposes isInDevMode.
packages/ponder-sdk/src/local-ponder-client.test.ts Adds unit tests for isInDevMode + updates imports.
packages/ponder-sdk/src/local-ponder-client.mock.ts Updates mock factory to provide ponderAppContext.
packages/ponder-sdk/src/indexing-metrics.ts Moves PonderAppCommand typing to new context module.
packages/ponder-sdk/src/index.ts Re-exports new context + deserializer modules.
packages/ponder-sdk/src/deserialize/ponder-app-context.ts Adds Zod schemas and deserializePonderAppContext().
packages/ponder-sdk/src/deserialize/indexing-metrics.ts Reuses shared command schema for metrics deserialization.
packages/ponder-sdk/src/deserialize/indexing-metrics.mock.ts Updates mock to import commands from new module.
apps/ensindexer/types/env.d.ts Declares globalThis.PONDER_COMMON injected by Ponder.
apps/ensindexer/src/lib/local-ponder-client.ts Builds ponderAppContext from PONDER_COMMON and passes to LocalPonderClient.
apps/ensindexer/src/lib/ensdb-writer-worker/singleton.ts Injects localPonderClient into worker construction.
apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.ts Skips public-config compatibility validation when isInDevMode.
apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.test.ts Adds dev-mode test and refactors to use a worker factory mock.
apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts Adds createMockEnsDbWriterWorker + createMockLocalPonderClient.
.changeset/old-seals-draw.md Changeset for @ensnode/ponder-sdk (context model).
.changeset/better-bats-switch.md Changeset for ensindexer (skip validation in dev mode).

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

Copy link
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: 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/better-bats-switch.md:
- Line 5: Replace the typo "skiping" with "skipping" in the changeset text line
that mentions "ENSDb Writer Worker" so the sentence reads "skipping validation
step in ENSDb Writer Worker while in dev mode."; update only the word and keep
the rest of the line unchanged.

In `@apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.test.ts`:
- Around line 84-86: The test is using persistent mocks via
vi.mocked(...).mockImplementation(...) which can leak between tests; change
those to one-shot mocks using
vi.mocked(validateEnsIndexerPublicConfigCompatibility).mockImplementationOnce(()
=> { throw new Error("incompatible"); }) (and similarly replace other
occurrences that call mockImplementation at the other spots) so each test gets
an isolated behavior and no cross-test leakage; update the three locations that
currently call mockImplementation to use mockImplementationOnce instead.

In `@packages/ponder-sdk/src/deserialize/ponder-app-context.ts`:
- Around line 33-38: The JSDoc for the Ponder App Context builder contains
redundant `@returns` tags that repeat the summary; remove the unnecessary `@returns`
lines from the JSDoc block that documents the function which builds the
unvalidated Ponder App Context (the comment referencing schemaPonderAppContext)
and also remove the redundant `@returns` in the other JSDoc block noted at lines
50-52 so the doc follows the repo guideline of not restating summaries.
- Around line 57-64: Replace the safeParse branch with a direct parse call: use
schemaRawPonderAppContext.transform(buildUnvalidatedPonderAppContext).pipe(schemaPonderAppContext).parse(unvalidatedRawPonderAppContext)
instead of .safeParse(...), remove the manual if (!validation.success) throw
block and use the returned parsed value (e.g., const validated = ...parse(...));
keep the same transform/pipe chain (schemaRawPonderAppContext,
buildUnvalidatedPonderAppContext, schemaPonderAppContext,
unvalidatedRawPonderAppContext) so validation fails fast by throwing rather than
manually checking validation.success.
🪄 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: 3a61495e-9046-4d90-b178-f11a3074de27

📥 Commits

Reviewing files that changed from the base of the PR and between f0007b4 and 9811b95.

📒 Files selected for processing (17)
  • .changeset/better-bats-switch.md
  • .changeset/old-seals-draw.md
  • apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts
  • apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.test.ts
  • apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.ts
  • apps/ensindexer/src/lib/ensdb-writer-worker/singleton.ts
  • apps/ensindexer/src/lib/local-ponder-client.ts
  • apps/ensindexer/types/env.d.ts
  • packages/ponder-sdk/src/deserialize/indexing-metrics.mock.ts
  • packages/ponder-sdk/src/deserialize/indexing-metrics.ts
  • packages/ponder-sdk/src/deserialize/ponder-app-context.ts
  • packages/ponder-sdk/src/index.ts
  • packages/ponder-sdk/src/indexing-metrics.ts
  • packages/ponder-sdk/src/local-ponder-client.mock.ts
  • packages/ponder-sdk/src/local-ponder-client.test.ts
  • packages/ponder-sdk/src/local-ponder-client.ts
  • packages/ponder-sdk/src/ponder-app-context.ts

@tk-o tk-o force-pushed the feat/ensdb-writer-worker-dev-mode-validation-skip branch from 9811b95 to 326f9a4 Compare March 22, 2026 10:06
@tk-o
Copy link
Contributor Author

tk-o commented Mar 22, 2026

@greptile review

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

♻️ Duplicate comments (3)
packages/ponder-sdk/src/deserialize/ponder-app-context.ts (2)

57-64: 🛠️ Refactor suggestion | 🟠 Major

Use .parse() for this fail-fast non-API deserialization path.

At Line [60], this path validates and then always throws on failure (Line [62]-Line [64]), so safeParse adds unnecessary branching. Prefer direct .parse(...).

♻️ Proposed change
-import { prettifyError, z } from "zod/v4";
+import { z } from "zod/v4";
@@
 export function deserializePonderAppContext(
   unvalidatedRawPonderAppContext: Unvalidated<RawPonderAppContext> | undefined,
 ): PonderAppContext {
-  const validation = schemaRawPonderAppContext
+  return schemaRawPonderAppContext
     .transform(buildUnvalidatedPonderAppContext)
     .pipe(schemaPonderAppContext)
-    .safeParse(unvalidatedRawPonderAppContext);
-
-  if (!validation.success) {
-    throw new Error(`Invalid raw Ponder App Context: ${prettifyError(validation.error)}`);
-  }
-
-  return validation.data;
+    .parse(unvalidatedRawPonderAppContext);
 }
#!/bin/bash
# Verify this function currently uses safeParse in a fail-fast path.
rg -n --type=ts 'deserializePonderAppContext|safeParse\(|\.parse\(' packages/ponder-sdk/src/deserialize/ponder-app-context.ts

As per coding guidelines "{apps,packages}//src//*.{ts,tsx}: Use zod.parse(...) for fail-fast validation in non-API code; use zod.safeParse(...) when you need non-throwing branch for optional or fallback values".

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

In `@packages/ponder-sdk/src/deserialize/ponder-app-context.ts` around lines 57 -
64, The code currently calls
schemaRawPonderAppContext.transform(buildUnvalidatedPonderAppContext).pipe(schemaPonderAppContext).safeParse(unvalidatedRawPonderAppContext)
and then throws on validation failure; replace this fail-fast path with a direct
.parse(...) so it throws automatically: call
schemaRawPonderAppContext.transform(buildUnvalidatedPonderAppContext).pipe(schemaPonderAppContext).parse(unvalidatedRawPonderAppContext)
and remove the manual success check/throw (retain the prettifyError helper only
if still needed elsewhere) so the function fails fast using Zod's built-in
exception.

33-38: 🧹 Nitpick | 🔵 Trivial

Remove redundant @returns tags in these JSDoc blocks.

The @returns text at Line [36]-Line [37] and Line [51] restates the summaries and should be removed to keep doc style consistent.

As per coding guidelines "**/*.{ts,tsx}: Do not add JSDoc @returns tags that merely restate the method summary; remove redundant comments during PR review".

Also applies to: 47-52

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

In `@packages/ponder-sdk/src/deserialize/ponder-app-context.ts` around lines 33 -
38, Remove the redundant JSDoc `@returns` tags that merely repeat the summary: in
the JSDoc for the buildUnvalidatedPonderAppContext block (the comment starting
"Build unvalidated Ponder App Context" that references rawPonderAppContext and
{`@link` schemaPonderAppContext}) and the other affected JSDoc block around lines
47–52; keep the summary and `@param` tags but delete the `@returns` lines so the
documentation follows the project's guideline against restating the method
summary.
apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.test.ts (1)

84-86: ⚠️ Potential issue | 🟡 Minor

Use one-shot implementations here to prevent cross-test mock leakage.

Line 84, Line 103, and Line 175 use persistent mockImplementation(...); with vi.clearAllMocks() in cleanup, those implementations can bleed into later tests.

♻️ Proposed fix
-      vi.mocked(validateEnsIndexerPublicConfigCompatibility).mockImplementation(() => {
+      vi.mocked(validateEnsIndexerPublicConfigCompatibility).mockImplementationOnce(() => {
         throw new Error("incompatible");
       });

-      vi.mocked(validateEnsIndexerPublicConfigCompatibility).mockImplementation(() => {
+      vi.mocked(validateEnsIndexerPublicConfigCompatibility).mockImplementationOnce(() => {
         throw new Error("incompatible");
       });

-      vi.mocked(validateEnsIndexerPublicConfigCompatibility).mockImplementation(() => {});
+      vi.mocked(validateEnsIndexerPublicConfigCompatibility).mockImplementationOnce(() => {});
In Vitest, does vi.clearAllMocks() reset mock implementations set via mockImplementation(), or only clear call history?

Also applies to: 103-105, 175-175

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

In `@apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.test.ts`
around lines 84 - 86, The tests set persistent mocks for
validateEnsIndexerPublicConfigCompatibility using
vi.mocked(...).mockImplementation(...), which can leak between tests; change
those to one-shot mocks by using
vi.mocked(validateEnsIndexerPublicConfigCompatibility).mockImplementationOnce(...)
(or the Vitest equivalent) in each test that currently calls mockImplementation
(the spots referencing validateEnsIndexerPublicConfigCompatibility around the
failing tests) so each test receives a single-use implementation and does not
affect subsequent tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.test.ts`:
- Around line 84-86: The tests set persistent mocks for
validateEnsIndexerPublicConfigCompatibility using
vi.mocked(...).mockImplementation(...), which can leak between tests; change
those to one-shot mocks by using
vi.mocked(validateEnsIndexerPublicConfigCompatibility).mockImplementationOnce(...)
(or the Vitest equivalent) in each test that currently calls mockImplementation
(the spots referencing validateEnsIndexerPublicConfigCompatibility around the
failing tests) so each test receives a single-use implementation and does not
affect subsequent tests.

In `@packages/ponder-sdk/src/deserialize/ponder-app-context.ts`:
- Around line 57-64: The code currently calls
schemaRawPonderAppContext.transform(buildUnvalidatedPonderAppContext).pipe(schemaPonderAppContext).safeParse(unvalidatedRawPonderAppContext)
and then throws on validation failure; replace this fail-fast path with a direct
.parse(...) so it throws automatically: call
schemaRawPonderAppContext.transform(buildUnvalidatedPonderAppContext).pipe(schemaPonderAppContext).parse(unvalidatedRawPonderAppContext)
and remove the manual success check/throw (retain the prettifyError helper only
if still needed elsewhere) so the function fails fast using Zod's built-in
exception.
- Around line 33-38: Remove the redundant JSDoc `@returns` tags that merely repeat
the summary: in the JSDoc for the buildUnvalidatedPonderAppContext block (the
comment starting "Build unvalidated Ponder App Context" that references
rawPonderAppContext and {`@link` schemaPonderAppContext}) and the other affected
JSDoc block around lines 47–52; keep the summary and `@param` tags but delete the
`@returns` lines so the documentation follows the project's guideline against
restating the method summary.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1eddb9b1-e009-4552-a28f-72f2b2b07bb1

📥 Commits

Reviewing files that changed from the base of the PR and between 9811b95 and 326f9a4.

📒 Files selected for processing (6)
  • .changeset/better-bats-switch.md
  • .changeset/old-seals-draw.md
  • apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts
  • apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.test.ts
  • apps/ensindexer/types/env.d.ts
  • packages/ponder-sdk/src/deserialize/ponder-app-context.ts

Copilot AI review requested due to automatic review settings March 22, 2026 11:18
@tk-o tk-o force-pushed the feat/ensdb-writer-worker-dev-mode-validation-skip branch from 326f9a4 to 64db38d Compare March 22, 2026 11:18
@vercel vercel bot temporarily deployed to Preview – ensnode.io March 22, 2026 11:18 Inactive
@vercel vercel bot temporarily deployed to Preview – admin.ensnode.io March 22, 2026 11:18 Inactive
@vercel vercel bot temporarily deployed to Preview – ensrainbow.io March 22, 2026 11:18 Inactive
@tk-o
Copy link
Contributor Author

tk-o commented Mar 22, 2026

@greptile review

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 16 out of 17 changed files in this pull request and generated no new comments.


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

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

Inline comments:
In `@apps/ensindexer/types/env.d.ts`:
- Around line 8-13: The file documents PONDER_COMMON but not ProcessEnv; make
comments consistent by adding a short JSDoc comment for the ProcessEnv
declaration (or alternatively remove the PONDER_COMMON block if you prefer
minimal docs). Locate the ProcessEnv type declaration and add a concise comment
describing it (e.g., "Node process env interface" or similar) to match the
existing PONDER_COMMON comment style, ensuring both declarations have equivalent
comment coverage and formatting.
🪄 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: 70618e04-0a09-4fc7-99b6-71a42fe3f23a

📥 Commits

Reviewing files that changed from the base of the PR and between 326f9a4 and 64db38d.

📒 Files selected for processing (2)
  • apps/ensindexer/src/lib/local-ponder-client.ts
  • apps/ensindexer/types/env.d.ts

Comment on lines +8 to +13
/**
* Global variable injected by Ponder at runtime,
* containing internal context of the local Ponder app.
*
* @see https://github.com/ponder-sh/ponder/blob/6fcc15d4234e43862cb6e21c05f3c57f4c2f7464/packages/core/src/internal/common.ts#L7-L15
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Keep declaration comments consistent within this file.

Only PONDER_COMMON is documented while ProcessEnv is not; please normalize comment coverage for consistency (either add a short comment for ProcessEnv or simplify this block).

♻️ Minimal consistency fix (example)
 declare global {
   namespace NodeJS {
+    // Runtime environment variables validated by "@/config/environment".
     interface ProcessEnv extends ENSIndexerEnvironment {}
   }

As per coding guidelines: "Maintain comment consistency within a file; address inconsistency if most declarations lack comments but one has them."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Global variable injected by Ponder at runtime,
* containing internal context of the local Ponder app.
*
* @see https://github.com/ponder-sh/ponder/blob/6fcc15d4234e43862cb6e21c05f3c57f4c2f7464/packages/core/src/internal/common.ts#L7-L15
*/
declare global {
namespace NodeJS {
// Runtime environment variables validated by "@/config/environment".
interface ProcessEnv extends ENSIndexerEnvironment {}
}
/**
* Global variable injected by Ponder at runtime,
* containing internal context of the local Ponder app.
*
* `@see` https://github.com/ponder-sh/ponder/blob/6fcc15d4234e43862cb6e21c05f3c57f4c2f7464/packages/core/src/internal/common.ts#L7-L15
*/
const PONDER_COMMON: PonderCommonType;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ensindexer/types/env.d.ts` around lines 8 - 13, The file documents
PONDER_COMMON but not ProcessEnv; make comments consistent by adding a short
JSDoc comment for the ProcessEnv declaration (or alternatively remove the
PONDER_COMMON block if you prefer minimal docs). Locate the ProcessEnv type
declaration and add a concise comment describing it (e.g., "Node process env
interface" or similar) to match the existing PONDER_COMMON comment style,
ensuring both declarations have equivalent comment coverage and formatting.

@tk-o tk-o force-pushed the feat/ensdb-writer-worker-dev-mode-validation-skip branch from 64db38d to 6a85c84 Compare March 22, 2026 13:11
@vercel vercel bot temporarily deployed to Preview – ensrainbow.io March 22, 2026 13:11 Inactive
@vercel vercel bot temporarily deployed to Preview – ensnode.io March 22, 2026 13:11 Inactive
@vercel vercel bot temporarily deployed to Preview – admin.ensnode.io March 22, 2026 13:11 Inactive
@tk-o
Copy link
Contributor Author

tk-o commented Mar 22, 2026

@greptile review

@tk-o tk-o marked this pull request as ready for review March 22, 2026 13:18
Copilot AI review requested due to automatic review settings March 22, 2026 13:18
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 16 out of 17 changed files in this pull request and generated 3 comments.


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

Comment on lines +195 to +199
// if the stored one is available.
// The validation is skipped if the local Ponder app is running in dev mode.
// This is to improve the development experience during ENSIndexer
// development, by allowing to override the stored config in ENSDb with
// the current in-memory config, without having to keep them compatible.
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

The method-level docs above say compatibility validation runs whenever a stored config exists, but the implementation now skips validation in dev mode. Please update the docstring/@throws description to reflect the new behavior (i.e., validation is conditional on both storedConfig and not being in dev mode).

Suggested change
// if the stored one is available.
// The validation is skipped if the local Ponder app is running in dev mode.
// This is to improve the development experience during ENSIndexer
// development, by allowing to override the stored config in ENSDb with
// the current in-memory config, without having to keep them compatible.
// if the stored one is available and the local Ponder app is not running
// in dev mode.
// The validation is intentionally skipped in dev mode to improve the
// development experience during ENSIndexer development, by allowing
// overriding the stored config in ENSDb with the current in-memory config
// without having to keep them compatible.

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

Choose a reason for hiding this comment

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

Thanks, will update the docs.

@tk-o tk-o force-pushed the feat/ensdb-writer-worker-dev-mode-validation-skip branch from 6a85c84 to 2ad57bd Compare March 22, 2026 16:22
@vercel vercel bot temporarily deployed to Preview – ensrainbow.io March 22, 2026 16:22 Inactive
@vercel vercel bot temporarily deployed to Preview – admin.ensnode.io March 22, 2026 16:22 Inactive
@vercel vercel bot temporarily deployed to Preview – ensnode.io March 22, 2026 16:22 Inactive
Copy link
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

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

Additional Suggestion:

JSDoc @throws documentation for run() method does not reflect that config validation is skipped in dev mode

Fix on Vercel

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

♻️ Duplicate comments (3)
apps/ensindexer/types/env.d.ts (1)

8-11: 🧹 Nitpick | 🔵 Trivial

Keep the declaration comments consistent within this file.

Only PONDER_COMMON is documented right now. Please either add a matching short comment for NodeJS.ProcessEnv or drop this block.

🧹 Minimal consistency fix
 declare global {
   namespace NodeJS {
+    /** Runtime environment variables validated by "@/config/environment". */
     interface ProcessEnv extends ENSIndexerEnvironment {}
   }
   /**
    * The "raw" context of the local Ponder app.

As per coding guidelines "Maintain comment consistency within a file; address inconsistency if most declarations lack comments but one has them".

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

In `@apps/ensindexer/types/env.d.ts` around lines 8 - 11, The file has an
inconsistent doc comment for PONDER_COMMON while NodeJS.ProcessEnv is
undocumented; either add a matching short comment above the NodeJS.ProcessEnv
declaration or remove the comment block for PONDER_COMMON so both declarations
match; locate the declarations for PONDER_COMMON and NodeJS.ProcessEnv in the
env.d.ts types and update the comments accordingly to keep them consistent.
packages/ponder-sdk/src/deserialize/ponder-app-context.ts (2)

63-75: 🛠️ Refactor suggestion | 🟠 Major

Use parse() for this fail-fast deserializer.

This path always throws on invalid input, so safeParse() only adds manual branching that the caller never uses.

♻️ Proposed change
-import { prettifyError, z } from "zod/v4";
+import { z } from "zod/v4";
@@
 export function deserializePonderAppContext(
   unvalidatedRawPonderAppContext: Unvalidated<RawPonderAppContext>,
 ): PonderAppContext {
-  const validation = schemaRawPonderAppContext
+  return schemaRawPonderAppContext
     .transform(buildUnvalidatedPonderAppContext)
     .pipe(schemaPonderAppContext)
-    .safeParse(unvalidatedRawPonderAppContext);
-
-  if (!validation.success) {
-    throw new Error(`Invalid raw Ponder App Context: ${prettifyError(validation.error)}`);
-  }
-
-  return validation.data;
+    .parse(unvalidatedRawPonderAppContext);
 }

Run this to confirm the function is using a fail-fast path and compare it with sibling deserializers:

#!/bin/bash
sed -n '63,76p' packages/ponder-sdk/src/deserialize/ponder-app-context.ts
rg -n --type=ts 'safeParse\(|\.parse\(' packages/ponder-sdk/src/deserialize

As per coding guidelines "Use zod.parse(...) for fail-fast validation in non-API code; use zod.safeParse(...) when you need non-throwing branch for optional or fallback values".

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

In `@packages/ponder-sdk/src/deserialize/ponder-app-context.ts` around lines 63 -
75, Replace the non-fail-fast safeParse branch in deserializePonderAppContext
with a direct fail-fast parse: call the transformed schema
(schemaRawPonderAppContext.transform(buildUnvalidatedPonderAppContext).pipe(schemaPonderAppContext))
using parse(...) instead of safeParse(...), remove the manual if
(!validation.success) branching and the prettified error handling, and let
parse() throw on invalid input so the function returns validation.data directly;
reference the symbols deserializePonderAppContext, schemaRawPonderAppContext,
buildUnvalidatedPonderAppContext, and schemaPonderAppContext to locate the
change.

41-47: 🧹 Nitpick | 🔵 Trivial

Drop the redundant @returns tags.

Both tags restate the summaries and add noise to the new docs.

As per coding guidelines "Do not add JSDoc @returns tags that merely restate the method summary; remove redundant comments during PR review".

Also applies to: 56-61

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

In `@packages/ponder-sdk/src/deserialize/ponder-app-context.ts` around lines 41 -
47, Remove the redundant JSDoc `@returns` tags that merely restate the summary in
the Ponder App Context builders: delete the duplicate `@returns` entries in the
JSDoc for the "Build unvalidated Ponder App Context" comment block and the
similar block at lines 56-61 so only the summary and useful param/throws tags
remain; locate the JSDoc around the function that mentions
schemaPonderAppContext (the build/unvalidated context function) and remove the
extra `@returns` annotations.
🤖 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/lib/ensdb-writer-worker/ensdb-writer-worker.ts`:
- Around line 147-156: The dev-mode bypass that skips config compatibility
validation in the function that loads/validates ENSDb config (look for the logic
around the dev-mode check in ensure/validate or the method that fetches stored
and in-memory configs) must be gated to avoid accidental overwrites of shared
ENSDb: require an explicit opt-in environment variable (e.g.,
ALLOW_DEV_MODE_CONFIG_OVERRIDE=true) before skipping validation, and
additionally verify the DATABASE_URL refers to a local/disposable target (reject
if it looks like a production/staging host) unless the opt-in is present; update
the conditional that currently short-circuits validation in dev mode to check
both the env opt-in and a local-DB pattern, and throw an error when dev-mode
bypass is requested without the opt-in or when DATABASE_URL is non-local so the
stored config cannot be silently overwritten.

---

Duplicate comments:
In `@apps/ensindexer/types/env.d.ts`:
- Around line 8-11: The file has an inconsistent doc comment for PONDER_COMMON
while NodeJS.ProcessEnv is undocumented; either add a matching short comment
above the NodeJS.ProcessEnv declaration or remove the comment block for
PONDER_COMMON so both declarations match; locate the declarations for
PONDER_COMMON and NodeJS.ProcessEnv in the env.d.ts types and update the
comments accordingly to keep them consistent.

In `@packages/ponder-sdk/src/deserialize/ponder-app-context.ts`:
- Around line 63-75: Replace the non-fail-fast safeParse branch in
deserializePonderAppContext with a direct fail-fast parse: call the transformed
schema
(schemaRawPonderAppContext.transform(buildUnvalidatedPonderAppContext).pipe(schemaPonderAppContext))
using parse(...) instead of safeParse(...), remove the manual if
(!validation.success) branching and the prettified error handling, and let
parse() throw on invalid input so the function returns validation.data directly;
reference the symbols deserializePonderAppContext, schemaRawPonderAppContext,
buildUnvalidatedPonderAppContext, and schemaPonderAppContext to locate the
change.
- Around line 41-47: Remove the redundant JSDoc `@returns` tags that merely
restate the summary in the Ponder App Context builders: delete the duplicate
`@returns` entries in the JSDoc for the "Build unvalidated Ponder App Context"
comment block and the similar block at lines 56-61 so only the summary and
useful param/throws tags remain; locate the JSDoc around the function that
mentions schemaPonderAppContext (the build/unvalidated context function) and
remove the extra `@returns` annotations.
🪄 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: cb52e173-d57d-4e82-8fd4-d39aca3a0268

📥 Commits

Reviewing files that changed from the base of the PR and between 6a85c84 and 2ad57bd.

📒 Files selected for processing (5)
  • apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.ts
  • apps/ensindexer/src/lib/local-ponder-client.ts
  • apps/ensindexer/types/env.d.ts
  • packages/ponder-sdk/src/deserialize/indexing-metrics.ts
  • packages/ponder-sdk/src/deserialize/ponder-app-context.ts

@tk-o tk-o merged commit 410f937 into main Mar 22, 2026
18 checks passed
@tk-o tk-o deleted the feat/ensdb-writer-worker-dev-mode-validation-skip branch March 22, 2026 20:37
@github-actions github-actions bot mentioned this pull request Mar 22, 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