Skip to content

Unified search: host consumer + selective Store inflate + live render type#5176

Merged
habdelra merged 4 commits into
mainfrom
cs-11434-unified-search-host-consumer-selective-store-inflate-live
Jun 10, 2026
Merged

Unified search: host consumer + selective Store inflate + live render type#5176
habdelra merged 4 commits into
mainfrom
cs-11434-unified-search-host-consumer-selective-store-inflate-live

Conversation

@habdelra

@habdelra habdelra commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Phase 1 / Stream B base of Unify prerendered-card-search and card-search: the host-side reader for the unified search document. Based on main (which already has the Phase-0 contracts + render-type rule).

Additive — it generalizes the consumer and tightens the Store deposit without removing the old path, and develops against fixtures (the live call-site wiring follows in a later Stream B ticket).

Changes

  • lib/unified-search-results.tsbuildRenderableSearchItems(doc, importCss) reads a UnifiedSearchCollectionDocument into renderable rows: an identity-only card (resolved from its rendered-html in included) becomes an inert htmlComponent with its scoped css imported via the loader; a full live card becomes a no-component row the caller renders live from the Store. css is deduped across rows.
  • services/store.tsaddResourceFromSearchData skips any meta.identityOnly resource. An attribute-less stub is never deposited, so it can't misrepresent the instance or clobber a correctly-loaded full one; the Store is populated for an HTML-backed row only at hydration.
  • components/card-search/item-button.gts — a @renderType arg drives the live CardRenderer's @codeRef, replacing the hardcoded CardDef (kept only as the default when no render type is threaded), so a live/fallback row renders as the same ancestor type as its prerendered-HTML siblings.

Tests

  • Consumer (unit): identity-only → inert component + css imported + render type echoed; full → no component; a css shared across rows imports once; a missing rendered-html → no component (graceful); an error rendered-htmlisError.
  • Store (integration): a prefer-HTML search does not deposit identity-only rows; an identity-only row does not clobber a pre-resident full instance (via a /_federated-search route override returning a unified doc).

Locally: host type-check + lint clean; unit tests pass standalone, the Store integration tests pass against the base-realm test stack.

The render-type visual parity (a live row rendered via @codeRef matching its HTML sibling) lands with the component-consolidation work that wires real unified data through the leaf; the render-type arg it depends on is in place here.

🤖 Generated with Claude Code

habdelra and others added 2 commits June 9, 2026 18:27
…nflate + live render type

Stream B base — the host reads the unified search document, keeps the Store
honest, and renders live cards as the resolved render type. Develops against
fixtures; live call-site wiring follows.

- lib/unified-search-results.ts: buildRenderableSearchItems maps a
  UnifiedSearchCollectionDocument to renderable rows — an identity-only card
  (resolved from its rendered-html in included) becomes an inert htmlComponent
  with its scoped css imported via the injected loader; a full live card
  becomes a no-component row the caller renders live. css is deduped across
  rows. + unit tests.
- services/store.ts: addResourceFromSearchData skips any meta.identityOnly
  resource — an attribute-less stub is never deposited, so it can't
  misrepresent the instance or clobber a correctly-loaded full one.
- components/card-search/item-button.gts: a @renderType arg drives the live
  CardRenderer's @CodeRef, replacing the hardcoded CardDef (which remains the
  default only when no render type is threaded), so a live row renders as the
  same ancestor type as its prerendered-HTML siblings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Verify that a prefer-HTML search never deposits an identity-only row into
the Store and never clobbers a pre-resident full instance for the same id,
by overriding the mock /_federated-search route to return a unified doc with
an identity-only card. Exports registerRealmServerRoute so a test can swap a
single realm-server route and restore it via registerDefaultRoutes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ac321b967e

ℹ️ 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".

Comment thread packages/host/app/services/store.ts Outdated
When a prefer-HTML search returns an identity-only row for a card already
fully loaded in the Store, return that resident instance instead of dropping
it: it stays represented in the results and a hydrated row keeps its live
presentation. A not-yet-loaded identity-only row is still skipped (renders
from its HTML); the stub is never deposited and a resident instance is never
clobbered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Preview deployments

Host Test Results

  1 files  ±    0    1 suites  ±0   13m 49s ⏱️ - 1h 36m 22s
355 tests  - 2 654  355 ✅  - 2 639  0 💤  - 15  0 ❌ ±0 
356 runs   - 2 672  356 ✅  - 2 657  0 💤  - 15  0 ❌ ±0 

Results for commit 26b70c1. ± Comparison against earlier commit 05d23d3.

Realm Server Test Results

    1 files      1 suites   10m 30s ⏱️
1 575 tests 1 575 ✅ 0 💤 0 ❌
1 666 runs  1 666 ✅ 0 💤 0 ❌

Results for commit 05d23d3.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the host-side “unified search” consumer utilities and related wiring to support mixed search rows (HTML-backed identity-only vs live Store-backed), along with Store behavior to avoid depositing identity-only stubs and a render-type threading hook for live rendering parity.

Changes:

  • Introduces buildRenderableSearchItems() to turn a unified search document into renderable rows, including CSS dedupe/import for HTML-backed rows.
  • Updates StoreService.addResourceFromSearchData() to skip depositing meta.identityOnly resources while still returning an already-resident full instance when present.
  • Extends card-search/item-button to accept a @renderType arg and use it for CardRenderer @codeRef (with a CardDef default).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/host/app/lib/unified-search-results.ts New unified search document consumer that builds renderable items and imports deduped CSS for HTML-backed results.
packages/host/app/services/store.ts Skips depositing identity-only search resources to avoid Store stubs/clobbers; returns resident full instance when already loaded.
packages/host/app/components/card-search/item-button.gts Adds @renderType arg and uses it for live CardRenderer @codeRef with a default fallback.
packages/host/tests/unit/unified-search-results-test.ts Unit coverage for identity-only vs live rows, CSS dedupe, missing rendered-html, and error propagation.
packages/host/tests/integration/store-test.gts Integration coverage ensuring identity-only search rows don’t enter/clobber the Store.
packages/host/tests/helpers/realm-server-mock/routes.ts Exports registerRealmServerRoute so integration tests can override the mock search route.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/host/app/lib/unified-search-results.ts
Comment thread packages/host/app/components/card-search/item-button.gts
// not-yet-loaded identity-only row is skipped and renders from its HTML.
if (resource.meta?.identityOnly === true) {
let existingInstance = this.peek(resource.id);
return existingInstance && isCardInstance(existingInstance)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖]

Minor edge case (not a crash) in the selective inflate: this identity-only branch is card-shaped, so it never returns a resident FileDef. this.peek(resource.id) resolves against the card type and isCardInstance is false for a FileDef, so an already-loaded file whose row comes back identity-only falls through to undefined — it renders inert-from-HTML rather than keeping its live presentation, even though the live instance is resident.

The full file-meta branch right below already does the type-aware thing (this.peek(resource.id, { type: 'file-meta' }) + isFileDefInstance). The identity-only branch could mirror it for file rows — e.g. branch on isFileMetaResource(resource) to pick the peek type and the instance check.

Harmless for the card path and for not-yet-loaded files (those render from HTML by design), so this is a follow-up, not a blocker. Noting it here since it's the selective-inflate's concern; surfaced while wiring the host file-meta consumer in #5180.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] Fixed on this branch (26b70c1). The identity-only inflate branch is now type-aware: a file row peeks (and type-checks) as a FileDef, mirroring the full file-meta branch below it — so an already-resident FileDef whose row comes back identity-only keeps its live instance instead of dropping to inert HTML. Added a store-test sibling of the resident-card test for the FileDef path.

Landing it here (cs-11434), the lowest branch where both the inflate branch and the file-meta infra live, rather than on the host FileDef-parity branch — it reaches that branch via the stack.

…ile-meta row

The selective inflate's identity-only branch peeked card-typed, so an
already-resident FileDef whose search row came back identity-only failed
`isCardInstance` and dropped to `undefined` — rendering inert from its HTML
instead of keeping its live instance. Make the resident lookup type-aware: a
file row peeks (and type-checks) as a FileDef, mirroring the full file-meta
branch directly below it.

Test: an identity-only file-meta row for an already-resident FileDef returns
the live FileDef (a file row is not dropped to HTML).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@habdelra
habdelra merged commit c2770cb into main Jun 10, 2026
96 of 100 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants