Skip to content

docs(adr): 0004 — Retriever contract (v1)#272

Open
EmersonBraun wants to merge 1 commit intomainfrom
foundation/adr-0004-retriever
Open

docs(adr): 0004 — Retriever contract (v1)#272
EmersonBraun wants to merge 1 commit intomainfrom
foundation/adr-0004-retriever

Conversation

@EmersonBraun
Copy link
Copy Markdown
Owner

Summary

Fourth ADR of Phase 0 — formalizes the Retriever contract: a single, narrow interface that serves RAG, BM25, hybrid search, web search, code search, and conversational memory recall through composition, not per-variant types.

Builds on #267 (Adapter), #270 (Tool), #271 (Memory).

Merge order: #267#270#271#272 (each rebase on main as merged; conflicts only on the ADR README index).

Highlight invariants

  • R1 Read-only — retrieval is observation, not transaction
  • R2 query vs messages — focused string + surrounding context; retrievers ignore what they don't need
  • R3 [] is success — empty results, not error
  • R4 Errors throw — intentional asymmetry vs Adapter (chunks) / Tool (status). Retrievers are called once per turn; chunked errors would be ceremony.
  • R6/R7 Optional but ordered scores — accommodates ranked + unranked backends without forcing fakes
  • R10 No per-call options — config at construction; preserves substitutability for composers
  • R11 Composition is transparent — composite retrievers satisfy R6/R7 even when fusing heterogeneous score scales

Key decision: indexing is NOT in the contract

RAG.ingest lives on the RAG type, not Retriever. This keeps Retriever substitutable across indexed (RAG over pgvector) and non-indexed (web search API) backends. Forcing an ingest method would either be a no-op for half the implementations or block them from satisfying the contract.

Trade-offs accepted

  • No per-call topK/threshold — must hold multiple configured retriever instances if needed (rare)
  • Score normalization is implementation burden for composite retrievers — known cost
  • No streaming retrieval — most consumers want full ranked list before reasoning; can be added if real use case emerges

Unlocks

Test plan

  • Doc renders on GitHub
  • ADR index updated
  • No code changes — pure documentation
  • Reviewer: does narrow single-method contract hold up against your imagined retrievers?
  • Reviewer: any case where R4 (throw, no sentinel) becomes painful?

Refs #214 #211

Single narrow contract — one method, one input, one output — that serves
RAG, BM25, hybrid search, web search, code search, and long-term memory
recall through composition rather than per-variant types.

11 invariants (R1-R11) covering:
- Read-only retrieval (R1)
- query as the question, messages as context (R2)
- Empty results are valid, not errors (R3)
- Errors throw — no sentinel values (R4) — intentional asymmetry vs Adapter/Tool
- Stable ids across calls (R5)
- Optional score: when present, descending sort (R6)
- Implementation-defined but consistent score scale (R7)
- No implicit per-call options (R10) — config at construction
- Composite retrievers must satisfy the contract (R11)

Indexing intentionally NOT in the contract — RAG.ingest lives on the
RAG type, not Retriever. This keeps Retriever substitutable across
indexed and non-indexed backends (web search has no ingest).

Unblocks #154 (RAG reranking), #155 (hybrid search), #172 (web search
tools), and any composite retriever pattern.

Refs #214
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