fix(vector): address PR review round 17 + local-mode collection-creation regression

Round 17 reviewer (🟡 Important):

1. docs/configuration.md degraded-migration runbook said `doc_id backfill
   failed on …` but the actual log line in qdrant_client.py:415 is
   `doc_id backfill scroll failed on …`. Operators grepping the runbook
   string would have missed it. Insert the `scroll` qualifier.

2. _create_one_payload_index returned True on the 400 schema-conflict
   path, so a wrong-type index discovered at create time skipped the
   consolidated `Payload index creation incomplete` summary — but a
   wrong-type index discovered via the existing-schema check at line
   195-206 did fire it. Tenants whose payload_schema is hidden from
   their JWT (Qdrant Cloud collection-scoped tokens) only ever observe
   the create-time path, so they never saw the operator-level summary.
   Return False so the summary fires in both cases.

3. docs/configuration.md said the upgrade-time delay was `proportional to
   point count while writes are issued` — overstating the cost. Writes
   are proportional to int-typed points only; the scroll itself is
   proportional to total point count. Reword.

Local-mode collection-creation regression (root-cause of failing
single-user / login-flow / multi-user-basic CI jobs):

PR #779 changed the existence probe in get_qdrant_client from
collection_exists() (returned bool in both modes) to get_collection()
+ except UnexpectedResponse(status_code=404). The HTTP-mode client
raises UnexpectedResponse with a 404 body, but the local/in-memory
client raises ValueError(f"Collection {name} not found") — see
qdrant_client/local/async_qdrant_local.py. The narrow except clause
let the ValueError propagate, app.py's lifespan re-raised as
RuntimeError, and the mcp container crashed on first start. Catch
ValueError too, with a `not found` substring guard so genuine
programming bugs (bad collection_name, etc.) still surface.

Tests: extend the existing 400-path test to assert the new
failed_fields contract; add two get_qdrant_client unit tests pinning
the local-mode VE catch (positive case + propagation case).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-05-10 18:33:51 +02:00
co-authored by Claude Opus 4.7
parent 363c2a2624
commit 8246d9a088
3 changed files with 184 additions and 14 deletions
+4 -3
View File
@@ -341,8 +341,9 @@ server runs two idempotent migrations:
legacy integer `doc_id` payloads to strings so they match the keyword
index. Idempotent: on a clean collection (all `doc_id` values already
`str`), the scroll runs but emits zero writes. On the first start after
the upgrade, expect a delay proportional to point count while writes
are issued.
the upgrade, expect a delay proportional to total point count for the
scroll itself, plus an additional delay proportional to any `int`-typed
`doc_id` points found while their payloads are rewritten.
Both steps emit INFO-level log lines so operators can track progress.
@@ -363,7 +364,7 @@ Both steps emit INFO-level log lines so operators can track progress.
> the index was not created. Searches filtering on that field will keep
> returning HTTP 400 (`Index required but not found`) until a subsequent
> restart succeeds in creating it.
> - `doc_id backfill failed on '<collection>'; will retry on next restart` —
> - `doc_id backfill scroll failed on '<collection>'; will retry on next restart` —
> the migration sentinel was not written. Legacy integer `doc_id`
> payloads remain invisible to the keyword index in the meantime; the
> scroll re-runs from scratch on the next process start.