Render edited messages in encrypted search results and stop URL queries failing the search#34004
Open
hayaksi1 wants to merge 1 commit into
Open
Render edited messages in encrypted search results and stop URL queries failing the search#34004hayaksi1 wants to merge 1 commit into
hayaksi1 wants to merge 1 commit into
Conversation
…es failing the search Seshat indexes message edits as standalone events, so an encrypted-room search matched the edit event, which the search render path cannot render — the result was silently dropped though still counted (element-hq#32356). And tantivy parses an unescaped colon as a field operator, so a URL query was rejected with FieldDoesNotExist and, because the all-rooms search awaited both legs together, failed the entire search (element-hq#32341). sanitizeSeshatResults now promotes a matched edit by re-keying the result to the original message id and lifting m.new_content into place (de-duplicating against the original, preserving the encryption sidecar), so edits render. A new hardenSeshatSearchTerm phrase-wraps a colon-bearing term for the local Seshat leg only, and combinedSearch runs the two legs with Promise.allSettled, degrading to the surviving leg and failing only when both fail.
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.
Problem
Two correctness bugs in encrypted (Seshat) message search:
(
m.replace) as a standalone event, so a search for the edited text matches theedit event. The search render path has no tile for a replace relation, so the
match silently fails to render even though it is still counted. The live timeline
never hits this because the SDK aggregates the edit onto its target — that
aggregation does not run in the search path.
full-text engine (tantivy) treats an unescaped colon as a
field:valueoperator,so a query such as
https://github.comis parsed as a search of the non-existentfield
httpsand Seshat rejects it withFieldDoesNotExist("https"). Because thecombined (all-rooms) search awaited both legs with
Promise.all, that rejectionfailed the entire search instead of falling back to the homeserver results.
Fix
All changes are confined to
Searching.ts— no UX or API surface change.sanitizeSeshatResultspost-processes each rawSeshat response. It keeps the existing
state_key: nullstrip, and additionallypromotes a matched edit by re-keying the result to the edit's target (the original
message id) and lifting
m.new_contentinto place. The SDK event mapper then resolvesthe renderable original (which carries the aggregated edit in a loaded room) instead
of the live
m.replace; for an unloaded original it builds a fresh event from thepromoted content. Promoted edits that collide with their original are de-duplicated to
avoid a duplicate tile / React-key clash. The encryption sidecar fields that
restoreEncryptionInfoconsumes are preserved. Only the matched event is re-keyed —an edit appearing solely as context is left untouched.
hardenSeshatSearchTermphrase-wraps a termcontaining a colon so tantivy parses it literally instead of as a field operator. It
is applied only to the local Seshat term; the homeserver leg keeps the raw term.
Additionally,
combinedSearchnow runs the two legs withPromise.allSettledanddegrades to the surviving leg if one rejects, failing only when both legs fail —
so a query one backend can't parse no longer takes down the whole search.
Tests
Searching-test.tsadds coverage for: term-hardening (plain term, colon/URL, already-quotedphrase, unbalanced quote, embedded quotes, and that the hardened term reaches Seshat while the
homeserver keeps the raw term); edit promotion (re-key + content lift, non-edit left alone,
context-only edit left alone, dedup of edit+original, and empty
m.new_contentleft alone sono blank tile); and combined-search degradation (server-only fallback, local-only fallback,
and reject only when both legs fail). The existing
state_keytests still pass.Fixes #32356
Fixes #32341
Checklist
public/exportedsymbols have accurate TSDoc documentation.