fix(search): address PR #813 review (viz verify-on-read, owners cache, docs)

- viz_routes: run verify_search_results before returning results. After the
  accessible_owners expansion the viz can surface OTHER users' shared docs, so
  it must drop ones the caller can no longer access (revoked share) — same as
  the nc_semantic_search tool path. (Blocking review item.)
- access_filter: cache list_accessible_owners per user for 30s to keep the OCS
  shares round-trip off the search hot path (failures aren't cached); document
  the single-page OCS limitation; add a clear_accessible_owners_cache() test
  helper. Comment the empty-accessible_owners MatchAny([]) edge case.
- verification: comment why cross-user eviction is a deliberate no-op (eviction
  is scoped to the querying user's id, so a recipient's revoked access never
  deletes the owner's points; the recipient self-heals via accessible_owners).
- algorithms: declare SearchResult.original_score (set by the viz route) so the
  now-precisely-typed result list type-checks.
- tests: cross-user eviction-no-op safety test; autouse owners-cache reset in
  the access_filter + shared-search tests; replace async-no-await qdrant fakes
  with AsyncMock (clears SonarCloud S7503).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-05-29 02:15:44 +02:00
co-authored by Claude Opus 4.8
parent 6206f4a634
commit b1fac2d7a8
8 changed files with 122 additions and 16 deletions
@@ -586,6 +586,15 @@ async def verify_search_results(
if evict_on_missing and inaccessible:
async def evict(doc_id: str, doc_type: str) -> None:
# Eviction is scoped to the QUERYING user's own points
# (user_id == the searcher). For a cross-user shared document
# (owner_id=alice surfaced to bob via accessible_owners), bob
# failing verification evicts with user_id=bob — a deliberate
# no-op, because alice's points carry user_id=alice and must NOT
# be deleted just because bob's share was revoked. Bob's view
# self-heals via list_accessible_owners (alice drops out of his
# accessible owners once OCS no longer reports the share). See the
# legacy-user_id semantics note in build_ownership_filter.
try:
await delete_document_points(doc_id, doc_type, user_id)
except Exception as e: