Skip to content

feat(retrieval): wire the cross-encoder reranker into the kb.context path (config-gated) #429

Description

@plind-junior

vouch already fuses lexical + semantic hits by reciprocal-rank fusion (embeddings/fusion.py:rrf_fuse, wired into context._retrieve) and already ships a cross-encoder reranker (embeddings/rerank.py: default_reranker, rerank). but the reranker is only reachable from one place — vouch search --rerank (cli.py). the context-pack path that actually feeds agents — context.build_context_pack_retrievekb.context — never reranks, and there's no config to turn it on. the highest-value read path is running fused-but-unranked while a finished reranker sits one import away.

this wires the existing reranker into _retrieve, behind a config flag, so kb.context benefits without changing its default behavior.

proposed surface

  • config under retrieval.rerank, read defensively like retrieval.reflex.*:
    • retrieval.rerank.enabled (default false — no behavior change until a kb opts in)
    • retrieval.rerank.top_k (rerank window; default = context limit)
  • in _retrieve, after rrf_fuse produces fused, when enabled, pass the fused hits through embeddings.rerank.rerank(query=..., hits=..., reranker=default_reranker(), top_k=...) before filter_hits. degrade gracefully to the fused order if the reranker extra isn't installed (the reranker is an optional embeddings dependency).
  • no new kb.* method — kb.context / kb.search gain the stage internally. the _meta surfacing (chore(deps-dev): update ruff requirement from >=0.6 to >=0.15.13 #8) can expose the rerank delta per hit.

review gate & scope

read-path ordering only — reranking changes how already-matched approved hits are ordered, never which artifacts are returned, and never touches stored knowledge, status, or lifecycle. no proposal, no kb.approve. it runs no LLM on the hot path (the cross-encoder is a local model, consistent with the existing --rerank behavior). defaults to disabled, so existing rankings are byte-identical until a kb opts in. scoring stays out of storage.py.

acceptance criteria

  • retrieval.rerank.enabled (default false) gates a rerank stage inside _retrieve after rrf_fuse.
  • with it on, kb.context results are reranked by the existing embeddings/rerank.py path; with it off, ordering is identical to today.
  • missing reranker extra degrades to fused order without error.
  • rerank changes ordering only, never membership; archived/superseded claims stay excluded as now.
  • tests/test_context.py covers on/off parity and the graceful-degrade path.
  • make check green.

related: #317 (recency/frequency signals in the same rerank step), #92 (backend config honoring), #226 (eval harness to prove the lift), #8 (surface the rerank delta).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions