Context
Phase 1 of #380 delivered the lexical positional index (v4: PostingEntry { doc_id, field_id, position }, delta+varint codec). Phase 2 adds phrase (contiguous multi-term) and --near (proximity) query support.
Design: .devflow/docs/adr-380-phase2-positional-search.md (ADR-380-P2).
Pivotal finding (dual-sourced research)
The v4 position is a document-absolute BYTE offset with zero tokenization, emitted for every trigram window (no dedup / cap / drop), one entry per (trigram, doc, position), and already decoded in the query hot path (reader.rs:461-462, 518, 536). This splits the scope cleanly:
- Exact phrase + byte/char-distance
--near → v4 query-only (no format bump, no rebuild, no size-guard change).
- Word/token-distance
--near N → v5 re-index (indexer must tokenize + store token positions; FORMAT_VERSION 4→5; automatic cold rebuild; size guard re-measured).
Scope decision: PENDING sign-off
The v4-query-only vs v5 choice is a product/risk decision — see the ADR. Implementation is gated on that sign-off.
Acceptance criteria
- AC-P2-1 (positive): a quoted phrase
"alpha beta" returns files where those terms appear contiguously (byte-adjacent), ordered.
- AC-P2-2 (negative, falsifiable): the same query must NOT return files where the terms appear only non-adjacently or reversed — must fail if reverted to bag-of-trigrams. (
--near N accepts within-window pairs, rejects beyond-window.)
- AC-P2-3 (no regression): non-phrase / non-near queries return byte-identical results to Phase 1; if v5, a v4 index cold-rebuilds under the v5 binary and serves correctly.
- AC-P2-4 (perf/size): phrase/near query latency < ~50 ms on the corpus-class benchmark; index size re-measured only if v5.
Implementation notes (from research)
- New dispatch branch modeled on
search_exact_intersection (reader.rs:499-661); the positional filter runs AFTER trigram intersection and BEFORE the truncation gate (verify-then-truncate-last, AD-355-2 / AD-372-4).
- New offset-preserving query extractor — current
extract_query_ngrams (ngram.rs:353) discards per-trigram query offsets.
- Size guard:
crates/rskim-search/src/index/reader_tests.rs:1103 (LEXICAL_SIZE_RATIO_CEILING = 5.0) — corrected ref (the AST guard < 2.2x is separately at ast_index/store/reader_tests.rs:550).
- Atomic-save ordering (if v5):
crates/rskim/src/cmd/search/index.rs:380-436 (ADR-006) — corrected ref (there is no crates/rskim-search/src/index.rs).
- UTF-8 caveat: byte-distance
--near != codepoint-distance on multi-byte text.
Refs #380, #174. Blocks the merge of PR #386 per the wave-4 close-out plan.
Context
Phase 1 of #380 delivered the lexical positional index (v4:
PostingEntry { doc_id, field_id, position }, delta+varint codec). Phase 2 adds phrase (contiguous multi-term) and--near(proximity) query support.Design:
.devflow/docs/adr-380-phase2-positional-search.md(ADR-380-P2).Pivotal finding (dual-sourced research)
The v4
positionis a document-absolute BYTE offset with zero tokenization, emitted for every trigram window (no dedup / cap / drop), one entry per(trigram, doc, position), and already decoded in the query hot path (reader.rs:461-462, 518, 536). This splits the scope cleanly:--near→ v4 query-only (no format bump, no rebuild, no size-guard change).--near N→ v5 re-index (indexer must tokenize + store token positions; FORMAT_VERSION 4→5; automatic cold rebuild; size guard re-measured).Scope decision: PENDING sign-off
The v4-query-only vs v5 choice is a product/risk decision — see the ADR. Implementation is gated on that sign-off.
Acceptance criteria
"alpha beta"returns files where those terms appear contiguously (byte-adjacent), ordered.--near Naccepts within-window pairs, rejects beyond-window.)Implementation notes (from research)
search_exact_intersection(reader.rs:499-661); the positional filter runs AFTER trigram intersection and BEFORE the truncation gate (verify-then-truncate-last, AD-355-2 / AD-372-4).extract_query_ngrams(ngram.rs:353) discards per-trigram query offsets.crates/rskim-search/src/index/reader_tests.rs:1103(LEXICAL_SIZE_RATIO_CEILING = 5.0) — corrected ref (the AST guard< 2.2xis separately atast_index/store/reader_tests.rs:550).crates/rskim/src/cmd/search/index.rs:380-436(ADR-006) — corrected ref (there is nocrates/rskim-search/src/index.rs).--near!= codepoint-distance on multi-byte text.Refs #380, #174. Blocks the merge of PR #386 per the wave-4 close-out plan.