From 6e5aa16c292dc402f004fff2626facb2100e5bfe Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Sun, 23 Aug 2026 12:14:19 -0500 Subject: [PATCH] =?UTF-8?q?Bit=C3=A1cora=20TV:=20registrar=20cuando=20la?= =?UTF-8?q?=20pantalla=20estuvo=20congelada=20u=20oculta?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Caso real resuelto con la bitácora (23/08, 12:11): tres rellamados de E001, el del medio no sonó. No fue la voz: la pestaña que anunciaba estaba en segundo plano —era el Mac de pruebas, no el televisor; lo delata la voz Paulina— y Chrome frena los relojes de las pestañas ocultas a ~1 tic por minuto. En ese hueco el llamado intermedio fue invisible: cuando la pestaña volvió a consultar, el servidor ya solo mostraba el estado más reciente. Para que ese estado deje de confundirse con un fallo de la voz, la pantalla registra ahora el evento 'lag' cuando detecta un hueco de más de 10 s entre tics o cuando pasa a segundo plano, y la tarjeta de Actividad lo traduce como «Pantalla congelada» con su explicación. En el televisor real —siempre visible, en primer plano— este estado no debe aparecer; si aparece, es la señal de que alguien lo dejó oculto o el equipo se suspendió. Co-Authored-By: Claude Fable 5 --- api/lab/get_tv_log.php | 2 +- lab_actividad.php | 1 + modules/turnero/api/log_tv.php | 2 +- modules/turnero/views/display_global.php | 15 +++++++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/api/lab/get_tv_log.php b/api/lab/get_tv_log.php index da17270..0fdbbdf 100644 --- a/api/lab/get_tv_log.php +++ b/api/lab/get_tv_log.php @@ -18,7 +18,7 @@ $resumen = $pdo->query( // Últimos incidentes (lo normal —start/end— no se lista: solo lo que falló) $stmt = $pdo->query( "SELECT evento, detalle, created_at FROM turnero_tv_log - WHERE evento IN ('mudo', 'sin_start', 'error') + WHERE evento IN ('mudo', 'sin_start', 'error', 'lag') ORDER BY id DESC LIMIT 30" ); $incidentes = []; diff --git a/lab_actividad.php b/lab_actividad.php index 224f31a..8ce9bba 100644 --- a/lab_actividad.php +++ b/lab_actividad.php @@ -294,6 +294,7 @@ const VOZ_EVENTO_TXT = { mudo: ['🔇 No sonó', 'text-danger', 'El llamado salió sin voz: ni el reintento habló'], sin_start: ['⚠️ Arrancó con reintento','text-warning','La voz elegida no arrancó; habló la del navegador'], error: ['⚠️ Error del motor', 'text-warning', 'El motor de voz falló a mitad; se reintentó'], + lag: ['⏸ Pantalla congelada', 'text-warning', 'La pestaña estuvo oculta o el equipo suspendido: en ese lapso no ve llamados. En el televisor debe estar siempre visible'], }; async function cargarVozTV() { diff --git a/modules/turnero/api/log_tv.php b/modules/turnero/api/log_tv.php index 37a84e7..19b65f8 100644 --- a/modules/turnero/api/log_tv.php +++ b/modules/turnero/api/log_tv.php @@ -26,7 +26,7 @@ $d = json_decode($raw, true); if (!is_array($d)) exit; $evento = $d['e'] ?? ''; -$PERMITIDOS = ['start', 'end', 'error', 'sin_start', 'mudo']; +$PERMITIDOS = ['start', 'end', 'error', 'sin_start', 'mudo', 'lag']; if (!in_array($evento, $PERMITIDOS, true)) exit; unset($d['e'], $d['t']); // el timestamp lo pone la base, no el cliente diff --git a/modules/turnero/views/display_global.php b/modules/turnero/views/display_global.php index 4c2886b..70214c2 100644 --- a/modules/turnero/views/display_global.php +++ b/modules/turnero/views/display_global.php @@ -667,6 +667,21 @@ const _uttAncladas = new Set(); // handlers no deben hacer nada más que soltar el anclaje. let _vozGen = 0; +// Vigía de congelamiento: Chrome frena los relojes de una pestaña oculta a ~1 +// tic por minuto. En ese estado la pantalla NO VE los llamados intermedios y +// no anuncia — y desde afuera parece un fallo de la voz. Si entre dos tics +// pasan más de 10 s, se deja constancia con el tamaño del hueco. +let _ultimoTic = Date.now(); +setInterval(() => { + const ahora = Date.now(); + const hueco = ahora - _ultimoTic; + _ultimoTic = ahora; + if (hueco > 10000) vozLog('lag', { gap_s: Math.round(hueco / 1000) }); +}, 2000); +document.addEventListener('visibilitychange', () => { + if (document.hidden) vozLog('lag', { oculta: 1 }); +}); + // ── Bitácora de la voz ── // Los fallos intermitentes no se pueden depurar mirando la pantalla: hay que // registrarlos cuando ocurren. Cada evento va a un anillo local (últimos 200,