# FIX 2026-07-01 — Reportes de Tatiana (coordinadora): naranja pegado + parpadeo

Servidor: deselpa.vozsi.com (138.68.97.77). Autor: David (asistido). Todo con backup.

## Síntomas reportados (audios + capturas WhatsApp 2026-07-01 ~10:55)

1. **SOL (ext 338)**: casilla NARANJA de reserva pegada, no se quita. Perjudica porque
   otras coordinaciones no le pasan llamadas creyendo que tiene reserva. La coordinadora
   no encontraba la reserva en el histórico.
2. **HADA (ext 348) y en general**: tarotista EN LLAMADA "baila" en el panel: alterna
   verde (disponible) ↔ consulta (ocupado) a cada refresco durante toda la llamada.
   Obliga a pausarla manualmente; a veces se olvida y pierde ~1h de llamadas.

## Causa raíz

### Problema 1 — naranja pegado (SOL)
`panel/api/estado_operadoras.php` pinta naranja (`clase_fila='reservaPendiente'`) cuando la
subquery LATERAL `rsv` cuenta reservas `estado IN ('pendiente','activa') AND activa=1 AND
eliminado=0`. **Esa cuenta NO filtraba por fecha.** SOL tenía la reserva **id 13562** con
`fecha_reserva = '0049-05-01'` (fecha CORRUPTA de captura, año 0049), `estado='pendiente'`,
creada 2026-05-02. Al no tener fecha válida, nunca se auto-finalizaba ni aparecía en el
histórico → naranja de por vida. Única reserva corrupta en toda la BD.

### Problema 2 — parpadeo verde↔consulta (HADA)
El daemon `panel/cron/sync_estados_mejorado.php` (systemd `panel-sync-asterisk`, cada 3s)
reescribe `tarotistas.estado_actual` y `asterisk.agentes.estado_ocupacion` según
`get_busy_agents_from_ami()` (`pbx/includes/ami_busy_agents.php`). Dos fallos combinados:
- **Detección frágil**: la Regla A (DISA→PSTN) exigía `context='disa-capture'`. Verificado en
  vivo por CoreShowChannels: durante la llamada la pata pasa a **`priority-control`**
  (appdata sigue siendo `PJSIP/<tel>@switch,...,U(sub-answer-agent^NNN^)`). En esos sondeos
  la Regla A no matcheaba y el agente **desaparecía** de la detección.
- **Sin histéresis**: un único sondeo sin detección bajaba `estado_actual` a 'disponible'
  (verde) al instante; el siguiente ciclo lo devolvía a 'ocupado' → parpadeo cada ~3s.
  (HADA tiene teléfono único, NO era colisión de datos como el caso YOLANDA del 2026-06-18.)

## Cambios aplicados (con backup `.bak_tatiana_20260701113710`)

1. **DATO** — reserva 13562 (SOL): `estado='finalizada', activa=0` (reversible; era
   pendiente/activa=1/fecha 0049-05-01). Naranja de SOL desaparece al instante.

2. **`panel/api/estado_operadoras.php`** — subquery `rsv`: añadido
   `AND fecha_reserva >= '2000-01-01'` para que una fecha corrupta no vuelva a pegar el
   naranja. Reservas reales (futuras/válidas) siguen pintando naranja igual.

3. **`pbx/includes/ami_busy_agents.php`** — Regla A: eliminado el requisito
   `context='disa-capture'`. Ahora detecta el agente por `PJSIP/<pstn>@switch` en el appdata
   en CUALQUIER contexto. Seguro: el gate por `pstnMap` sólo mapea teléfonos de agentes
   reales (un número de cliente no mapea a agente).

4. **`panel/cron/sync_estados_mejorado.php`** — histéresis anti-parpadeo:
   `define('HISTERESIS_CICLOS', 2)`. Exige 2 sondeos "no ocupado" consecutivos antes de
   soltar 'ocupado' (contador `static $missOcupado` por agente). Un colgado real se refleja
   tras ~6s (inocuo; la cortesía ya retiene después). Daemon reiniciado 11:39:48 CEST.

## Verificación
- `php -l` OK en los 3 ficheros; `diff` vs backup = sólo los añadidos previstos.
- SOL: naranja=0. MORGANA=0. HADA=1 y YOLANDA=2 (reservas REALES vigentes → correcto).
- Reservas corruptas restantes: 0. Daemon `active (running)` sin errores.

## Reversión
```
cp -p FICHERO.bak_tatiana_20260701113710 FICHERO   # los 3 ficheros
systemctl restart panel-sync-asterisk.service
# Reserva SOL (si hiciera falta): UPDATE reservas SET estado='pendiente',activa=1 WHERE id=13562;
```

## Pendiente / seguimiento
- Origen de la fecha corrupta 0049: revisar `crear_reserva.php`/`editar_reserva.php` por si
  aceptan fechas sin validar (evitar futuras basuras). No tocado hoy.
- Si aún se viera algún parpadeo residual en llamadas muy largas, subir `HISTERESIS_CICLOS`
  a 3 o revisar más contextos de la Regla B (patas `PJSIP/switch-*` con `CallerIDNum='s'`).
