2f205eb0d9
Closes the last MVP infrastructure gap. Queued like-toggles,
Lidarr requests, and quarantine-unflags now actually reach the
server instead of accumulating in cached_mutations forever.
New:
- cache/mutations/MutationReplayer.kt — @Singleton. On
construction subscribes to AuthStore.sessionCookie and runs a
drain pass on every signed-in transition (cold start with
persisted cookie OR fresh sign-in). Reads pending rows in
FIFO order via CachedMutationDao.getAll, dispatches each by
kind to the raw Retrofit API:
LIKE_TOGGLE → LikesApi.like / unlike
REQUEST_CREATE → DiscoverApi.createRequest
QUARANTINE_UNFLAG → QuarantineApi.unflag
Crucially, uses the raw API interfaces — going through the
Repository wrappers would re-enqueue on failure, creating an
infinite-loop. Successful rows are deleted; failed rows stay in
place with attempts + lastAttemptAt updated. Unknown kinds are
dropped (claim success) so a stale schema entry can't wedge the
queue. Single in-flight via Mutex so back-to-back cookie events
coalesce.
Modified:
- MinstrelApplication.kt — adds @Inject lateinit var
mutationReplayer (same construct-the-singleton trick used for
ResumeController and SyncController). Without the @Inject Hilt
never instantiates the replayer and its init {} cookie observer
never subscribes.
Closes Phase 18 + every known MVP infrastructure gap. Remaining
known follow-ups (NOT MVP blockers):
- WorkManager-driven connectivity-listener replayer so queued
writes drain even with the app backgrounded. Current trigger
set (app open + sign-in) covers the common path.
- Exponential backoff + max-attempts cap so permanently-failing
rows eventually fail visibly rather than silently retrying
forever. Retry-forever is cheap given small queue sizes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>