fix: a popup save no longer undoes a network switch the background saved during it (closes #641)
check / check (push) Canceled after 0s
e2e / e2e-chrome (push) Canceled after 0s
e2e / e2e-firefox (push) Canceled after 0s

The popup's saveState() and the background's updateState() each read the
stored record, change it and write it back, and each was ordered only within
its own context, so a write by one could land between the other's read and
write and be lost. Both now hold the browser's lock (navigator.locks, shared
by every page and the background) from the read to the write, through
withLock() in src/shared/browserApi.js; the recovery screen's reset takes it
too. The lock also orders a page's own saves, so both per-context queues are
gone. The unit tests get a small lock from a Jest setup file.

Model: opus-5-5
This commit is contained in:
2026-10-20 15:00:17 +00:00
parent 4109c4d44a
commit 6a1fb7da39
16 changed files with 199 additions and 58 deletions
+11
View File
@@ -1389,6 +1389,17 @@ carries a `schemaVersion` — `STATE_SCHEMA_VERSION` in
`saveState()` and the background's `updateState()` both do, so whichever context
wrote last, the record says which build's shape it is in.
Each write reads the record, changes it and writes it back, holding a lock from
the read to the write: the browser's own (`navigator.locks`), which every page
of the extension and its background share, taken through `withLock()` in
`src/shared/browserApi.js`. The popup's `saveState()`, the background's
`updateState()` and the StateRecovery reset all take it, so no write lands
between another write's read and its write, where it would be lost. Chrome has
it from version 69, older than any Chrome that runs a Manifest V3 extension, in
pages and in the service worker; Firefox from version 96, older than the 115
`manifest/firefox.json` declares. Where it is missing, a write fails rather than
going ahead without it.
Version 1 is the shape that shipped before versions existed, so a stored record
with no `schemaVersion` is version 1 rather than a defect: it loads normally and
is migrated in place by being stamped on the first write. An upgrade never shows