fix(signals): refresh() after a held manual write stays a quiet re-ask - #3265
Merged
Merged
Conversation
When an action wrote to a derived store and later called refresh(store), the lift of the manual-write mask (solidjs#3026) dropped the re-ask classification, so the refetch was treated as a brand-new question and pended every leaf: every sibling row lit up isPending, and a row-scoped affects() could not narrow it (a mark only turns pending on). The lift now falls through to the normal re-ask marking. Same-question motion stays silent; only the written slot and any declared affects() mark read pending until the truth lands. Same-tick precedence (solidjs#2692) is unchanged. Regression in the question-scoped pending suite, observed through tracked readers as JSX reads them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: ccd451f 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
An action doing
affects(row, "id"); setList(...); yield save(); refresh(list)on a plain derived store lit upisPending(() => item.id)on every row during the refetch, not just the marked one.Root cause
The
setListputs a manual-write mask on the derived store, held open by the action's transaction. Whenrefresh(list)runs after the yield it lifts that mask (#3026), and the lift deliberately skipped the re-ask classification. Without it the refetch was treated as a brand-new question, and a new question pends every leaf. A mark can only turn pending on, soaffects()could not narrow it.Measured on the app shape:
refreshsetList+refresh, with or withoutaffectsaffects(row,"id")+refreshFix
The lift falls through to the normal re-ask marking. Same-question motion stays silent; only the written slot and any declared
affects()mark read pending until the truth lands. Same-tick precedence (#2692) is unchanged, and the #3026 refresh-in-action tests still pass.Tests
tests/question-scoped-pending.test.tsgains3.4-held-write: the marked slot pends from click through landing, every sibling leaf and the array length stay silent. Verdicts are observed through tracked readers, as JSX reads them; a bareisPending()after the generator returns sees the mark as already released because nothing subscribed keeps the transaction alive through the refetch. Fails without the fix at the refetch-window assertion.🤖 Generated with Claude Code