Skip to content

feat(server): kb.explain_ranking — expose why a result ranked where it did #432

Description

@plind-junior

_retrieve returns each hit as (kind, id, summary, score, backend) — one opaque score and a backend label. a reviewer tuning retrieval (fusion weights, the reranker in #5, the recency/frequency signals in #317) has no way to see why an artifact surfaced or got dropped: how much came from lexical vs. semantic rank, what the rrf contribution was, whether the reranker moved it, whether a gate (budget, uncited, status filter) cut it. the ranker is a black box exactly where it most needs to be inspectable.

this proposes a read-only kb.explain_ranking that returns the per-candidate breakdown behind a query.

proposed surface

vouch explain-ranking "<query>" [--limit N] [--format text|json]
# kb.explain_ranking over mcp/jsonl

per candidate, return: lexical rank (FTS5), semantic rank (embedding), the rrf contribution, the rerank delta when #5 is enabled, the recency/frequency factors when #317 is enabled, the salience factor, and the gate outcome (kept / budget-dropped / uncited / status-filtered). it re-runs the existing _retrieve pipeline in an instrumented mode rather than duplicating the scoring math.

four registration sites (server.py, jsonl_server.py, capabilities.py, cli.py) plus tests/test_explain_ranking.py. the corresponding UI panel belongs in the vouch-ui console, not src/vouch/web — this issue is the backend that feeds it.

review gate & scope

pure read-time introspection over the retrieval pipeline — no writes, no proposals, no kb.approve, no lifecycle change. it exposes only what kb.context already computes internally, viewer-scoped the same way, so it can't reveal artifacts a caller couldn't already retrieve. storage.py stays pure i/o; the instrumentation lives in the retrieval layer.

acceptance criteria

related: #5 (rerank — this explains its effect), #317 (recency/frequency signals to surface), #92 (backend config).

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

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