Skip to content

Isolate per-file indexing failures instead of aborting the whole realm#5389

Draft
richardhjtan wants to merge 3 commits into
mainfrom
fix/index-runner-file-error-isolation
Draft

Isolate per-file indexing failures instead of aborting the whole realm#5389
richardhjtan wants to merge 3 commits into
mainfrom
fix/index-runner-file-error-isolation

Conversation

@richardhjtan

@richardhjtan richardhjtan commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Origin

Found while debugging the Virtual Piano App in the public catalog: its in-card song search showed "No Music Sheets found" when the app ran from the catalog realm, yet worked after remixing into a personal realm. First root cause: the local catalog realm's boxel_index was completely empty — its from-scratch reindex had gotten through 652 of 1166 files, hit one stuck prerender-visit request (a 120s abort on a listing-thumbnail PNG), and the whole job died, discarding all the already-indexed rows. The realm still mounted "successfully," so every search against it silently returned nothing. This PR fixes that all-or-nothing failure mode. (The same investigation surfaced a second, independent bug in how search results are hydrated for alias-prefixed realms, fixed in #5388.)

Summary

  • IndexRunner.tryToVisit rethrew any non-404 error from a file's visit (e.g. a prerender-visit timeout/abort), which unwound the entire fromScratch/incremental visit loop and skipped batch.done().
  • Since batch.done() is what promotes the working table into the live boxel_index, a single file's transport-level failure discarded every other already-successfully-indexed file in the same job — leaving the realm mounted but with an empty or stale search index, and no error surfaced anywhere.
  • The indexer already isolates per-file failures for in-band render errors (an error_doc row for just that card), but a transport-level failure — where no prerender response ever arrives — bypassed that model entirely and became all-or-nothing for the whole realm.
  • Fix: catch non-404 failures per file and record a file-error entry for that URL, mirroring the existing error_doc pattern, so the rest of the realm still indexes and commits.
  • Follow-up from review: Batch.invalidate() pre-tombstones every existing row type at a URL, so the file-error write alone would let an existing card's untouched instance tombstone be promoted — silently deleting a previously-good card from search over a transient error. The failed URL is re-checked and, when it's a card, an instance-error entry is written too, preserving the last-known-good instance the same way the in-band render-error path does.

Test plan

  • Regression test added (indexing-test.ts › per-file failure isolation): a wrapping Prerenderer throws an abort-style transport error for one armed URL; asserts the incremental job still commits (sibling card stays searchable), both the file and instance rows carry the error without being tombstoned, the instance keeps its last-known-good pristine_doc, and a later successful rewrite clears the error state
  • Red/green verified: with the fix reverted to main's version, exactly this test fails — the whole incremental-index job rejects with the injected transport error
  • Full indexing-test.ts run on the rebased branch: 62/62 pass
  • tsc --noEmit clean on changed files
  • Branch rebased onto latest main (clean; adapted comments to the visitFileForIndexing rename from the prerender-split refactor)

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6ae5858e07

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/runtime-common/index-runner.ts Outdated
@richardhjtan richardhjtan marked this pull request as draft July 2, 2026 14:14
@richardhjtan richardhjtan requested a review from Copilot July 2, 2026 14:14

Copilot AI left a comment

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.

Pull request overview

This PR makes realm indexing more robust by preventing a single file’s transport-level prerender/visit failure from aborting the entire indexing batch (and therefore preventing batch.done() from promoting the working index into the live boxel_index table).

Changes:

  • Updates IndexRunner.tryToVisit to treat non-404 visit failures as per-file failures by writing a persisted file-error index entry for the URL.
  • Ensures dependency-row cache invalidation and stats.fileErrors accounting happen on this new error path.

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

Comment thread packages/runtime-common/index-runner.ts
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Host Test Results

    1 files  ± 0      1 suites  ±0   2h 37m 44s ⏱️ + 17m 47s
3 469 tests +97  3 454 ✅ +97  15 💤 ±0  0 ❌ ±0 
3 488 runs  +97  3 473 ✅ +97  15 💤 ±0  0 ❌ ±0 

Results for commit caea2d7. ± Comparison against earlier commit 5e88b86.

Realm Server Test Results

    1 files  ±  0      1 suites  ±0   10m 46s ⏱️ + 1m 14s
1 817 tests +143  1 817 ✅ +143  0 💤 ±0  0 ❌ ±0 
1 896 runs  +143  1 896 ✅ +143  0 💤 ±0  0 ❌ ±0 

Results for commit caea2d7. ± Comparison against earlier commit 5e88b86.

tryToVisit rethrew any non-404 error from a file visit, which unwound
the entire fromScratch/incremental visit loop and skipped batch.done().
Since batch.done() is what promotes the working table into the live
boxel_index, a single file's transport-level failure (e.g. a prerender
timeout) discarded every other already-successfully-indexed file in
the same job, leaving the realm mounted with an empty or stale search
index and no error surfaced.

Catch non-404 errors per file and record a file-error entry for that
URL instead, mirroring the error_doc pattern already used for in-band
render errors, so the rest of the realm still indexes and commits.
Batch.invalidate() tombstones every existing type at a URL up front,
including the instance row for a previously-indexed card. The prior
commit's file-error entry only overwrote the file tombstone, so
batch.done() would promote the untouched instance tombstone and
silently remove an existing card from search over a transient error
(e.g. a prerender timeout) instead of preserving it with an error row
the way the in-band render-error path does.

Re-check whether the failed URL is a card and, if so, also write an
instance-error entry alongside the file-error one.
Injects a wrapping Prerenderer whose prerenderVisit throws an
abort-style transport error for one armed URL — the failure mode the
in-band error paths can't reach, since they all require a prerender
response to exist. Asserts that when an existing card's visit fails
this way, the incremental job still commits (a sibling card stays
searchable), the card's file and instance rows carry the error without
being tombstoned, the instance keeps its last-known-good pristine_doc,
and a later successful rewrite clears the error state.

Without the isolation fix this test fails with the whole
incremental-index job rejecting on the injected transport error.
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