fix(server-storage): conditional writes for every playlist mutation, ordered adoption, keep journals until copied

- Every playlist mutation is sent on the version it was read at: the
  payload's ETag, else the playlist's last read (portal documents have no
  payload). Refused versions are tracked per playlist, so a conflict on
  one never disables the check on another at the same revision. Imports
  and start-up migrations (dbUpsertAppPlaylists) stay unconditional.
- A closed tab's adopted edits replay before this tab's queued ones, from
  the base of its first step, so newer progress is not replaced by older.
- A reload or adoption removes the old page load's saved writes only when
  this page saved its copy; each closed tab is adopted once per page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5.5 committed 2026-10-12 21:31:49 +02:00
1 parent 7afb9758f4
commit 067190e1df
8 files changed
+334 -85

No files matched your search

@@ -209,11 +209,10 @@ https://claude.ai/artifact/3WheJAgeNL5ag6kmtPrJcD
## 11. Risks
- **Concurrent edits on two devices**: a metadata edit (`keepPayload`) is
sent with `If-Match` on the version it was read at; on a `412` the
per-playlist write queue runs the mutation again on a fresh read. Other
document writes (refresh, import) stay last write wins; every playlist
mutation re-reads first, so the window is one round trip.
- **Concurrent edits on two devices**: a playlist mutation is sent with
`If-Match` on the version it was read at; on a `412` the per-playlist
write queue runs the mutation again on a fresh read. Imports and start-up
migrations stay last write wins.
Xtream map entries are written on the tag they were read at and replayed
on the server's value after a `412`, so both devices' edits are kept.
- **Large payloads**: M3U global favorites and backup export read all full