Ports the docs-mcp-template fix. This corpus was the badly exposed one.
RERANK_DOC_MAX_CHARS was a flat 2000 CHARACTERS standing in for the reranker's
1024-TOKEN pair limit, and the comment claimed that was "≈ 500-700 tokens" with
headroom for the query. Measured against {RERANK_URL}/tokenize, that estimate
is wrong for this corpus by nearly 2x:
chars/token floor 1.92 tokens @2000-char cap: max 1042, p99 1031, p95 1017
41 of 250 sampled chunks (16%) exceeded 1000 tokens
Identifier-dense variety/trial tables tokenise far worse than prose (crop-chem's
floor is 1.47). Since llama.cpp 500s the ENTIRE batch when any one (query, doc)
pair exceeds bert.context_length=1024 — a hard architectural ceiling on a BERT
cross-encoder, not something a bigger --ubatch-size lifts — one oversized chunk
silently dropped that whole query to fused order. Observed in prod as 1034/1040/
1043-token rejections.
The cap is now derived from RERANK_CTX_TOKENS / RERANK_CHARS_PER_TOKEN / a query
reserve (1523 chars here — still generous, because this corpus's density is
accounted for rather than guessed), budgeting the PAIR to ~94% of the ceiling.
The query is truncated too; previously only the document was. eval/retrievers.py
default moved in step so the harness measures what production runs.
Eval (21 golden queries, k=5) — no regression, failures eliminated:
hybrid+rerank 21/21 Recall 100% P@1 90.48% MRR 0.905 (unchanged)
oversize rerank rejections during the run: 3 -> 0
(same run's no-rerank `hybrid` row: P@1 61.90% — the cliff this avoids)
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01AiYH8nxc6DgUTdwHnP9PEe