feat(search): token-boundary matching and body-text tier [roadmap:v0.10.3] - #68
Merged
Merged
Conversation
Settle the body-text open question in guide-tool-surface (ADR-037,
ADR-038): describe token-boundary matching and the five-tier ladder, and
pin the additive snippet field names ('section', 'snippet') and their
placement on heading/body match entries before any code lands.
Implements rac/roadmaps/v0.10.x-guide/v0.10.3-search-quality.md.
…p:v0.10.3]
Replace substring search with deterministic, tiered token-boundary
matching across one Core implementation that serves rac find and
search_artifacts identically.
Matching (ADR-037): identifiers, title, path, section headings, and body
text tokenize on non-alphanumeric boundaries and camelCase transitions;
a query term matches a token by casefolded equality or prefix; multi-term
queries require every term to match somewhere (AND); 'lore' no longer
matches Explorer, 'relation' still finds relationships.
Body-text tier (ADR-038): the ladder extends to id, title, path, heading,
body. Heading and body text reach search through the corpus snapshot the
walk already produces — Product gains search_sections (original heading
and line text), populated by the parser and carried on the index entry and
repository model, so no file is re-read and search_artifacts keeps one
corpus walk per call. Heading/body matches carry additive snippet fields
('section', 'snippet') with the first matching line in document order;
metadata-match entry shapes are byte-identical to before (ADR-007). The
rac find human view shows the snippet indented under matched rows.
Implements rac/roadmaps/v0.10.x-guide/v0.10.3-search-quality.md.
Add the token-boundary battery to the resolve battery: tokenization
(camelCase, non-alnum, punctuation-only), prefix matching, word-boundary
exclusion, multi-term AND, the five-tier ordering (id > title > path >
heading > body), body-only match with snippet, first-line determinism, and
the metadata-match byte-identical shape. Add the lore-vs-Explorer named
regression to the dogfood battery on the dogfood corpus.
Extend the mcp battery: a body-match snippet payload byte-equal to the CLI
find JSON, the metadata-match four-field shape, and whole-item truncation
of a snippet-bearing match.
Re-pin the find goldens to the new semantics ('markdown' now also surfaces
a roadmap by its body, with a snippet) and update the Explorer adapter's
trailing-type-token test, whose punctuation-only query no longer means
'match everything' under token matching.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements
rac/roadmaps/v0.10.x-guide/v0.10.3-search-quality.md.Adds:
loreno longer matches Explorer artifacts.sectionandsnippetfields so an agent can triage matches without retrieving each candidate.guide-tool-surfacedesign: the body-text open question is settled and the snippet field shape was pinned before any code landed.lore-vs-Explorerregression test, and a token-boundary test battery (+13 tests, 934 total).Roadmap / ADR Trace
Roadmap:
rac/roadmaps/v0.10.x-guide/v0.10.3-search-quality.mdRelevant ADRs:
rac/decisions/adr-037-token-boundary-search-matching.md— the matching semanticsrac/decisions/adr-038-body-text-search-tier.md— the body tier, snippets, and the permanent rejection of embeddings/fuzzy/scoringrac/decisions/adr-007-json-contract-stability.md— additive response rulesrac/decisions/adr-031,adr-032,adr-033— consumer boundary, statelessness, response budgetDesign:
rac/designs/guide-tool-surface.md(revised in this PR, first commit).Scope
Included
rac.services.resolve(tokenize, five-tier_match_entry, rewrittensearch_index) servingrac findandsearch_artifactsidenticallyProduct.search_sectionsstructure that preserves original heading and line text (the existingsectionsmap is lossy — casefolded/joined — and untouched, since other consumers depend on it); no file re-reads, exactly one corpus walk persearch_artifactscall (regression-pinned)rac findhuman output shows snippets indented under heading/body-matched rowssearch_sectionsinternally; the index JSON contract (to_dict) is unchangedExcluded
Product / Architecture Decisions
markdownvia its body line "Adopt Markdown everywhere", with snippet — intended body-tier behavior)..md); it was updated to use a real token — the wildcard was never a documented feature.rac resolve,get_artifact,get_related) is untouched: alias matching stays exact; only search matching changed.User-Facing Contract
CLI
rac findinterface unchanged. Human output gains an indented↳ Section: linerow under heading/body matches.JSON Output
Search match entries (CLI
--jsonandsearch_artifacts, identical):{"id": "...", "type": "...", "title": "...", "path": "...", "section": "...", "snippet": "..."}section/snippetpresent only on heading/body matches. All other shapes unchanged.Exit Codes
Unchanged.
Verification
Ran
Plus a live stdio MCP client:
search_artifacts("lore")returned exactly the five Lore-related artifacts (title matches without snippets, body matches with), byte-equal torac find lore --json.Covered
loreexcludes Explorer artifacts on the dogfood corpusdelete user,delete,soft-deletestill surface the demo decision —soft-deletetokenizes to [soft, delete] under AND)search_artifactscall;get_related's one-walk regression still passesReview Path
rac/designs/guide-tool-surface.md— the revised search contract (read first; the code implements this)src/rac/services/resolve.py— tokenizer, tiers, snippet capturesrc/rac/core/models.py,core/markdown.py,services/index.py,services/repository.py—search_sectionsplumbingsrc/rac/output/human.py— snippet displaytests/test_resolve.py,test_dogfood.py,test_mcp_tools.py,tests/golden/— the re-pinned contractsNotes For Reviewer
Implementation Process
Implemented with AI assistance under the roadmap contract. Final scope, review, and acceptance decisions were made by the maintainer.