fix(chunk-context): address PR #767 round-2 review — gate, parity, doc

Latest reviewer comment flagged five items on top of the original PR. This
commit addresses every one:

🟡 1. Skip the offset-based Qdrant fallback for `doc_type=file` when
   `chunk_index` is supplied. Qdrant Cloud's strict mode rejects unindexed
   filter fields with HTTP 400, which `_get_chunk_from_qdrant` catches and
   logs at `logger.error` — masking real Qdrant problems in monitoring.
   Notes/cards keep the offset fallback (cheap, useful for legacy data).

🟡 2. Add a `logger.warning` and clarifying inline comment in the doc-text
   fallback path when `chunk_index` is None — surfaces the pre-existing
   "0/N misreport" so callers can detect it. Type-nullability propagation
   is deferred to a follow-up (out of scope for this hotfix).

🟢 3. Simplify `if chunk_text and doc_id_int is not None:` →
   `if chunk_text:` with an inner `assert doc_id_int is not None` for
   `ty` narrowing. The outer second clause was dead.

🟢 4. Add `doc_type` `FieldCondition` to the offset-based image lookup in
   both `visualization.py` and `viz_routes.py` for parity with the
   `chunk_index` branches.

🟢 5. Inline the `chunk_filter` local in `visualization.py` directly into
   the `must=[]` list (matches `viz_routes.py` style).

Adds `tests/unit/test_chunk_context_offset_gate.py` with three regression
tests covering the gate matrix: (file, with-index → skip offset),
(note, with-index → still tries offset), (file, no-index → still tries
offset). Lives at top-level rather than `tests/unit/search/` to side-step
a pre-existing circular-init issue in `nextcloud_mcp_server.search`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-05-08 21:28:50 +02:00
co-authored by Claude Opus 4.7
parent 8457c427a5
commit 51c1d42ea3
4 changed files with 174 additions and 6 deletions
+8 -4
View File
@@ -578,9 +578,6 @@ async def get_chunk_context(request: Request) -> JSONResponse:
# Prefer chunk_index for the highlighted-image lookup (always indexed);
# fall back to (chunk_start_offset, chunk_end_offset) when not provided.
if chunk_index is not None:
chunk_filter = FieldCondition(
key="chunk_index", match=MatchValue(value=chunk_index)
)
points_response = await qdrant_client.scroll(
collection_name=settings.get_collection_name(),
scroll_filter=Filter(
@@ -596,7 +593,10 @@ async def get_chunk_context(request: Request) -> JSONResponse:
key="doc_type",
match=MatchValue(value=doc_type),
),
chunk_filter,
FieldCondition(
key="chunk_index",
match=MatchValue(value=chunk_index),
),
]
),
limit=1,
@@ -615,6 +615,10 @@ async def get_chunk_context(request: Request) -> JSONResponse:
FieldCondition(
key="user_id", match=MatchValue(value=user_id)
),
FieldCondition(
key="doc_type",
match=MatchValue(value=doc_type),
),
FieldCondition(
key="chunk_start_offset",
match=MatchValue(value=start),