Protect live race results and shrink cross-browser staleness

Investigated whether two admin browsers open at once can overwrite each
other's changes, per an explicit request to report the risk before
making bigger changes. Found that POST /api/state always replaces the
entire stored document with a client's in-memory copy, with no version
check and no per-field merge - and a browser only ever pushes, never
re-fetching server state after page load except on the Overlay view.
An idle browser's next save, even an unrelated edit, could silently
revert another browser's more recent changes, worst case a live race's
in-progress results.

Two scoped fixes instead of the bigger optimistic-locking rework (that
needs real UX decisions about conflicting saves, deferred separately):

1. server.js now remembers which session results were just written by
   a real live decoder passing (/api/passings) and protects that key
   for 15 seconds against being reverted by a stale full-state save,
   while still applying the rest of that save normally.
2. Every non-Overlay view now quietly refreshes its data in the
   background every 15 seconds (skipped while a local edit is
   pending), without ever calling renderView(), so it can never
   discard an open, unsaved edit form - shrinking how stale a
   browser's next save can be from hours to seconds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
larssand
2026-09-09 12:56:58 +02:00
parent be9a2de31a
commit 3373f8dddd
8 changed files with 160 additions and 6 deletions

View File

@@ -8,6 +8,12 @@ The application version is maintained in `package.json` and displayed in the adm
No changes recorded yet.
## 1.4.3 - 2026-09-09
### Fixed
- Two admin browsers open at once could silently overwrite each other's work: any save pushed a browser's entire in-memory copy of the data, so an idle tab's next save - even an unrelated one - could revert another browser's more recent changes, including a live race's in-progress results. Live results computed from real timing data are now protected from being reverted for a short window after they arrive, and every view now quietly refreshes its data in the background every 15 seconds (without ever discarding an open, unsaved edit), so the data behind any save stays fresh instead of getting stale over hours.
## 1.4.2 - 2026-09-09
### Fixed