address arch review: guard the page cap, coalesce syncs, tighten buffers

- Paged loops now throw when they hit maxPages with a full last page, so a
  truncated enumeration aborts the entity's collect and skips its prune
  instead of deleting rows the sync never saw. The cap is injectable for
  tests.
- Move sync serialization into SyncManager (tryLock coalesces duplicate
  requests) and construct SyncService there; SourceRepository only exposes
  the active MusicSource. Removes the repo <-> sync import cycle.
- Re-throw CancellationException instead of reporting a cancelled sync as
  failed.
- Add buffer(1) to the outer albums/songs/playlistSongs flows so their
  flowOn channel cannot hold 64 batches.
- Rank prefetch is best-effort (missing frequent/recent no longer aborts
  the album sync).
- Skip playlist entries without an id, keeping positions contiguous.
- Chunk stale-disc deletes like the other prunes.
- Update the implementation plan line that still described the old
  single-transaction sync.
This commit is contained in:
austinried
2026-10-04 00:29:58 +00:00
parent 3c941ef0f2
commit c48ec670d8
8 changed files with 130 additions and 55 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ Everything needed to mirror a server library locally:
- `MusicSource` abstraction with `SubsonicClient`, `SubsonicXml` and `SubsonicSource`.
- Room 3 schema on bundled SQLite, so the SQLite version is identical on every device.
- `SyncService`: fetch first, then a single transaction of upserts with diff-based pruning.
- `SyncService`: stream each entity in batches, upserting per batch and pruning the IDs the server no longer lists; the sync is not atomic.
- Unit tests (client, XML, sync), native integration tests against navidrome and gonic, and CI (`unit`, `lint`, `integration`) with warm caches.
## Phase 2 - UI vertical slice (done)