Rela AIRela AI Docs
Monitoreo de Condición

Inbox Unificado (Alert Aggregator)

Un único inbox de alertas por activo: las detecciones de anomalías, energía y pronóstico colapsan en una sola fila. Severidad canónica, dedup por ventana, re-open automático en escalación.

Inbox Unificado — Alert Aggregator

El problema clásico: tres sistemas de detección independientes (anomalías mecánicas, anomalías energéticas, pronóstico de vida útil) producen tres alertas "críticas" cuando una bomba se degrada. El operador ve tres filas, duda cuál atender, y el ruido mata la señal.

La solución: un único inbox que consolida las tres fuentes en una fila por activo, con severidad = la más alta observada, fuente(s) = unión de detectores, y un trail de cambios de severidad para auditar cómo escaló el incidente.

Resumen ejecutivo

Un pico → una alerta. Antes: 3 rojos en el inbox por el mismo evento físico. Después: 1 fila con source_systems = [anomaly, energy, prognostics]. El operador actúa una vez, el sistema cierra las tres detecciones juntas.

¿Para qué sirve?

  • Eliminar redundancia: el mismo fenómeno (spike de vibración) puede disparar detección ML + residual energético + RUL crítico en segundos. Son la misma historia.
  • Preservar el trail: la consolidación no pierde información — cada detector aporta al campo sources de la alerta consolidada con su summary y su momento.
  • Severidad canónica max: la alerta refleja el peor diagnóstico. Si anomalía dice warning y prognostics dice critical, la fila queda critical.
  • Escalación automática: si el operador marca la alerta como "reconocida" pero llega una nueva detección de severidad mayor, la alerta se reabre (reopened_reason = severity_upgrade). Nadie pierde visibilidad.

¿Cómo funciona?

Contrato de entrada

Cada uno de los tres detectores llama al aggregator después de persistir su propio registro:

ingest_alert(
    tenant_id,
    asset_id,
    source_system="anomaly" | "energy" | "prognostics",
    severity="warning" | "high" | "critical",
    summary="...",
    source_doc_id="<opcional, id en la colección origen>",
    extra={...}
)

Filtro de entrada: solo severity >= warning alimenta el aggregator. info es ruido, no incidente.

Reglas de merge

flowchart TD
  IN[Nueva detección<br/>asset_id + severity] --> Q{¿Hay fila activa<br/>para ese asset<br/>en la ventana?}
  Q -- No --> INS[Insertar fila nueva<br/>status=open]
  Q -- Sí --> CMP{¿Severidad entrante<br/>&gt; stored?}
  CMP -- Sí --> UP[Upgrade<br/>severity=max<br/>push sources<br/>re-open si estaba ack]
  CMP -- No --> EQ[Merge silencioso<br/>count += 1<br/>source_systems addToSet<br/>NO push sources]
  • Ventana de dedup: alert_dedup_window_minutes (default 60, configurable por tenant).
  • Búsqueda: se consideran filas open y acknowledged. Una alerta reconocida dentro de la ventana sigue siendo "live" para dedup.
  • Upgrade de severidad: severity := max(stored, incoming) según la escala canónica info < warning < high < critical.
  • Re-open en escalación: si la fila estaba acknowledged y entra una severidad mayor → vuelve a open con reopened_reason = severity_upgrade.
  • Hysteresis del trail: si la severidad entrante es igual o menor a la almacenada, count y source_systems se actualizan pero la lista sources no crece. La idea: el trail registra cambios de severidad, no repeticiones triviales que ensuciarían la UI.

Persistencia

Colección _alerts per-tenant. Campos clave:

CampoSignificado
asset_idIdentidad del activo afectado. Llave de dedup.
statusopen / acknowledged / (con reopened_* si reabrió).
severityMax histórica dentro de la fila.
source_systemsSet de detectores que aportaron: ["anomaly","energy","prognostics"].
sourcesLista append-only con el trail de upgrades: cada entry tiene system, severity, summary, doc_id, at.
countTotal de detecciones ingeridas (incluye mergeos silenciosos).
first_seen_at, last_seen_atMarcas temporales.

Tests que codifican el contrato

El comportamiento está codificado en tests de integración en tests/predictive/test_alert_aggregator_cross_system.py:

  • test_single_spike_consolidates_into_one_alert — simula los 3 detectores disparando en la misma ventana sobre el mismo activo → len(_alerts) == 1, source_systems == {anomaly, energy, prognostics}, severity == critical, count == 3, len(sources) == 3 (todas upgrades).
  • test_two_assets_two_separate_alerts — spikes en assets distintos → 2 filas separadas, sin bleed.
  • test_upgrade_reopens_acknowledged_alert — ACK + critical entrante → status vuelve a open con reopened_reason.
  • test_same_severity_on_ack_keeps_it_acknowledged — ACK + mismo severity entrante → no reabre.
  • test_lower_severity_does_not_push_source_trail — stored critical + warning entrante → $push al trail NO ocurre.

Si algún refactor cambia la semántica, el test rompe.

¿Cómo usarlo?

Ver el inbox

Desde el dashboard:

  1. Operaciones → Alertas — lista del tenant, orden por last_seen_at descendente.
  2. Columnas: Asset · Severity · Source systems · Count · First seen · Last seen · Actions.
  3. Filtros: por severidad, por fuente, por status, por rango de fechas.

Acciones por alerta

AcciónEfecto
Acknowledgestatus := acknowledged, registra actor. Útil para "ya vi, voy a investigar".
Create taskConvierte la alerta en orden de trabajo, vinculando todas las sources.
NotifyDispara WhatsApp/email (via reglas o manual).
CloseCierra el incidente. Si entra una nueva detección, es un nuevo incidente.

Configuración per-tenant

Ajustes vía Configuración Predictiva:

  • alert_dedup_window_minutes — default 60. Reducir = menos consolidación, más filas. Aumentar = más consolidación, puede mezclar incidentes genuinamente distintos si están cerca en tiempo.

Antes / Después

Inbox antes del aggregator

[14:02:15] CRITICAL  anomaly_detection   pump-B07  vibration ensemble score 0.92
[14:02:17] CRITICAL  energy_anomaly      pump-B07  z=3.4 on kwh
[14:02:21] CRITICAL  prognostics         pump-B07  RUL 18h

3 filas. ¿Cuál atiendo primero? ¿Son el mismo problema? ¿Cierro una o las tres?

Inbox después del aggregator

[14:02:15→14:02:21] CRITICAL  pump-B07  [anomaly,energy,prognostics]  count=3
  └ sources:
      14:02:15  anomaly      warning→   ensemble score 0.75
      14:02:17  energy       →high      z=3.4 on kwh
      14:02:21  prognostics  →critical  RUL 18h

Una sola fila. Severidad es la peor. El trail cuenta la historia de escalación. Un solo ACK cierra las tres.

Limitaciones y supuestos

  • Dedup es por asset_id. Dos métricas distintas del mismo activo colapsan en la misma fila. Si quieres filas por métrica, es otro modelo — no es el caso de este aggregator.
  • La ventana es deslizante sobre last_seen_at. Una detección que llega fuera de la ventana abre una fila nueva aunque el incidente sea conceptualmente el mismo. Ajustar alert_dedup_window_minutes para tu patrón operativo.
  • El trail captura upgrades, no repeticiones. Si tu auditoría necesita saber cuántas veces dispara cada detector, el campo count lo tiene — sources solo guarda los cambios de severidad.
  • No es un sistema de workflow completo. ACK / notify / create task son endpoints del aggregator; la gestión de turnos, asignaciones y SLAs vive en Órdenes de Trabajo.

Beneficios clave

  • Un solo inbox por activo — menos ruido, más acción.
  • Severidad canónica max entre los tres detectores, con trail auditable.
  • Re-open automático en escalación — no se pierde visibilidad post-ACK.
  • Hysteresis inteligente — el trail refleja cambios de severidad, no repeticiones.
  • Window dedup configurable por tenant.
  • Tests de integración E2E que garantizan el contrato.

En esta página