M9 diagnostics follow-ups: playback relabel, sort, connected fix, per-skip + track-identity #105

Merged
bvandeusen merged 4 commits from dev into main 2026-06-30 19:19:15 -04:00
Owner

Follow-ups on top of the M9 device-diagnostics release, all CI-green on dev.

Web

  • Diagnostics view defaults to most-recent-500; start/end window moved to a collapsed "Advanced" disclosure; newest-first sort (with oldest-first option); export follows displayed order.

Diagnostics relabel

  • route + player_state events now report kind: "playback" (they fire for every output, not just UPnP); upnp_sync reserved for genuine UPnP/Sonos signal. Migration 0037 extends the kind CHECK.

Output-picker bug fix

  • OutputRoute.isConnected was derived from RouteInfo.connectionState, which stays DISCONNECTED for local SYSTEM routes even when active — so a connected Bluetooth device showed "Available". Subtitle now uses isSelected; dead isConnected field removed.

Diagnostics depth (for the UPnP desync hunt)

  • Per-skip track_change event captured at the instant of each skip — the 45s heartbeat was missing rapid-skip moments.
  • Track-identity enrichment: track_change + heartbeat now carry local_track_id + sonos_uri (the URL the speaker is actually streaming), so a re-cast index wobble no longer makes desync ambiguous.
  • sonos_* zeroed unless a remote route is active — fixes cast→phone stale-state pollution.

Refs Scribe M9 (#119), tasks #1204 #1205 #1210 #1211.

🤖 Generated with Claude Code

Follow-ups on top of the M9 device-diagnostics release, all CI-green on dev. ## Web - Diagnostics view defaults to most-recent-500; start/end window moved to a collapsed "Advanced" disclosure; **newest-first sort** (with oldest-first option); export follows displayed order. ## Diagnostics relabel - `route` + `player_state` events now report `kind: "playback"` (they fire for every output, not just UPnP); `upnp_sync` reserved for genuine UPnP/Sonos signal. Migration 0037 extends the kind CHECK. ## Output-picker bug fix - `OutputRoute.isConnected` was derived from `RouteInfo.connectionState`, which stays DISCONNECTED for local SYSTEM routes even when active — so a connected Bluetooth device showed "Available". Subtitle now uses isSelected; dead `isConnected` field removed. ## Diagnostics depth (for the UPnP desync hunt) - **Per-skip `track_change` event** captured at the instant of each skip — the 45s heartbeat was missing rapid-skip moments. - **Track-identity enrichment**: `track_change` + heartbeat now carry `local_track_id` + `sonos_uri` (the URL the speaker is actually streaming), so a re-cast index wobble no longer makes desync ambiguous. - `sonos_*` zeroed unless a remote route is active — fixes cast→phone stale-state pollution. Refs Scribe M9 (#119), tasks #1204 #1205 #1210 #1211. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bvandeusen added 4 commits 2026-06-30 19:19:08 -04:00
The diagnostics view already defaulted to the most recent 500 events (no
window); make that the obvious path. Device/Kind stay primary; the
start/end window + row cap move into a collapsed "Advanced filters"
disclosure (auto-opens when a window is active) with a "Reset to recent
500" action. Caption now states whether you're seeing the recent default
or a windowed slice.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K55iTxn95BtshocgdE1shW
feat(diagnostics): 'playback' kind, newest-first sort, fix active-route subtitle
test-go / test (push) Successful in 32s
test-web / test (push) Successful in 41s
android / Build + lint + test (push) Successful in 3m40s
test-go / integration (push) Successful in 4m30s
79f2d79a2e
Relabel (#1204): route + player_state events fire for every output route,
not just UPnP — split them into a new 'playback' kind; 'upnp_sync' now
means genuinely UPnP/Sonos signal (drops, resync). Migration 0037 adds
'playback' to the kind CHECK; server whitelist, Android reporter labels,
and the web kind filter updated.

Web sort: the diagnostics list gains a Newest/Oldest-first sort (default
newest at top); export follows the displayed order.

Fix (#1205): OutputRoute.isConnected was derived from RouteInfo.connectionState,
which stays DISCONNECTED for local SYSTEM routes even when active — so a
connected Bluetooth device showed "Available" and reported connected:false.
The picker subtitle now uses isSelected (route == selected route); the dead
isConnected field is removed and the misleading `connected` field dropped
from the diagnostics route event (it only ever logs the active route).

Refs Scribe M9 (#119), tasks #1204 #1205.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K55iTxn95BtshocgdE1shW
feat(android/diagnostics): per-skip track-change event
android / Build + lint + test (push) Successful in 3m35s
cdfc79e6ab
Heartbeats are 45s apart and missed a rapid skip burst (local_index
16→22 in one gap). Add a 'playback' track_change event emitted on each
queue-index / current-track change, snapshotting local vs Sonos
index+position + server_health + upnp_loading + route — so a transient
skip-induced desync is captured at the instant it happens. (uiState is a
conflated StateFlow, so a very rapid burst may coalesce intermediate
indices; we still get the boundaries + the snapshot.)

Refs Scribe M9 (#119), task #1210.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K55iTxn95BtshocgdE1shW
feat(android/diagnostics): track-identity enrichment + zero stale Sonos state
android / Build + lint + test (push) Successful in 3m27s
392454b249
Numeric indices wobble across re-casts (offset +1↔0 seen during output
toggling), making "same track?" ambiguous. Enrich both the track_change
event and the heartbeat with local_track_id (TrackRef.id) and sonos_uri
(RemotePlayerState.currentTrackUri — the URL the speaker is actually
streaming), so a desync is unambiguous.

Also fixes the cast→phone stale-state pollution (#1211): sonos_* is now
zeroed unless a remote route is active, via a shared putSonos() helper —
so a just-ended cast's RemotePlayerState can't masquerade as live Sonos
data in the diagnostics.

Refs Scribe M9 (#119), tasks #1210 #1211.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K55iTxn95BtshocgdE1shW
bvandeusen merged commit 611715154b into main 2026-06-30 19:19:15 -04:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/minstrel#105