Resumen ejecutivo
Dos remates de la validación E2E de la sonda TCP del 22-07:
-
Fleco 3 (principal): Equipos legítimamente solo-TCP (con ICMP bloqueado por firewall) ya no generan falsas alarmas de “pérdida total de conectividad”. Si el Agente reporta
ping_loss=100%pero la sonda TCP fresca confirma el target vivo, el CNS suprime el insight (HTTP 429) sin gastar llamada de IA. -
Fleco 1 (menor): Campo puerto del modal TCP Probe ya no miente — cuando activas la sonda con el campo vacío, se guarda
22(el valor sugerido en el placeholder) en lugar de rechazar silenciosamente o quedar indefinido.
Fleco 2 (contador tcp_cycles en /info) + fix de raíz en el propio Agente → próxima versión del .exe.
Problema que se resuelve
Contexto: Equipos solo-TCP en centros de datos modernos
Muchos firewalls corporativos y edge bloquean ICMP intencionalmente (ping). Un equipo puede estar perfectamente operativo vía SSH/RDP/HTTP (TCP) pero “invisible” a ICMP.
El falso positivo de v1.63.3
El Agente reportaba fielmente loss=100% en cada ciclo de ping del equipo, porque el ping estaba bloqueado. El CNS creaba un insight “device unreachable” → enviaba IA → llenaba Observatory de ruido rojo. Además, ese equipo consumía rápidamente el límite de 10 insights/hora (rate limit).
Confirmación: Leyendo monitoring/anomaly_detector.py, el ciclo era:
- Check ping: “100% loss” → anomalía válida → dispatch a
receive_insightcada 5 min de cooldown - Sin otra fuente de verdad (TCP estaba habilitado pero su resultado se ignoraba o llegaba tarde)
- Llena CNS de alertas “packet loss” hasta agotar rate limit
En el test E2E del 22-07 no se vio porque el rate limit ya estaba saturado por otro lado.
Solución
Lógica en receive_insight() (monitoring/api/insights.py, línea 92-103)
# Un equipo legítimamente solo-TCP (ICMP bloqueado por firewall) reporta
# loss=100% en cada ciclo de ping del Agente aunque esté vivo; si la sonda
# TCP fresca lo da up, el "total loss" es falso positivo — se suprime antes
# de gastar la llamada de IA y de llenar el CNS de ruido. Se responde 429
# (no un 4xx nuevo) porque la flota 2.16.x desplegada lo trata como
# rate-limit benigno; un status desconocido contaría como error del reporter.
try:
ping_loss = float(data.snmp_data.get("ping_loss"))
except (TypeError, ValueError):
ping_loss = None
if ping_loss is not None and ping_loss >= 100 and target.resolve_reachability(ping_loss) == "up":
return 429, {"error": "suppressed: total ICMP loss but a fresh TCP probe reports the device up"}
Semántica:
ping_loss >= 100%(total loss, no parcial) → condición estricta para evitar suprimir problemas realesresolve_reachability(ping_loss) == "up"→ consulta el modelo, que integra las sondas TCP/HTTP/SNMP disponibles- Si
tcp_enabled=Truey la última sonda TCP fue “up” hace <60s (configurable), devuelve “up” - Si no hay TCP o está stale, devuelve el estado según los otros protocolos
- Si
- Respuesta HTTP 429 intencionada: la flota desplegada (v2.16.x) lo interpreta como “rate limit benigno, sin error” — no incrementa contador de fallos del Agente
Degradación parcial NO se suprime: loss < 100% es un síntoma real (paquetes se pierden pero llegan algunos) → sí crea insight aunque TCP esté vivo.
UX: Modal TCP Probe — campo Puerto (ObservatorySettings.js, línea 185-190)
Antes: placeholder "22" sugería un default inexistente. Si activabas la sonda con el campo vacío, el formulario pedía “Please enter a valid port” sin aclarar cuál era la expectativa.
Ahora:
// El placeholder del campo es "22": si activas la sonda con el campo vacío,
// 22 es el valor que se guarda de verdad (el placeholder no puede mentir).
const port = parseInt(document.getElementById('tcp-settings-port').value) || (enabled ? 22 : null);
Si enabled=true y el campo está vacío → port=22 se guarda. La validación backend (validate_tcp en schema) rechazará solo puertos inválidos (fuera de 1-65535).
Tests
Nuevos en tests/api/test_tcp_probe.py (clase TestInsightTcpSuppression):
test_total_loss_with_fresh_tcp_suppressed: Loss=100%, TCP check <5s → HTTP 429, no se crea insighttest_total_loss_with_stale_tcp_creates_insight: Loss=100%, TCP check >1h old → HTTP 200, sí se crea insighttest_partial_loss_with_fresh_tcp_not_suppressed: Loss=30%, TCP up → HTTP 200, sí se crea insight (es real)
Todos verdes en local con settings idénticos al CI.
Integración con MonitoringTarget
El modelo MonitoringTarget proporciona:
-
resolve_reachability(ping_loss)(método nuevo, v1.63.3): Devuelve"up"si:- El target está
enabled=True - Y cualquiera de las sondas activas (TCP, SNMP, HTTP, ping) da “up” con timestamp reciente
- Prioriza TCP si está disponible y es fresco (<60s)
- El target está
-
Campos de estado TCP:
tcp_enabled: ¿está activa la sonda TCP?tcp_port: puerto a usar (22 por defecto ahora)last_tcp_up: bool, resultado de la última sondalast_tcp_check: datetime, cuándo se hizo
Línea de tiempo
- 2026-07-22: Click-test E2E, se detectan los flecos
- 2026-07-23 v1.63.4: Lanzado con fleco 3 (supresión) + fleco 1 (placeholder) server-side y frontend
- Próxima versión del .exe (2026-08 estimado): Fleco 2 + fix de raíz en el Agente (no emitir anomalía si TCP está up)
Impacto de usuario
- ✅ Menos ruido rojo en Observatory para infraestructuras con firewall restrictivo
- ✅ Menor gasto de límite de llamadas IA (429 es gratis)
- ✅ UX más honesta en modal de configuración TCP
Notas técnicas
- Rate limit 429: Elegido para compatibilidad atrás con v2.16.x del Agente, que reconoce 429 como “rate limit benigno”. Un 4xx nuevo sería interpretado como error del reporter.
- Loss < 100%: No se suprime. Una pérdida parcial (aunque TCP funciona) puede indicar problemas reales (ej. congestión asimétrica).
- Pendiente fleco 2: El Agente necesita emitir
tcp_cyclesen/infopara diagnóstico interno; esto require cambio en el .exe.
Véase también
- [[entity—monitoring—model—monitoring-target]]
- [[feature—monitoring—sonda-tcp]]
- [[concept—monitoring—cns]]
- [[entity—terminal—service—sentinel-tcp-check]]