Problem
An unset API base URL throws ApiError(0, ...), and isOffline() treats any status === 0 as a network failure. So a build shipped without the env var doesn’t fail loudly — every request looks “offline”: the banner pins on, load() falls back to empty/cached state, and every like/save/topic/learn is enqueued into a durable queue that can never flush.
Evidence — mobile/src/api/client.ts (ApiError(0, 'EXPO_PUBLIC_API_BASE_URL is not set') and the network-failure ApiError(0, ...) share status 0); mobile/src/services/remoteProgressRepository.ts isOffline(). isApiConfigured() and isSupabaseConfigured exist but are never consumed by the UI.
Impact — A misconfigured OTA/build degrades to a permanently-“offline”, broken app with no diagnostic, silently accumulating a queue that will never drain.
Suggested direction — Give misconfiguration a distinct error (not status 0) so it isn’t queued as offline; gate the UI on isApiConfigured()/isSupabaseConfigured with a visible hard-fail in dev/preview.
Problem
An unset API base URL throws
ApiError(0, ...), andisOffline()treats anystatus === 0as a network failure. So a build shipped without the env var doesn’t fail loudly — every request looks “offline”: the banner pins on,load()falls back to empty/cached state, and every like/save/topic/learn is enqueued into a durable queue that can never flush.Evidence —
mobile/src/api/client.ts(ApiError(0, 'EXPO_PUBLIC_API_BASE_URL is not set')and the network-failureApiError(0, ...)share status 0);mobile/src/services/remoteProgressRepository.tsisOffline().isApiConfigured()andisSupabaseConfiguredexist but are never consumed by the UI.Impact — A misconfigured OTA/build degrades to a permanently-“offline”, broken app with no diagnostic, silently accumulating a queue that will never drain.
Suggested direction — Give misconfiguration a distinct error (not
status 0) so it isn’t queued as offline; gate the UI onisApiConfigured()/isSupabaseConfiguredwith a visible hard-fail in dev/preview.