Unified search: collapse federated runners, mergers & handlers into one#5167
Conversation
Collapse the duplicated federated runners, mergers, and HTTP handlers onto the single projection-parametrized search(). No wire-shape change — both federated endpoints still emit today's two doc shapes; the prefer-HTML emission lands in the next step. - search-utils.ts: one fanOutRealmSearch fan-out shared by searchRealms (live) and searchPrerenderedRealms (now thin wrappers, differing only in the per-realm method, failure label, and merge). combineSearchResults dedupes included by the identity pair (type, id) rather than id alone, so a card and its rendered-html (same id) coexist while a shared css or linked card travels once. - realm-server handlers: extract the job-scoped cache + ETag/304 protocol into one respondWithJobScopedSearchCache core both handlers call; handle-search-prerendered shrinks to parse + run + delegate. handle-search parses the unified request and folds render/dataOnly/cardUrls into the cache key, so the two endpoints can't collide and a render/dataOnly difference segregates entries + ETags. Job-id + consuming-realm gating and 304 path unchanged. Tests: merge dedup over (type, id); live cache-key segregation by render/dataOnly/cardUrls; the existing endpoint suites pass unchanged as the parity goldens. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 28607d7d30
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
Collapses duplicated federated search fan-out/merge logic and shared job-scoped caching behavior into single, projection-parameterized primitives, as part of the “unified search” refactor while preserving existing endpoint wire shapes.
Changes:
- Refactors federated realm fan-out into a shared
fanOutRealmSearchand updates the unified merge to dedupeincludedby(type, id). - Extracts job-scoped cache + ETag/304 behavior into
respondWithJobScopedSearchCacheand reuses it in both federated handlers. - Adds targeted tests for
(type,id)included dedupe and cache-key/ETag segregation across unified request members.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/runtime-common/search-utils.ts | Introduces unified merge semantics and shared federated fan-out helper used by both live and prerendered runners. |
| packages/realm-server/handlers/handle-search.ts | Parses unified request members and folds them into the job-scoped cache key; extracts shared cache/ETag logic. |
| packages/realm-server/handlers/handle-search-prerendered.ts | Reuses the shared job-scoped cache/ETag helper to remove duplicated caching logic. |
| packages/realm-server/tests/unified-search-contracts-test.ts | Adds unit coverage for unified combineSearchResults included-dedupe behavior. |
| packages/realm-server/tests/server-endpoints/search-test.ts | Adds endpoint coverage ensuring cache-key/ETag segregation by unified request members. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…the cache key - combineSearchResults: write the (type, id) identity separator as a backslash escape rather than a raw NUL byte, so the source stays ASCII. A raw NUL made text tooling (rg/grep) classify the whole file as binary; the runtime separator is unchanged. - handle-search: fold cardUrls into the job-scoped cache key only when non-empty. An empty array is a no-op filter, so folding it would fragment the cache against an equivalent request that omits cardUrls. The segregation test now asserts cardUrls: [] shares the plain-query entry. - Reword the comments introduced in this change to state the current contract. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Host Test Results 1 files ± 0 1 suites ±0 1h 50m 51s ⏱️ - 3m 6s Results for commit a01b7a1. ± Comparison against earlier commit 7dc6516. Realm Server Test Results 1 files ±0 1 suites ±0 10m 44s ⏱️ +12s Results for commit a01b7a1. ± Comparison against earlier commit 7dc6516. |
…ch-collapse-federated-runners-mergers-handlers # Conflicts: # packages/realm-server/handlers/handle-search-prerendered.ts # packages/runtime-common/search-utils.ts
Phase 1 / Stream A step 2 of Unify prerendered-card-search and card-search: collapse the duplicated federated runners, mergers, and HTTP handlers onto the single projection-parametrized
search(). No wire-shape change — both federated endpoints still emit today's two doc shapes (the existing endpoint suites are the parity goldens); the prefer-HTML emission turns on in the next step.The change
runtime-common/search-utils.tsfanOutRealmSearchfan-out (filter dead realms → settle concurrently → log per-realm failures → return fulfilled docs in realm order).searchRealms(live) andsearchPrerenderedRealms(prerendered) are now thin wrappers over it, differing only in the per-realm method they call, the failure label, and the merge.combineSearchResultsdedupesincludedby the JSON:API identity pair(type, id)instead ofidalone — so acardand itsrendered-html(which share the card URL as id) can coexist, while acss(hash id) or a linkedcardshared across realms travels once. Parity-preserving for today'scard/file-metaincluded.realm-server/handlers/respondWithJobScopedSearchCachecore that both handlers call;handle-search-prerendered.tsshrinks to parse + run + delegate.handle-search.tsnow parses the unified request (render/dataOnly/cardUrls) and folds those members into the cache key, so the two endpoints can't collide on a shared key and arender/dataOnlydifference segregates entries + ETags. Job-id + consuming-realm gating and the 304 path are unchanged.Tests
cssand a shared linkedcardacross two realms appear once inincluded; acardand its same-idrendered-htmlboth survive ((type, id)discriminates whereidalone would collapse them)./_federated-search): requests differing only onrender.format/render.renderType/dataOnly/cardUrlsget distinct entries + ETags; an explicit defaultrenderand a plain query share one entry; identical requests still hit — and the render members don't yet change the response body./_federated-search+/_federated-search-prerenderedsuites (federation, caching, ETag/304, auth, errors) pass unchanged as the parity goldens.Locally:
runtime-common+realm-servertype-check clean; unified-search contracts 20/20, job-scoped-search-cache 16/16, the two federated endpoint suites 89/89.🤖 Generated with Claude Code