Skip to content

Store repair after a late save from another window - #218

Merged
grunion-ai merged 4 commits into
mainfrom
claude/firefox-store-flake-4076
Nov 1, 2026
Merged

grunion-ai merged 4 commits into
mainfrom
claude/firefox-store-flake-4076

Conversation

@grunion-ai

Copy link
Copy Markdown
Owner

What changed

A window now repairs localStorage when another window's older save lands after its own newer one.

  • template.html: on a storage event for the model, a window that already built on that model and finds it in the store writes its newer model back. On a storage event for the log, it writes the log back when the store is missing any of its entries.
  • deck.html and library.html: rebuilt from the template.
  • test/autosave.test.mjs: a deterministic test that replays the late save in all four browser projects. The existing shape check on the storage listener moves to the new code. Its check that receive() writes nothing stays as it was.
  • docs/editor.md and CHANGELOG.md: the "never writes back" claim now names the exception.

Why

The Firefox two-window failure on main (runs 40194889668 and 40340413387, plus 36496159863 and 36493033117 per #197) is a real lost edit, not a slow test. #197 treated it as a read that came too early.

Window B is typing when window A saves. A writes its model and tells B over BroadcastChannel. B commits its words on top and saves. B's save can still reach the store first, so A's older model lands last and stays there. Both windows show the right deck in memory, and a reload loses B's words.

Verification

A temporary CI workflow ran the two-window flow in Firefox, with three loops alongside the full suite and one loop alone. It read the store from A, from B and from a fresh page.

Build Under suite load Alone
Before the fix (run 41317077509) 12 of 180 lost the edit 0 of 60
After the fix (run 41318413161) 0 of 180 0 of 60
  • In all 12 failures the store still held A's older model after 30 seconds, from A, from B and from the fresh page. B's write was logged 1 to 8 ms after A's.
  • After the fix, the slowest wait for the store to carry B's words was 60 ms.
  • 40 local Firefox runs on macOS passed before the fix, so the race needs CI's load to show.
  • The new test fails on the old template in Chromium and Firefox with a 2 s timeout, and passes with the fix in Chromium, WebKit, Firefox and the embedded pane.
  • The probe did not count how often the repair fired, so the after-fix row shows the outcome only.
  • The workflow and probe script are removed from this branch.

ponytail:

  • template.html, restoreModel and restoreLog: localStorage tier only, since only that tier has a storage event. The IndexedDB tier has no repair. Upgrade path: read the store back after a save made on top of a heard model.
  • template.html, restoreModel: if A saves a third model in the moment B repairs, B's write can land after it and leave the store one model behind until the next save. Upgrade path: stamp each model with a sequence number and refuse older writes.

🤖 Generated with Claude Code

Your Name and others added 4 commits November 1, 2026 09:36
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@grunion-ai
grunion-ai merged commit 0ecc47d into main Nov 1, 2026
1 check passed
@grunion-ai
grunion-ai deleted the claude/firefox-store-flake-4076 branch November 1, 2026 16:15
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.

1 participant