Repository navigation
fix(signals): a removed optimistic row stays removed when another removal's refresh lands (#4441) - #4458
Conversation
) A keyed arrangement guess re-based over an older truth (`_laneRebase`) wrote the composed rows back into `view.rows`, and the next re-base composed from those. A derive's landing writes key by key (`d.length = n`, then `d[i] = row`), so each partial write re-bases: the first one showed the old row at the truncated length, the re-base appended it as a truth row the guess lacked, and from then on it was part of "the guess". The removed row came back once the refresh landed (D-35, F-11). Each re-base now composes from the guess as the setter wrote it (`view.g`). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015hPxMkC3jg3Uivh65gvaf2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015hPxMkC3jg3Uivh65gvaf2
🦋 Changeset detectedLatest commit: 07bda74 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)
Bundled with Rolldown (what Vite ships), brotli q11, decimal KB. A scenario fails only when it is over its brotli cap and its minified size is more than 20 B over the minified recorded with the cap; over the cap within that allowance is brotli layout noise and passes with a warning. Caps and their recorded minified in |
Coverage Report for CI Build 41043974575Coverage remained the same at 78.1%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
Merging this PR will not alter performance1 warning
Comparing Footnotes
|
…ad; seat rows D1''/L1''/V3'' (#4472) * fix(signals): a netted write read in a strict untrack is no staged read; seat rows D1''/L1''/V3'' #4452 made a signal's staging equal to its committed value (writes that netted, D-8) a read of the screen in `read`'s fast block. The reader-seat table still raised Fl on that read (rows D1 / L1 / D7, and V3 for a verdict reader), so the shadow's seat parted from the flags and every later read of the pass reported too ("world after the read", "verdict seat after the read", B2 "born held"): 8 INV-seat-3 classes (x59) in the signals suite, 7 in web, and 60 in the generator (37 / 35 / 43 at 2,000 cases x seeds 3289 / 91501 / 7, every pair). Bisected over every merge 7135a77..131ceb8: 0 before #4452 (66c6f56), 60 at it, none added by #4453, #4458, #4460, #4454, #4457 or #4455. The runtime follows the rule (D-8: a tick whose writes net to the committed value made no proposal), so the table was stale: rows D1''/L1'' (D7'' in a lane) and V3'' serve P and raise nothing. Shadow: 0 classes in signals, web and the generator. With the rows in, the shadow found the path #4452 missed: in dev a labelled `untrack` read (`strictRead`) takes the slow path, where `serve` still called `stagedRead`, so dev held the errored re-run that prod (fast block) does not. `serve` now skips it for a netted signal in dev; prod folds the test away (0 B on every scenario). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015hPxMkC3jg3Uivh65gvaf2 * fix(signals): gate serve's netted skip on the strict read, not on dev Only the strict untrack read skips the fast block in dev; a hydration snapshot or a promoted write reaches serve in dev and prod alike and keeps the staged-read mark. 0 B in prod. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015hPxMkC3jg3Uivh65gvaf2 --------- Co-authored-by: Claude <noreply@anthropic.com>
Summary
Before: with two removals pending on an optimistic keyed list, a refresh that landed for the first one brought its removed row back. The lane's re-base wrote its composition over the guess (
view.rows). The derive's key-by-key landing then appended a truth row that a partial write had shown, and that row stuck.After: each re-base composes from the rows the guess actually wrote, over the latest truth (D-35, F-11). A removed row stays removed until its own removal resolves.
How
LaneViewkeeps the guess as written in a newgfield._laneRebasecomposes fromginstead of fromview.rows:const guessed = (view.g ??= view.rows).Size vs next @ 7135a77: the compiled floor (hello world) is unchanged.
app: hydrating + every store primitive familyis −31 B brotli / +6 B minified. No cap is crossed.How did you test this change?
packages/signals/tests/optimistic-removed-row-returns-4441.test.ts. It fails onnext.server-functions-adapter-requestalso fails onnext.errored-loading-superseded-pass-3750failed once under load and passed 2 of 2 reruns.Fixes #4441
Generated by Claude Code