Milestone 4 of 8
Find exact phrase matches with complete traces
Intersect ordered positions under query offsets, retain overlapping and repeated-term matches, and show which candidate starts survive each step.
A phrase is an intersection of positions, not a substring search. The trace should show how possible starts survive each query-term offset.
Goal
Find every exact phrase match using adjacent searchable-term positions and record a complete trace of candidates and surviving starts.
Inputs
Use the positional index and analyzed phrase queries. For query terms
q[0] ... q[m-1], a match starts at indexed position s only when every
q[i] occurs at s + i in the same document. Phrase matching uses
indexed_position, not raw character adjacency or full-token positions.
Deliverables
Implement src/phrases.py. Produce output/phrase_matches.jsonl and matching
trace records in output/match_traces.jsonl. Each phrase match must retain
query ID, document ID, start and end indexed positions, every matched term,
every indexed and full-token position, and a deterministic ordinal.
Each trace records candidate documents and the surviving starts after offset zero, after each later term, and after the final intersection. A missing-term, invalid, or zero-candidate query receives an explicit no-match reason rather than a fabricated match.
Checks
Check a a in a a a and preserve both overlapping matches. Check repeated
terms, phrases longer than a document, shared prefixes, one match after a
failed candidate, exact case, non-ASCII terms, underscores, and punctuation
between searchable terms. Verify every recorded position belongs to the same
document and term occurrence, and every end position is the final matched
indexed position.
Check that the trace's surviving starts exactly predict the emitted matches.
Return every match, including overlaps; do not add scores, top_k, or
zero-match fillers. Keep query-file order and defer the complete cross-query
result order to the later results milestone.
Workspace
Keep offset intersection and phrase trace construction in src/phrases.py.
Read the positional index and query analysis without changing either. Save
phrase matches and traces in deterministic JSONL form.
Hints
HintStart with the first term
q[0]. For offset i, retain a start only if s + i is a
position of q[i].HintA set is not the final evidence
HintOverlap is expected
Review
Trace a a in a a a by hand. Which starts survive after the second offset?
What would the trace reveal if the implementation accidentally treated a
phrase as raw-character equality?
How to check your work
Checks compare phrase records and offset traces with the tiny repeated-term fixture. The supplied fixture uses exact adjacent searchable positions and retains every overlap; it does not infer meaning from the phrase.