Skip to content

fix(signals): preserve parked effects when transitions merge - #3310

Closed
DerpyCrabs wants to merge 2 commits into
solidjs:nextfrom
DerpyCrabs:fix/preserve-merged-transition-effects
Closed

fix(signals): preserve parked effects when transitions merge#3310
DerpyCrabs wants to merge 2 commits into
solidjs:nextfrom
DerpyCrabs:fix/preserve-merged-transition-effects

Conversation

@DerpyCrabs

@DerpyCrabs DerpyCrabs commented Sep 8, 2026

Copy link
Copy Markdown

Summary

Fixes lost render updates when a pending action merges into another transaction. Signal values commit correctly, but the DOM can remain stale because mergeTransitionState does not transfer the outgoing transaction’s parked effect queues.

The fix restores those effects into the scheduler and clears the outgoing stash. Includes a minimal regression test and a patch changeset for @solidjs/signals.

How did you test this change?

Confirmed the regression test fails on current next (94fe5b46) without this fix and passes with it. Also verified a standalone reproduction using only @solidjs/signals and the original application’s grid-switching and clipboard-replacement failures.

Completed validation using Node 24, matching .nvmrc:

  • pnpm i — passed.
  • pnpm --filter @solidjs/compiler run build — passed; prerequisite used by upstream CI.
  • pnpm build — all 25 tasks passed.
  • pnpm test — all 33 tasks passed, including workspace type tests: 4,399 tests passed, 3 skipped.
  • Prettier check of all changed files — passed.

@changeset-bot

changeset-bot Bot commented Sep 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b25f2d9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 11 packages
Name Type
@solidjs/signals Patch
test-integration Patch
@solidjs/web Patch
@solidjs/babel-plugin Patch
@solidjs/compiler Patch
@solidjs/diagnostics Patch
@solidjs/element Patch
@solidjs/h Patch
@solidjs/html Patch
solid-js Patch
@solidjs/universal Patch

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

@DerpyCrabs
DerpyCrabs force-pushed the fix/preserve-merged-transition-effects branch from db4644b to b25f2d9 Compare September 8, 2026 11:43
ryansolid added a commit that referenced this pull request Sep 8, 2026
When a pending action's transaction merges into another (initTransition
called with a transaction while a different one is active), the outgoing
transaction's parked effects — its _queueStash, filled by every flush that
found it incomplete — were dropped on the floor. Signal values still
committed through the surviving transaction, but the render effects that
would have painted them never ran: stale DOM after a correct commit.

Restore the outgoing stash onto the live queue at the merge site. This
flush then parks those effects again under the surviving transaction or
runs them when it completes — the lifecycle every other parked effect has.
The outgoing transaction is dead after the merge (_done chased, removed
from `transitions`, never stashed into or completed), so its stash is not
reset; nothing reads it again.

Regression test from the PR: two actions, the second holding an optimistic
write the first later merges into; on `next` the render effect stays at
[0] after both settle, with the fix it reaches [0, 1].

No changeset: rc.7 is already versioned on `next` but unpublished (the
Release run was blocked by the Compiler-binaries harness bug fixed in the
previous commit), so the entry is folded directly into the rc.7 section of
packages/signals/CHANGELOG.md rather than triggering an rc.8 bump.

Closes #3310

Co-authored-by: DerpyCrabs <derpycrabs@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@ryansolid

Copy link
Copy Markdown
Member

Confirmed and landed as b1c4399 — thank you for the reproduction and the fix, this was a real lost-update bug. Your regression test is in verbatim and you're credited as co-author.

Two small changes from your diff:

  • The restore moved to the merge site in `initTransition` (`this.restoreQueues(outgoing._queueStash)`) rather than inside `mergeTransitionState`. Same behaviour; that phrasing measures byte-neutral on the core-floor size budget where the original form was +19 B (and brotli amplified it to +93 B in the store scenario, over the cap).
  • The `outgoing._queueStash = { ... }` reset was dropped. After the merge the outgoing transaction is dead — `_done` chased, removed from `transitions`, never stashed into or completed again — so nothing reads that stash; the reset was dead bookkeeping.

The changeset was folded straight into the rc.7 changelog instead of committed as a file: rc.7 was already versioned on `next` but its publish had been blocked by an unrelated CI harness issue, so this rides along in rc.7 rather than waiting for rc.8.

Closing in favour of the landed commit.

Claude via Cursor

@ryansolid ryansolid closed this Sep 8, 2026
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