CreaRack-SL

Funciones principales

build_state_context(sections, user) → str

Orquesta la construcción del contexto. Itera las secciones solicitadas, llama a cada builder privado y concatena los resultados en un bloque [CONTEXTO …]. Desde v1.119.0 antepone al bloque el aviso de _agent_disconnection_notice cuando aplica (ver abajo).

_agent_disconnection_notice(org) → str (v1.119.0 · task #293 · corregida en v1.132.13 · task #309)

Problema que resuelve: el bloque de contexto se etiquetaba “datos en vivo del sistema” aunque el Agente del cliente llevara horas mudo — los conteos de alerts/devices se presentaban sin avisar de su antigüedad.

Decisión de producto (Edu): avisar, no ocultar. Se antepone una línea de aviso si el último Agente visto de la organización lleva status="offline" más de 30 minutos (mismo umbral que racks/services/integrity.py). Umbral: _AGENT_STALE_THRESHOLD_MINUTES = 30.

Lógica (v1.132.13): si algún AgentInstance de la org está online, no hay aviso; si no, se toma el de last_seen más reciente sin filtrar por rol. Por qué: la versión de v1.119.0 filtraba role="primary", y el failover degrada a secondary al Agente que se desconecta — en el instante en que el aviso empezaba a hacer falta ya no quedaba ningún “primary” que mirar. Con un solo Agente por organización (las dos reales) el aviso era imposible por construcción (medido en PROD el 13-09-2026: cadena vacía en ambas orgs con el Agente 15 h mudo; cronología real: desconexión 12-09 13:29, failover primary→secondary 13:30).

Salida: "(el Agente de monitorización lleva {N}h desconectado — estos datos pueden estar desactualizados)", insertada tras la cabecera [CONTEXTO: ...] y antes de las líneas de sección.

_build_alerts_context(user, is_admin) → str

⚠️ Corregida en s56 / commit 06a228a — ver [[incident—20260511—informante-alerts-conteo-incorrecto]]. Y en v1.132.13 (task #309): la fuente 2 pasa de last_status crudo a status_effective.

Agrega 3 fuentes operativas de alertas:

#FuenteModeloFiltro
1AlertEvent activosAlertEventalert__organization=org, resolved_at__isnull=True
2Devices caídosMonitoringTargetorganization=org y status_effective == "down" (property Python: se itera el queryset, dataset pequeño — mismo patrón que monitoring/api/targets.py)
3Insights IA pendientesAIInsightorganization=org, status in [PENDING, EXECUTING]

El resumen devuelto etiqueta explícitamente cada categoría:

Alertas activas: 133 (devices caídos: 128, alertas configuradas: 5, insights IA pendientes: 0).
 Top devices caídos: sw-core1, sw-core2, ... (+123 más sin detallar).

El campo is_admin controla si se listan los top devices caídos y las alertas configuradas individuales (los viewers solo reciben el conteo total). El texto de cero alertas ya no afirma “todos los devices en up”: dice “ningún device caído con medida reciente”.

Antes de s56 (comportamiento incorrecto): solo contaba AlertEvent. Devices caídos e insights IA se ignoraban, causando que el Informante respondiera “0 alertas activas” con 128 devices caídos en PROD.

_build_devices_context(user, is_admin) → str

Resumen de MonitoringTarget del tenant por status_effective (v1.132.13 · task #309): total, online, offline y “sin dato reciente” como categoría propia — Devices: 3 (online: 1, offline: 1, sin dato reciente: 1).; si ninguno tiene medida reciente, Devices: N, ninguno con dato reciente (sin medida del Agente de monitorización). sin lista de caídos. Para admins lista los 5 primeros devices caídos (con medida reciente) con IP. Desde s56 añade el sufijo (+N más sin detallar) cuando la lista está truncada, para que el modelo entienda que es parcial.

Antes de v1.132.13 (comportamiento incorrecto): contaba por last_status crudo, que no caduca. Con el Agente de la org 2 mudo 15 h, metía en el prompt “Devices: 187 (online: 117, offline: 70). Caídos: 172.25.10.204; …” con la instrucción de no inventar números, cuando el criterio del resto de la app daba {'unknown': 187}. La migración a status_effective de la task #277 llegó a 15 sitios del monitoring y este fichero se quedó fuera (su propio comentario lo reconocía).

_build_signage_context(user, is_admin) → str

Resumen del estado de Digital Signage del tenant. Desde v1.119.0 (task #296.1) ya NO consulta ContentDeployment: la tabla tiene 0 filas en las 6 organizaciones de PROD y nadie la escribe desde que se retiró su endpoint en v1.38.1 — el bloque de “despliegues fallidos 24h” era código muerto que solo podía devolver silencio. El resumen de reproductores (mismo builder) no se toca.

_build_health_context(user, is_admin) → str

Tres checks operacionales, sin modelo propio: ping a la base de datos (siempre), espacio libre en disco y uptime del proceso (estos dos últimos solo para admins, por ser info sensible de infra).

Uptime corregido en v1.126.0 (2026-09-06 · task #293 pt.2): antes restaba la fecha de modificación (mtime) del propio fichero help_state.py, es decir la fecha del build de la imagen. Tras un reinicio del proceso sin deploy nuevo el uptime mostrado no se movía, y justo después de un deploy marcaba “0h” aunque el proceso llevara horas arriba. Ahora se mide desde _PROCESS_STARTED_AT, una constante de módulo fijada al importarse — y core/apps.py importa help_state en ready() para que ese instante sea el arranque real del worker, no la primera pregunta que alguien le hace al Informante.


Aislamiento multi-tenant

  • Todo filtro incluye organization=org explícito.
  • El TenantRLSMiddleware aplica RLS Postgres, pero AlertEvent no tiene FK directa a Organization (se filtra vía alert__organization), por lo que el RLS no es suficiente por sí solo.
  • MonitoringTarget y AIInsight sí tienen FK directa a Organization y aprovechan RLS + filtro explícito.

Tests

Los tests de integración viven en tests/api/test_help.py. Casos relevantes añadidos en s56:

  • test_build_context_with_targets_down — device last_status=down con last_check reciente → cuenta como alerta (desde v1.132.13 el fixture fija last_check: sin medida reciente sería “sin dato reciente”).
  • test_build_context_with_pending_insight — AIInsight.Status.PENDING → cuenta como alerta.
  • test_build_context_no_active_alerts — las 3 fuentes vacías → "Alertas activas: 0".

Añadidos en v1.119.0 (tests/api/test_help.py): aviso de agente desconectado (>30 min offline), ausencia de aviso con agente online o sin last_seen, y retirada del bloque ContentDeployment de _build_signage_context.

Añadidos en v1.126.0 (tests/network/test_ronda_0906_tanda5.py — sí, viven junto al test del backfill de firmware, no en tests/api/test_help.py): test_uptime_counts_from_process_start (mockea _PROCESS_STARTED_AT y comprueba el texto “uptime ~2h5m”) y test_uptime_is_hidden_from_non_admins.

Añadidos en v1.132.13 (tests/api/test_help_state_agent_mute_309.py): todo caducado → “ninguno con dato reciente” sin “Caídos” y CON aviso aunque el Agente sea secondary offline; mezcla fresco/caducado → online/offline/sin dato reciente; aviso con secondary degradado; sin aviso si alguno está en línea; sin aviso bajo el umbral.


Historial de cambios relevantes

VersiónCambio
v1.132.13 (2026-09-15)Task #309 (ronda 13-09): _build_devices_context/_build_alerts_context cuentan por status_effective con la categoría “sin dato reciente”; _agent_disconnection_notice deja de exigir role="primary" (era imposible por construcción con un solo Agente). PR #543.
v1.126.0 (2026-09-06)_build_health_context: el uptime del proceso deja de medir la mtime del fichero y pasa a medir _PROCESS_STARTED_AT, fijada al importar el módulo desde core/apps.py.ready() (task #293 pt.2).
v1.119.0 (2026-09-06)_agent_disconnection_notice (task #293): avisa en el bloque de contexto si el Agente primary lleva >30 min offline, sin ocultar los números. _build_signage_context deja de consultar ContentDeployment (task #296.1, tabla muerta desde v1.38.1).
s56 (2026-05-11)_build_alerts_context amplía a 3 fuentes; _build_devices_context añade tail “+N más”.
Anterior_build_alerts_context solo contaba AlertEvent → bug en PROD (ver [[incident—20260511—informante-alerts-conteo-incorrecto]]).

Véase también

  • [[incident—20260511—informante-alerts-conteo-incorrecto]] — incidente PROD que motivó el fix de s56
  • [[entity—monitoring—model—alertevent]] — modelo AlertEvent (fuente 1 del contexto de alertas)
  • [[entity—monitoring—model—monitoringtarget]] — modelo MonitoringTarget (fuente 2)
  • [[entity—monitoring—model—aiinsight]] — modelo AIInsight / CNS Sentinel (fuente 3)
  • [[crearack—redes-infra—monitorizacion]] — visión general del módulo de monitorización
  • [[entity—monitoring—model—monitoring-target]] — documenta status_effective, el criterio de frescura que motivó el aviso de task #293