fix(core): retry a lazy ORM import in lower.ts after a rejection - #1286
Conversation
whereCombinators and vectorLowering cached the promise from a lazy import() even when it rejected, so a single transient import failure was permanent for the life of the process. A rejection now clears the cache so the next call retries; a successful import is still cached. Closes #1231 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HWS4RTvCjP7p5J2LrjNUMR
|
Deployment failed for project stack-docs with the following error: Learn More: https://vercel.com/open-saas?upgradeToPro=build-rate-limit |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
🦋 Changeset detectedLatest commit: 7bdab21 The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
borisno2
left a comment
There was a problem hiding this comment.
Single-pass review at high effort (Agent tool unavailable in this context — no multi-agent fan-out or subagent verify pass ran; I worked all 8 angles myself in one context). This is a small, tightly-scoped fix (69 lines in lower.ts, +68 new test lines). I traced the ??= + synchronous-catch-handler reset logic by hand for races and found none — the mutual exclusion via pending/pendingVector staying truthy while a promise is in flight rules out two generations of the cache ever being confused. No callers depend on the old permanent-cache-on-rejection behavior. No correctness bugs found; the two comments below are low-severity cleanup/docs notes only.
Generated by Claude Code
… cache whereCombinators and vectorLowering duplicated the identical cache-unless-rejected pattern; centralizing it in one lazyImport<T> helper means the race-sensitive logic only needs to be correct once, and moving vectorLowering's loader inline restores its "Known limits" TSDoc onto the exported symbol (it had drifted onto an unexported helper when the previous commit split it out for type inference). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HWS4RTvCjP7p5J2LrjNUMR
|
The Generated by Claude Code |
Coverage Report for Core Package Coverage (./packages/core)
File Coverage
|
||||||||||||||||||||||||||||||||||||||
Coverage Report for UI Package Coverage (./packages/ui)
File CoverageNo changed files found. |
Coverage Report for CLI Package Coverage (./packages/cli)
File CoverageNo changed files found. |
Coverage Report for Auth Package Coverage (./packages/auth)
File CoverageNo changed files found. |
Coverage Report for Storage Package Coverage (./packages/storage)
File CoverageNo changed files found. |
Coverage Report for RAG Package Coverage (./packages/rag)
File CoverageNo changed files found. |
Coverage Report for Storage S3 Package Coverage (./packages/storage-s3)
File CoverageNo changed files found. |
Coverage Report for Storage Vercel Package Coverage (./packages/storage-vercel)
File CoverageNo changed files found. |
Summary
packages/core/src/secured/lower.tsloads Prisma'sand/or/allcombinators (whereCombinators) and the pgvector expression builders (vectorLowering) through a lazyimport(), caching the resulting promise in a module-level variable so the package root's static import graph stays free of@prisma/orm-postgres.Both cached the promise even when it rejected. A single transient import failure was therefore permanent for the life of the process: every later call re-awaited the same rejected promise, and every secured read (and any
.nearest()vector search) would fail until the process restarted, with no way to recover.whereCombinatorswas the specific case flagged in A rejected lazy ORM import in lower.ts is cached permanently, poisoning the process #1231 (deliberately left unfixed in The Where vocabulary and its lowering; the filter module retyped #1220, which was scoped to the blocking findings).vectorLoweringhas the exact same caching pattern in the same file, so I fixed it too rather than leave an identical latent bug sitting next to the one just fixed.What changed
Both functions now clear their module-level cache in a
.catch()before rethrowing, so:??=guard is unchanged).vectorLowering's inline.then()callback was extracted into a smallloadVectorLowering()async function — chaining.catch()directly after the original inline.then()broke TypeScript's contextual typing for theorder/boundclosures (their parameter types are inferred from theVectorLoweringinterface via thePromise<VectorLowering>assignment target, which chaining.catch()onto the same expression disrupted). No behavioral change beyond the fix itself.Test plan
packages/core/src/secured/lower.test.ts: for bothwhereCombinatorsandvectorLowering, mocks the lazy import to throw once, asserts the call rejects, then un-mocks it and asserts the next call succeeds — proving the retry. A separate test proves a successful import is still cached (one factory call across repeated callers).pnpm build(tsc) — cleanpnpm test— 85 files, 1663 passed / 2 skipped (core package)pnpm lint— 0 errors (2 pre-existing warnings, both untouched by this change)pnpm manypkg fixandpnpm format— no changes needed@opensaas/stack-core: patch)Closes #1231
🤖 Generated with Claude Code
https://claude.ai/code/session_01HWS4RTvCjP7p5J2LrjNUMR
Generated by Claude Code