fix(signals): preserve sibling queues during traversal - #2947
Conversation
🦋 Changeset detectedLatest commit: 09d2540 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 |
Merging this PR will not alter performance
Comparing Footnotes
|
…osal #2947 recovered the cursor when a child removed itself or one earlier sibling, but a single dispose can remove several sibling queues at once (a root owning more than one boundary). The list then shifts by more than a slot and the cursor lands past an unprocessed later sibling, whose effects never run. Stamp each child with the current pass before running it, so the traversal is idempotent and a shift can be recovered by rescanning from the front. Children appended mid-pass keep running in that pass, as before. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Merged — thanks, the diagnosis was right and the regression test is a good one. One thing worth flagging for the record: the fix as written recovers the cursor for one removal, but a single I've landed a follow-up on Costs ~30 B brotli in the |
The scenario measured 12.59 KB and had already drifted past the 12.5 KB cap before this batch of fixes. The overage is accumulated correctness work on paths createStore always retains — reconcile's container-kind guard (#2946), the projection derive-swap path (#2941), and the queue traversal pass stamp (#2947) — not a shakeable feature. Restores the ~2% headroom the sibling scenarios carry. Co-authored-by: Cursor <cursoragent@cursor.com>
The bug
Queue.run()traverses child queues with a monotonically increasing array index. A boundary effect can dispose its owner while its queue is running, which removes that queue from_children. The next sibling then shifts into the current index and is skipped, leaving its already-queued effects unexecuted with no later flush scheduled.The fix
Advance the traversal index only while the child that just ran still occupies that slot. If it removed itself or an earlier sibling, process the child that shifted into the current index before advancing.
A regression test creates two loading-boundary queues, disposes the first from its effect, and verifies that the second effect still runs in the same flush.
Tests
vitest run: 78 files, 1,147 tests passedtsc -p tsconfig.build.json --noEmit@solidjs/signalspatch release