fix(server-storage): a superseded page sends and saves nothing; re-reads keep other tabs' newer saves

A suspended tab's retry timer could run before it was shown again: touch()
recreated the record another tab had removed when it adopted the page's
writes, so the page sent them again over newer edits. The facade now
treats a page whose record is gone as superseded: the queue sends nothing
(maySend hook), its journal and record are not written again, and the
retry timer reloads it like a page shown again.

A re-read answered after another tab saved an entry no longer writes the
older answer over the shared cache: entries changed while the read
travelled are kept, with an unknown tag, so the next write here
conflicts and replays instead of removing what the other tab saved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5.5 committed 2026-10-14 14:11:33 +02:00
1 parent 52d733e1c7
commit e286a62b2e
7 files changed
+184 -21

No files matched your search

+4 -2
View File
@@ -237,7 +237,8 @@ settings and guards read them in every build.
its record closed on `pagehide` (not into the back-forward cache, where
its record goes stale, as in a background tab the browser suspends;
restored or shown again after another tab adopted it, the page reloads
rather than send those writes again), and
rather than send those writes again, and until then it neither sends nor
saves them, also when its retry timer runs first), and
only a closed, stale or missing record is taken over: a duplicated tab,
which copies `sessionStorage`, leaves the running tab its writes. A page
load that still looked live (or whose close flag storage refused) is
@@ -266,7 +267,8 @@ settings and guards read them in every build.
stays parked). Replayed edits keep recently viewed lists newest first,
as the app cuts them at their limit from the end. Also,
re-reads run one at a time and keep entries edited while they were in
flight or not yet saved. A response body cut off after its headers counts
flight or not yet saved, and entries another tab saved meanwhile (the
answer predates them; their next write here conflicts and replays). A response body cut off after its headers counts
as offline. Each write is sent on the tag of the entry it was made
against (`UserDataWriteQueue`); after a `412` the edit (before → after) is
replayed on the server's current value, so another device's change to the