You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The client-side config-on-connect read-back (#800app_config: segment / protocol / live_offset_s / peak_bitrate_mbps, and now muted from #838) is gated on the localProxy flag, so it silently does not apply on any LocalProxy-OFF run.
Android: applyServerAppConfig() opens with if (!_state.value.localProxy) return — android/InfiniteStreamPlayer/app/src/main/java/com/infinitestream/player/state/PlayerViewModel.kt:879
Why the guard is wrong
localProxy (is.flag.local_proxy) toggles the on-device LocalHTTPProxy (rewrite-through-127.0.0.1 vs direct) — it does not control whether playback routes through go-proxy. Per the code's own comment in composeURLAndLoad, session playback always routes through the go-proxy port regardless of localProxy, and app_config is read from /api/sessions on the API port (reachable regardless). So the session and its app_config exist whether or not LocalProxy is on; tying the overlay to localProxy couples it to an unrelated flag.
Net effect: any harness/characterization run with -is.flag.local_proxy false (the characterization default — see the feedback_char_localproxy_autorecovery_off convention) never applies server-pushed app_config.
Verification caveat from #838 (launch-arg confound)
The #838 config-on-connect mute verification ran with CHAR_LOCAL_PROXY=true, so LocalProxy was ON and the overlay did run (the applied server overlay … muted= log — which is emitted after the guard — fired). But that verification did not isolate config-on-connect as the cause of the client's mute state, because the char probe also sets mute via the -is.flag.mutedlaunch arg (ProbeConfig.Muted → runner/probe.go), which is not guarded by localProxy. Both sinks carried the same value, so "audio was muted" could be attributed to the launch arg alone.
Concretely, this is exactly why "mute worked even though the char default is LocalProxy OFF" is unsurprising: the launch arg mutes regardless; it's the config-on-connect overlay that's gated. The only unconfounded config-on-connect evidence from #838 is server-side (GET /api/sessions showing app_config.muted per player), which owes nothing to localProxy.
Proposed change
Drop the localProxy guard in applyServerAppConfig() on both platforms (or replace it with a check that actually reflects "playback routes through go-proxy", which is always true today). The fetch is already best-effort — a miss / non-proxied target is a no-op — so removing the guard is low-risk.
This touches all#800app_config fields, not just mute, so it warrants its own PR (not a quiet change) and a fleet re-verify.
Acceptance criteria
The re-verify must isolate config-on-connect from the launch arg, and use a value opposite the app default so the overlay is the only thing that could produce it:
2×2 (or at least the two diagonal cells) on a Device Farm fleet:
LocalProxy OFF → overlay does not run → app stays at its default (muted=true); noapplied server overlay log. (Pre-fix baseline; post-fix this must change to apply.)
LocalProxy ON → overlay runs → muted=false (audible); applied server overlay … muted=false log present.
Confirm from data both server- and client-side: GET /api/sessionsapp_config.muted=false per player (identical in both cells — proves the value is stored regardless of LocalProxy), plus the per-sim overlay-log presence/absence (proves the guard's effect).
After the fix: the OFF cell now applies the overlay (audible) — i.e. config-on-connect no longer depends on localProxy.
Problem
The client-side config-on-connect read-back (#800
app_config:segment/protocol/live_offset_s/peak_bitrate_mbps, and nowmutedfrom #838) is gated on thelocalProxyflag, so it silently does not apply on any LocalProxy-OFF run.applyServerAppConfig()opens withguard localProxy else { return }—apple/InfiniteStreamPlayer/InfiniteStreamPlayer/PlayerViewModel.swift:1087applyServerAppConfig()opens withif (!_state.value.localProxy) return—android/InfiniteStreamPlayer/app/src/main/java/com/infinitestream/player/state/PlayerViewModel.kt:879Why the guard is wrong
localProxy(is.flag.local_proxy) toggles the on-device LocalHTTPProxy (rewrite-through-127.0.0.1vs direct) — it does not control whether playback routes through go-proxy. Per the code's own comment incomposeURLAndLoad, session playback always routes through the go-proxy port regardless oflocalProxy, andapp_configis read from/api/sessionson the API port (reachable regardless). So the session and itsapp_configexist whether or not LocalProxy is on; tying the overlay tolocalProxycouples it to an unrelated flag.Net effect: any harness/characterization run with
-is.flag.local_proxy false(the characterization default — see thefeedback_char_localproxy_autorecovery_offconvention) never applies server-pushedapp_config.Verification caveat from #838 (launch-arg confound)
The #838 config-on-connect mute verification ran with
CHAR_LOCAL_PROXY=true, so LocalProxy was ON and the overlay did run (theapplied server overlay … muted=log — which is emitted after the guard — fired). But that verification did not isolate config-on-connect as the cause of the client's mute state, because the char probe also sets mute via the-is.flag.mutedlaunch arg (ProbeConfig.Muted→runner/probe.go), which is not guarded bylocalProxy. Both sinks carried the same value, so "audio was muted" could be attributed to the launch arg alone.Concretely, this is exactly why "mute worked even though the char default is LocalProxy OFF" is unsurprising: the launch arg mutes regardless; it's the config-on-connect overlay that's gated. The only unconfounded config-on-connect evidence from #838 is server-side (
GET /api/sessionsshowingapp_config.mutedper player), which owes nothing tolocalProxy.Proposed change
Drop the
localProxyguard inapplyServerAppConfig()on both platforms (or replace it with a check that actually reflects "playback routes through go-proxy", which is always true today). The fetch is already best-effort — a miss / non-proxied target is a no-op — so removing the guard is low-risk.This touches all #800
app_configfields, not just mute, so it warrants its own PR (not a quiet change) and a fleet re-verify.Acceptance criteria
The re-verify must isolate config-on-connect from the launch arg, and use a value opposite the app default so the overlay is the only thing that could produce it:
app_config.muted: false(audible) on the session, with no-is.flag.mutedlaunch arg.falseis opposite the app's default-muted (Mute audio across all client apps — default muted, settable from every config path #838), so muting/unmuting is attributable solely to the overlay.muted=true); noapplied server overlaylog. (Pre-fix baseline; post-fix this must change to apply.)muted=false(audible);applied server overlay … muted=falselog present.GET /api/sessionsapp_config.muted=falseper player (identical in both cells — proves the value is stored regardless of LocalProxy), plus the per-sim overlay-log presence/absence (proves the guard's effect).localProxy.CHAR_LOCAL_PROXY=truenote from the Mute audio across all client apps — default muted, settable from every config path #838 mute matrix specs once it's no longer required./api/sessionslookup (metricsBaseURL) resolves correctly with LocalProxy off (it should — API port, not the on-device proxy).References