The first version of the spectr-ai web frontend had a spinner. You uploaded a contract, the spinner spun, and several minutes later results appeared, or didn't. My test users (friends, so they were honest) all did the same thing: around the ninety-second mark they refreshed the page, killing the audit that was about to finish. A spinner with no progress is indistinguishable from a hang, and users act accordingly.
So I rebuilt the pipeline around Server-Sent Events, and most of what I learned wasn't in the SSE tutorials, because tutorials stream a chat completion for ten seconds and call it a day. Multi-minute jobs with real state are a different problem. Here's what actually mattered.
Why SSE and not WebSockets
Short version: the browser never needs to talk back mid-job. The client uploads a contract, then listens. That's exactly the shape SSE was built for, one-directional server-to-client over plain HTTP. No connection upgrade, no socket lifecycle management, and the browser's EventSource gives you automatic reconnection for free, which turns out to be the most valuable feature of the whole protocol. WebSockets would work, but I'd be maintaining bidirectional machinery to use ten percent of it.






