From c03223a41c457100815ef94c88dedb1e2997b315 Mon Sep 17 00:00:00 2001 From: Chris Coutinho Date: Fri, 22 May 2026 21:29:48 +0200 Subject: [PATCH] fix(vector-sync): use resolved collection name in orphan sweep The startup sweep was reading settings.qdrant_collection (the raw config value, default "nextcloud_content") instead of settings.get_collection_name(), which is what every other vector-sync operation uses. When QDRANT_COLLECTION is not overridden, get_collection_name() auto-generates a {deployment-id}-{model-name} name; the sweep was targeting a non-existent collection and silently returning (0, 0). Also adds the AsyncQdrantClient type annotation that was missing on sweep_orphan_placeholders, and renames its parameter from collection_name to collection to make it clear the value must be the resolved name. Co-Authored-By: Claude Opus 4.7 (1M context) --- nextcloud_mcp_server/app.py | 7 +++---- nextcloud_mcp_server/vector/placeholder.py | 13 +++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/nextcloud_mcp_server/app.py b/nextcloud_mcp_server/app.py index 2a92cafe..9c99b2aa 100644 --- a/nextcloud_mcp_server/app.py +++ b/nextcloud_mcp_server/app.py @@ -1452,15 +1452,14 @@ def get_app(transport: str = "streamable-http", enabled_apps: list[str] | None = return try: qdrant_client = await get_qdrant_client() - swept, kept = await sweep_orphan_placeholders( - qdrant_client, settings.qdrant_collection - ) + collection = settings.get_collection_name() + swept, kept = await sweep_orphan_placeholders(qdrant_client, collection) logger.info( "vector_sync.orphan_sweep", extra={ "swept": swept, "kept": kept, - "collection": settings.qdrant_collection, + "collection": collection, }, ) except Exception: diff --git a/nextcloud_mcp_server/vector/placeholder.py b/nextcloud_mcp_server/vector/placeholder.py index e31ae871..af569ae6 100644 --- a/nextcloud_mcp_server/vector/placeholder.py +++ b/nextcloud_mcp_server/vector/placeholder.py @@ -21,7 +21,7 @@ import logging import time import uuid -from qdrant_client import models +from qdrant_client import AsyncQdrantClient, models from qdrant_client.models import FieldCondition, Filter, MatchValue, PointStruct from nextcloud_mcp_server.config import get_settings @@ -340,8 +340,8 @@ _ORPHAN_SWEEP_BATCH_SIZE = 100 async def sweep_orphan_placeholders( - qdrant_client, - collection_name: str, + qdrant_client: AsyncQdrantClient, + collection: str, *, batch_size: int = _ORPHAN_SWEEP_BATCH_SIZE, ) -> tuple[int, int]: @@ -362,7 +362,8 @@ async def sweep_orphan_placeholders( Args: qdrant_client: Async Qdrant client. - collection_name: Target collection. + collection: Target collection (resolved name from + ``settings.get_collection_name()``, not the raw config key). batch_size: Scroll page size. Default 100 — small enough that a single delete payload is reasonable, large enough that round-trip count stays bounded for typical placeholder @@ -383,7 +384,7 @@ async def sweep_orphan_placeholders( while True: points, offset = await qdrant_client.scroll( - collection_name=collection_name, + collection_name=collection, scroll_filter=placeholder_filter, limit=batch_size, offset=offset, @@ -404,7 +405,7 @@ async def sweep_orphan_placeholders( if orphan_ids: await qdrant_client.delete( - collection_name=collection_name, + collection_name=collection, points_selector=orphan_ids, ) swept += len(orphan_ids)