CreaRack-SL

Remate de la sonda TCP: supresión inteligente de falsos positivos (v1.63.4)

Resumen ejecutivo

Dos remates de la validación E2E de la sonda TCP del 22-07:

  1. 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.

  2. 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_insight cada 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 reales
  • resolve_reachability(ping_loss) == "up" → consulta el modelo, que integra las sondas TCP/HTTP/SNMP disponibles
    • Si tcp_enabled=True y 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
  • 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):

  1. test_total_loss_with_fresh_tcp_suppressed: Loss=100%, TCP check <5s → HTTP 429, no se crea insight
  2. test_total_loss_with_stale_tcp_creates_insight: Loss=100%, TCP check >1h old → HTTP 200, sí se crea insight
  3. test_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)
  • 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 sonda
    • last_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_cycles en /info para 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]]