Skip to content

Match type filters through re-export spellings via canonical code refs - #5800

Draft
lukemelia wants to merge 1 commit into
mainfrom
cs-12168-type-filtered-search-expands-the-adoption-chain-for-card
Draft

Match type filters through re-export spellings via canonical code refs#5800
lukemelia wants to merge 1 commit into
mainfrom
cs-12168-type-filtered-search-expands-the-adoption-chain-for-card

Conversation

@lukemelia

Copy link
Copy Markdown
Contributor

What this does

A filter.type/on code ref that names a type through a re-exporting module — the canonical example being base FileDef addressed via its documented file-api module, which re-exports it from card-api — silently matched nothing. Index rows stamp types with the canonical (defining-module) key from identifyCard, so only the canonical spelling ever joined the membership keys: filtering on base FileDef returned zero rows while concrete subtype filters matched, making the base-type filter a silent dead end.

Two halves, kept in agreement:

  • Query engine: each type condition's ref now resolves through the definition lookup, and the compiled types membership predicates union the canonical ref's spelling-tolerant keys (RRI / real-URL / virtual-alias) with the as-given ref's. Because the definition lookup is async, the type condition becomes a deferred expression node resolved in pass 1, alongside the existing deferred kinds. A ref whose definition doesn't resolve keeps only its spelling-based keys and matches nothing, exactly as before.
  • Host search resource: the same rewrite is applied (via the loader + identifyCard) before client-side matching — the matcher compares refs against identifyCard of an instance's class, so an uncanonicalized re-export spelling would strip the server's correct results during live reconciliation. Until the rewrite settles for the active filter, or when a ref doesn't resolve, the search stays a server-only passthrough so the two evaluations can't disagree.

The shared walker (runtime-common/query-canonicalization.ts) rewrites type/on refs through any/every/not without mutating the input tree, and single-flights duplicate ref spellings by memoizing the in-flight promise — sibling nodes are walked concurrently, so a value-memo would double-resolve.

Test plan

  • packages/realm-server/tests/search-entries-engine-test.ts: a pure base-FileDef filter matches every file row across subtypes, and the file-api re-export spelling matches the same rows as the canonical card-api spelling (36/36 pass locally).
  • packages/host/tests/unit/query-canonicalization-test.ts: rewrite of top-level and nested refs, input-tree immutability, unresolvable refs marking the result incomplete, and duplicate refs resolving once (8/8 pass locally via the dev test page).
  • Typechecks pass across runtime-common, realm-server, and host.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Preview deployments

Host Test Results

    1 files  ±  0      1 suites  ±0   1h 54m 21s ⏱️ + 23m 5s
4 162 tests +627  4 148 ✅ +624  14 💤 +3  0 ❌ ±0 
4 180 runs  +630  4 166 ✅ +627  14 💤 +3  0 ❌ ±0 

Results for commit 7921aea. ± Comparison against earlier commit bcbbc1f.

Realm Server Test Results

    1 files  ±0      1 suites  ±0   15m 17s ⏱️ -23s
2 176 tests ±0  2 176 ✅ ±0  0 💤 ±0  0 ❌ ±0 
2 256 runs  ±0  2 256 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 7921aea. ± Comparison against earlier commit bcbbc1f.

A filter whose `type`/`on` ref named a type through a re-exporting module
(e.g. file-api's FileDef, re-exported from card-api) silently matched
nothing: index rows stamp `types` with the canonical (defining-module) key
from identifyCard, so only the canonical spelling joined the membership
keys. Filtering on base FileDef via its documented file-api module returned
zero rows while subtype filters matched.

The query engine now resolves each type condition's ref through the
definition lookup and unions the canonical ref's spelling-tolerant keys with
the as-given ref's, so both spellings compile to the same `types` membership
predicates. The type condition becomes a deferred expression node
(pass-1-resolved) since the definition lookup is async.

The host's search resource applies the same rewrite before client-side
matching — the matcher compares against identifyCard of the instance's
class, so an uncanonicalized re-export spelling would strip the server's
correct results during reconciliation. Until the rewrite settles for the
active filter (or when a ref doesn't resolve), the search stays a
server-only passthrough.

The shared canonicalization walker single-flights duplicate ref spellings
by memoizing the in-flight promise: sibling filter nodes are walked
concurrently, and a value-memo would let both siblings miss.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@lukemelia
lukemelia force-pushed the cs-12168-type-filtered-search-expands-the-adoption-chain-for-card branch from bcbbc1f to 7921aea Compare August 18, 2026 20:58
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.

1 participant