Skip to main content

Anatomy of a search

Search is a single, non-generative round trip. No language model writes the answer, which is why it returns in a fraction of the time a chat turn takes.

Trace how every matcher consumes current authorization before Search can rank or project a row.

1 · Resolve the requester​

The request arrives at POST /api/search with a validated identity envelope. Kaizen resolves the member, their verified email as the document-ACL principal, their workroom, and the selected Search agent — which contributes retrieval parameters, not authority.

A selected scope (a collection, a Project filter) can only narrow the member's current access. It never widens it.

2 · Prepare the query​

Two optional preparation steps run within their own latency budgets:

  • Query expansion rewrites the query into useful variants. Off by default.
  • Query embedding produces the vector for the semantic branch, under an interactive latency budget kept separate from the worker's bulk embedding budget.

If embedding exceeds its budget, the lexical branches still answer. Search degrades rather than failing.

Every branch stops waiting for the query embedding at the embedding budget or at half the per-branch ceiling, whichever comes first, and then degrades rather than coming back empty. Uploaded documents and chat history answer from their lexical indexes. Connector documents have no lexical path of their own: without an embedding they fall back to a fuzzy title match, and only when the query carries no facet or date filter; with a filter, that branch contributes nothing to the answer.

The per-branch ceiling cancels a branch outright, including any fallback still pending inside it, which is why a slow embedding must never consume the whole branch. The model gateway enforces the embedding budget itself, so a timed-out query embedding is audited like any other failed model call; the branch only abandons the call itself, shortly after that budget, if the gateway overruns it. That matters most while documents are still being dense-indexed, when query embeddings compete with ingestion for the same embedding deployment.

note

The bound covers the embedding wait only. An embedding that arrives just inside it still leaves the semantic query to finish before the branch ceiling; a vector index slow enough to run past the ceiling is cancelled, and Search then answers partially for that branch.

3 · Retrieve, inside the authorization relation​

This is the step that matters most.

Kaizen does not retrieve candidates and then filter them. Current workroom, owner, direct, Project access, and Project lifecycle checks live inside the PostgreSQL query, and every branch must consume that relation before it emits anything:

BranchWhat it is
BM25Strong term relevance, when the text-search substrate is available
GIN full-textThe built-in PostgreSQL lexical fallback
HNSW vectorBounded semantic candidate discovery, in indexed mode
Exact vector distanceThe authorization oracle and the indexed-retrieval rollback mode
FuzzyAn optional fallback for near-miss terms

Branch output, fusion, snippets, facets, counts, cache writes, API projection, audit detail, and model context all consume authorized survivors only. Raw candidate IDs and text never cross into application code.

The documented HNSW nuance​

PostgreSQL's HNSW access method can inspect index rows before relational filters are fully applied. Those rows may influence internal index traversal, so Kaizen does not describe the method as authorization-prefiltered.

Instead, each indexed branch joins the full current authorization relation inside PostgreSQL, uses bounded transaction-local iterative-scan settings, and exposes only authorized survivors. Exact reranking consumes only those survivors too.

With indexed retrieval disabled, Kaizen materializes the complete eligible relation first and then performs lexical scoring and exact vector distance, without traversing the protected indexes at all.

4 · Fuse and rerank​

Authorized lexical and semantic survivors are combined with deterministic reciprocal-rank fusion. Determinism matters: it is what stops a library filter and the Search page from disagreeing about the same corpus.

An administrator can optionally select a Kamiwaza reranker deployment to reorder ACL-visible document evidence. With no reranker selected, Kaizen keeps the fused order and makes no reranking call — there is no silent default.

5 · Project the result​

Snippets, facets, counts, and journal anchors are produced only from the final authorized projection.

Results carry a type distinction that survives into Chat:

  • document and uploaded-document hits carry evidence authority — they can be cited as fact;
  • chat and Project hits carry navigation authority — they help you find prior work but never enter the citation ledger merely because they matched.

6 · Return, and re-check on use​

Result cards are disposable projections, not capabilities. Opening an anchor re-authorizes it. A stale card or a copied URL cannot preserve a revoked grant — Kaizen returns a generic unavailable state without revealing what changed.

If one independent provider is unavailable, the response is labeled partial and returns what the others authorized, rather than failing whole.

One pipeline, several callers​

The Search page, the Projects and Chats library filters, and every eligible agent's search and conversation_history_search tools use the same server-owned matching pipeline. Providers contribute documents, uploads, Projects, and chat history; one deterministic merge ranks the authorized projections.

That is deliberate. Two search implementations would eventually disagree, and the disagreement would be an access-control bug rather than a relevance bug.

Performance shape​

SettingDefaultEffect
SEARCH_DEFAULT_LIMIT10Results returned
SEARCH_POOL_SIZE50Candidate pool before fusion
SEARCH_MAX_PER_DOCUMENT3Caps one document dominating results
SEARCH_SNIPPET_CHARS280Snippet length
SEARCH_EMBED_LATENCY_BUDGET_SECONDS5.0Query-embedding ceiling, and never more than half the branch ceiling
SEARCH_BRANCH_LATENCY_BUDGET_SECONDS8.0Per-branch ceiling
HNSW_EF_SEARCH80Vector recall versus latency

See Scaling & performance for tuning these against a real corpus.