refactor(search): address PR #750 round 2 review feedback

Implements fire-and-forget eviction (ADR-019 §"Lazy eviction"): the
search response no longer waits on Qdrant deletes, instead spawning
evict() on a long-lived lifespan-owned task group. Falls back to inline
eviction in modes without vector sync and in unit tests.

Also: harden _verify_news_items against non-numeric ids (fail open
instead of crashing the verifier); document the get_file_info None-on-404
contract; add INDEXED_DOC_TYPES single source of truth in vector/scanner.py
referenced by the CI-guard test; write a Verify-on-Read Latency Budget
section in docs/configuration.md covering the unbounded news.get_items
fetch. Closes the two remaining ADR-019 implementation checklist items.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-05-01 18:53:32 +02:00
co-authored by Claude Opus 4.7
parent 7784ec02d7
commit 21e5608a39
7 changed files with 195 additions and 26 deletions
+11 -2
View File
@@ -156,8 +156,17 @@ def configure_semantic_tools(mcp: FastMCP):
# BEFORE trimming to `limit`, so we don't lose accessible results
# to the limit slot that ghosts would otherwise occupy. We also
# run this BEFORE context expansion to avoid re-fetching docs that
# are about to be dropped.
verified_results = await verify_search_results(client, all_results)
# are about to be dropped. Pass the lifespan-owned task group so
# eviction of dropped points is fire-and-forget (does not block
# the response).
eviction_task_group = getattr(
ctx.request_context.lifespan_context, "eviction_task_group", None
)
verified_results = await verify_search_results(
client,
all_results,
eviction_task_group=eviction_task_group,
)
search_results = verified_results[:limit]
# Convert SearchResult objects to SemanticSearchResult for response