CreaRack-SL

Motor de Integridad F1 — cruce plano↔realidad con métricas separadas

Descripción General

Motor de Integridad F1 es la primera fase de la Barra de Integridad (Integrity Bar): un sistema que computa automáticamente la clasificación de cada equipo documentado en los racks contra la realidad observada en la LAN del cliente, a través de dos señales independientes:

  1. DeviceProfile del discovery (qué ve el sensor de red)
  2. MonitoringTarget del monitoreo (qué dice el agente local)

El motor NUNCA usa solo una métrica de confianza. En su lugar, separa deliberadamente:

  • fidelity_pct — de lo observable, cuánto cuadra con el plano (máx relevancia para el usuario, mín ruido)
  • coverage_pct — cuánto del plano puede ver el sensor (metadato, importante para detectar puntos ciegos)

Un equipo no observable (sin IP de gestión, sin perfil, sin monitorización) jamás baja la fidelidad: se va a cuarentena (unobservable).

Cronología y Contexto

  • Decisión: 2026-07-17 · Converge storm (18 citas verificadas) → roast (RESHAPE de confianza alta)
  • Informes: workspace.crearack.com/informes/{storm,roast}/barra-integridad-rack-2026-07-17.html
  • Gate de activación: task #202 del Gestor (umbral ≥80% de drifts reales)
  • Impacto usuario: NINGUNO todavía — F1 es motor + datos internos
  • Próximas fases:
    • F2: reconciliación (cola + ITSM)
    • F3: UI (radar interno del MSP)
    • F4: informe de diligencia

Clasificación por Equipo

Cada dispositivo del plano se clasifica en uno de estos montones:

ClaseCriterioAcción
matched_aliveIdentidad conocida + evidencia fresca de vida (perfil ≤7d O monitorización up)OK
matched_staleIdentidad conocida pero sin evidencia fresca (drift candidato: retirado/apagado/desconectado)Revisar
ip_conflictLa identidad no cuadra: perfil en otra IP O IP del plano vinculada a otro equipoRevisar
unobservablePlano sin identidad de red (sin IP, sin perfil, sin monitorización)Cuarentena (NO baja fidelity)

A nivel organización, se añade:

ClaseCriterioAcción
undocumentedPerfil vivo en la LAN que no está en ningún plano (drift candidato: equipo montado sin documentar)Revisar

Componentes del Motor

Servicio racks.services.integrity

Función pública: compute_integrity(organization, fresh_days=7, target_fresh_minutes=30)

  • Itera TODOS los racks + dispositivos de la org
  • Cruza con DeviceProfile (discovery) + MonitoringTarget (monitoreo)
  • Classifica cada equipo con evidencia (IP, hostname, serial, MAC, timestamps)
  • Retorna JSON-serializable con racks/summary/undocumented

Función de persistencia: persist_snapshots(organization, result, snapshot_date=None)

  • Escribe fotos diarias (una fila/rack + resumen de org con rack=NULL)
  • Idempotente por (org, rack, fecha) — update_or_create
  • Sin UI → no se expone en API todavía

Modelo RackIntegritySnapshot

class RackIntegritySnapshot(models.Model):
    organization = ForeignKey(Organization, CASCADE)
    rack = ForeignKey(Rack, CASCADE, null=True, blank=True)  # NULL = org-summary
    date = DateField()
    
    fidelity_pct = FloatField(null=True, blank=True)
    coverage_pct = FloatField(null=True, blank=True)
    
    counts = JSONField(default=dict)  # {matched_alive, matched_stale, ...}
    findings = JSONField(default=list)  # [{device_id, classification, reason, evidence}, ...]
    
    # RLS: patrón core-0029, migraciones 0014+0015

Comando rack_integrity_probe

python manage.py rack_integrity_probe --org 1
python manage.py rack_integrity_probe --org 1 --save        # guarda snapshot
python manage.py rack_integrity_probe --org 1 --json        # JSON para logs

Salida human-readable con tabla de racks + avisos a revisar (stale/conflict) + vivos sin documentar.

Task Diaria compute_integrity_snapshots

@db_periodic_task(crontab(hour="4", minute="15"))  # 04:15 UTC, tras backups
@lock_task("rack-integrity-snapshots")
def compute_integrity_snapshots():
    # Itera org.all() con bypass GUC ('0')
    # Persiste snapshot para cada org
    # Logger: info al terminar

Decisiones de Diseño Clave

1. Dos Métricas Separadas (NO Una Única Confianza)

Problema: Un equipo sin perfil de discovery pero con monitorización “up” parecía 100% confiable. Pero el sensor tal vez nunca lo vió → fidelidad falsa.

Solución RESHAPE (roast 17-07):

  • fidelity_pct = matched_alive / observable — solo de lo que vemos, cuánto cuadra
  • coverage_pct = observable / total — cuánto del plano podemos ver

Un equipo unobservable contribuye al denominador de coverage, pero NUNCA al numerador de fidelity.

2. Sin Impacto de Usuario (Gate Antes de Exponer)

F1 es puro motor + datos. La UI llega en F2-F4 tras validar que el detector acierta ≥80% (task #202, design partner en sept).

Si exponemos ahora, confundimos al usuario con un beta que no sabemos si funciona → pérdida de confianza.

3. RLS Patrón core-0029

Migraciones 0014 (tabla) + 0015 (política). El scoping manual en Huey (GUC ‘0’ con bypass admin) es idéntico al del resto de tasks de background.

4. Umbrales Ajustables, Pré-Declarados

Los defaults (DEFAULT_FRESH_DAYS=7, DEFAULT_TARGET_FRESH_MINUTES=30) son ajustables por flag de comando. El gate de calibración decide los definitivos, no hardcodeamos.

Límites Honestos

  • QUÉ sabe el motor: existencia, vida (up/down), identidad (IP/MAC/serial)
  • QUÉ NO sabe: posición física (rack/U) — requiere cruce con plano + auditoría humana
  • Punto ciego documentado: una mudanza dentro de la misma red (mismo rack/modelo/IP reasignada) puede NO detectarse; la solución es el asset inventory manual (out-of-scope F1)

Véase también

  • [[entity—racks—service—integrity]]
  • [[entity—racks—model—rack-integrity-snapshot]]
  • [[entity—racks—command—rack-integrity-probe]]
  • [[entity—racks—task—compute-integrity-snapshots]]
  • [[concept—saas—multi-tenancy]]
  • [[decision—20260403—multi-tenancy-rls]]