A phone switches from wifi to cellular. To the operating system, that’s routine. To a client mid game session, it used to be fatal.
Every in-flight request died with the old interface. Players got dropped out of live games. The only recovery was restarting the app, which nobody does mid-game, so they just left instead.
That failure mode is what I spent the summer on. Not a feature so much as a piece of infrastructure everything else could eventually lean on.
The shape of the problem
Raw network callbacks from the OS are noisy. A phone walking near the edge of a room can flap between wifi and cellular a dozen times a minute, and associating with a network is not the same as that network actually reaching the internet, especially behind a captive portal that intercepts everything until you accept its terms. Any fix had to survive both kinds of noise, and it had to work the same way whether the thing on the other end was an HTTP request, a QUIC stream, or Roblox’s own UDP game transport, each with different rules for what recovery even means.
What I built
Connectivity: a signal layer, not a patch. Per-platform monitors report OS-level changes into one shared, platform-agnostic core manager. That manager collapses the noise with debouncing, deduplication, and a generation counter that throws out stale or superseded events when two transitions race each other. On top of that sits a validation probe, a deliberately plain 204 no-content endpoint, chosen specifically because captive portals can’t fake a real response to it, so the system knows the difference between “connected to a network” and “connected to the internet.”
Two signals come out the other side: one carrying a snapshot of interface type and validation state, one for validation updates alone. What each consumer does with that signal depends on what it is. Regular HTTP connections get flushed and recreated cleanly on the new interface. QUIC connections migrate in place under RFC 9000, no re-handshake needed. Roblox’s own UDP game transport re-authenticates the client using a token issued ahead of time, which is the part that actually matters to a player: it’s why switching from wifi to cellular mid-game doesn’t end the game session.
Earning trust before spending it
The rollout started on iOS at a 15% bucket, and the first phase connected nothing to it at all. No consumer depended on the signal yet. It just watched, quietly, so we could compare what it reported against what was actually happening before a single line of production behavior relied on it being right. Only after that did HTTP migration, then the game transport, get wired in.
That sequencing was the part of this project I’d point to first if asked what I actually learned. It’s slower than shipping behind a flag and calling it done. It’s also the reason nothing broke when real traffic started flowing through it.
Where it went
I scoped this for HTTP and game-transport migration. Because it shipped as a general signal instead of a narrow fix, five other systems adopted it on their own, including voice chat’s connection migration and telemetry annotation, without me building either integration. The work is being presented at RDC 2026, Roblox’s developer conference, this September.
I’ve played this game since I was six. Working on the actual engine underneath it isn’t incidental to me, it’s a strange, real convergence of the two halves of my life.