- **Full-text search recall for natural-language queries** (`opencontractserver/llms/vector_stores/core_vector_stores.py`, `_run_fts_query`). The FTS arm built its query with `plainto_tsquery` (via `SearchQuery`'s default), which ANDs every lexeme — so a multi-concept question like *"What are the main risks or obligations across these documents?"* matched **no** annotation (no single row contains all terms) and the arm returned zero rows. When a corpus has no embeddings, hybrid search degraded to that empty FTS arm and the agent answered "I found nothing." `_run_fts_query` now OR-combines per-token `plainto_tsquery` sub-queries, so any term match qualifies while `SearchRank` still ranks annotations matching more terms higher. Per-token `plainto` safely elides stopwords without raising a tsquery syntax error (no manual stopword list or raw-tsquery escaping). This is the single FTS entry point for the hybrid, fts-only, and `global_search` paths, so the recall fix applies across all of them. Measured on a 53-document SEC-filing corpus: the example question went from 0 → 8 full-text matches. Regression test: `test_hybrid_search.py::TestHybridSearch::test_fts_matches_natural_language_query_spanning_annotations`.
