Repository navigation
Conversation
) A setter's returned array is written by index. On rows without a key, the container's arrangement guess was judged equal to the committed rows, because two keyless rows at one index counted as the same row (#3898). The guess was dropped before the seam, so `<For>` (which reads the container) never re-ran, while direct reads saw the per-index guesses. A keyless row has only its contents: at the same index it is the same row when the store would reconcile it unchanged (the #3898 echo still confirms), and another row otherwise. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_015hPxMkC3jg3Uivh65gvaf2
🦋 Changeset detectedLatest commit: 9a71cb5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 15 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 |
Size (brotli, eager entry chunk)
|
Coverage Report for CI Build 40674997604Coverage remained the same at 78.727%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
|
I'm closing this in favour of #4360. That PR fixes #4344 with a broader Generated by Claude Code |
Merging this PR will not alter performance1 warning
Comparing Footnotes
|
Fixes #4344
Summary
Before: an action does
setItems(() => [row("c"), row("b"), row("a")])on acreateOptimisticStorewhose rows have noid. While it is pending, direct reads givec,b,a, but<For>(keyed and non-keyed) keeps renderinga,b,c. With anidon the rows,<For>showsc,b,a. This regressed in 1c14992 (#3898 / #3937).Cause: a returned array is written by index.
notifyOptimisticWritesputs a guess on each index node, which direct reads see. It also puts an arrangement guess (LaneView) on the container node, which is the node<For>/mapArrayreads.optimisticWritedrops a guess that the node's comparator calls equal to what the user saw. The container's comparator (arrangement→arrangementEqual→rowSame) has counted two keyless rows at the same index as the same row since #3937. So the reorder was judged "no change of arrangement", the container guess never reached the seam, and<For>never re-ran. The same rule also kept the screen from hearing the revert at the settle.After: a keyless row has only its contents. At the same index it is the same row when the store would reconcile it unchanged (
GlobalQueue._echoes, the cycle-safe check #3898's landing already uses). Otherwise it is a different row. A server echo of a keyless guess still confirms the arrangement (#3898). A reorder or a replaced row now changes the container, so direct reads and<For>agree both at the guess (F-11: the guess shows at once) and after the settle (D-33: nothing wrote the truth, so the guess reverts). Keyed rows are unchanged: they still match on the key.One line of logic in
rowSame, with no new exports, computations or effects.How did you test this change?
packages/signals/tests/optimistic-reorder-keyless-4344.test.ts. It covers plain and derived stores, rows with and withoutid, keyed and non-keyedmapArray, a returned reorder, and a swap written in the draft. It checks the exact list output at the guess, one tick later, and after the settle (revert toa,b,c). For the derived store it also checks the action writing the truth, which landsc,b,a. The 10 keyless cases fail onnextand pass here.packages/web/test/optimistic-reorder-keyless-for-4344.spec.tsx. This is the issue's repro with exactinnerHTMLchecks at the guess, one tick later, and after the settle, for<For>keyed andkeyed={false}, with and withoutid. Both keyless cases fail onnextand pass here.nextin this environment (uncommitted-input-overwritten,server-functions-adapter-request"keeps a rebuild failure's own error…",lone-spread-hydration-key-4240with a locally stale native compiler,c03-hydration-done-counts-holds).served-error-no-reask"[streamed] the content waits for its sheet" failed once under load and passed on rerun.tsc -p tsconfig.build.jsonin signals: clean.scripts/size: onlyapp: hydrating + every store primitive familychanges, by +9 B minified (95,467 → 95,476; recordedcapMinified95,467, so within the 20 B allowance) and +26 B brotli locally. No cap or floor moves.Generated by Claude Code