Skip to content

[WIP] Prep for ENSIndexer Build ID#1929

Draft
tk-o wants to merge 1 commit intomainfrom
feat/ensindexer-build-id
Draft

[WIP] Prep for ENSIndexer Build ID#1929
tk-o wants to merge 1 commit intomainfrom
feat/ensindexer-build-id

Conversation

@tk-o
Copy link
Copy Markdown
Member

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

Use file checksum including nested imports

Lite PR

Tip: Review docs on the ENSNode PR process

Summary

  • Created the fileChecksum helper to create a checksum for a file in ENSIndexer app. The checksum includes all nested imports required for the file.

Why

  • Ponder Build ID implements file checksum approach based on the literal contents of the file. This does not work well when the file includes only static re-exports, as the file contents won't change even if the re-exported objects changed.

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)

Use file checksum including nested imports
Copilot AI review requested due to automatic review settings April 14, 2026 19:07
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 14, 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 14, 2026 7:07pm
ensnode.io Skipped Skipped Apr 14, 2026 7:07pm
ensrainbow.io Skipped Skipped Apr 14, 2026 7:07pm

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 14, 2026

⚠️ No Changeset found

Latest commit: ccfb0bd

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 14, 2026

Warning

Rate limit exceeded

@tk-o has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 42 minutes and 43 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 42 minutes and 43 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f25647ec-7280-41d6-a052-87ae083798db

📥 Commits

Reviewing files that changed from the base of the PR and between 319d619 and ccfb0bd.

📒 Files selected for processing (2)
  • apps/ensindexer/src/lib/file-checksum.ts
  • apps/ensindexer/src/lib/indexing-engines/ponder.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ensindexer-build-id

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

Prepares ENSIndexer for a future “Build ID” by introducing a logical file checksum that includes nested TypeScript imports (to avoid missing changes hidden behind re-exports).

Changes:

  • Added a fileChecksum() helper that uses a TypeScript Program to gather transitive source dependencies and hash their contents.
  • Wired checksum computation into the Ponder indexing activation path (currently logging the per-file checksums; Build ID calculation is still TODO).

Reviewed changes

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

File Description
apps/ensindexer/src/lib/indexing-engines/ponder.ts Calls the checksum helper during activation and logs the results.
apps/ensindexer/src/lib/file-checksum.ts New helper to compute a checksum for an entrypoint including nested imports.

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

} from "ponder:registry";

import { waitForEnsRainbowToBeReady } from "@/lib/ensrainbow/singleton";
import { fileChecksum } from "@/ponder/logical-checksum";
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

Import path looks incorrect: @/ponder/logical-checksum doesn’t exist under apps/ensindexer/src (tsconfig @/* maps to ./src/*). This will fail typecheck/build. Import fileChecksum from the module you added (e.g. @/lib/file-checksum) or add the missing src/ponder/logical-checksum.ts file.

Suggested change
import { fileChecksum } from "@/ponder/logical-checksum";
import { fileChecksum } from "@/lib/file-checksum";

Copilot uses AI. Check for mistakes.
Comment on lines +181 to +185
console.log(`Logical checksum`, {
ponderConfig: ponderConfigChecksum,
ponderSchema: ponderSchemaChecksum,
ponderLogic: ponderLogicChecksum,
});
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

This console.log will run on every startup (once per process) and will bypass the app’s structured logger. Please switch to logger (and/or gate behind a debug flag) to avoid noisy stdout in production.

Suggested change
console.log(`Logical checksum`, {
ponderConfig: ponderConfigChecksum,
ponderSchema: ponderSchemaChecksum,
ponderLogic: ponderLogicChecksum,
});
if (process.env.DEBUG) {
console.log(`Logical checksum`, {
ponderConfig: ponderConfigChecksum,
ponderSchema: ponderSchemaChecksum,
ponderLogic: ponderLogicChecksum,
});
}

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +2
// src/lib/checksum.ts

Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

File header comment is misleading (// src/lib/checksum.ts) and doesn’t match the actual filename (file-checksum.ts). Please update or remove it to avoid confusion when navigating/searching.

Suggested change
// src/lib/checksum.ts

Copilot uses AI. Check for mistakes.
Comment on lines +6 to +8
import ts from "typescript";

import { logger } from "@/lib/logger";
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

fileChecksum imports typescript at runtime. In this package, typescript is currently a devDependency, so environments that install only production deps will crash when this code runs. Either move typescript to dependencies or change the implementation to avoid requiring the TypeScript compiler at runtime.

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +71
const tsSourceFiles = new Set<string>(allTsFiles);

if (tsSourceFiles.size === 0) {
throw new Error(`No source files found for entry point: ${entryPoint}`);
} else {
logger.info({
msg: "Files included in logic checksum",
entryPoint,
filesCount: tsSourceFiles.size,
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

Checksum depends on the iteration order of tsProgram.getSourceFiles(). That ordering is not part of a stable public contract, so the same project can produce different checksums across TS versions/OS, causing unnecessary Build ID churn. Sort the final file list (e.g. by normalized file path) before hashing to make the checksum deterministic.

Suggested change
const tsSourceFiles = new Set<string>(allTsFiles);
if (tsSourceFiles.size === 0) {
throw new Error(`No source files found for entry point: ${entryPoint}`);
} else {
logger.info({
msg: "Files included in logic checksum",
entryPoint,
filesCount: tsSourceFiles.size,
const tsSourceFiles = Array.from(
new Map(allTsFiles.map((file) => [file.replace(/\\/g, "/"), file])).entries(),
)
.sort(([normalizedFileA], [normalizedFileB]) => normalizedFileA.localeCompare(normalizedFileB))
.map(([, file]) => file);
if (tsSourceFiles.length === 0) {
throw new Error(`No source files found for entry point: ${entryPoint}`);
} else {
logger.info({
msg: "Files included in logic checksum",
entryPoint,
filesCount: tsSourceFiles.length,

Copilot uses AI. Check for mistakes.

for (const file of tsSourceFiles) {
const content = ts.sys.readFile(file);
if (content) hash.update(content);
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

If ts.sys.readFile(file) returns undefined (permissions/race/missing file), the current code silently skips that file, producing a checksum that no longer represents the full dependency set. It’s safer to throw (or at least log+fail) when any expected source file can’t be read.

Suggested change
if (content) hash.update(content);
if (content === undefined) {
throw new Error(`Failed to read source file for checksum: ${file}`);
}
hash.update(content);

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +52
export function fileChecksum(entryPoint: string, tsConfigPath: string = "tsconfig.json"): string {
const root = process.cwd();
const resolvedEntry = resolve(root, entryPoint);

logger.info({
msg: "Computing entrypoint checksum",
entryPoint,
resolvedEntry,
});

// Read tsconfig
const tsConfigFile = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
if (tsConfigFile.error) {
throw new Error(`Failed to read tsconfig: ${tsConfigPath}`);
}

const parsedTsConfig = ts.parseJsonConfigFileContent(
tsConfigFile.config,
ts.sys,
root,
undefined,
tsConfigPath,
);

const tsProgram = ts.createProgram([resolvedEntry], parsedTsConfig.options);
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

New helper has non-trivial behavior (nested import resolution + hashing) but no tests. Adding a file-checksum.test.ts with small fixture files would help lock in: (1) checksum changes when an imported file changes (even if entrypoint is only a re-export), and (2) determinism across runs.

Copilot uses AI. Check for mistakes.
} from "ponder:registry";

import { waitForEnsRainbowToBeReady } from "@/lib/ensrainbow/singleton";
import { fileChecksum } from "@/ponder/logical-checksum";
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
import { fileChecksum } from "@/ponder/logical-checksum";
import { fileChecksum } from "@/lib/file-checksum";

Import path is incorrect: trying to import from @/ponder/logical-checksum but the file is actually at @/lib/file-checksum

Fix on Vercel


const hash = createHash("sha256");

for (const file of tsSourceFiles) {
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
for (const file of tsSourceFiles) {
// Sort files to ensure deterministic hash output across different runs and machines
const sortedFiles = Array.from(tsSourceFiles).sort();
for (const file of sortedFiles) {

File checksum for Build ID is non-deterministic due to unsorted iteration over TypeScript source files returned by compiler

Fix on Vercel

Copy link
Copy Markdown
Member

@shrugs shrugs left a comment

Choose a reason for hiding this comment

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

cool! surface level read looks good to me. i don't have any expertise with ts meta stuff, so claude's probably more informed than i am

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