Reconcile eligible live searches against in-memory Store state#5327
Draft
lukemelia wants to merge 2 commits into
Draft
Reconcile eligible live searches against in-memory Store state#5327lukemelia wants to merge 2 commits into
lukemelia wants to merge 2 commits into
Conversation
Wire the runtime-common instance matcher/comparator into SearchResource so an eligible live search derives its displayed result set from the server result reconciled against the Store, rather than the raw server result alone: - Add Store candidates that match the filter but are absent from the server result, scoped to the query's target realm(s); remove server cards that no longer match locally. Unresolvable predicates never add a candidate and never remove a server card. - Re-sort the merged set with the query's sort comparator. - Recompute reactively on Store mutation (create/edit/save/delete) via the tracked identity map and a Store mutation-version signal — not only when the server search re-runs. Eligibility is gated to live searches with a complete, client-evaluable result set; one-shot StoreService.search() and non-live/paginated/matches searches stay server-only passthroughs. StoreService exposes the candidate pool (allCardInstances / allFileMetaInstances) and a getMatchAPI() slice for the matcher. The candidate pool dedupes by instance identity: the Store keys each card under both its local and remote id, so an un-deduped pool would surface — and the merge would render — the same card twice. The merge dedupes by id as a second guard. CS-11416 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A live demo of the client-side Store filtering step: two live searches (active and archived) share one Store, each sorted by priority. Creating, archiving, re-prioritizing, or deleting a widget reconciles both lists in place before the realm reindexes, with no server round-trip. The list renders whenever it has results so a background live-refresh doesn't blank it. CS-11416 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
eacca56 to
9c2642e
Compare
Contributor
Preview deploymentsHost Test Results 1 files 1 suites 1h 40m 19s ⏱️ Results for commit 9c2642e. For more details on these errors, see this check. Realm Server Test Results 1 files 1 suites 10m 46s ⏱️ Results for commit 9c2642e. |
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.
What
Wires the runtime-common instance matcher/comparator into
SearchResourceso an eligible live search derives its displayed result set from the server result reconciled against in-memory Store state — the list self-corrects the instant a card is created, edited, or deleted, before the realm reindexes. One-shotStoreService.search()and non-live searches are unaffected.This builds the full-recompute version; an incremental / dirty-set optimization is out of scope and left for separate, measurement-gated work.
How
SearchResource.displayedInstances(new, backs theinstancesgetter): for an eligible live search itunresolvablepredicate never removes a server result),unresolvablecandidates are not added),isClientFilterEligible): live search + matcher loaded + a complete result set (instances.length === meta.page.total) + a client-evaluable filter. Anything else (non-live, paginated/incomplete,matches/full-text) is a server-only passthrough.StoreService.instanceMutationVersionsignal (covers in-place edit/save).StoreServiceexposes the candidate pool (allCardInstances/allFileMetaInstances) and agetMatchAPI()slice for the matcher.Notable correctness detail
The Store keys each instance under both its local id and its remote id, so an un-deduped candidate pool returns the same card twice — which the merge would render as two rows.
allCardInstances/allFileMetaInstancesdedupe by instance identity, and the merge dedupes by id as a second guard. Regression test included.Demo
experiments-realm/client-filter-playground.gts— two live searches (active / archived) over one Store, each sorted by priority. Create, archive/activate, re-prioritize, or delete a widget and both lists reconcile in place with no_federated-searchround-trip (the server reindex catches up a beat later). The list renders whenever it has results, so a background live-refresh doesn't blank it.Tests
tests/integration/resources/search-test.ts,client-side Store filtering stepmodule:store.search, non-live, incompletely-loaded (paginated), and non-client-evaluable (matches) all stay server-only.Notes for reviewers
isLoadingissearch.isRunning, so it flipstrueon every background live-refresh. Consumers that render a loading branch ahead of their results will blank on each round-trip — the demo orders its template to render results when present to avoid this. A resource-levelisRefreshing/ initial-load-only distinction would give consumers flash-free behavior by default; left out here to avoid changing sharedisLoadingsemantics.🤖 Generated with Claude Code