
Transcripción en directo cuando el firewall bloquea los WebSockets
A las redes corporativas les encanta permitir HTTPS y matar sin ruido las conexiones WebSocket. Eso rompe en silencio la transcripción en tiempo real. GeekBye v2.0.8 recurre automáticamente a un transporte solo-HTTPS — y publicarlo destapó un bug que habría dejado toda la función inútil.
Hay una forma concreta y exasperante en que la transcripción en tiempo real falla en una red corporativa. Tu Wi-Fi está bien. HTTPS funciona — puedes cargar cualquier web. Pero la transcripción en directo simplemente... no arranca, y nada te dice por qué.
El culpable es una clase de proxy corporativo que permite el tráfico HTTPS normal pero bloquea el upgrade de WebSocket — el handshake que convierte una conexión HTTPS en el canal persistente y bidireccional que necesita la transcripción en tiempo real. Para el proxy, un WebSocket parece un túnel sin vigilancia hacia fuera de la red, así que lo mata. Para ti, la transcripción está rota en silencio.
GeekBye v2.0.8 añadió una alternativa automática para exactamente esto — y construirla sacó a la luz un bug que habría hecho que toda la función no hiciera nada.
Por qué una alternativa, no solo un reintento
Ya gestionamos las redes inestables. Si tu conexión se cae a mitad de sesión, GeekBye reconecta con backoff y almacena tu audio para que no se pierda nada — esa es otra función, tratada en por qué tu notetaker con IA se detiene con mal Wi-Fi.
Pero un WebSocket bloqueado no es una conexión inestable. Reintentar el mismo WebSocket contra un proxy que rechaza WebSockets falla de la misma forma cada vez, para siempre. El único arreglo es un transporte distinto — uno que parezca el HTTPS plano que el proxy ya permite.
Así que v2.0.8 recurre a un transporte solo-HTTPS sobre el mismo endpoint autenticado:
- De bajada (transcripciones que te llegan): server-sent events — una respuesta HTTPS de larga duración que el proxy ve como una descarga en streaming corriente.
- De subida (tu audio que sale): peticiones POST por lotes, cada una con un fragmento de audio y un número de secuencia para que el servidor pueda reensamblarlos en orden aunque la red los reordene.
Sin socket persistente, nada que parezca un túnel — solo peticiones y respuestas HTTPS. Si un proxy te deja usar una web, deja esto.
El bug que habría publicado una función muerta
Aquí está la parte que merece la lectura. Se supone que la alternativa se activa cuando la conexión WebSocket agota sus intentos con una firma de transporte bloqueado — cada intento fallando en el upgrade, sin problema de auth ni de cuota, al menos un rechazo con forma de proxy. Un proxy que bloquea un WebSocket suele responder al upgrade con un HTTP 403 Forbidden o 407.
El problema: nuestro código de conexión ya tenía una regla según la cual un 403 significa error fatal de autenticación — para, muéstralo al usuario, no reintentes. Lo cual es correcto casi en todas partes. Pero significaba que el 403 de un proxy bloqueante — la señal exacta que debería haber activado la alternativa — se lanzaba en cambio como error fatal antes de que la lógica de la alternativa pudiera siquiera ejecutarse. Solo una caída bruta de conexión (un cierre 1006) llegaba a la alternativa. Así que la función habría funcionado para el caso raro y fallado en silencio para su objetivo principal real: el proxy corporativo.
Cazamos esto mientras endurecíamos la versión, no en producción. El arreglo: un 403/407 en la etapa del upgrade del WebSocket ahora se trata como recuperable, para que el bucle de conexión pueda agotarse hacia la alternativa — mientras que un fallo genuino de autenticación (que llega de otra forma, tras completarse el upgrade) sigue fallando rápido, exactamente como antes. Un test de regresión ahora fija la distinción: un 403 de proxy bloqueante debe recurrir a la alternativa; un 403 de auth real no debe.
El resto del endurecimiento siguió la misma línea paranoica: un timeout en cada POST de subida para que un proxy que acepta una petición pero nunca responde no pueda atascar el flujo de audio, y una garantía de que un problema genuino de inicio de sesión nunca pueda quedar enmascarado en silencio por la maquinaria de la alternativa.
Lo probamos contra un proxy hostil real
Una función cuyo propósito entero es sobrevivir a redes hostiles no se puede validar solo con tests unitarios — los tests unitarios no tienen proxies. Antes de habilitarla, pasamos la app real por un reverse proxy local configurado para hacer exactamente lo que hacen los proxies corporativos: reenviar HTTPS, rechazar los upgrades de WebSocket con un 403.
El rastro en los logs es el recibo: cuatro intentos de WebSocket bloqueados, la firma de agotamiento reconocida, el cambio automático al transporte HTTPS, y luego una sesión de transcripción sana de 96 segundos sobre HTTPS puro — 66 segmentos de transcripción, cero caídas. El failover funciona porque lo vimos hacer failover.
Tres lecciones transferibles
- "Funciona con Wi-Fi inestable" y "funciona detrás de un proxy hostil" son garantías distintas. Una necesita reconexión; la otra necesita un transporte distinto. Confundirlas deja a toda una población de usuarios corporativos rota en silencio.
- Tu clasificación de errores puede esconder tu propia función de sí misma. Una regla correcta el 99% del tiempo (403 = auth fatal) era exactamente errónea para el 1% al que esta función existía para servir. Cuando añades una alternativa, audita si la condición que la dispara puede siquiera llegar a la alternativa.
- Prueba al adversario, no solo el camino feliz. El único test honesto de "sobrevive a un proxy que bloquea WebSockets" es un proxy que bloquea WebSockets. Construimos uno.
GeekBye v2.0.8 publicó la alternativa HTTPS con flag y validada. Para el trabajo de fiabilidad junto al que se sitúa, mira por qué tu notetaker con IA se detiene con mal Wi-Fi, y para los lanzamientos vecinos de esta serie, por qué tu notetaker con IA deja de grabar en mitad de la reunión (v2.0.9) y por qué la transcripción con IA malinterpreta los términos técnicos (v2.0.11).