Skip to content

Make indexer module pre-warm populate the definition cache#5042

Open
habdelra wants to merge 6 commits into
mainfrom
cs-11306-module-definition-pre-warm-is-a-silent-no-op-in-the-indexer
Open

Make indexer module pre-warm populate the definition cache#5042
habdelra wants to merge 6 commits into
mainfrom
cs-11306-module-definition-pre-warm-is-a-silent-no-op-in-the-indexer

Conversation

@habdelra
Copy link
Copy Markdown
Contributor

Background and Goal

The indexer's module-definition pre-warm step runs in the worker, reports success, and persists zero definition-cache rows. Every type-filtered store.search() during the visit phase then resolves its card definition on demand, firing a same-affinity prerenderModule mid-render — the exact mid-render sub-prerender serialization pre-warm exists to prevent, which contributes to render timeouts on aggregate-card-heavy realms.

Root cause: the worker builds a bare CachingDefinitionLookup with no registered realm, so preWarmModulesTable's getCachedDefinitions call self-resolves a null cache context (buildLookupContext returns null) and returns without persisting. Because it returns rather than throws, the failure counter stays 0 — so pre-warm logs success while doing nothing. Definitions still get cached, but lazily, by the realm-server during the visit phase — precisely the on-demand path pre-warm was meant to eliminate.

Where to start

  • packages/runtime-common/index-runner.tspreWarmModulesTable now threads the context getModuleCacheContext() already computes into the populate call instead of relying on self-resolution.
  • packages/runtime-common/definition-lookup.ts — new populateDefinitionCacheEntry(args) on the DefinitionLookup interface: a read-through populate that takes explicit cache context rather than self-resolving it via #realms / a remote probe.

Key decisions

  • The explicit warm context is keyed identically to the visit-phase reader (cacheScope: 'realm-auth', cacheUserId = realm-owner user id, resolvedRealmURL = realm URL) — the same context the read-only batch reader already uses — so the warmed row is the one the reader reads, not a mismatched key.
  • If a private realm resolves an empty cache user id (a misconfiguration that shouldn't occur, since the owner id derives from the realm username), pre-warm is skipped with a warning rather than writing keys the reader can't read or failing the index job — preserving the existing "pre-warm never fails the batch" contract.
  • The regression test uses a lightweight pg-adapter + mock-prerenderer setup (no realm-server / Chromium) to assert the bare-lookup no-op vs. the explicit-context persist, and that a realm-scoped reader reads the warmed row without re-prerendering.

The worker constructs a bare CachingDefinitionLookup with no registered
realm, so preWarmModulesTable's getCachedDefinitions call self-resolved a
null context and persisted nothing — pre-warm reported success while doing
nothing, leaving every type-filtered search to resolve its card definition
on demand mid-render.

Thread the cache context the IndexRunner already computes into a new
explicit-context read-through populate (populateDefinitionCacheEntry),
keyed identically to the visit-phase reader (realm-auth / realm-owner
user id). Skip pre-warm with a warning if a private realm resolves an
empty cache user id, so it never writes keys the reader cannot read.

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

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

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: 14c58465ae

ℹ️ 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/runtime-common/index-runner.ts Outdated
Resolving the pre-warm cache context fetches realm _info, which can
transiently fail. Pre-warm is best-effort, so wrap the context lookup so
a failure warns and skips pre-warm — letting the visit phase populate on
demand — instead of throwing out of preWarmModulesTable and aborting the
whole indexing run.

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

github-actions Bot commented May 29, 2026

Preview deployments

Host Test Results

    1 files  ±0      1 suites  ±0   1h 45m 22s ⏱️ - 7m 26s
2 842 tests ±0  2 827 ✅ +1  15 💤 ±0  0 ❌ ±0 
2 861 runs  ±0  2 846 ✅ +2  15 💤 ±0  0 ❌  - 1 

Results for commit 9116388. ± Comparison against earlier commit 4565b4c.

Realm Server Test Results

    1 files  ±0      1 suites  ±0   13m 0s ⏱️ -24s
1 517 tests ±0  1 516 ✅ ±0  1 💤 ±0  0 ❌ ±0 
1 608 runs  ±0  1 607 ✅ ±0  1 💤 ±0  0 ❌ ±0 

Results for commit 9116388. ± Comparison against earlier commit 4565b4c.

…-module-definition-pre-warm-is-a-silent-no-op-in-the-indexer
@habdelra habdelra changed the base branch from main to factory-lint-main May 29, 2026 22:14
@habdelra habdelra requested a review from Copilot May 29, 2026 22:16
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a silent no-op in the indexer worker's module-cache pre-warm. The worker constructs a bare CachingDefinitionLookup with no registered realm; the previous self-resolving getCachedDefinitions path returned null from buildLookupContext and persisted nothing while reporting success. The fix introduces an explicit-context populate API and threads the same context the visit-phase reader uses.

Changes:

  • New populateDefinitionCacheEntry(args) on DefinitionLookup (and both implementations) accepting explicit cache context instead of self-resolving via #realms/remote probe.
  • IndexRunner.preWarmModulesTable now resolves cache context via getModuleCacheContext() and calls the explicit populate; gracefully skips with a warning on context-resolution failure or on a private realm with empty cache user id.
  • Regression test in definition-lookup-test.ts reproducing the bare-lookup no-op vs. explicit-context persist, and verifying the warmed key is read by a realm-scoped reader without re-prerendering.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/runtime-common/index-runner.ts Resolve cache context, validate non-empty user id for private realms, and call new explicit-context populate.
packages/runtime-common/definition-lookup.ts Add PopulateDefinitionCacheEntryArgs and populateDefinitionCacheEntry on interface + both implementations.
packages/realm-server/tests/definition-lookup-test.ts Adds worker-bare-lookup regression test asserting no-op vs explicit-context persistence and key alignment.
packages/realm-server/tests/matches-filter-integration-test.ts Update stub to satisfy expanded DefinitionLookup interface.
packages/host/tests/unit/index-query-engine-test.ts Update stub to satisfy expanded DefinitionLookup interface.

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

habdelra and others added 3 commits May 29, 2026 18:23
Pre-warm sweeps every realm .gts/.gjs to prime sibling card modules, so
it also touches files that aren't cards and fail to prerender (e.g. a
non-card realm.gts). Persisting those errors pollutes the modules cache
with rows no reader requested. Thread a skipErrorPersist flag through the
populate path so pre-warm returns without caching a non-missing prerender
error; the on-demand visit-phase lookup still re-derives and caches the
error if the module is genuinely needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The fixture realm's indexing now pre-warms its card modules (including
person.gts) into the modules cache. The lookupDefinition / invalidation /
extensionless-invalidation tests asserted prerenderModule call counts
assuming a cold cache, so a pre-warmed row made the first lookup a cache
hit (0 calls instead of 1). Clear the modules table at the start of each,
matching the pattern the other prerender-count tests in this module use.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pre-warm exists to keep the prerender server's affinity-scoped tab pool
from deadlocking on a mid-render sub-prerender. The in-browser realm (host
tests run a Realm + IndexRunner inside a Chrome tab) has no separate
prerender server or tab pool, so pre-warm is pointless there — and harmful:
the in-browser realm shares the global card-reference prefix registry with
the host, so populating the definition cache before the host registers a
prefix bakes in keys the prefixed reader can't match (a real server only
ever receives resolved URLs over the wire and never hits this). Skip
pre-warm when running in the browser test environment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@habdelra habdelra requested a review from a team May 30, 2026 00:03
@habdelra habdelra changed the base branch from factory-lint-main to main May 30, 2026 00:07
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.

2 participants