Files
system-docs/v4-archive/contratos-comunes/docs/SENTINEL.md
2025-12-24 17:28:34 +00:00

50 KiB

07a. SENTINEL — Sistema de Auditoría

Manual de Arquitectura Técnica — Documento 07a
Versión: 1.2
Dependencia: S-CONTRACT.md
Estado: Enterprise Standard


A.1 Introducción a SENTINEL

SENTINEL es el sistema de auditoría automatizada del ecosistema GRACE. Opera como un guardián silencioso que verifica la integridad, calidad y conformidad de todas las operaciones.

┌─────────────────────────────────────────────────────────────────┐
│                    PRINCIPIO SENTINEL                           │
│                                                                 │
│   "Confía, pero verifica. Verifica todo, siempre, sin excepción"│
└─────────────────────────────────────────────────────────────────┘

A.1.1 Objetivos

  1. Integridad: Verificar que los datos no han sido alterados.
  2. Conformidad: Validar cumplimiento del contrato común.
  3. Calidad: Detectar degradación en los módulos IA.
  4. Anomalías: Identificar patrones sospechosos o errores sistemáticos.
  5. Trazabilidad: Asegurar que todo evento tiene su registro.

A.1.2 Filosofía Dual

SENTINEL implementa una estrategia de dos velocidades:

Aspecto SENTINEL-LIGHT SENTINEL-DEEP
Analogía Guardia de seguridad Detective investigador
Enfoque Exhaustivo, superficial Selectivo, profundo
Motor Reglas + ML ligero LLM pesado
Frecuencia Continua (cada 5 min) Periódica (cada hora)
Costo Mínimo Variable

A.2 SENTINEL-LIGHT (Centinela Rápido)

A.2.1 Arquitectura

┌─────────────────────────────────────────────────────────────────┐
│                      SENTINEL-LIGHT                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐         │
│  │   RULES     │    │  STATS      │    │  ALERTS     │         │
│  │   ENGINE    │───▶│  COLLECTOR  │───▶│  DISPATCHER │         │
│  └─────────────┘    └─────────────┘    └─────────────┘         │
│         │                  │                  │                 │
│         ▼                  ▼                  ▼                 │
│  ┌─────────────────────────────────────────────────────────────┤
│  │                    SYS_LOG (Source)                         │
│  └─────────────────────────────────────────────────────────────┤
│                            │                                    │
│                            ▼                                    │
│  ┌─────────────────────────────────────────────────────────────┤
│  │                 AUDIT_RESULTS (Sink)                        │
│  └─────────────────────────────────────────────────────────────┤
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

A.2.2 Ciclo de Ejecución

CADA 5 MINUTOS:
┌────────────────────────────────────────────────────────────────┐
│ 1. QUERY                                                       │
│    SELECT * FROM SYS_LOG                                       │
│    WHERE audit_status = 'PENDING'                              │
│    AND timestamp_created > NOW() - INTERVAL '10 minutes'       │
│    ORDER BY timestamp_created                                  │
│    LIMIT 1000                                                  │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ 2. APPLY RULES                                                 │
│    Para cada registro:                                         │
│    - Ejecutar reglas de integridad                             │
│    - Ejecutar reglas de conformidad                            │
│    - Ejecutar reglas de rendimiento                            │
│    - Acumular resultados                                       │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ 3. CLASSIFY                                                    │
│    - PASS: Todas las reglas OK                                 │
│    - WARN: Reglas de severidad MEDIUM fallaron                 │
│    - FAIL: Reglas de severidad HIGH/CRITICAL fallaron          │
└────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌────────────────────────────────────────────────────────────────┐
│ 4. UPDATE & ESCALATE                                           │
│    - UPDATE SYS_LOG SET audit_status, audit_light_ts           │
│    - INSERT AUDIT_RESULTS con resumen del batch                │
│    - Si FAIL → marcar para SENTINEL-DEEP                       │
│    - Si CRITICAL → alerta inmediata                            │
└────────────────────────────────────────────────────────────────┘

A.2.3 Catálogo de Reglas

Reglas de Integridad (I-*)

rules:
  I-001:
    name: "Hash de entrada coincide"
    description: "Verificar que input_hash == SHA256(archivo en input_ref)"
    severity: CRITICAL
    condition: |
      VERIFY_HASH(input_ref, input_hash) == true
    on_fail:
      action: ESCALATE_DEEP
      alert: IMMEDIATE
      
  I-002:
    name: "Hash de salida coincide"
    description: "Verificar que output_hash == SHA256(archivo en output_ref)"
    severity: CRITICAL
    condition: |
      output_ref IS NULL OR VERIFY_HASH(output_ref, output_hash) == true
    on_fail:
      action: ESCALATE_DEEP
      alert: IMMEDIATE
      
  I-003:
    name: "Cadena de trazas válida"
    description: "Si tiene parent_trace_id, el padre debe existir"
    severity: HIGH
    condition: |
      parent_trace_id IS NULL 
      OR EXISTS(SELECT 1 FROM SYS_LOG WHERE trace_id = parent_trace_id)
    on_fail:
      action: LOG_WARN
      alert: BATCH
      
  I-004:
    name: "Referencias no huérfanas"
    description: "input_ref y output_ref deben apuntar a archivos existentes"
    severity: HIGH
    condition: |
      FILE_EXISTS(input_ref) == true
      AND (output_ref IS NULL OR FILE_EXISTS(output_ref) == true)
    on_fail:
      action: ESCALATE_DEEP
      alert: BATCH
      
  I-005:
    name: "Idempotency key única por trace"
    description: "No debe haber duplicados de idempotency_key con distinto resultado"
    severity: MEDIUM
    condition: |
      NOT EXISTS(
        SELECT 1 FROM SYS_LOG 
        WHERE idempotency_key = {current.idempotency_key}
        AND trace_id != {current.trace_id}
        AND output_hash != {current.output_hash}
      )
    on_fail:
      action: LOG_WARN
      alert: BATCH

Reglas de Conformidad (C-*)

rules:
  C-001:
    name: "Campos obligatorios presentes"
    description: "Verificar campos requeridos según perfil"
    severity: HIGH
    condition: |
      IF profile == 'FULL':
        ALL_PRESENT(trace_id, step_id, idempotency_key, module_name, 
                    input_hash, input_ref, status_code)
      ELSE:
        ALL_PRESENT(trace_id, idempotency_key, module_name, status_code)
    on_fail:
      action: LOG_ERROR
      alert: BATCH
      
  C-002:
    name: "Status code válido"
    description: "status_code debe ser un valor permitido"
    severity: HIGH
    condition: |
      status_code IN ('PENDING', 'RUNNING', 'SUCCESS', 'PARTIAL', 
                      'ERROR', 'TIMEOUT', 'FALLBACK', 'CANCELLED')
    on_fail:
      action: LOG_ERROR
      alert: BATCH
      
  C-003:
    name: "Step type válido"
    description: "step_type debe ser un valor permitido"
    severity: HIGH
    condition: |
      step_type IN ('INIT', 'VALIDATE', 'ROUTE', 'TRANSFORM', 'FALLBACK',
                    'PERSIST', 'NOTIFY', 'COMPLETE', 'ERROR', 'AUDIT', 'CANCEL')
    on_fail:
      action: LOG_ERROR
      alert: BATCH
      
  C-004:
    name: "Confidence en rango"
    description: "Si existe confidence, debe estar entre 0 y 1"
    severity: MEDIUM
    condition: |
      confidence IS NULL OR (confidence >= 0 AND confidence <= 1)
    on_fail:
      action: LOG_WARN
      alert: BATCH
      
  C-005:
    name: "Timestamps coherentes"
    description: "timestamp_completed >= timestamp_started >= timestamp_created"
    severity: MEDIUM
    condition: |
      timestamp_started IS NULL OR timestamp_started >= timestamp_created
      AND timestamp_completed IS NULL OR timestamp_completed >= timestamp_started
    on_fail:
      action: LOG_WARN
      alert: BATCH
      
  C-006:
    name: "Batch coherente"
    description: "Si is_batch, debe tener batch_id y item_index válidos"
    severity: MEDIUM
    condition: |
      batch_id IS NULL 
      OR (batch_item_index > 0 AND batch_items_total >= batch_item_index)
    on_fail:
      action: LOG_WARN
      alert: BATCH

Reglas de Rendimiento (P-*)

rules:
  P-001:
    name: "Duración dentro de umbral"
    description: "duration_ms no debe exceder 3x el esperado para el módulo"
    severity: MEDIUM
    params:
      thresholds:
        CLASSIFIER: 1500
        OCR_CORE: 10000
        ASR_ENGINE: 60000
        SUMMARIZER: 5000
        EMBEDDINGS: 2000
        default: 30000
    condition: |
      duration_ms IS NULL 
      OR duration_ms < GET_THRESHOLD(module_name) * 3
    on_fail:
      action: LOG_WARN
      alert: BATCH
      
  P-002:
    name: "Tasa de error por módulo"
    description: "Tasa de errores en última hora < 5%"
    severity: HIGH
    scope: AGGREGATE
    window: 1 HOUR
    condition: |
      (SELECT COUNT(*) FILTER(WHERE status_code IN ('ERROR', 'TIMEOUT'))::float 
       / NULLIF(COUNT(*), 0)
       FROM SYS_LOG 
       WHERE module_name = {current.module_name}
       AND timestamp_created > NOW() - INTERVAL '1 hour'
      ) < 0.05
    on_fail:
      action: ESCALATE_DEEP
      alert: IMMEDIATE
      
  P-003:
    name: "Fallback excesivo"
    description: "Tasa de fallback en última hora < 20%"
    severity: MEDIUM
    scope: AGGREGATE
    window: 1 HOUR
    condition: |
      (SELECT COUNT(*) FILTER(WHERE status_code = 'FALLBACK')::float 
       / NULLIF(COUNT(*), 0)
       FROM SYS_LOG 
       WHERE module_name = {current.module_name}
       AND timestamp_created > NOW() - INTERVAL '1 hour'
      ) < 0.20
    on_fail:
      action: LOG_WARN
      alert: BATCH
      
  P-004:
    name: "Confidence por debajo de baseline"
    description: "Confidence promedio no debe caer más de 0.1 del baseline"
    severity: MEDIUM
    scope: AGGREGATE
    window: 1 HOUR
    params:
      baselines:
        CLASSIFIER: 0.90
        OCR_CORE: 0.85
        ASR_ENGINE: 0.80
        default: 0.80
    condition: |
      (SELECT AVG(confidence)
       FROM SYS_LOG 
       WHERE module_name = {current.module_name}
       AND confidence IS NOT NULL
       AND timestamp_created > NOW() - INTERVAL '1 hour'
      ) >= GET_BASELINE(module_name) - 0.10
    on_fail:
      action: ESCALATE_DEEP
      alert: BATCH

Reglas de Seguridad (S-*)

rules:
  S-001:
    name: "PII con cifrado adecuado"
    description: "Si pii_detected=true, encryption_profile debe ser E2E_BASIC o superior"
    severity: HIGH
    condition: |
      pii_detected == false 
      OR encryption_profile IN ('E2E_BASIC', 'E2E_STRICT')
    on_fail:
      action: ESCALATE_DEEP
      alert: IMMEDIATE
      
  S-002:
    name: "Datos SECRET con cifrado estricto"
    description: "Si data_sensitivity=SECRET, encryption_profile debe ser E2E_STRICT"
    severity: CRITICAL
    condition: |
      data_sensitivity != 'SECRET'
      OR encryption_profile == 'E2E_STRICT'
    on_fail:
      action: ESCALATE_DEEP
      alert: IMMEDIATE
      
  S-003:
    name: "Key Vault referenciado para cifrado"
    description: "Si encryption_profile != NONE, debe existir key_vault_ref"
    severity: HIGH
    condition: |
      encryption_profile == 'NONE'
      OR key_vault_ref IS NOT NULL
    on_fail:
      action: LOG_ERROR
      alert: BATCH

A.2.4 Output de SENTINEL-LIGHT

{
  "sentinel_type": "LIGHT",
  "version": "1.2",
  "execution_id": "uuid-ejecucion",
  "timestamp_start": "2025-12-01T10:30:00.000Z",
  "timestamp_end": "2025-12-01T10:30:03.450Z",
  "duration_ms": 3450,
  
  "scope": {
    "window_start": "2025-12-01T10:20:00.000Z",
    "window_end": "2025-12-01T10:30:00.000Z",
    "records_queried": 1250,
    "records_processed": 1250
  },
  
  "summary": {
    "passed": 1230,
    "warnings": 15,
    "failures": 5,
    "pass_rate": 0.984
  },
  
  "by_severity": {
    "CRITICAL": 1,
    "HIGH": 3,
    "MEDIUM": 16,
    "LOW": 0
  },
  
  "by_rule": {
    "I-001": {"passed": 1250, "failed": 0},
    "I-002": {"passed": 1249, "failed": 1},
    "C-001": {"passed": 1248, "failed": 2},
    "P-001": {"passed": 1235, "failed": 15},
    "S-001": {"passed": 1248, "failed": 2}
  },
  
  "by_module": {
    "CLASSIFIER": {"total": 500, "passed": 498, "failed": 2},
    "OCR_CORE": {"total": 300, "passed": 295, "failed": 5},
    "ASR_ENGINE": {"total": 50, "passed": 48, "failed": 2}
  },
  
  "escalations": [
    {
      "trace_id": "uuid-problema-1",
      "step_id": "uuid-step-1",
      "rule_violated": "I-002",
      "severity": "CRITICAL",
      "details": "Output hash mismatch: expected abc123, got def456",
      "escalate_to": "DEEP",
      "alert_sent": true
    },
    {
      "trace_id": "uuid-problema-2",
      "step_id": "uuid-step-2",
      "rule_violated": "S-001",
      "severity": "HIGH",
      "details": "PII detected but encryption_profile=NONE",
      "escalate_to": "DEEP",
      "alert_sent": true
    }
  ],
  
  "aggregate_alerts": [
    {
      "rule": "P-002",
      "module": "OCR_CORE",
      "message": "Error rate 6.2% exceeds threshold 5%",
      "severity": "HIGH",
      "escalate_to": "DEEP"
    }
  ],
  
  "next_run": "2025-12-01T10:35:00.000Z"
}

A.3 SENTINEL-DEEP (Analista Profundo)

A.3.1 Arquitectura

┌─────────────────────────────────────────────────────────────────┐
│                      SENTINEL-DEEP                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐         │
│  │   QUEUE     │    │    LLM      │    │   REPORT    │         │
│  │   MANAGER   │───▶│   ANALYZER  │───▶│  GENERATOR  │         │
│  └─────────────┘    └─────────────┘    └─────────────┘         │
│         │                  │                  │                 │
│         │                  │                  │                 │
│  ┌──────┴──────┐    ┌──────┴──────┐   ┌──────┴──────┐          │
│  │ Escalations │    │   Claude/   │   │   Findings  │          │
│  │ + Sampling  │    │   GPT-4o    │   │   + Actions │          │
│  └─────────────┘    └─────────────┘   └─────────────┘          │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

A.3.2 Triggers de Ejecución

Trigger Condición Prioridad Acción
ESCALATION SENTINEL-LIGHT marcó para DEEP ALTA Analizar inmediatamente
ERROR_CRITICAL Regla CRITICAL violada CRÍTICA Analizar + alertar
HOURLY_SAMPLE Cron cada hora NORMAL Muestreo aleatorio
PATTERN_DETECTED Mismo error 3+ veces ALTA Investigar patrón
DRIFT_ALERT Confidence < baseline - 0.1 MEDIA Analizar tendencia
MANUAL Solicitud de operador VARIABLE Según solicitud

A.3.3 Estrategia de Muestreo

def select_for_deep_analysis(window_hours=1):
    """
    Selecciona registros para análisis profundo.
    """
    candidates = []
    
    # 1. TODOS los escalados de LIGHT (prioridad máxima)
    escalated = query("""
        SELECT * FROM SYS_LOG 
        WHERE audit_status IN ('LIGHT_WARN', 'LIGHT_FAIL')
        AND audit_deep_ts IS NULL
        AND timestamp_created > NOW() - INTERVAL '{window_hours} hours'
    """)
    candidates.extend(escalated)
    
    # 2. TODOS los errores no analizados
    errors = query("""
        SELECT * FROM SYS_LOG
        WHERE status_code IN ('ERROR', 'TIMEOUT')
        AND audit_deep_ts IS NULL
        AND timestamp_created > NOW() - INTERVAL '{window_hours} hours'
    """)
    candidates.extend(errors)
    
    # 3. Muestreo aleatorio de exitosos (5% o mínimo 10)
    success_count = query("""
        SELECT COUNT(*) FROM SYS_LOG
        WHERE status_code = 'SUCCESS'
        AND audit_deep_ts IS NULL
        AND timestamp_created > NOW() - INTERVAL '{window_hours} hours'
    """)
    sample_size = max(10, int(success_count * 0.05))
    
    sampled = query(f"""
        SELECT * FROM SYS_LOG
        WHERE status_code = 'SUCCESS'
        AND audit_deep_ts IS NULL
        AND timestamp_created > NOW() - INTERVAL '{window_hours} hours'
        ORDER BY RANDOM()
        LIMIT {sample_size}
    """)
    candidates.extend(sampled)
    
    # 4. Registros con confidence anormalmente baja
    low_confidence = query("""
        SELECT * FROM SYS_LOG
        WHERE confidence IS NOT NULL
        AND confidence < 0.6
        AND audit_deep_ts IS NULL
        AND timestamp_created > NOW() - INTERVAL '{window_hours} hours'
    """)
    candidates.extend(low_confidence)
    
    return deduplicate(candidates)

A.3.4 Prompt del Sistema SENTINEL-DEEP

# ROL
Eres SENTINEL-DEEP, el sistema de auditoría profunda del ecosistema GRACE.
Tu función es analizar registros del sistema para:
1. Verificar cumplimiento del contrato común
2. Investigar causa raíz de errores
3. Detectar patrones y anomalías
4. Validar calidad y coherencia de resultados

# CONTEXTO DEL SISTEMA
- **Arquitectura**: GRACE (18 microservicios cognitivos) + ALFRED (orquestador n8n)
- **Filosofía**: "Alfred Decide, GRACE Transforma"
- **Contrato**: S-CONTRACT v1.2
- **Perfiles**: FULL (trazabilidad completa), LITE (mínimo necesario)

# CONOCIMIENTO DEL CONTRATO
## Campos obligatorios FULL
- envelope: trace_id, step_id, idempotency_key, timestamp_init
- routing: module
- payload: type, content
- storage: input_ref, input_hash

## Campos obligatorios LITE
- envelope: trace_id, idempotency_key
- routing: module
- payload: type, content

## Status codes válidos
SUCCESS, PARTIAL, ERROR, TIMEOUT, FALLBACK, PENDING, RUNNING, CANCELLED

## Step types válidos
INIT, VALIDATE, ROUTE, TRANSFORM, FALLBACK, PERSIST, NOTIFY, COMPLETE, ERROR, AUDIT, CANCEL

# TAREA
Analiza los registros proporcionados y genera un informe estructurado.

Para cada registro, evalúa:

## 1. CONFORMIDAD DEL CONTRATO
- ¿Tiene todos los campos obligatorios según su perfil?
- ¿Los valores están en rangos válidos?
- ¿La estructura es coherente internamente?

## 2. INTEGRIDAD DE DATOS
- ¿Los hashes son consistentes?
- ¿Las referencias apuntan a recursos válidos?
- ¿La cadena de trazas es válida?

## 3. CALIDAD DEL RESULTADO
- ¿El confidence reportado es creíble?
- ¿El resultado tiene sentido para el tipo de input?
- ¿Hay señales de alucinación o error del modelo?

## 4. CAUSA RAÍZ (si hay error)
- ¿Qué falló exactamente?
- ¿Es problema de datos, módulo, infraestructura, o configuración?
- ¿Es caso aislado o patrón recurrente?

## 5. RECOMENDACIÓN
- Acción correctiva inmediata
- Prevención para el futuro
- ¿Requiere escalado a humano?

# OUTPUT OBLIGATORIO
Responde ÚNICAMENTE con un JSON válido siguiendo este schema exacto:

```json
{
  "analysis_id": "uuid",
  "timestamp": "ISO8601",
  "records_analyzed": 0,
  "findings": [
    {
      "trace_id": "uuid",
      "step_id": "uuid",
      "diagnosis": {
        "contract_compliant": true,
        "integrity_valid": true,
        "quality_credible": true,
        "issues": []
      },
      "root_cause": {
        "category": "DATA|MODULE|INFRA|CONFIG|UNKNOWN|NONE",
        "description": "string",
        "is_pattern": false,
        "pattern_id": null,
        "related_traces": []
      },
      "recommendation": {
        "action": "string",
        "prevention": "string",
        "urgency": "LOW|MEDIUM|HIGH|CRITICAL",
        "escalate_human": false,
        "escalate_reason": null
      },
      "confidence": 0.95
    }
  ],
  "patterns_detected": [],
  "summary": {
    "total_issues": 0,
    "critical": 0,
    "high": 0,
    "medium": 0,
    "low": 0,
    "human_escalation_needed": false
  }
}

REGLAS CRÍTICAS

  1. NUNCA inventes datos que no estén en los registros
  2. Si no puedes determinar algo, usa "UNKNOWN" y confidence bajo
  3. Sé conservador con las recomendaciones de escalado a humano
  4. Busca PATRONES entre múltiples registros
  5. El output debe ser JSON válido, sin texto adicional

## A.3.5 Flujo de Análisis

┌────────────────────────────────────────────────────────────────┐ │ 1. COLLECT │ │ - Recoger registros según estrategia de muestreo │ │ - Agrupar por trace_id para contexto completo │ │ - Cargar datos relacionados (input/output refs) │ └────────────────────────────────────────────────────────────────┘ │ ▼ ┌────────────────────────────────────────────────────────────────┐ │ 2. ENRICH │ │ - Añadir contexto del M-CONTRACT del módulo │ │ - Añadir historial reciente del mismo módulo │ │ - Añadir métricas de baseline │ └────────────────────────────────────────────────────────────────┘ │ ▼ ┌────────────────────────────────────────────────────────────────┐ │ 3. ANALYZE (LLM) │ │ - Enviar al LLM con prompt del sistema │ │ - Timeout: 60 segundos │ │ - Fallback: GPT-4o → Claude → Local-Summary │ └────────────────────────────────────────────────────────────────┘ │ ▼ ┌────────────────────────────────────────────────────────────────┐ │ 4. VALIDATE │ │ - Parsear JSON de respuesta │ │ - Validar schema │ │ - Verificar coherencia de findings │ └────────────────────────────────────────────────────────────────┘ │ ▼ ┌────────────────────────────────────────────────────────────────┐ │ 5. PERSIST │ │ - INSERT en AUDIT_RESULTS │ │ - UPDATE SYS_LOG.audit_status, audit_deep_ts │ │ - Registrar patrones detectados │ └────────────────────────────────────────────────────────────────┘ │ ▼ ┌────────────────────────────────────────────────────────────────┐ │ 6. ESCALATE │ │ - Si human_escalation_needed → notificar │ │ - Si pattern detectado → crear alerta │ │ - Si acción urgente → trigger workflow │ └────────────────────────────────────────────────────────────────┘


## A.3.6 Output de SENTINEL-DEEP

```json
{
  "sentinel_type": "DEEP",
  "version": "1.2",
  "analysis_id": "uuid-analysis",
  "trigger": "ESCALATION",
  "timestamp_start": "2025-12-01T11:00:00.000Z",
  "timestamp_end": "2025-12-01T11:00:12.350Z",
  "duration_ms": 12350,
  
  "model_used": {
    "provider": "openrouter",
    "model_id": "anthropic/claude-sonnet-4-20250514",
    "tokens_input": 4500,
    "tokens_output": 1200,
    "cost_units": 0.0089
  },
  
  "scope": {
    "records_queried": 25,
    "records_analyzed": 25,
    "trace_ids": ["uuid-1", "uuid-2", "..."]
  },
  
  "findings": [
    {
      "trace_id": "uuid-problema-1",
      "step_id": "uuid-step-1",
      "diagnosis": {
        "contract_compliant": false,
        "integrity_valid": true,
        "quality_credible": true,
        "issues": [
          "Campo 'coverage' ausente en response de OCR_CORE",
          "Schema output_v1 requiere coverage cuando confidence < 0.8"
        ]
      },
      "root_cause": {
        "category": "MODULE",
        "description": "OCR_CORE v1.0 no incluye campo coverage cuando la imagen tiene baja calidad. El módulo debería retornar coverage=0 en estos casos.",
        "is_pattern": true,
        "pattern_id": "PAT-2025-001",
        "related_traces": ["uuid-2", "uuid-5", "uuid-12"]
      },
      "recommendation": {
        "action": "Actualizar OCR_CORE para incluir coverage=0.0 cuando confidence < 0.5",
        "prevention": "Añadir validación de schema en Alfred antes de persistir",
        "urgency": "MEDIUM",
        "escalate_human": true,
        "escalate_reason": "Requiere cambio de código en módulo"
      },
      "confidence": 0.92
    }
  ],
  
  "patterns_detected": [
    {
      "pattern_id": "PAT-2025-001",
      "description": "OCR_CORE omite campo coverage en respuestas de baja confianza",
      "occurrences": 4,
      "first_seen": "2025-12-01T08:15:00.000Z",
      "affected_module": "OCR_CORE",
      "severity": "MEDIUM",
      "recommended_fix": "Patch en M-CONTRACT de OCR_CORE"
    }
  ],
  
  "contract_audit": {
    "total_checked": 25,
    "compliant": 21,
    "non_compliant": 4,
    "compliance_rate": 0.84,
    "common_violations": [
      {"field": "coverage", "count": 4},
      {"field": "tokens_output", "count": 1}
    ]
  },
  
  "summary": {
    "total_issues": 5,
    "critical": 0,
    "high": 1,
    "medium": 3,
    "low": 1,
    "human_escalation_needed": true,
    "patterns_found": 1,
    "new_patterns": 1
  },
  
  "actions_triggered": [
    {
      "type": "NOTIFICATION",
      "target": "admin@tzzr.pro",
      "template": "sentinel_escalation",
      "sent_at": "2025-12-01T11:00:15.000Z"
    }
  ],
  
  "next_scheduled": "2025-12-01T12:00:00.000Z"
}

A.4 Tabla AUDIT_RESULTS

CREATE TABLE AUDIT_RESULTS (
  -- ═══════════════════════════════════════════════════════════
  -- IDENTIFICACIÓN
  -- ═══════════════════════════════════════════════════════════
  id                    UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  sentinel_type         VARCHAR(10) NOT NULL,
  execution_id          UUID NOT NULL,
  timestamp             TIMESTAMPTZ DEFAULT NOW(),
  
  -- ═══════════════════════════════════════════════════════════
  -- TRIGGER Y SCOPE
  -- ═══════════════════════════════════════════════════════════
  trigger_type          VARCHAR(50),
  window_start          TIMESTAMPTZ,
  window_end            TIMESTAMPTZ,
  records_queried       INTEGER,
  records_processed     INTEGER,
  
  -- ═══════════════════════════════════════════════════════════
  -- EJECUCIÓN
  -- ═══════════════════════════════════════════════════════════
  duration_ms           INTEGER,
  model_used            VARCHAR(100),
  tokens_input          INTEGER,
  tokens_output         INTEGER,
  cost_units            DECIMAL(12,8),
  
  -- ═══════════════════════════════════════════════════════════
  -- RESULTADOS AGREGADOS
  -- ═══════════════════════════════════════════════════════════
  passed_count          INTEGER,
  warning_count         INTEGER,
  failure_count         INTEGER,
  pass_rate             DECIMAL(5,4),
  
  -- ═══════════════════════════════════════════════════════════
  -- DETALLES (JSONB)
  -- ═══════════════════════════════════════════════════════════
  findings              JSONB,
  patterns_detected     JSONB,
  by_severity           JSONB,
  by_rule               JSONB,
  by_module             JSONB,
  escalations           JSONB,
  
  -- ═══════════════════════════════════════════════════════════
  -- ESCALADO
  -- ═══════════════════════════════════════════════════════════
  human_escalation      BOOLEAN DEFAULT FALSE,
  escalation_notified   BOOLEAN DEFAULT FALSE,
  escalation_notified_at TIMESTAMPTZ,
  escalation_acknowledged BOOLEAN,
  escalation_acknowledged_by VARCHAR(100),
  escalation_resolved   BOOLEAN,
  resolution_notes      TEXT,
  resolution_timestamp  TIMESTAMPTZ,
  
  -- ═══════════════════════════════════════════════════════════
  -- REFERENCIAS
  -- ═══════════════════════════════════════════════════════════
  related_traces        UUID[],
  pattern_ids           VARCHAR(50)[],
  
  -- ═══════════════════════════════════════════════════════════
  -- CONSTRAINTS
  -- ═══════════════════════════════════════════════════════════
  CONSTRAINT valid_sentinel_type CHECK (
    sentinel_type IN ('LIGHT', 'DEEP')
  )
);

-- ═══════════════════════════════════════════════════════════════
-- ÍNDICES
-- ═══════════════════════════════════════════════════════════════
CREATE INDEX idx_audit_timestamp ON AUDIT_RESULTS(timestamp);
CREATE INDEX idx_audit_type ON AUDIT_RESULTS(sentinel_type);
CREATE INDEX idx_audit_escalation ON AUDIT_RESULTS(human_escalation, escalation_resolved) 
  WHERE human_escalation = TRUE;
CREATE INDEX idx_audit_patterns ON AUDIT_RESULTS USING GIN(pattern_ids);

A.5 Tabla PATTERNS (Detección de Patrones)

CREATE TABLE AUDIT_PATTERNS (
  -- ═══════════════════════════════════════════════════════════
  -- IDENTIFICACIÓN
  -- ═══════════════════════════════════════════════════════════
  id                    UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  pattern_id            VARCHAR(50) UNIQUE NOT NULL,
  
  -- ═══════════════════════════════════════════════════════════
  -- DESCRIPCIÓN
  -- ═══════════════════════════════════════════════════════════
  description           TEXT NOT NULL,
  category              VARCHAR(50),
  affected_module       VARCHAR(50),
  severity              VARCHAR(20),
  
  -- ═══════════════════════════════════════════════════════════
  -- ESTADÍSTICAS
  -- ═══════════════════════════════════════════════════════════
  first_seen            TIMESTAMPTZ NOT NULL,
  last_seen             TIMESTAMPTZ NOT NULL,
  occurrence_count      INTEGER DEFAULT 1,
  affected_traces       UUID[],
  
  -- ═══════════════════════════════════════════════════════════
  -- RESOLUCIÓN
  -- ═══════════════════════════════════════════════════════════
  status                VARCHAR(20) DEFAULT 'OPEN',
  recommended_fix       TEXT,
  fix_implemented       BOOLEAN DEFAULT FALSE,
  fix_implemented_at    TIMESTAMPTZ,
  fix_notes             TEXT,
  
  -- ═══════════════════════════════════════════════════════════
  -- METADATA
  -- ═══════════════════════════════════════════════════════════
  created_at            TIMESTAMPTZ DEFAULT NOW(),
  updated_at            TIMESTAMPTZ DEFAULT NOW(),
  created_by            VARCHAR(50) DEFAULT 'SENTINEL-DEEP',
  
  -- ═══════════════════════════════════════════════════════════
  -- CONSTRAINTS
  -- ═══════════════════════════════════════════════════════════
  CONSTRAINT valid_status CHECK (
    status IN ('OPEN', 'INVESTIGATING', 'FIXING', 'RESOLVED', 'WONT_FIX', 'DUPLICATE')
  ),
  CONSTRAINT valid_severity CHECK (
    severity IN ('LOW', 'MEDIUM', 'HIGH', 'CRITICAL')
  )
);

-- Índices
CREATE INDEX idx_patterns_status ON AUDIT_PATTERNS(status) WHERE status != 'RESOLVED';
CREATE INDEX idx_patterns_module ON AUDIT_PATTERNS(affected_module);
CREATE INDEX idx_patterns_severity ON AUDIT_PATTERNS(severity);

A.6 Integración con Alfred (n8n)

A.6.1 Workflow SENTINEL-LIGHT

┌─────────────────────────────────────────────────────────────────┐
│                  WORKFLOW: SENTINEL-LIGHT                       │
│                  Trigger: Schedule (*/5 * * * *)                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  [Schedule Trigger]                                             │
│        │                                                        │
│        ▼                                                        │
│  [NocoDB: Query SYS_LOG]                                        │
│  "audit_status = PENDING AND created > -10min"                  │
│        │                                                        │
│        ▼                                                        │
│  [Function: Apply Rules]                                        │
│  - Integrity rules                                              │
│  - Conformity rules                                             │
│  - Performance rules                                            │
│  - Security rules                                               │
│        │                                                        │
│        ├─────────────┬─────────────┐                            │
│        ▼             ▼             ▼                            │
│  [If: PASS]    [If: WARN]    [If: FAIL]                         │
│        │             │             │                            │
│        ▼             ▼             ▼                            │
│  [NocoDB:       [NocoDB:      [NocoDB:                          │
│   Update         Update        Update                           │
│   LIGHT_PASS]    LIGHT_WARN]   LIGHT_FAIL]                      │
│        │             │             │                            │
│        │             │             ▼                            │
│        │             │      [Queue for DEEP]                    │
│        │             │             │                            │
│        └─────────────┴─────────────┘                            │
│                      │                                          │
│                      ▼                                          │
│  [NocoDB: Insert AUDIT_RESULTS]                                 │
│        │                                                        │
│        ▼                                                        │
│  [If: Critical Alert]                                           │
│        │                                                        │
│        ▼                                                        │
│  [Send Notification]                                            │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

A.6.2 Workflow SENTINEL-DEEP

┌─────────────────────────────────────────────────────────────────┐
│                  WORKFLOW: SENTINEL-DEEP                        │
│                  Trigger: Schedule (0 * * * *) + Webhook        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  [Schedule/Webhook Trigger]                                     │
│        │                                                        │
│        ▼                                                        │
│  [Function: Select Candidates]                                  │
│  - Escalations from LIGHT                                       │
│  - Errors not analyzed                                          │
│  - Random sampling                                              │
│  - Low confidence records                                       │
│        │                                                        │
│        ▼                                                        │
│  [NocoDB: Fetch Full Records + Context]                         │
│        │                                                        │
│        ▼                                                        │
│  [Function: Enrich with M-CONTRACT]                             │
│        │                                                        │
│        ▼                                                        │
│  [OpenRouter: Claude/GPT-4]                                     │
│  - System prompt: SENTINEL-DEEP                                 │
│  - User prompt: Records JSON                                    │
│  - Response: Analysis JSON                                      │
│        │                                                        │
│        ▼                                                        │
│  [Function: Validate Response]                                  │
│        │                                                        │
│        ├─────────────┬─────────────┐                            │
│        ▼             ▼             ▼                            │
│  [NocoDB:       [NocoDB:      [NocoDB:                          │
│   Update         Insert        Upsert                           │
│   SYS_LOG]       AUDIT_        PATTERNS]                        │
│                  RESULTS]                                       │
│        │             │             │                            │
│        └─────────────┴─────────────┘                            │
│                      │                                          │
│                      ▼                                          │
│  [If: Human Escalation]                                         │
│        │                                                        │
│        ▼                                                        │
│  [Send Detailed Notification]                                   │
│  - Email with findings                                          │
│  - Link to dashboard                                            │
│  - Recommended actions                                          │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

A.7 Métricas y Dashboard

A.7.1 KPIs de SENTINEL

Métrica Fórmula Target Alerta
Pass Rate (LIGHT) passed / total > 98% < 95%
Error Rate errors / total < 2% > 5%
Escalation Rate escalated / total < 5% > 10%
MTTR (Mean Time To Resolve) avg(resolution_time) < 4h > 8h
Pattern Detection Rate patterns_new / week informativo > 5/semana
False Positive Rate false_positives / escalations < 10% > 20%

A.7.2 Queries para Dashboard

-- Pass rate últimas 24h
SELECT 
  DATE_TRUNC('hour', timestamp) as hour,
  passed_count::float / NULLIF(records_processed, 0) as pass_rate
FROM AUDIT_RESULTS
WHERE sentinel_type = 'LIGHT'
AND timestamp > NOW() - INTERVAL '24 hours'
ORDER BY hour;

-- Top 5 reglas más violadas
SELECT 
  rule_key,
  SUM((rule_data->>'failed')::int) as total_failures
FROM AUDIT_RESULTS,
     jsonb_each(by_rule) as rules(rule_key, rule_data)
WHERE timestamp > NOW() - INTERVAL '7 days'
GROUP BY rule_key
ORDER BY total_failures DESC
LIMIT 5;

-- Patrones abiertos por severidad
SELECT severity, COUNT(*) 
FROM AUDIT_PATTERNS 
WHERE status = 'OPEN'
GROUP BY severity;

-- Escalaciones pendientes
SELECT * FROM AUDIT_RESULTS
WHERE human_escalation = TRUE
AND escalation_resolved = FALSE
ORDER BY timestamp DESC;

A.8 Checklist de Implementación SENTINEL

SENTINEL-LIGHT:

  • Crear workflow en n8n con trigger cada 5 min
  • Implementar todas las reglas I-, C-, P-, S-
  • Configurar umbrales por módulo
  • Crear notificaciones para alertas CRITICAL
  • Implementar actualización de SYS_LOG
  • Crear inserts en AUDIT_RESULTS

SENTINEL-DEEP:

  • Crear workflow con trigger horario + webhook
  • Implementar estrategia de muestreo
  • Configurar integración con OpenRouter (Claude/GPT-4)
  • Implementar validación de respuesta JSON
  • Crear sistema de detección de patrones
  • Implementar notificaciones con findings detallados

Tablas:

  • Crear tabla AUDIT_RESULTS con índices
  • Crear tabla AUDIT_PATTERNS con índices
  • Configurar políticas de retención

Monitoreo:

  • Dashboard con KPIs
  • Alertas por Slack/Email
  • Reportes semanales automáticos

Fin del Documento 07a — SENTINEL

Referencia: S-CONTRACT.md v1.2