Follow-up to the v2026.06.11 history-recording repair. A full Android↔server
connection-point audit cleared the silent-contract bug class and surfaced a
cluster of offline/playback-robustness defects, now fixed.
Fixes
Playback double-count on background — PlayEventsReporter close-by-id
routing + paused-only onStop + in-flight guard; new PLAY_ENDED durable
mutation kind. Eliminates the duplicate/skip-misclassified row produced on
every screen-lock.
Server idempotency — RecordOfflinePlay dedup on (user, track, started_at); RecordPlayEnded skips a duplicate skip_event on re-close
(+2 integration tests). Makes at-least-once replay safe.
Like-toggle collapse — supersede older toggles per entity so retries
can't invert the final like state.
Connectivity-return trigger — drain/sync on NetworkStatusController → Healthy; SyncController.syncSafe gains a single-in-flight mutex.
Commits d2a22e49 + 4ecb1680. CI green on dev head 4ecb1680 (server run 884 ✓,
Android run 885 ✓). Tracked in Scribe task #776.
Follow-up to the v2026.06.11 history-recording repair. A full Android↔server
connection-point audit cleared the silent-contract bug class and surfaced a
cluster of offline/playback-robustness defects, now fixed.
## Fixes
1. **Playback double-count on background** — `PlayEventsReporter` close-by-id
routing + paused-only `onStop` + in-flight guard; new `PLAY_ENDED` durable
mutation kind. Eliminates the duplicate/skip-misclassified row produced on
every screen-lock.
2. **Replayer poison rows** — `SENT/DROP/RETRY` model; permanent 4xx + corrupt
payloads dropped, 408/429/5xx/transport retry.
3. **Server idempotency** — `RecordOfflinePlay` dedup on `(user, track,
started_at)`; `RecordPlayEnded` skips a duplicate skip_event on re-close
(+2 integration tests). Makes at-least-once replay safe.
4. **Like-toggle collapse** — supersede older toggles per entity so retries
can't invert the final like state.
5. **Connectivity-return trigger** — drain/sync on `NetworkStatusController →
Healthy`; `SyncController.syncSafe` gains a single-in-flight mutex.
Commits d2a22e49 + 4ecb1680. CI green on dev head 4ecb1680 (server run 884 ✓,
Android run 885 ✓). Tracked in Scribe task #776.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Audit of every Android↔server connection point (2026-06-11) cleared the
silent-contract class that caused the events `type` bug, but surfaced a
cluster of offline/playback-robustness defects. Fixes:
1. Playback double-count on background. PlayEventsReporter no longer
enqueues a partial play_offline + leaves the live row open on every
screen-lock. closeCurrent() now routes by whether the server has an
open row: close-by-id (durable PLAY_ENDED on failure) when it does,
offline only when no row exists, and a no-op while a play_started is
in flight (the server auto-closes that orphan). onStop only durably
closes a *paused* play — a still-playing one is left to the live path
under the foreground service. Adds the PLAY_ENDED mutation kind.
2. Replayer poison rows. MutationReplayer now classifies each replay as
SENT / DROP / RETRY: permanent 4xx (and corrupt payloads) are dropped
instead of retried forever; 408/429/5xx/transport still retry.
3. Offline-play / close-by-id idempotency (server). RecordOfflinePlay
dedups on (user, track, started_at); RecordPlayEnded skips a second
skip_events insert when re-closing an already-ended row. Makes the
at-least-once replay safe against lost-response duplicates.
4. Like-toggle collapse. Replayer drops like-toggles superseded by a
later toggle for the same entity, so partial-failure + differential
retry can't invert the final like state.
5. Connectivity-return trigger. MutationReplayer + SyncController now
also drain/sync when NetworkStatusController recovers to Healthy, so
an offline→online transition mid-session doesn't wait for a cold
start. SyncController.syncSafe gains a single-in-flight mutex.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
LoopWithTooManyJumpStatements — replace the two continues with a
filtered sequence + a single null guard.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Follow-up to the v2026.06.11 history-recording repair. A full Android↔server
connection-point audit cleared the silent-contract bug class and surfaced a
cluster of offline/playback-robustness defects, now fixed.
Fixes
PlayEventsReporterclose-by-idrouting + paused-only
onStop+ in-flight guard; newPLAY_ENDEDdurablemutation kind. Eliminates the duplicate/skip-misclassified row produced on
every screen-lock.
SENT/DROP/RETRYmodel; permanent 4xx + corruptpayloads dropped, 408/429/5xx/transport retry.
RecordOfflinePlaydedup on(user, track, started_at);RecordPlayEndedskips a duplicate skip_event on re-close(+2 integration tests). Makes at-least-once replay safe.
can't invert the final like state.
NetworkStatusController → Healthy;SyncController.syncSafegains a single-in-flight mutex.Commits
d2a22e49+4ecb1680. CI green on dev head4ecb1680(server run 884 ✓,Android run 885 ✓). Tracked in Scribe task #776.
🤖 Generated with Claude Code