fix: PR #813 review — cap unified_search multi-type pool; document deck self-only

🟡 Performance: unified_search's _execute sorted but did not cap the merged
multi-doc_type pool, so N doc_types each fetched at search_limit sent
N*search_limit candidates into verify-on-read (one Nextcloud round-trip each).
Cap to search_limit*2 after the sort, matching vector_search, nc_semantic_search
and the viz_routes pattern — bounding verification cost to O(2*search_limit)
regardless of how many doc_types are requested.

🟡 Consistency: _get_deck_metadata_from_qdrant is the one internal Qdrant lookup
that uses a raw user_id filter instead of build_ownership_filter. This is not a
bug — deck cards are a documented cross-user gap (the Deck API is per-user, so
cross-user context can't be fetched with the caller's credentials) — but the
inconsistency was unexplained. Added a comment documenting the deliberate
self-only scope.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-05-29 17:49:21 +02:00
co-authored by Claude Opus 4.8
parent 063bd06ba6
commit 29500bea7e
2 changed files with 15 additions and 1 deletions
+7 -1
View File
@@ -190,7 +190,13 @@ async def _get_deck_metadata_from_qdrant(
qdrant_client = await get_qdrant_client()
settings = get_settings()
# Query for any chunk of this card (we just need metadata)
# Query for any chunk of this card (we just need metadata).
# Intentionally self-only (raw user_id, not build_ownership_filter):
# deck cards are a documented cross-user gap — the Deck API is per-user,
# so cross-user deck context can't be fetched with the caller's
# credentials anyway (see the doc_type=="file"-only gate in
# get_chunk_with_context). Every other internal Qdrant lookup here is
# ACL-aware; this one is the deliberate exception.
scroll_result = await qdrant_client.scroll(
collection_name=settings.get_collection_name(),
scroll_filter=Filter(