Skip to content

fix(server): search every settled message, not just each turn's last one - #417

Merged
omegent-app[bot] merged 68 commits into
fork/devfrom
fix/search-all-assistant-messages
Aug 20, 2026
Merged

omegent-app[bot] merged 68 commits into
fork/devfrom
fix/search-all-assistant-messages

Conversation

@omegent-app

@omegent-app omegent-app Bot commented Aug 20, 2026

Copy link
Copy Markdown

Thread search restricted assistant matches to the single row a turn names as its
terminal message:

messages.message_id IN (
  SELECT turns.assistant_message_id FROM projection_turns AS turns
  WHERE turns.assistant_message_id IS NOT NULL
)

Providers stream an answer as many assistant items — roughly ten per turn now,
and climbing as chunking gets finer — and only the last is linked as
turns.assistant_message_id. Everything said before it was invisible to search.
That is why full-text search appeared to "stop working" without anything
visibly changing: the query never changed, the shape of the data under it did.

Measured on a live state.sqlite

searchable
before 7,118 / 20,094 settled messages (35%)
after 20,094 (100%)
assistant messages before 3,430 / 16,406 (21%)

A real query for worktree goes from 138 to 187 threads.

All 425 threads with assistant text had some searchable row, so the symptom
was a search quietly missing most of what was said, not one missing whole
threads — which is exactly why it was hard to pin down.

Scope

  • Tool calls were never involved. They are activities in
    projection_thread_activities, not rows in projection_thread_messages, so
    they stay out by construction.
  • system notices are now excluded explicitly rather than incidentally.
  • Per-thread dedupe is unchanged: thread_match_rank = 1 still collapses a
    thread to one best row, preferring a user match, then the most recent.
  • Streaming rows stay excluded via the existing is_streaming = 0.

Known limit

A phrase that straddles a split boundary still will not match — each message row
is matched independently, so "the quick brown" in one item and "fox" in the next
is two rows, not one string. Fixing that means matching against a per-turn
concatenation, which is a bigger change with its own cost; happy to do it as a
follow-up if it matters in practice.

Tests

The existing test asserted the old behaviour outright — its fixture literally
read 'Interim needle must not be searchable.' — so that expectation is
inverted here, and a split-answer case is added whose matching half is not the
turn's assistant_message_id. Mutation-checked: restoring the old restriction
fails both new assertions.

Co-authored-by: Patrick Roza 42661+patroza@users.noreply.github.com

Brechard and others added 30 commits August 15, 2026 16:13
)

Co-authored-by: Rodrigo Brechard <rodrigo@clubtidy.fr>
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: maria <maria@kuuro.net>
…#6392)

Co-authored-by: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com>
Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com>
…ingdotgg#7082)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…g#7083)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…in GitHubPullRequestCli (pingdotgg#7385)

Signed-off-by: aoright <102943475+aoright@users.noreply.github.com>
Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com>
t3dotgg and others added 27 commits August 19, 2026 00:47
…tgg#6286)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: GPT-5.6 <noreply@openai.com>
Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com>
Merges 66 upstream commits into fork/dev. Notable weld points:

- ChatComposer: upstream pingdotgg#7150 relocated the prompt editor, length validation
  and footer, leaving the fork's copies as a second live layout. Ported the
  fork-only pieces into upstream's copies first — the environment-unavailable
  placeholder, the model picker's usage snapshot, and the attach-images button
  that drives the hidden iOS file input — then dropped the stale layout.
- MessagesTimeline: upstream's new active-turn block indexes whatever it
  iterates; the fork walks its collapsed/interleaved list, so the block was
  rebased onto that list to keep the indices referring to one array.
- DesktopUpdates: upstream's action reservation and widened installable check,
  kept compatible with the fork's Linux dir-install mode.
- CommandPalette: dropped the `open` prop upstream removed while keeping the
  fork's file-picker / content-search overlays, and took upstream's newer
  reduceCommandPaletteUiState over the fork's relocated copy of the old one.
- mobile-showcase-screenshots: GitHub-hosted runners (this fork has no
  Blacksmith) with upstream's palette-driven timeout.
- ProviderRegistry.test: kept the fork's coverage for mergeProviderSnapshots /
  selectProvidersByKind, which upstream deleted while leaving both exported.

Upstream's new t3code/no-native-title-tooltip rule flagged seven fork-only
components; four had a title duplicating an existing aria-label, three needed
the label moved off the native tooltip.

rerere was disabled for this merge: it had replayed earlier resolutions onto
new upstream content, which is exactly how a weld goes silently wrong.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
Thread search restricted assistant matches to the one row a turn names as its
terminal message:

    messages.message_id IN (SELECT turns.assistant_message_id FROM projection_turns ...)

Providers stream an answer as many assistant items — roughly ten per turn now,
and climbing as chunking gets finer — and only the last is linked as
turns.assistant_message_id. Everything said before it was invisible to search,
which is why full-text search "stopped working" without anything visibly
changing.

Measured on a live state.sqlite: 7,118 of 20,094 settled messages were
searchable (35%); for assistant messages alone it was 3,430 of 16,406 (21%).
Every thread still had *some* searchable text, so the symptom was a search that
quietly missed most of what was said rather than one that missed whole threads.
A real query for "worktree" goes from 138 to 187 threads.

Tool calls were never involved: they are activities in
projection_thread_activities, not rows in projection_thread_messages, so they
stay out by construction. 'system' notices are now excluded explicitly rather
than incidentally.

Per-thread dedupe is unchanged — thread_match_rank = 1 still collapses a thread
to a single best row, preferring a user match, then the most recent.

The existing test asserted the old behaviour outright ("Interim needle must not
be searchable"), so it is inverted here, with a split-answer case added whose
matching half is not the turn's assistant_message_id. Both fail if the old
restriction comes back.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
@github-actions github-actions Bot added the 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. label Aug 20, 2026
@omegent-app
omegent-app Bot merged commit 30193b9 into fork/dev Aug 20, 2026
5 checks passed
@omegent-app
omegent-app Bot deleted the fix/search-all-assistant-messages branch August 20, 2026 07:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships.

Projects

None yet

Development

Successfully merging this pull request may close these issues.