Skip to content

fix(grep): send synonym alternations to the embedding daemon - #446

Open
eastagiletracker wants to merge 1 commit into
activeloopai:mainfrom
eastagiletracker:agile-board/embed-alternation-patterns
Open

eastagiletracker wants to merge 1 commit into
activeloopai:mainfrom
eastagiletracker:agile-board/embed-alternation-patterns

Conversation

@eastagiletracker

@eastagiletracker eastagiletracker commented Sep 29, 2026 •

Copy link
Copy Markdown

This PR proposes sending synonym alternations like data loss|concurrent writer|race condition to the embedding daemon instead of falling back to lexical-only grep (Fixes #86). We include this PR work along with a full history of your repo at https://eastagiletracker.com/projects/747. You can sign in with your GitHub ID to claim ownership of the project.

What changed

patternIsSemanticFriendly counted | as a regex metacharacter and rejected any pattern with more than one, so a grep with two or more alternatives never reached EmbedClient.embed() and searchDeeplakeTables ran the lexical LIKE/ILIKE branch only. A list of synonyms is exactly the query semantic recall is meant to answer, so paraphrase matches were being lost. This follows the fix proposed in #86: | no longer counts toward the metacharacter limit, patterns with more than one other metacharacter (e.g. (foo|bar)\+) are still skipped, and alternations are capped at 8 alternatives so a many-clause pattern still goes lexical. The change is applied to both copies of the function, src/hooks/grep-direct.ts (the grep fast path used by the pre-tool-use hooks) and src/shell/grep-interceptor.ts (the virtual shell), and keeps the two in sync. No version bump is included, so you can decide whether it goes into a release.

Reproduction at current main (e054fb1): a vitest case with the embed client stubbed calls handleGrepDirect(api, "memory", "sessions", { pattern: "silent data loss|concurrent writer|race condition", ... }) and gets 0 embed() calls, with no <#> operator in the generated SQL (lexical-only).

Verification: npx vitest run before and after the change gives the same failure set (4 tests that also fail on a clean main in this environment: embeddings-client warmup auto-spawn, two plugin-cache rmSync/rename cases, and spawn-detached real-process; all spawn or filesystem permission related, none touch grep). After: 5861 passed, the 9 new tests included. tsc --noEmit and jscpd src are clean. New tests: a new grep-direct-semantic.test.ts covers handleGrepDirect (alternation embeds and produces the hybrid <#> query, the 8-alternative limit on both sides, regex-heavy patterns containing | still skip, patterns shorter than 2 characters still skip), and grep-interceptor.test.ts gains the same cases for the shell interceptor. With the source change reverted, the 4 alternation-embedding tests fail and the skip cases stay green.

How this was managed

This work was tracked as https://eastagiletracker.com/projects/747/stories/776572 on https://eastagiletracker.com/projects/747, a board imported from this repo's issues and pull requests (425 stories) and used to manage this change.

board

If you'd rather not receive contributions like this, reply no-more-prs on this pull request and we won't open any further ones on your repositories.


Lawrence W. Sinclair
CEO / East Agile
linkedin.com/in/lwsinclair/
eastagile.com

Summary by CodeRabbit

  • New Features
    • Semantic search now supports grep patterns with up to eight pipe-separated alternatives, including common synonym searches.
  • Bug Fixes
    • Patterns with excessive regex complexity or more than eight alternatives remain ineligible for semantic search, while simple patterns continue to work as expected.

patternIsSemanticFriendly counted `|` as a regex metacharacter, so any
pattern with two or more alternatives (`data loss|concurrent writer|race
condition`) was rejected and grep fell back to lexical-only search, even
though a list of synonyms is the case embeddings answer best.

Stop counting `|` toward the metachar limit in both the pre-tool-use
fast path (grep-direct) and the virtual shell interceptor, and cap the
number of alternatives at 8 so a pathological many-clause pattern still
goes lexical. Patterns with more than one other metachar are unchanged.
@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: activeloopai/hivemind/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 3dba7fce-e674-46be-b02e-24d2e3260362

📥 Commits

Reviewing files that changed from the base of the PR and between e054fb1 and e5e5e48.

📒 Files selected for processing (4)
  • src/hooks/grep-direct.ts
  • src/shell/grep-interceptor.ts
  • tests/claude-code/grep-direct-semantic.test.ts
  • tests/claude-code/grep-interceptor.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

Both grep paths now allow semantic embedding for patterns with up to eight pipe-separated alternatives, subject to the existing short-pattern and metacharacter checks. Tests cover alternation limits and embedding behavior.

Changes

Semantic grep eligibility

Layer / File(s) Summary
Update semantic eligibility and tests
src/hooks/grep-direct.ts, src/shell/grep-interceptor.ts, tests/claude-code/grep-direct-semantic.test.ts, tests/claude-code/grep-interceptor.test.ts
Both paths exclude `

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to e5e5e

The change enables semantic search for bounded synonym patterns. No issue identified here requires resolution before merge.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to e5e5e

Bounded synonym searches can now return semantically related records. With the default semantic-output behavior, even a filename-only or count-only search can return record text. The searches remain scoped to requested paths, but this wider exposure merits design review.

Retained concerns

  • Medium · security · inferred: Newly eligible alternation searches can enter the existing semantic-output branch, which returns full selected-row text instead of honoring filename-only, count-only, or line-level grep refinement. If a caller expects restricted output, additional memory or session content can reach the agent.
Security review details

Security Blast Radius

  • inferred — A caller-controlled alternation can now cause selected memory or session rows within the requested search paths to be returned as text to the agent, including lines outside a literal grep match. The evidence does not establish access outside those paths or across tenants.

Security Findings and Attack Paths

  • inferred — For a newly eligible alternation, a filename-only or count-only request can receive full text from retrieved rows when semantic emit-all is active. This expands reachability of a pre-existing behavior; no actual sensitive-record disclosure was verified.

Trust Boundaries and Controls

  • observed — The shell checks the virtual mount before search; database queries carry a target-path filter; embedding failures fall back without a vector. These controls limit the supported attack path but do not enforce grep output flags in semantic emit-all mode.

Resilience and Maintainability Implications

  • observed — The two eligibility implementations make the same routing change, while their existing semantic-output branches remain separate. Keeping their output controls aligned matters as more patterns reach those branches.

Hardening Proposals

  • proposed — Preserve filename-only, count-only, and other output-limiting options after semantic retrieval, or explicitly exclude incompatible options from semantic routing in both entrypoints.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary change: sending grep synonym alternations to the embedding daemon.
Description check ✅ Passed The description provides a detailed summary, explains the version-bump decision, and documents the test plan and verification results. It does not use the exact template headings or checkboxes and inc…
Linked Issues check ✅ Passed The PR satisfies the coding requirements in [#86]. Both patternIsSemanticFriendly implementations exclude | from the metacharacter count, reject patterns with more than one remaining metacharacter…
Out of Scope Changes check ✅ Passed The changes stay within [#86]. The source edits implement the required gating behavior in both specified files. The added tests verify that behavior. No unrelated feature, refactor, or administrative …
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Warning

⚠️ This pull request has been flagged as potential spam (promotional) by CodeRabbit slop detection and should be reviewed carefully.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

embeddings: alternation patterns (a|b|c) skip the embedding daemon and fall back to lexical-only

1 participant