feat(search)!: hybrid search_notes — lexical leg, mode/effort axes#53
Merged
Conversation
…_notes BREAKING CHANGE: search_notes now takes mode: 'hybrid'|'lexical' (retrieval channel) and effort: 'quick'|'deep' (replacing the old mode: 'quick'|'deep'); old mode values are rejected. Response results key renamed to semantic_matches, with a new lexical_matches placeholder (always [] until the lexical leg is wired up).
Add a real-vault (FsVaultReader + LexicalIndex) e2e test covering intersection between legs, Ukrainian apostrophe+case folding, filter binding both legs, and lexical-only mode on a cold corpus. Extract makeLexicalVault/makeMockEngine into a shared _hybrid-helpers module (rather than importing across .test.ts files) and extend it with sources/engine/listMatchingPaths overrides. Close gaps found during the spec self-check: hybrid-mode effort->lexical-cap sizing, mode:lexical never touching an available corpus, inflected-substring matching, hard-wrapped phrase and code-fence-heading matching through the full rank pipeline, and reproducible ordering across repeated searches.
AlexMost
force-pushed
the
worktree-hybrid-search-notes
branch
from
July 6, 2026 09:41
13c9f4d to
41cb146
Compare
This was referenced Jul 6, 2026
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
Makes
search_noteshybrid: it now runs a semantic leg (embedding similarity) and a new lexical (exact-match) leg over note titles, headings, and body — curing the tool's worst failure mode (silent semantic noise on exact terms/names/codes, or a cold/absent corpus) without the agent having to re-query.OpenSpec change:
hybrid-search-notes(archived atopenspec/changes/archive/2026-07-05-hybrid-search-notes/; specs synced intoopenspec/specs/hybrid-search/+mcp-tool-surface/).results→semantic_matches; new siblinglexical_matches(grouped per note).mode: "quick" | "deep"is rejected (no alias). Now two orthogonal axes:mode: "hybrid" | "lexical"(defaulthybrid) — which legs run.effort: "quick" | "deep"(defaultquick) — result volume (absorbs the oldmodevalues).effort, redefinesmode(ADR-0005 satisfied by the major bump).What's inside
src/lib/obsidian/lexical/:normalize(case/NFKD/apostrophe-unification incl. Ukrainian) →blocks(mdast AST blocks with line positions) →match(AND-substring + phrase) →rank(six deterministic tiers → density → backlink_count → path) →snippet(grapheme-safe window), fronted by a per-vaultLexicalIndexwith an mtime cache.mode: "lexical"never touches the corpus loader; hybrid on a cold/absent corpus returns lexical matches instead of throwing; an available corpus that errors still surfacesDEPENDENCY_ERROR.filter, multi-query merge (matched_queries), and multi-vault fan-out all bind both legs identically.mdast-util-from-markdown(MIT) +@types/mdast(dev) — first markdown parser in the repo.finding-notes.md/reading-and-modifying.md),routing.mdrewritten around one search entry point, newdocs/architecture/lexical-search.md, parameter dictionary updated.Verification
npm test— 758 passing (706 → 758, +52),npm run lintclean,npx tsc --noEmitclean,npm run buildOK.openspec validate --all— all valid.Release
Do not release from this branch — after merge, run
npm run releaseonmain(major version bump; breaking notes ride thefeat(search)!:commit).🤖 Generated with Claude Code