Repository navigation
Conversation
… patterns cli-core's message search counted and dated every message of every chat for its coverage on each search: 0.45 s at 1M messages, whatever the query. Read off the trigger-kept chat counts and each chat's newest message on its time index, the step takes 0.2 ms and `договор*` falls from 478 ms to 31 ms. A frequent word end (`*ени`) is checked up to the page and answers instead of being refused. Synthetic stores of 100k and 1M messages, before (cli-core 0.641.0) and after (fix/search-gaps), p50 of 7 warm runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
leemour
added a commit
to WireCatLabs/cli-core
that referenced
this pull request
Nov 12, 2026
…faster coverage (#2871) ## Task Fix the search gaps of the 2026-11-11 audit that the owner approved (NEED-2560 answer A, TASK-986), in one PR. The shape of search results and pagination is unchanged. ## Why Agents and people wrote queries that found nothing and said nothing (`status:open`, `invoice^2`, `author:` in messages), used two names for one concept, or hit a refusal that named no alternative. Every message search also spent about 0.45 s at 1M messages counting every chat's messages for its coverage. ## What | Gap | Example | Before | After | |---|---|---|---| | BUG-740 unknown field | `status:open` | searched as the words, 0 hits, no error | `query.unknown-field`: `tasks list status:open`, or quote it | | BUG-740 notes field in messages | `author:x`, `site:x` | 0 hits, no error | `query.unsupported-field`: "a notes field — search notes reads it" | | BUG-741 boost | `invoice^2` | searched the text "invoice^2", 0 hits | `query.unsupported-operator`: drop it (`invoice`) or quote it | | UX-221 aliases | `sender:olga`, `title:Альфа` | sender: unknown; title: matched nothing in messages | `sender:` is `from:`; `title:` is the chat title (messages) and the subject (mail); one mapping table in the guide | | UX-224 presence | `_exists_:from`, `subject:*` | refused / unsupported | keeps messages that have a value; other fields refuse with `has:file`, `has:link`… | | UX-223 tasks | `tasks list request`, `title:request` | `query.bare-word` / title prefix only | finds "Review the request" | | UX-223 contacts | `contacts list phone:+34`, `email:example.com` | `+34` misparsed; no email/phone | matched (phone by digits) | | UX-223 deals | `search all title:Поставка` | words anywhere in the deal | the deal's or lead's title only | | UX-222 reasons | `chat:Альфа*` fitting nothing; 2-letter chat search | bare not_found / validation | `query.no-match` with `chat:*Альфа*`; `query.short-text` with a hint | | PERF-99 word end | `*ени` at 1M | refused (candidate rows), no term named | 50 hits in 647 ms; a page it cannot fill names the term and suggests `*part*` | | PERF-100 coverage | `договор*` at 1M | 478 ms | 31 ms (coverage read 445 ms → 0.2 ms) | | DEBT-326 | `after:` | reason `legacy_date_field` (not registrable) | `query.legacy-date-field`, registered; the reasons test now also reads `searchError(...)` | | DEBT-327 | `bin/verify-query-reference` on JDK 25 | failed on Java object ids | passes on JDK 21 and 25 | Not done, and why: - **Tasks in `search all`**: memo's MCP gates each `search all` lane by permission and has no tasks gate, so a tasks lane would show task titles where `tasks.list` is denied. It needs memo's gate in the same bump. - **Meeting description, and `title:` in `meetings search`**: needs a new hit scope or a folded description column (a migration). Meeting titles already match in `search all`. Breaking items are under "Changed — may break callers" in [the changelog fragment](changes/fix-search-gaps.md). Measurement: [cli-testing, performance/search/coverage-step](https://github.com/WireCatLabs/cli-testing/tree/main/performance/search/coverage-step) (WireCatLabs/cli-testing#356). ## Testing - Each new or changed test fails on main's sources (25 tests in 14 files) and passes here. - typecheck, lint, docs:check and the full suite pass locally; verify-query-reference passes on JDK 21 and 25. - Every behavior in the table was run against a seeded synthetic store, before (main's dist) and after. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Why
The 2026-11-11 search audit (PERF-100, PERF-99) found that every cli-core message search spent about 0.48 s at 1M messages on its coverage step, and that a frequent word end such as
*ениwas refused before any message was checked. The cli-core fix ships in the search-gaps pull request; this page records the measurement that justified it.What
performance/search/coverage-step/README.md: why, setup, results at 100k and 1M before/after, what it showed, what was not measured.bench.mjsand the rawresults/.performance/search/README.mdandPROCESS.md.Headline
договор**ениSynthetic stores only.
🤖 Generated with Claude Code