fix(signals): exempt the thenable probe from the store strict-read check - #3263
Merged
Merged
Conversation
Resolving a promise with a store proxy — refresh(store)'s waiter delivers the store, Promise.resolve(store), `return store` from an async function — makes the engine read `store.then` synchronously in the caller's scope. When that scope carries a strict-read label (an effect callback, a component body) the read produced a spurious STRICT_READ_UNTRACKED warning, and against a refetching derived store it could escalate to the PENDING_ASYNC_UNTRACKED_READ throw, rejecting the promise being resolved. `await refresh(list)` inside an action logged the warning on every call. The `then` probe is not a read the user wrote; it is now exempt from both. Regressions live in the store strict-read suite. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: ccd1605 The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 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 |
ryansolid
added a commit
that referenced
this pull request
Sep 4, 2026
…atch #3264/#3265/#3266 (+ dev-only #3263) land ~35 B on always-retained store paths, and #3262's handleAsync try/catch adds ~5 B to the core scenarios. A golf pass was attempted and measured strictly worse in every direction (helper extraction +29 B, full inline +70 B, has-trap arm merge -1/+7 B) — the graph is at its brotli optimum post-#3270. Ratchet per convention with audit notes: createStore 14.16 -> 14.20 KB, isPending/latest 10.04 -> 10.05, store-family app 26.25 -> 26.27. No package source changes, no changeset. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolving a promise with a store proxy makes the engine read
store.thensynchronously to check for a thenable. That read goes through the store's get trap in whatever scope the resolution happens.refresh(store)'s waiter effect resolves with the store from its callback, which carries thean effect callbackstrict-read label, so everyawait refresh(list)inside an action logged:The diagnostic payload is
{ property: "then", source: "store" }— the engine's probe, not a read the user wrote.Promise.resolve(store)orreturn storefrom an async function in a component body hit the same path, and against a refetching derived store the probe could escalate to thePENDING_ASYNC_UNTRACKED_READthrow, rejecting the promise being resolved.Fix
The store trap's strict-read branch skips the
thenkey. Real untracked reads still warn.Tests
Three cases folded into
tests/strict-read-pending-store.test.ts:await refresh(store)on a derived store,Promise.resolve(store)in a component body next to a control read that still warns, and a probe on a refetching derived store. All three fail without the fix.Verified in a client-mode app on rc.6: one Vote click logged the warning with the pristine bundle and nothing with the patched one.
🤖 Generated with Claude Code