Barra de Integridad F3: Veredicto "Cambio Real" abre incidencia CNS/ITSM
Barra de Integridad F3: Veredicto “Cambio Real” abre incidencia CNS/ITSM
Versión: 1.61.0 (2026-07-17)
Ámbito: Racks · Monitoring (CNS/ITSM)
Impacto usuario: Ninguno fuera de org 1 (módulo solo activo en org 1, calibración #202)
Resumen ejecutivo
Cuando un usuario de la Barra de Integridad (radar de sincronización planos ↔ red) emite un veredicto “Cambio real” en la cola de reconciliación, el sistema ahora abre automáticamente una incidencia AIInsight en el CNS/ITSM existente con:
- Explicación generada por la IA (evidencia fresca del sensor como contexto).
- Sin comandos ejecutables (la resolución es corregir el plano, no el dispositivo).
- Caducidad de 14 días (no las 4h por defecto de una anomalía operativa).
Al reconocer (acknowledge) la incidencia en Observatory, un hook des-silencia el IntegrityAck vinculado → el próximo probe re-verifica el sujeto contra el plano:
- Si el plano quedó corregido → pasa a
matched_alive(aviso desaparece). - Si no → re-avisa en la cola.
Límite honesto v1: Solo hay incidencia si el sujeto tiene target de monitorización (FK obligatoria en AIInsight que CNS derreferencia por todas partes). Si no lo tiene, la API responde {queued: false, reason: "subject has no monitoring target"} y la página lo muestra.
Arquitectura y flujo
1. Veredicto “Real change” en el endpoint /api/racks/integrity/ack
POST /api/racks/integrity/ack
{
"kind": "matched_stale" | "undocumented",
"verdict": "real_change",
"device_id" | "profile_id": <id>,
}
↓ (200 OK)
{
"ok": true,
"ack_id": <id>,
"muted_until": "ISO8601",
"gate": {...},
"itsm": {
"queued": true | false,
"reason"?: "subject has no monitoring target"
}
}
Nota: El campo itsm es None para otros veredictos (false_alarm, plan_updated).
2. Puente: racks/services/integrity_itsm.py
Responsabilidades:
-
resolve_ticket_target(org, device=None, profile=None): Devuelve elMonitoringTargetque ancla la incidencia, oNonesi no existe.- Para un
device: busca target directo o por IP de gestión. - Para un
profile: busca target por IP de la red. - Usa
select_related("organization")para evitar SynchronousOnlyOperation en contexto async.
- Para un
-
_drift_context(org, ack): Recomputa la evidencia fresca del sujeto desde el motor (fuente única de verdad).- Devuelve
(reason, evidence, label)o(None, None, None)si el sujeto ya no aparece encompute_integrity(). - Los tickets se abren siempre con
subject_labelpreservado en elack(inmutable desde el click).
- Devuelve
-
open_drift_ticket(ack_id): Crea la incidenciaAIInsightde documentación.- Idempotente: si el
ackya tieneinsight_id, devuelve ese id sin crear otro. - Condicional: si no hay target, devuelve
Nonesin crear (la API lo reporta en respuesta). - Async-safe: usa
async_to_syncpara llamar acreate_drift_insight(que es async).
- Idempotente: si el
3. Tarea Huey: racks/tasks.open_integrity_drift_ticket(ack_id)
@db_task()
def open_integrity_drift_ticket(ack_id):
# Best-effort: si falla (rate limit, proveedor caído), el aviso sigue en cola.
integrity_itsm.open_drift_ticket(ack_id)
Rationale: La llamada al proveedor de IA y recomputo de contexto pueden tomar segundos. No caben en el request del click del usuario (que debe ser <100ms). Por eso se encola en background con Huey — el campo itsm en la respuesta dice {"queued": true} siempre que el target exista.
4. Servicio: monitoring/services/insight_service.create_drift_insight()
Nueva función especializada para tickets documentales (drift):
async def create_drift_insight(
*,
target: MonitoringTarget,
anomaly_description: str,
evidence: dict,
subject_label: str,
provider_name: str = "static",
) -> AIInsight:
"""Ticket ITSM de drift documental sin comandos ni maintenance-window."""
Diferencias vs. create_insight() operativo:
| Aspecto | create_insight() | create_drift_insight() |
|---|---|---|
| Ventana mantenimiento | ✅ Sí (anomalía operativa) | ❌ No (no afecta al equipo) |
| Comandos | ✅ Propuestos por IA | ❌ Siempre [] (nunca Apply) |
| is_actionable | ✅ Si hay comandos | ❌ Siempre False |
| TTL (expires_at) | 4 horas (por defecto) | 14 días (DRIFT_TICKET_TTL_DAYS) |
| RiskLevel | HIGH/MEDIUM según IA | LOW (siempre) |
| Categoría | CONNECTIVITY/PERFORMANCE/etc | OTHER |
Reutilización sin duplicación: Se extrajo _analyze_with_fallback() de create_insight() para que ambas usen la misma lógica de IA + fallback a reglas estáticas.
5. Hook en acknowledge_insight() (monitoring/services/insight_service.py)
# Al reconocer una incidencia (usuario en Observatory):
def acknowledge_insight(insight: AIInsight, user=None, notes: str = ""):
insight.status = AIInsight.Status.ACKNOWLEDGED
insight.acknowledged_at = timezone.now()
insight.acknowledged_by = user
insight.save()
# Barra de Integridad F3 — des-silenciar acks vinculados
unmuted = IntegrityAck.objects.filter(
insight=insight,
muted_until__gt=now
).update(muted_until=now)
Efecto: El próximo probe de integridad re-verifica el sujeto sin esperar a la caducidad original del silenciamiento (típicamente 30 días).
6. Nuevas migraciones
Migración racks/migrations/0018_integrityack_insight.py:
AddField(
model_name="integrityack",
name="insight",
field=models.ForeignKey(
"monitoring.AIInsight",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="integrity_acks",
),
)
FK nullable → permite acks sin incidencia (p.ej. sujeto sin target).
Internacionalización (i18n)
Completada: 28 strings JS + 11 de plantilla al catálogo (djangojs.po/django.po).
- Página completa de Integrity ya traducida al español.
- Novos strings de F3: “Real change recorded — an ITSM incident is being opened…” y variante sin target.
- Chequeo de duplicados msgctxt-aware +
check_po.py0 errores.
Testing
8 tests nuevos en tests/racks/test_integrity_itsm.py (proveedor IA: “static” offline):
- ✅ Ticket sin comandos y con TTL largo (14 días).
- ✅ Idempotencia per
ack_id. - ✅ Sin target → sin ticket + respuesta honesta.
- ✅ Perfil undocumented anclado por IP.
- ✅ Ciclo acknowledge → unmute → re-verify.
- ✅ Endpoint
/api/racks/integrity/ackconitsmfield. - ✅ Veredictos otros (no
real_change) no tocan ITSM.
139 tests de regresión CNS verdes en Docker.
Observaciones y deuda
- Hueco pre-existente (no tocado):
AIInsight.resolved_atno lo escribe ningún flujo (se consulta para métricas SLA de MTTR pero nunca se actualiza). Anotado para decisión aparte. - Limitación honesta v1: Solo hay ticket si target existe. Los avisos de integrity en sujetos sin monitorización siguen viviendo en la cola del radar (no se generan incidencias “huérfanas”).
Véase también
- [[entity—racks—service—integrity-itsm]]
- [[entity—monitoring—service—create-drift-insight]]
- [[entity—racks—endpoint—integrity-ack]]
- [[entity—racks—model—integrity-ack]]
- [[entity—monitoring—model—aiinsight]]