Milestone 5 of 8

Find bounded proximity matches with complete traces

Apply after and either-side rules, calculate intervening terms, handle identical terms without self-pairs or duplicates, and retain boundary and rejection evidence.

Proximity asks how far two occurrences are apart in the searchable stream. The direction and the distance boundary are part of the query contract.

Goal

Find every bounded proximity match for after and either, calculate the intervening searchable terms, and retain exact acceptance and rejection trace evidence.

Inputs

Use the positional index and analyzed proximity queries. For distinct left and right occurrences in one document, calculate:

intervening_terms = abs(right_indexed_position - left_indexed_position) - 1

The count must be no greater than maximum_intervening_terms. For after, the right occurrence follows the left. For either, either source order is valid. When the terms are identical, use distinct occurrences only: either emits each unordered pair once in increasing position order, and after emits each increasing pair once.

Deliverables

Implement src/proximity.py. Produce output/proximity_matches.jsonl and trace records that retain query ID, document ID, left and right role positions, source-order span, intervening count, direction, term text, indexed and full-token positions, deterministic ordinal, and a trace reference or embedded trace evidence.

Each trace records candidate documents, occurrence pairs considered, computed gaps, direction decisions, boundary decisions, and the surviving pairs.

Checks

Check zero, exact-boundary, and over-boundary gaps; both directions; missing terms; punctuation between terms; repeated occurrences; and a document with no searchable terms. Check after rejects reversed pairs and either accepts both orders. Check same-term queries for no self-pairs, no duplicate unordered pairs, and the specified after order.

Verify intervening_terms is zero for adjacent searchable terms even when full-token positions have punctuation between them. Verify every emitted pair has distinct occurrences and that traces predict both emitted and rejected pairs. Do not add scores or silently change the distance rule.

Workspace

Keep proximity comparisons and traces in src/proximity.py. Read the shared positional index and query analysis without mutation. Save proximity matches and traces in deterministic JSONL form; the later results milestone will apply the cross-query display order.

Hints

HintSeparate roles from source order
Keep left and right role positions even when either accepts the right occurrence first. The source span is a separate, ordered pair of positions.
HintHandle identical terms explicitly
A generic nested loop can emit a pair twice or pair an occurrence with itself. Define the valid index pairs before applying direction and gap tests.
HintBoundaries are evidence
Record the exact gap and configured limit for a rejected pair. “Too far” is not the same reason as “wrong order.”

Review

Use two identical terms at positions 2 and 4 with a limit of 1. Which query directions accept the pair, and how many records should appear? Explain why a full-token gap can differ from the searchable-term gap.

How to check your work

Checks compare matches and traces with the boundary and same-term fixtures. The reference applies direction and distance literally and reports rejected pairs; it does not rank or deduplicate by an unstated preference.

LLM PrimerFind bounded proximity matches with complete traceshttps://llmprimer.com/python/projects/build-a-phrase-and-proximity-search-engine/find-bounded-proximity-matches-with-complete-traces© 2026 LLM Primer