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
- Integridad: Verificar que los datos no han sido alterados.
- Conformidad: Validar cumplimiento del contrato común.
- Calidad: Detectar degradación en los módulos IA.
- Anomalías: Identificar patrones sospechosos o errores sistemáticos.
- 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
- NUNCA inventes datos que no estén en los registros
- Si no puedes determinar algo, usa "UNKNOWN" y confidence bajo
- Sé conservador con las recomendaciones de escalado a humano
- Busca PATRONES entre múltiples registros
- 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