Skip to content

fix(workspace-search): repair wedged search indexing - #712

Closed
posthog[bot] wants to merge 1 commit into
mainfrom
posthog-self-driving/fixworkspaces-repair-search-indexing-f7b9b0
Closed

fix(workspace-search): repair wedged search indexing#712
posthog[bot] wants to merge 1 commit into
mainfrom
posthog-self-driving/fixworkspaces-repair-search-indexing-f7b9b0

Conversation

@posthog

@posthog posthog Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Problem

  • Hybrid workspace search (shipped in feat(workspaces): add hybrid workspace search #701) can wedge permanently for a workspace: newly added documents and files never become searchable, search silently returns stale results, and nothing surfaces the failure.
  • Root cause: kernel_search_vector_deletes is created with CREATE TABLE IF NOT EXISTS outside the version-reset drop set, because its rows reference vectors still live in Vectorize and must survive resets. A Durable Object whose table was created by an earlier iteration of the schema never gains the attempts columnIF NOT EXISTS is a no-op and the reset never touches it.
  • flushVectorDeletes is the first statement in WorkspaceSearchIndexer.processBatch and queries WHERE attempts < …, so an affected object throws SqlError: no such column: attempts on every alarm tick and dies before indexing a single item — forever, with no self-healing path.
  • Secondary: embedWorkspaceSearchTexts calls ai.run("@cf/baai/bge-m3", …) with no retry, so a single transient AiError: 3043 burns one of the five index attempts and opens a fresh error-tracking issue.

Changes

  • Real migration in initializeWorkspaceSearchStorage: PRAGMA table_info check, then ALTER TABLE kernel_search_vector_deletes ADD COLUMN attempts INTEGER NOT NULL DEFAULT 0 when absent. Chosen over moving the table into the reset drop set — a drop would discard queued deletes and orphan their vectors in Vectorize.
  • Bounded retry with backoff around ai.run: retryable AiErrors (3xxx internal, 5xx-class upstream) are retried in-process (4 attempts, exponential backoff capped at 2s); permanent client/validation codes fail fast. A transient hiccup no longer consumes an index attempt or pages anyone.

Note

Failed items are already visible via the lexical fallback — searchKeyword includes vector_status = 'failed' and getStatus reports partial — so exhausted items keep surfacing in keyword results rather than vanishing.

Tests

  • New workspace-search-embeddings.test.ts: retryable-vs-permanent classification, retry-then-succeed, attempt-budget exhaustion, and fail-fast on permanent errors.

Why

Restore a brand-new flagship surface (hybrid workspace search) that is silently, permanently broken for any affected workspace, with no client-visible error and no recovery short of a code fix.


Created with PostHog Desktop from this inbox report.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Review in cubic

Migrate the delete queue to add the `attempts` column when it predates the
schema, and retry transient Workers AI embedding errors in-process.

The delete queue survives version resets, so `CREATE TABLE IF NOT EXISTS`
never adds `attempts` to an object whose table was created earlier. flushVectorDeletes
is the first statement in processBatch and queries `WHERE attempts < ...`, so an
affected object throws "no such column: attempts" on every alarm tick and never
indexes anything. Add a pragma-guarded ALTER TABLE.

Also wrap ai.run in bounded retry with backoff for retryable AiErrors (3xxx
internal and 5xx-class upstream) so a transient hiccup like 3043 no longer burns
an index attempt or opens an error-tracking issue.

Generated-By: PostHog Code
Task-Id: 6c0075cb-ea15-438c-8391-1a37c875860b
@github-actions

Copy link
Copy Markdown

React Doctor found 1 new issue in 1 file · 1 warning · score 92 / 100 (Great) · 1 fixed · vs main

1 warning

src/features/workspaces/search/workspace-search-embeddings.ts

  • ⚠️ L21 await inside a loop async-await-in-loop

Reviewed by React Doctor for commit b42088e. See inline comments for fixes.

text: batch,
truncate_inputs: true,
});
const output = await runEmbeddingWithRetry(ai, batch, options);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/async-await-in-loop (warning)

This makes the for…of loop slow because each await runs one after another, so collect the independent calls & run them together with await Promise.all(items.map(...))

Fix → Collect the items, then use await Promise.all(items.map(...)) so independent work runs at the same time

Docs

@urjitc urjitc mentioned this pull request Aug 5, 2026
@urjitc

urjitc commented Aug 5, 2026

Copy link
Copy Markdown
Member

Closing as partially superseded and no longer suitable to merge as one PR. The critical kernel_search_vector_deletes.attempts migration already landed on main as a3cb6ca7. If Workers AI embedding retries are still needed based on current telemetry, they should return as a separate focused PR against current main.

@urjitc urjitc closed this Aug 5, 2026
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Dev Board Aug 5, 2026
@urjitc
urjitc deleted the posthog-self-driving/fixworkspaces-repair-search-indexing-f7b9b0 branch August 12, 2026 22:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant