Skip to content

fix(knowledge): keep vector candidate selection bounded - #7960

Merged
waleedlatif1 merged 2 commits into
stagingfrom
fix/bounded-vector-candidates
Sep 18, 2026
Merged

waleedlatif1 merged 2 commits into
stagingfrom
fix/bounded-vector-candidates

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • The bounded ANN traversal is now the entire vector candidate set. When visibility filters enough neighbours that it cannot fill its limit, it yields fewer candidates instead of widening the search
  • Removes the exhaustive fallback, which rescored every chunk in the projection and joined the visible document set to it. That path is O(corpus) and is what made the vector leg exceed its budget
  • vectorCandidateScan now reports planned or underfilled, so a reduced rerank pool is visible in diagnostics rather than silent. vectorInitialCandidateCount is dropped with the CTE that produced it

Why, with measurements

Every organization-scoped search was timing out on the vector leg and returning no vector results at all. Instrumentation traced it to the candidate CTE, and the plans explain it. All figures below are EXPLAIN (ANALYZE, BUFFERS) on the same search index, where visibility admitted a tenth of the corpus:

approach time why
Exhaustive rescan (removed) 1,931ms sequential scan of every chunk, distance per row, spills to disk
Deeper scan (max_scan_tuples 1k→20k) 5,103ms / 9,654ms consecutive identical runs; iterative scan degrades sharply with depth
Join visibility before scoring 8,363ms turns a sequential scan into a random index lookup per document
Bounded traversal (kept) ~115ms fills 640 in ~500ms, or underfills cheaply

The rescan was already the best of the widening strategies, which is the point: no widening strategy is affordable. On a corpus an order of magnitude larger it runs well past the retrieval budget, and a leg that exceeds its budget contributes nothing — so fewer candidates strictly beats every alternative measured.

This also matches the documented failure mode for filtered ANN search: post-filtering that escalates to progressively larger scans is known to produce unpredictable latency, and the exhaustive variant is its degenerate case.

Trade-off

Recall is lower when visibility is selective enough to underfill the traversal, because the rerank pool is smaller. It is strictly higher than the current behaviour, which returns an empty vector leg once the budget is exceeded. Authorization is unchanged — the same visibility predicate still gates every candidate, and the surviving query keeps the live-source conditions.

Type of Change

  • Bug fix

Testing

Query plans measured on a real corpus for each alternative above. Unit test rewritten to assert the underfilled traversal is kept rather than widened, and that the candidate query contains no UNION ALL or filtered_scores. Lint, check:audits (46 audits), docs-manifest:check, block-registry check, and type-check pass; knowledge suites pass (2,921 tests).

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

An underfilled ANN traversal rescored the whole compact projection and joined the
visible document set to it. That fallback is O(corpus): on a 132k-chunk index it
took 1.9s, and on a corpus an order of magnitude larger it exceeds the retrieval
budget, so the vector leg returned nothing at all rather than fewer rows.

Widening the search has no affordable form here. Measured at 10% visibility on the
same index, scanning 6.5k tuples instead of 1.5k took 5.1s and 9.7s on consecutive
identical runs, and joining visibility before scoring took 8.4s because it turns a
sequential scan into a random lookup per document. The bounded traversal itself
costs ~115ms whether or not it fills.

The traversal is now the whole candidate set. An underfilled one yields fewer
candidates and is reported as such, which strictly beats a leg that times out.
@vercel

vercel Bot commented Sep 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Sep 18, 2026 4:24am UTC

Request Review

@cubic-dev-ai cubic-dev-ai Bot 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.

No issues found across 4 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Re-trigger cubic

@greptile-apps

greptile-apps Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge, with no outstanding correctness, security, or repository-rule issues identified.

Summary

This PR keeps vector candidate selection within a bounded ANN traversal instead of widening an underfilled search into a corpus-wide rescan.

  • Removes the exhaustive filtered-projection fallback and reranks only candidates returned by the bounded traversal.
  • Reports underfilled candidate pools through updated diagnostics.
  • Updates unit and latency integration coverage to recognize and validate the new query plan.
  • Fixes both previously reported issues: the latency assertions now target the current plan, and the scan documentation describes the underfill policy.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Start vector retrieval] --> B[Bounded HNSW traversal]
    B --> C[Apply document visibility and tag checks]
    C --> D{Candidate limit filled?}
    D -->|Yes| E[Report planned scan]
    D -->|No| F[Report underfilled scan]
    E --> G[Rerank bounded candidates]
    F --> G
    G --> H[Return authorized vector results]
Loading

Reviews (2) · Last reviewed commit: "fix(knowledge): match the latency plan a..."

Comment thread apps/sim/lib/knowledge/search/queries.ts
Comment thread apps/sim/lib/knowledge/search/queries.ts
…ersal

The plan assertion still required the removed CTEs, and the predicates selecting
which captured query to assert against matched the old CTE name with a lowercase
fallback the rendered statement never produces. The candidate assertions would
have stopped running rather than failing, so they now key on the visibility
lateral through one shared predicate.

The plan check drops the fallback-specific expectations and gains the one that
guards this change: the traversal must never reach the projection by document
lookup or sequential scan, at any candidate count.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot 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.

No issues found across 4 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Re-trigger cubic

@waleedlatif1
waleedlatif1 merged commit b0a68f2 into staging Sep 18, 2026
34 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/bounded-vector-candidates branch September 18, 2026 04:29
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.

1 participant