Skip to content

Epic: RAG retrieval layer — /embed + pgvector store + actor-scoped similarity search #125

Description

@qiuethan

Blocked by

No response

Summary

The helper-bot epic (#81) is meant to answer questions grounded in our docs via RAG. Content acquisition (#82) covers getting the text; nothing else on the board covers turning that text into retrievable vectors and querying them. This epic is the retrieval layer that sits between #82 and #81.

This body replaces the original scope. Four things were wrong with it:

  1. It delivered nothing anyone could use. All six sub-issues were plumbing, so the epic could complete in full and no member would notice — value only appeared once Epic: Member-facing helper bot (LLM-backed, docs-grounded Q&A) #81 wired it up. A /doc search surface is now the last step, so the epic lands something members use and Epic: Member-facing helper bot (LLM-backed, docs-grounded Q&A) #81 becomes "make it conversational" rather than "make it exist."
  2. Nothing triggered indexing. "Re-index on change" had no caller: this platform has no scheduler, no queue, and no background worker anywhere, and docs/ARCHITECTURE.md rules out running one inside a source of truth. Resolved in the Model below.
  3. Model changes had no owner. RAG: pgvector store + embeddings schema (documentation-system) #174 records the embedding model per row "so a model change is detectable", but no issue said what happens when it is detected. Re-embedding is both a migration and a Bedrock cost event.
  4. Two blocking design questions sat in prose. Chunk size/overlap and hybrid-vs-pure-vector are decisions the pipeline gets built on top of, so they move to a spike that runs first and produces an answer.

#176 and #177 are merged. Visibility filtering has to happen inside the retrieval query rather than after ranking, so "build the query" and "filter the query" are not separable pieces of work — split either way round, one of them is unstartable. They become one issue whose acceptance includes the authorization tests, and #177 is closed as superseded.

Model

Four stages, each independently testable: decide (spike the chunking and search strategy against real catalogued content), embed (LLM service gains /embed), index (chunk + upsert into pgvector on documentation-system), retrieve (top-k similarity search, actor-scoped and citable, in one endpoint) — then a thin surface so the capability is visible to members.

Two constraints govern the shape:

  • Retrieval is an authorization boundary. The LLM is not a trust boundary. A user must never retrieve a chunk from a document they cannot read, regardless of how the question is phrased. Filtering happens in the query, not after ranking — otherwise top-k is computed over documents the user cannot see and returns fewer results than it should. This is why retrieval and visibility are a single issue rather than two.
  • Nothing runs inside a source of truth. Indexing is triggered by the ingest path that already exists in src/ingest.py — which is already fetching content at that point — plus an explicit authenticated admin re-index endpoint for backfill and repair. No job runner lives inside the catalog, so this stays consistent with the API-only principle rather than becoming an exception to it.

Index catalog entities, not URL-documents. The pipeline keys on whatever the catalog holds, not on the URL-fetch path that happens to populate it today. Meeting records are coming (see the meeting-knowledge epic) and will be catalogued entities with no source URL. A pipeline written around URL-fetched docs silently excludes them, and that gets discovered months later when the helper bot cannot answer a question about a decision the org definitely made.

Corpus reality: only the Google connector is built — services/connectors/src/sources/ holds google.py and nothing else. Notion (#85) and GitHub (#86) widen the corpus but are not required to start.

Decomposition (build order)

Area

service, docs-system, bot

What we can build on

Not in this epic

Open questions

  • Should the relevance floor be absolute or relative to the top hit? An absolute threshold behaves badly across differently-sized corpora.
  • Does /doc search respect the same visibility rules as /doc list, or is search deliberately narrower to start?

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/botDiscord botarea/docs-systemdocumentation-system service & content pipelinearea/serviceBackend API services (generic/cross-cutting)epicContainer issue; progress tracked via sub-issuestype/featureNew capability or enhancement

    Type

    No type

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions