fix(android): don't flip offline on WAN-validation flicker — trust /healthz #85

Merged
bvandeusen merged 1 commits from dev into main 2026-06-04 23:02:28 -04:00
Owner

Same-day re-cut on the per-day mutable CalVer scheme (post-v2026.06.04 papercut #2).

False "server offline" → playback "Source error" on a healthy LAN server

On-device: the app reported the server offline while it wasn't, a track failed with load_failed / "Source error", then recovered on its own.

Root cause (proven from the code):

  • ConnectivityObserver.online gated on NET_CAPABILITY_VALIDATED. That capability tracks whether Android reached its own WAN internet-validation probe (Google's generate_204) — not whether the self-hosted Minstrel server is reachable. The server is usually on the LAN.
  • A transient WAN/DNS blip (or Android's periodic re-validation) momentarily drops VALIDATED while the LAN server stays reachable. (logcat around the incident shows ERR_NAME_NOT_RESOLVED + Wi-Fi capability churn.)
  • ServerHealthController flips to Offline the instant online goes false — no debounce. The /healthz hysteresis added earlier today only guards the ServerDown path.
  • OfflineGatedDataSource.open() then throws OfflineException on the in-flight stream read → ExoPlayer SOURCE error → PlaybackErrorReporter → the load_failed event.

Fix:

  • ConnectivityObserver — require INTERNET only, not VALIDATED. The device-link signal now answers only "is there a network at all" (airplane mode); the /healthz poll (VersionCheckController, with its own failure hysteresis) is the authority on whether Minstrel is reachable. A WAN-validation flicker with a healthy LAN no longer reads as offline.
  • ServerHealthController — add a WARN-tier ServerHealth -> X transition log. The signal had zero instrumentation, which is why this was hard to diagnose from logcat.

Verify on device

  • Watch adb logcat -s Minstrel during a Wi-Fi/WAN hiccup: ServerHealth should stay Healthy (or go ServerDown only after sustained /healthz failures), never flip to Offline from a brief validation drop. Playback of a streaming (non-cached) track no longer dies with "Source error" on a momentary blip.

🤖 Generated with Claude Code

Same-day re-cut on the per-day mutable CalVer scheme (post-v2026.06.04 papercut #2). ## False "server offline" → playback "Source error" on a healthy LAN server On-device: the app reported the server offline while it wasn't, a track failed with `load_failed` / "Source error", then recovered on its own. **Root cause (proven from the code):** - `ConnectivityObserver.online` gated on `NET_CAPABILITY_VALIDATED`. That capability tracks whether Android reached its own WAN internet-validation probe (Google's `generate_204`) — **not** whether the self-hosted Minstrel server is reachable. The server is usually on the LAN. - A transient WAN/DNS blip (or Android's periodic re-validation) momentarily drops `VALIDATED` while the LAN server stays reachable. (logcat around the incident shows `ERR_NAME_NOT_RESOLVED` + Wi-Fi capability churn.) - `ServerHealthController` flips to `Offline` the **instant** `online` goes false — no debounce. The `/healthz` hysteresis added earlier today only guards the *ServerDown* path. - `OfflineGatedDataSource.open()` then throws `OfflineException` on the in-flight stream read → ExoPlayer SOURCE error → `PlaybackErrorReporter` → the `load_failed` event. **Fix:** - `ConnectivityObserver` — require `INTERNET` only, not `VALIDATED`. The device-link signal now answers only "is there a network at all" (airplane mode); the `/healthz` poll (`VersionCheckController`, with its own failure hysteresis) is the authority on whether Minstrel is reachable. A WAN-validation flicker with a healthy LAN no longer reads as offline. - `ServerHealthController` — add a WARN-tier `ServerHealth -> X` transition log. The signal had zero instrumentation, which is why this was hard to diagnose from logcat. ## Verify on device - Watch `adb logcat -s Minstrel` during a Wi-Fi/WAN hiccup: `ServerHealth` should stay `Healthy` (or go `ServerDown` only after sustained `/healthz` failures), never flip to `Offline` from a brief validation drop. Playback of a streaming (non-cached) track no longer dies with "Source error" on a momentary blip. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bvandeusen added 1 commit 2026-06-04 23:02:24 -04:00
fix(android): don't flip offline on WAN-validation flicker — trust /healthz
android / Build + lint + test (push) Successful in 3m38s
5c0db429b3
A self-hosted Minstrel server is usually on the LAN, but ConnectivityObserver
gated 'online' on NET_CAPABILITY_VALIDATED — which tracks whether Android
reached its own WAN internet-validation probe, not whether Minstrel is
reachable. A transient WAN/DNS blip (or Android's periodic re-validation)
momentarily drops VALIDATED while the LAN server stays reachable. That flipped
ServerHealth -> Offline with NO debounce (only the /healthz path got hysteresis),
and OfflineGatedDataSource fast-failed the in-flight stream read with
OfflineException -> ExoPlayer SOURCE error -> the load_failed 'Source error'
event. On-device: 'app said server offline while it wasn't', one track failed,
then recovered when VALIDATED returned.

- ConnectivityObserver: require INTERNET only, not VALIDATED. The /healthz poll
  (VersionCheckController, with its own failure hysteresis) is the authority on
  whether Minstrel is reachable; the device-link signal only answers 'is there a
  network at all' (airplane mode).
- ServerHealthController: add a WARN-tier transition log. The signal had zero
  instrumentation, which is why this was hard to diagnose from logcat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bvandeusen merged commit 301c3bfb86 into main 2026-06-04 23:02:28 -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#85