Files
system-docs/v4-archive/grace/docs/06_GRACE_CAPA_COGNITIVA.md
2025-12-24 17:28:34 +00:00

63 KiB

06. GRACE — CAPA COGNITIVA

Manual de Arquitectura Técnica v5.0
Sistema SFE/HST Enterprise


TL;DR — GRACE en 30 segundos

Alfred (n8n) = El cuerpo. Local, determinista, decide flujos.
GRACE (18 módulos) = El cerebro. Transforma datos, no decide.

Alfred envía imagen → GRACE extrae texto → Alfred guarda en The Vault.

GRACE es self-hosted en el servidor del usuario. Los logs quedan locales.
Puede llamar a APIs externas (GPU serverless, LLMs premium) pero son opcionales y stateless.

"GRACE transforma, Alfred decide."


Índice

  1. Introducción
  2. Modelo de Despliegue
  3. Contrato Común v1.2
  4. Envelope Universal
  5. Sistema de Logging
  6. Los 18 Módulos
  7. Arquitectura de Providers
  8. Fallback Chains
  9. Pipelines Oficiales
  10. Implementación de Referencia

1. Introducción

1.1 ¿Qué es GRACE?

GRACE (antes Jarvis) es la capa cognitiva determinista del sistema: un conjunto de 18 microservicios de IA desacoplados. Diligente, amable, no comete errores. Siempre igual.

┌─────────────────────────────────────────────────────────────────┐
│                          GRACE                                  │
│                                                                 │
│   • NO es chatbot                                               │
│   • NO guarda estado                                            │
│   • NO toma decisiones de flujo                                │
│   • Transforma datos según request                             │
│   • Intercambiable: sustituir modelo sin romper sistema        │
│                                                                 │
│   "GRACE transforma, Alfred decide."                           │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

1.2 Principios de GRACE

Principio Descripción
Stateless Nunca guarda estado entre llamadas
Determinista Misma entrada → siempre misma salida
Intercambiable Sustituir modelo sin romper sistema
Trazable Toda ejecución registrada vía trace_id
No persiste datos Archivos solo en Hostinger/Vault

1.3 Arquitectura Híbrida de Dos Tiers

                    ┌──────────────────┐
                    │   ALFRED (n8n)   │
                    │   Orquestador    │
                    └────────┬─────────┘
                             │
              ┌──────────────┼──────────────┐
              │              │              │
              ▼              ▼              ▼
       ┌──────────┐   ┌──────────┐   ┌──────────┐
       │  TIER 1  │   │  TIER 1  │   │  TIER 2  │
       │ AUTOALOJ.│   │ AUTOALOJ.│   │   APIs   │
       │  Ligero  │   │  Pesado  │   │ Premium  │
       │  (CPU)   │   │  (GPU)   │   │(Fallback)│
       └──────────┘   └──────────┘   └──────────┘
       
       Regex/Rules    Whisper Large   Claude Sonnet 4
       Hashing        SDXL/Flux       GPT-4o Vision
       Local Hash     InsightFace     Gemini 2.5 Pro

1.4 ¿Por qué GRACE?

El nombre GRACE evoca las cualidades del sistema:

  • Generativa — Produce outputs estructurados
  • Reliable — Determinista y trazable
  • Agnostic — Independiente del provider
  • Cognitive — Capa de inteligencia
  • Efficient — Optimiza costo/calidad

2. Modelo de Despliegue

2.1 Arquitectura Self-Hosted

GRACE se despliega en el servidor del usuario (personal o corporativo), no como servicio centralizado. Esto garantiza:

  • Soberanía de datos: Los logs y procesamientos quedan bajo control del usuario
  • Multi-tenancy local: Una instancia de GRACE puede servir a múltiples usuarios/organizaciones
  • Flexibilidad: Posibilidad de peticiones externas si se requiere, pero no como dependencia
┌─────────────────────────────────────────────────────────────────┐
│              SERVIDOR DEL USUARIO (VPS/On-Premise)              │
│              Hostinger KVM / AWS / Azure / Bare Metal           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                      GRACE                               │   │
│  │                 (Container Docker)                       │   │
│  │                                                          │   │
│  │   ┌─────────┐  ┌─────────┐  ┌─────────┐               │   │
│  │   │ TIER 1  │  │ TIER 1  │  │ TIER 2  │               │   │
│  │   │ LOCAL   │  │  GPU    │  │ PREMIUM │               │   │
│  │   │ (CPU)   │  │ Server- │  │ (APIs)  │               │   │
│  │   │         │  │  less   │  │         │               │   │
│  │   └────┬────┘  └────┬────┘  └────┬────┘               │   │
│  │        │            │            │                      │   │
│  │        └──────┬─────┴────────────┘                      │   │
│  │               ▼                                          │   │
│  │         Buffer Interno ──► Flush                        │   │
│  │                              │                          │   │
│  └──────────────────────────────│──────────────────────────┘   │
│                                 │                               │
│                                 ▼                               │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │              SYS_LOG (PostgreSQL/NocoDB)                 │  │
│  │         Base de datos LOCAL en servidor usuario          │  │
│  │         Soporta múltiples usuarios/organizaciones        │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                 │                               │
│         ┌───────────────────────┼───────────────────────┐      │
│         ▼                       ▼                       ▼      │
│  ┌─────────────┐        ┌─────────────┐        ┌─────────────┐ │
│  │  SENTINEL   │        │  SENTINEL   │        │   NOTARIO   │ │
│  │   LIGHT     │        │    DEEP     │        │ (Blockchain)│ │
│  │ (cron 5min) │        │ (cron 1h)   │        │  (diario)   │ │
│  └─────────────┘        └─────────────┘        └─────────────┘ │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
                                 │
                                 │ Solo llamadas stateless
                                 │ (TIER 1 GPU / TIER 2 Premium)
                                 ▼
┌─────────────────────────────────────────────────────────────────┐
│                    SERVICIOS EXTERNOS                           │
│         (Sin retención de datos, llamadas efímeras)             │
├─────────────────────────────────────────────────────────────────┤
│  TIER 1 GPU Serverless    │  TIER 2 APIs Premium               │
│  • RunPod                 │  • Anthropic (Claude)              │
│  • Modal                  │  • OpenAI (GPT-4o)                 │
│  • Replicate              │  • Google (Gemini)                 │
│                           │  • ElevenLabs, Deepgram, etc.      │
└─────────────────────────────────────────────────────────────────┘

2.2 Qué Vive Dónde

Componente Ubicación Notas
GRACE (API) Servidor usuario Container Docker, stateless
SYS_LOG Servidor usuario PostgreSQL/NocoDB local
SENTINEL Servidor usuario Procesos cron o workflows n8n
NOTARIO Servidor usuario Collector local + escritura blockchain
Archivos Servidor usuario Hostinger/Vault local
TIER 1 LOCAL Servidor usuario Tesseract, embeddings, hashing
TIER 1 GPU Externo (opcional) RunPod/Modal, llamadas stateless
TIER 2 Premium Externo (opcional) APIs comerciales, sin retención

2.3 Flujo de Datos y Privacidad

┌─────────────────────────────────────────────────────────────────┐
│                    FLUJO DE PRIVACIDAD                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. DATOS SENSIBLES (PII, documentos, audio)                   │
│     └──► Nunca salen del servidor del usuario                  │
│     └──► Procesados por TIER 1 LOCAL cuando es posible         │
│     └──► Si requieren TIER 2: se envía solo lo necesario       │
│                                                                 │
│  2. LLAMADAS EXTERNAS (TIER 1 GPU / TIER 2)                    │
│     └──► Stateless: no se guarda contexto en el proveedor      │
│     └──► Efímeras: payload entra, resultado sale, nada persiste│
│     └──► Opcionales: se pueden deshabilitar completamente      │
│                                                                 │
│  3. LOGS Y AUDITORÍA                                           │
│     └──► 100% en servidor del usuario                          │
│     └──► SENTINEL corre localmente                             │
│     └──► Usuario tiene control total de sus datos              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

2.4 Configuración Multi-Usuario

Una instancia de GRACE puede servir a múltiples usuarios/organizaciones:

┌─────────────────────────────────────────────────────────────────┐
│                    MULTI-TENANCY LOCAL                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  GRACE (única instancia)                                        │
│       │                                                         │
│       ├──► Usuario A (player_id: uuid-A)                       │
│       │    └── Sus logs en SYS_LOG con player_id filtrado      │
│       │    └── Sus archivos en /vault/A/                       │
│       │                                                         │
│       ├──► Usuario B (player_id: uuid-B)                       │
│       │    └── Sus logs en SYS_LOG con player_id filtrado      │
│       │    └── Sus archivos en /vault/B/                       │
│       │                                                         │
│       └──► Organización C (bandera_id: uuid-C)                 │
│            └── Múltiples players bajo misma bandera            │
│            └── Políticas de acceso por bandera                 │
│                                                                 │
│  Segregación por: player_id + bandera_id en cada request       │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

2.5 Modos de Operación

Modo TIER 1 LOCAL TIER 1 GPU TIER 2 Uso
Offline Máxima privacidad, funcionalidad básica
Híbrido Balance privacidad/capacidad
Completo Máxima capacidad, fallbacks completos

Configuración en settings:

# Modo offline (sin llamadas externas)
TIER_1_GPU_ENABLED = False
TIER_2_PREMIUM_ENABLED = False

# Modo híbrido (solo GPU serverless)
TIER_1_GPU_ENABLED = True
TIER_2_PREMIUM_ENABLED = False

# Modo completo (todos los tiers)
TIER_1_GPU_ENABLED = True
TIER_2_PREMIUM_ENABLED = True

3. Contrato Común v1.2

2.1 Propósito

El Contrato Común es la interfaz universal que garantiza:

  • Intercambiabilidad de módulos (locales ↔ remotos)
  • Trazabilidad completa de cada operación
  • Auditoría automatizada en tiempo real
  • Tolerancia a fallos con degradación elegante
┌─────────────────────────────────────────────────────────────────┐
│                    PRINCIPIO FUNDAMENTAL                        │
│                                                                 │
│   "Un módulo que no cumple el contrato, no existe para Alfred" │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

2.2 Decisión de Enrutamiento

Alfred selecciona el provider según:

Factor Decisión
Complejidad de tarea Simple → TIER 1 Local, Compleja → TIER 2 Premium
Latencia requerida Crítica → TIER 1, Tolerante → TIER 2
Costo computacional Bajo → TIER 1, Alto → TIER 1 GPU Serverless
Disponibilidad Fallo TIER 1 → Fallback TIER 2
Volumen Alto volumen → TIER 1 (batch), Puntual → Cualquiera
Calidad requerida Máxima → TIER 2 Premium

2.3 Perfiles de Request

Perfil Campos Incluidos Uso
MINIMAL envelope, routing, payload Debug rápido
STANDARD + context, storage Producción normal
FULL + security, metadata Auditoría completa

4. Envelope Universal

3.1 REQUEST

{
  "contract_version": "1.2",
  "profile": "FULL",
  
  "envelope": {
    "trace_id": "uuid-v4-global",
    "parent_trace_id": "uuid-v4-padre|null",
    "step_id": "uuid-v4-paso-actual",
    "step_index": 1,
    "total_steps": 5,
    "idempotency_key": "sha256-del-input",
    "timestamp_init": "2025-12-01T10:30:00.000Z",
    "ttl_ms": 30000
  },
  
  "routing": {
    "module": "OCR_CORE",
    "version": "1.0",
    "tier_preference": ["TIER_1_GPU", "TIER_1_LOCAL", "TIER_2_PREMIUM"],
    "provider_preference": ["runpod", "modal", "google_vision"],
    "fallback_chain": ["OCR_LOCAL", "OCR_GOT", "OCR_GEMINI"],
    "max_fallback_level": 2
  },
  
  "context": {
    "lang": "es",
    "mode": "strict",
    "pii_filter": true,
    "bandera_id": "uuid-jurisdiccion",
    "player_id": "uuid-actor",
    "method_hash": "sha256-metodo-activo"
  },
  
  "payload": {
    "type": "text|image|audio|document|structured",
    "encoding": "utf-8|base64|url",
    "content": "...",
    "content_hash": "sha256-del-contenido",
    "schema_expected": "nombre-del-schema-salida"
  },
  
  "storage": {
    "input_location": "internal|external",
    "input_ref": "hostinger://path|s3://bucket/key",
    "output_location": "internal|external",
    "output_ref": "hostinger://path",
    "persist_intermediate": true
  },
  
  "security": {
    "encryption_profile": "NONE|E2E_BASIC|E2E_STRICT",
    "data_sensitivity": "LOW|MEDIUM|HIGH|SECRET",
    "pii_detected": false
  }
}

3.2 Campos del Envelope

Campo Tipo Descripción
trace_id UUID v4 Identificador único de la ejecución completa
parent_trace_id UUID v4 Si es sub-proceso, referencia al padre
step_id UUID v4 Identificador único de este paso específico
step_index integer Posición en la cadena de procesamiento
total_steps integer Total de pasos estimados
idempotency_key SHA256 Hash del contenido para evitar reprocesamiento
timestamp_init ISO8601 Momento de creación de la petición
ttl_ms integer Tiempo máximo de vida en milisegundos

3.3 RESPONSE

{
  "contract_version": "1.2",
  
  "envelope": {
    "trace_id": "uuid-v4-global",
    "step_id": "uuid-v4-paso-actual",
    "timestamp_init": "2025-12-01T10:30:00.000Z",
    "timestamp_end": "2025-12-01T10:30:00.450Z"
  },
  
  "status": {
    "code": "SUCCESS|PARTIAL|ERROR|TIMEOUT|FALLBACK",
    "fallback_level_used": 0,
    "tier_used": "TIER_1_GPU",
    "provider_used": "runpod",
    "module_instance": "OCR_GOT_RUNPOD_V1"
  },
  
  "result": {
    "schema": "nombre-del-schema",
    "data": {
      "text": "Contenido extraído...",
      "blocks": [...],
      "confidence": 0.98
    }
  },
  
  "quality": {
    "confidence": 0.985,
    "coverage": 1.0,
    "tokens_used": 1250,
    "validation_passed": true
  },
  
  "metadata": {
    "model_id": "got-ocr-2.0",
    "model_version": "2024-10",
    "processing_ms": 450,
    "retries": 0,
    "cost_units": 0.0012
  },
  
  "storage": {
    "output_persisted": true,
    "output_ref": "hostinger://processed/2025/12/01/uuid.json",
    "output_hash": "sha256..."
  },
  
  "errors": [],
  "warnings": []
}

3.4 Códigos de Status

Código Significado Acción Alfred
SUCCESS Ejecución completa y válida Continuar flujo
PARTIAL Resultado incompleto pero usable Evaluar y decidir
ERROR Fallo no recuperable Activar fallback o abortar
TIMEOUT Excedió TTL Activar fallback
FALLBACK Éxito usando módulo alternativo Log + continuar

5. Sistema de Logging

4.1 Filosofía

┌─────────────────────────────────────────────────────────────────┐
│                    PRINCIPIO DE LOGGING                         │
│                                                                 │
│   "Si no está en el log, no ocurrió. Si ocurrió, está en log." │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

4.2 Arquitectura de Dos Capas

┌─────────────────┐
│  LOG INTERNO    │ → Buffer local en GRACE, alta velocidad
│  (transitorio)  │ → Mantiene últimos N registros en memoria
└────────┬────────┘
         │ flush cada N segundos o N registros
         ▼
┌─────────────────┐
│  LOG EXTERNO    │ → PostgreSQL/NocoDB (FUENTE DE VERDAD)
│  (permanente)   │ → Tabla SYS_LOG
└────────┬────────┘
         │
┌────────┴────────┐
│                 │
▼                 ▼
┌─────────────┐  ┌─────────────┐
│  SENTINEL   │  │  SENTINEL   │
│    LIGHT    │  │    DEEP     │
│             │  │             │
│ • Cada 5min │  │ • Cada 1h   │
│ • 100% regs │  │ • ~5% + err │
│ • Reglas ML │  │ • LLM pesado│
│ • Costo min │  │ • Análisis  │
└─────────────┘  └─────────────┘

4.3 Estructura de SYS_LOG

CREATE TABLE SYS_LOG (
  -- Identificación
  id                    UUID PRIMARY KEY,
  trace_id              UUID NOT NULL,
  parent_trace_id       UUID,
  step_id               UUID NOT NULL,
  idempotency_key       CHAR(64),
  
  -- Secuencia
  step_index            INTEGER NOT NULL,
  step_type             VARCHAR(50) NOT NULL,
  profile               VARCHAR(10) DEFAULT 'FULL',
  
  -- Batch
  batch_id              UUID,
  batch_item_index      INTEGER,
  batch_items_total     INTEGER,
  
  -- Temporalidad
  timestamp_created     TIMESTAMPTZ DEFAULT NOW(),
  timestamp_started     TIMESTAMPTZ,
  timestamp_completed   TIMESTAMPTZ,
  duration_ms           INTEGER,
  
  -- Módulo y Provider
  module_name           VARCHAR(100) NOT NULL,
  module_version        VARCHAR(20),
  tier_used             VARCHAR(20),
  provider_requested    VARCHAR(50),
  provider_used         VARCHAR(50),
  fallback_level        INTEGER DEFAULT 0,
  model_id              VARCHAR(100),
  
  -- Estado
  status_code           VARCHAR(20) NOT NULL,
  error_code            VARCHAR(50),
  error_message         TEXT,
  
  -- Payload
  input_hash            CHAR(64),
  input_ref             VARCHAR(500),
  input_type            VARCHAR(50),
  output_hash           CHAR(64),
  output_ref            VARCHAR(500),
  
  -- Calidad
  confidence            DECIMAL(5,4),
  coverage              DECIMAL(5,4),
  tokens_input          INTEGER,
  tokens_output         INTEGER,
  validation_passed     BOOLEAN,
  
  -- Costo
  cost_units            DECIMAL(10,6),
  
  -- Contexto
  bandera_id            UUID,
  player_id             UUID,
  method_hash           CHAR(64),
  human_readable        TEXT,
  
  -- Seguridad
  encryption_profile    VARCHAR(20),
  data_sensitivity      VARCHAR(20),
  pii_detected          BOOLEAN DEFAULT FALSE,
  
  -- Auditoría
  audit_status          VARCHAR(20) DEFAULT 'PENDING',
  audit_light_ts        TIMESTAMPTZ,
  audit_deep_ts         TIMESTAMPTZ,
  
  -- Blockchain
  blockchain_pending    BOOLEAN DEFAULT TRUE,
  blockchain_tx_ref     VARCHAR(100),
  notario_batch_id      UUID
);

-- Índices críticos
CREATE INDEX idx_syslog_trace ON SYS_LOG(trace_id);
CREATE INDEX idx_syslog_module ON SYS_LOG(module_name, timestamp_created);
CREATE INDEX idx_syslog_status ON SYS_LOG(status_code, timestamp_created);
CREATE INDEX idx_syslog_audit ON SYS_LOG(audit_status);

4.4 Configuración del Logger Externo

# app/core/logging_external.py

class ExternalLoggerConfig:
    """Configuración del sistema de logging externo."""
    
    # Buffer local
    BUFFER_SIZE: int = 100          # Máximo registros en memoria
    FLUSH_INTERVAL_SEC: int = 5     # Flush cada N segundos
    
    # Conexión externa
    EXTERNAL_URL: str               # URL de NocoDB/PostgreSQL
    EXTERNAL_TABLE: str = "SYS_LOG"
    BATCH_INSERT_SIZE: int = 50     # Registros por inserción
    
    # Retry
    MAX_RETRIES: int = 3
    RETRY_DELAY_MS: int = 1000
    
    # Fallback
    FALLBACK_FILE: str = "/var/log/grace/fallback.jsonl"

6. Los 18 Módulos

5.1 Familia: VISIÓN

Módulo 1: IMAGE_PROCESSOR

nombre: Procesado de Imagen
función: Limpieza, resize, crop, denoise
tier_primario: TIER_1_LOCAL
fallback: TIER_1_GPU
input: image (url/base64)
output: image_url, dimensions, format
pii: false
providers:
  tier_1_local: [pillow, opencv]
  tier_1_gpu: [runpod_sdxl_preprocessor]

Módulo 2: PDF_SCANNER

nombre: PDF/Escáner
función: Recorte automático, deskew, contraste
tier_primario: TIER_1_LOCAL
fallback: TIER_1_GPU
input: image/pdf
output: cleaned_image_url
pii: false
providers:
  tier_1_local: [pypdf, pdf2image]
  tier_1_gpu: [runpod_doctr]

Módulo 3: OCR_CORE

nombre: OCR
función: Lectura de texto
modos: fast, strict
tier_primario: TIER_1_GPU
fallback: TIER_2_PREMIUM
input: image
output: text, blocks[], confidence
pii: puede_contener
providers:
  tier_1_local: [tesseract]
  tier_1_gpu: [runpod_got_ocr, modal_qwen_vl]
  tier_2_premium: [google_vision, gemini_2_5_pro]

5.2 Familia: VOZ

Módulo 4: ASR (Speech-to-Text)

nombre: Transcripción de Audio
función: Audio a texto
modos: fast, accuracy
tier_primario: TIER_1_GPU
fallback: TIER_2_PREMIUM
input: audio (url/base64)
output: text, segments[], language
pii: true (voz)
providers:
  tier_1_local: [whisper_tiny, whisper_base]
  tier_1_gpu: [runpod_faster_whisper_large_v3, groq_whisper]
  tier_2_premium: [deepgram_nova_3, openai_whisper]
notas: |
  Faster Whisper es la implementación principal (CTranslate2).
  2-4x más rápido que Whisper original, mismo modelo large-v3.
  Soporta diarización y timestamps a nivel de palabra.

Módulo 5: TTS (Text-to-Speech)

nombre: Síntesis de Voz
función: Texto a audio
voces: neutral_f, neutral_m, corporate, soft
tier_primario: TIER_1_GPU
fallback: TIER_2_PREMIUM
input: text
output: audio_url, duration_ms
pii: true (voz generada)
providers:
  tier_1_gpu: [runpod_xtts_v2, modal_bark]
  tier_2_premium: [elevenlabs, openai_tts]

5.3 Familia: IDENTIDAD

Módulo 6: FACE_VECTOR

nombre: Vectores Faciales
función: Extracción de vector facial normalizado
tier_primario: TIER_1_GPU
input: image (rostro)
output: vector[512], quality_score
pii: true (biométrico)
ubicacion_output: VAULT (no SFE)
providers:
  tier_1_gpu: [runpod_insightface, modal_arcface]
  tier_2_premium: [aws_rekognition]

Módulo 7: ID_CONSOLIDATION

nombre: Consolidación de Identidad
función: Fusión de múltiples vectores, elimina outliers
tier_primario: TIER_1_LOCAL
input: vectors[]
output: consolidated_vector, confidence
pii: true
providers:
  tier_1_local: [numpy_consolidator]

Módulo 8: AVATAR_GEN

nombre: Generador de Avatares
función: Genera avatar neutral 512px desde vector
tier_primario: TIER_1_GPU
input: vector facial o imagen
output: avatar_url
pii: false (avatar sintético)
providers:
  tier_1_gpu: [runpod_sdxl, modal_flux, replicate_flux]
  tier_2_premium: [dalle_3]

5.4 Familia: NLP

Módulo 9: SUMMARIZER

nombre: Resumen Automático
función: Resume texto
modos: simple, structured
output_estructurado:
  - objetivos
  - hallazgos
  - acuerdos
  - riesgos
tier_primario: TIER_2_PREMIUM
input: text
output: summary | structured_summary
pii: puede_contener
providers:
  tier_1_local: [local_llama_8b]
  tier_2_premium: [claude_sonnet_4, gpt_4o]

Módulo 10: CLASSIFIER

nombre: Clasificación Automática
función: Clasifica documentos por tema/tipo
tier_primario: TIER_1_LOCAL
fallback: TIER_2_PREMIUM
input: text | document
output: category, confidence, tags[]
pii: false
providers:
  tier_1_local: [embeddings_classifier, rules_classifier]
  tier_2_premium: [claude_sonnet_4, gpt_4o]

Módulo 11: TASK_DETECTOR

nombre: Detección de Tareas
función: Extrae acciones de texto
tier_primario: TIER_2_PREMIUM
input: text
output: tasks[]
  - action
  - responsible
  - due_date
  - dependencies
pii: puede_contener (nombres)
providers:
  tier_1_local: [local_llama_8b]
  tier_2_premium: [claude_sonnet_4, gpt_4o]

5.5 Familia: SEMÁNTICA

Módulo 12: EMBEDDINGS

nombre: Embeddings
función: Texto a vectores semánticos
tier_primario: TIER_1_LOCAL
fallback: TIER_2_PREMIUM
input: text
output: vector[1536], model_id
pii: false
providers:
  tier_1_local: [sentence_transformers, bge_m3]
  tier_1_gpu: [runpod_bge_large]
  tier_2_premium: [voyage_3_large, openai_ada_3]

Módulo 13: SIMILARITY

nombre: Similaridad
función: Compara vectores
métricas: cosine, dot, euclidean
tier_primario: TIER_1_LOCAL
input: vector_a, vector_b
output: score, metric_used
pii: false
providers:
  tier_1_local: [numpy_similarity, faiss]

5.6 Familia: ESTRUCTURACIÓN

Módulo 14: FIELD_EXTRACTOR

nombre: Extracción de Campos
función: Extrae datos estructurados
campos_típicos:
  - importe
  - fecha
  - proveedor
  - lineas[]
  - cif
tier_primario: TIER_2_PREMIUM
input: text | document
output: extracted_fields{}
pii: puede_contener
providers:
  tier_1_local: [regex_extractor, local_llama_8b]
  tier_2_premium: [claude_sonnet_4, gpt_4o, gemini_2_5_pro]

Módulo 15: HASH_SIGNER

nombre: Hash/Firma
función: Genera SHA256/SHA512/BLAKE2B estable
tier_primario: TIER_1_LOCAL
input: any
output: hash, algorithm, timestamp
pii: false
providers:
  tier_1_local: [hashlib_python]

Módulo 16: INPUT_TRANSLATOR

nombre: Traductor de Entrada
función: Normaliza enums y payloads
tier_primario: TIER_1_LOCAL
input: raw_payload
output: normalized_payload
pii: false
providers:
  tier_1_local: [json_transformer]

Módulo 17: OUTPUT_TRANSLATOR

nombre: Traductor de Salida
función: Convierte outputs a formato legacy
tier_primario: TIER_1_LOCAL
input: standard_output
output: legacy_format
pii: false
providers:
  tier_1_local: [json_transformer]

Módulo 18: LANG_NORMALIZER

nombre: Normalización de Lenguaje
función: Detecta idioma y confianza
tier_primario: TIER_1_LOCAL
input: text
output: language_code, confidence, script
pii: false
providers:
  tier_1_local: [langdetect, lingua]
  tier_2_premium: [google_translate_detect]

7. Arquitectura de Providers

6.1 Definición de Tiers

┌─────────────────────────────────────────────────────────────────┐
│                    ARQUITECTURA DE PROVIDERS                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  TIER 1: AUTOALOJADOS                                           │
│  ─────────────────────                                          │
│                                                                 │
│  ┌─────────────────┐  ┌─────────────────┐                       │
│  │  TIER 1 LOCAL   │  │  TIER 1 GPU     │                       │
│  │                 │  │  (Serverless)   │                       │
│  │  • CPU only     │  │                 │                       │
│  │  • Latencia min │  │  • GPU on-demand│                       │
│  │  • Costo fijo   │  │  • Pay-per-use  │                       │
│  │  • Siempre on   │  │  • Auto-scale   │                       │
│  │                 │  │                 │                       │
│  │  Hashing        │  │  Whisper Large  │                       │
│  │  Regex          │  │  SDXL/Flux      │                       │
│  │  Embeddings     │  │  InsightFace    │                       │
│  │  LangDetect     │  │  GOT-OCR        │                       │
│  └─────────────────┘  └─────────────────┘                       │
│                                                                 │
│  Proveedores GPU Serverless:                                    │
│  • RunPod (principal)                                           │
│  • Modal (alternativo)                                          │
│  • Replicate (fallback)                                         │
│                                                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  TIER 2: APIs PREMIUM (Fallback/Calidad Máxima)                 │
│  ───────────────────────────────────────────────                │
│                                                                 │
│  ┌─────────────────────────────────────────────┐                │
│  │                                             │                │
│  │  NLP Complejo        │  Visión              │                │
│  │  • Claude Sonnet 4   │  • GPT-4o Vision     │                │
│  │  • GPT-4o            │  • Gemini 2.5 Pro    │                │
│  │                      │                      │                │
│  │  Voz                 │  Embeddings          │                │
│  │  • ElevenLabs TTS    │  • Voyage-3-large    │                │
│  │  • Deepgram Nova-3   │  • OpenAI Ada-3      │                │
│  │                      │                      │                │
│  └─────────────────────────────────────────────┘                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

6.2 Tabla de Providers por Módulo

Módulo TIER 1 Local TIER 1 GPU TIER 2 Premium
IMAGE_PROCESSOR Pillow, OpenCV RunPod SDXL -
PDF_SCANNER PyPDF, pdf2image RunPod DocTR -
OCR_CORE Tesseract RunPod GOT-OCR, Modal Qwen-VL Google Vision, Gemini 2.5
ASR Whisper tiny/base RunPod Faster Whisper Large V3, Groq Deepgram Nova-3, OpenAI
TTS - RunPod XTTS-v2, Modal Bark ElevenLabs
FACE_VECTOR - RunPod InsightFace AWS Rekognition
ID_CONSOLIDATION NumPy - -
AVATAR_GEN - RunPod SDXL, Modal Flux DALL-E 3
SUMMARIZER LLaMA 8B local - Claude Sonnet 4, GPT-4o
CLASSIFIER Embeddings + Rules - Claude Sonnet 4
TASK_DETECTOR LLaMA 8B local - Claude Sonnet 4, GPT-4o
EMBEDDINGS Sentence-Transformers RunPod BGE-Large Voyage-3-large
SIMILARITY NumPy, FAISS - -
FIELD_EXTRACTOR Regex - Claude Sonnet 4, Gemini 2.5
HASH_SIGNER hashlib - -
INPUT_TRANSLATOR JSON transformer - -
OUTPUT_TRANSLATOR JSON transformer - -
LANG_NORMALIZER langdetect, lingua - Google Translate

6.3 Configuración de Provider

# app/core/providers.py

from enum import Enum
from pydantic import BaseModel

class Tier(str, Enum):
    TIER_1_LOCAL = "tier_1_local"
    TIER_1_GPU = "tier_1_gpu"
    TIER_2_PREMIUM = "tier_2_premium"

class ProviderConfig(BaseModel):
    """Configuración de un provider específico."""
    name: str
    tier: Tier
    endpoint: str | None = None
    api_key_env: str | None = None
    timeout_ms: int = 30000
    max_retries: int = 3
    cost_per_unit: float = 0.0
    
class ModuleProviders(BaseModel):
    """Providers disponibles para un módulo."""
    module: str
    primary_tier: Tier
    fallback_order: list[str]
    providers: dict[str, ProviderConfig]

# Ejemplo: OCR_CORE
OCR_CORE_PROVIDERS = ModuleProviders(
    module="OCR_CORE",
    primary_tier=Tier.TIER_1_GPU,
    fallback_order=[
        "runpod_got_ocr",
        "modal_qwen_vl",
        "tesseract_local",
        "google_vision",
        "gemini_2_5_pro"
    ],
    providers={
        "tesseract_local": ProviderConfig(
            name="Tesseract",
            tier=Tier.TIER_1_LOCAL,
            cost_per_unit=0.0
        ),
        "runpod_got_ocr": ProviderConfig(
            name="GOT-OCR 2.0",
            tier=Tier.TIER_1_GPU,
            endpoint="https://api.runpod.ai/v2/got-ocr/runsync",
            api_key_env="RUNPOD_API_KEY",
            cost_per_unit=0.0004
        ),
        "modal_qwen_vl": ProviderConfig(
            name="Qwen2.5-VL",
            tier=Tier.TIER_1_GPU,
            endpoint="https://your-app.modal.run/ocr",
            api_key_env="MODAL_API_KEY",
            cost_per_unit=0.0003
        ),
        "google_vision": ProviderConfig(
            name="Google Cloud Vision",
            tier=Tier.TIER_2_PREMIUM,
            api_key_env="GOOGLE_VISION_API_KEY",
            cost_per_unit=0.0015
        ),
        "gemini_2_5_pro": ProviderConfig(
            name="Gemini 2.5 Pro",
            tier=Tier.TIER_2_PREMIUM,
            api_key_env="GOOGLE_AI_API_KEY",
            cost_per_unit=0.00125
        )
    }
)

8. Fallback Chains

7.1 Concepto

Cada módulo define una cadena de recuperación automática que combina tiers y providers:

┌─────────────────────────────────────────────────────────────────┐
│                    PRINCIPIO DE FALLBACK                        │
│                                                                 │
│   "TIER 1 primero, TIER 2 solo si falla o se requiere calidad" │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

7.2 Ejemplo: OCR_CORE

OCR_CORE Request
    │
    ├──► TIER 1 GPU: RunPod GOT-OCR
    │         │
    │         ├── SUCCESS → return
    │         │
    │         └── FAIL → next
    │
    ├──► TIER 1 GPU: Modal Qwen-VL
    │         │
    │         ├── SUCCESS → return (status: FALLBACK)
    │         │
    │         └── FAIL → next
    │
    ├──► TIER 1 LOCAL: Tesseract
    │         │
    │         ├── SUCCESS → return (status: FALLBACK)
    │         │
    │         └── FAIL → next
    │
    ├──► TIER 2: Google Vision
    │         │
    │         ├── SUCCESS → return (status: FALLBACK)
    │         │
    │         └── FAIL → next
    │
    └──► TIER 2: Gemini 2.5 Pro
              │
              ├── SUCCESS → return (status: FALLBACK)
              │
              └── FAIL → ERROR (chain exhausted)

7.3 Ejemplo: ASR

ASR Request
    │
    ├──► TIER 1 GPU: RunPod Faster Whisper Large V3
    │         │       (CTranslate2, 2-4x más rápido)
    │         │
    │         ├── SUCCESS → return
    │         │
    │         └── FAIL/TIMEOUT → next
    │
    ├──► TIER 1 GPU: Groq Whisper
    │         │       (API ultra-rápida)
    │         │
    │         ├── SUCCESS → return
    │         │
    │         └── FAIL → next
    │
    ├──► TIER 1 LOCAL: Whisper-base
    │         │    (calidad reducida pero funciona)
    │         │
    │         ├── SUCCESS → return (warning: quality_degraded)
    │         │
    │         └── FAIL → next
    │
    └──► TIER 2: OpenAI Whisper
              │
              ├── SUCCESS → return
              │
              └── FAIL → ERROR

7.4 Configuración de Fallback en Request

{
  "routing": {
    "module": "ASR_ENGINE",
    "tier_preference": ["TIER_1_GPU", "TIER_1_LOCAL", "TIER_2_PREMIUM"],
    "provider_preference": ["ASR_FASTER_WHISPER", "ASR_GROQ", "whisper_local", "ASR_OPENAI"],
    "fallback_chain": [
      {
        "provider": "ASR_FASTER_WHISPER",
        "timeout_ms": 30000,
        "retry_on": ["TIMEOUT", "SERVER_ERROR"],
        "notes": "RunPod Serverless - CTranslate2, 2-4x más rápido"
      },
      {
        "provider": "ASR_GROQ",
        "timeout_ms": 15000,
        "retry_on": ["TIMEOUT", "SERVER_ERROR"],
        "notes": "Groq API - inferencia ultra-rápida"
      },
      {
        "provider": "whisper_local",
        "timeout_ms": 60000,
        "accept_quality_degradation": true,
        "notes": "Whisper base local - calidad reducida"
      },
      {
        "provider": "ASR_OPENAI",
        "timeout_ms": 30000,
        "notes": "OpenAI Whisper API - fallback final"
      }
    ],
    "max_fallback_level": 3
  }
}

7.5 Transformaciones Pre-Retry

Antes de pasar al siguiente provider, se pueden aplicar transformaciones:

Módulo Transformación Descripción
OCR_CORE resize(800px) Reducir tamaño de imagen
OCR_CORE binarize Convertir a blanco/negro
OCR_CORE deskew Corregir rotación
OCR_CORE upscale(1.5x) Aumentar resolución
ASR VAD + noise_reduction Limpiar audio
ASR downsample(16kHz) Reducir sample rate
IMAGE compress(quality=80) Reducir peso

9. Pipelines Oficiales

8.1 Pipeline: Factura/Ticket

┌─────────────────────────────────────────────────────────────────┐
│                    PIPELINE FACTURA                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. IMAGE_PROCESSOR ──► Limpieza imagen                        │
│           │           (TIER 1 LOCAL)                            │
│           ▼                                                     │
│  2. PDF_SCANNER ──► Recorte y deskew                           │
│           │         (TIER 1 LOCAL)                              │
│           ▼                                                     │
│  3. OCR_CORE (strict) ──► Extracción texto                     │
│           │               (TIER 1 GPU → TIER 2 fallback)       │
│           ▼                                                     │
│  4. FIELD_EXTRACTOR ──► Campos estructurados                   │
│           │              (TIER 2 PREMIUM: Claude/GPT)          │
│           ▼                                                     │
│  5. CLASSIFIER ──► Categorización                              │
│           │        (TIER 1 LOCAL: embeddings)                  │
│           ▼                                                     │
│  6. HASH_SIGNER ──► Hash del documento                         │
│           │          (TIER 1 LOCAL)                            │
│           ▼                                                     │
│  7. PERSIST ──► The Vault + Hostinger                          │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

8.2 Pipeline: Reunión

┌─────────────────────────────────────────────────────────────────┐
│                    PIPELINE REUNIÓN                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  AUDIO:                                                         │
│  1. ASR ──► Transcripción                                      │
│           │  (TIER 1 GPU: Whisper Large V3)                    │
│           ▼                                                     │
│  2. LANG_NORMALIZER ──► Detectar idioma                        │
│           │              (TIER 1 LOCAL)                        │
│           ▼                                                     │
│  3. SUMMARIZER (structured) ──► Resumen estructurado           │
│           │                     (TIER 2: Claude Sonnet 4)      │
│           ▼                                                     │
│  4. TASK_DETECTOR ──► Extraer acciones                         │
│           │           (TIER 2: Claude Sonnet 4)                │
│           ▼                                                     │
│  5. EMBEDDINGS ──► Vector para búsqueda                        │
│           │        (TIER 1 LOCAL)                              │
│           ▼                                                     │
│  6. PERSIST ──► The Vault (Milestone: acta)                    │
│                        (Bloques: cada tarea)                   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

8.3 Pipeline: Onboarding Facial

┌─────────────────────────────────────────────────────────────────┐
│                    PIPELINE ONBOARDING                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. IMAGE_PROCESSOR ──► Normalizar imagen                      │
│           │             (TIER 1 LOCAL)                         │
│           ▼                                                     │
│  2. FACE_VECTOR ──► Extraer vector 512D                        │
│           │          (TIER 1 GPU: InsightFace)                 │
│           │          (⚠️ PII: true)                            │
│           ▼                                                     │
│  3. ID_CONSOLIDATION ──► Fusionar si hay múltiples             │
│           │               (TIER 1 LOCAL)                       │
│           ▼                                                     │
│  4. AVATAR_GEN ──► Generar avatar neutral                      │
│           │        (TIER 1 GPU: SDXL/Flux)                     │
│           ▼                                                     │
│  5. PERSIST ──► VAULT (vector facial cifrado E2E_STRICT)       │
│              ──► Player.avatar_url (público)                   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

10. Implementación de Referencia

9.1 Estructura del Proyecto

grace/
├── app/
│   ├── __init__.py
│   ├── main.py                    # FastAPI app
│   │
│   ├── api/
│   │   ├── __init__.py
│   │   ├── router.py              # Router principal
│   │   └── endpoints/
│   │       ├── vision.py          # /vision/*
│   │       ├── voice.py           # /voice/*
│   │       ├── identity.py        # /identity/*
│   │       ├── nlp.py             # /nlp/*
│   │       ├── semantic.py        # /semantic/*
│   │       └── structure.py       # /structure/*
│   │
│   ├── core/
│   │   ├── __init__.py
│   │   ├── config.py              # Settings
│   │   ├── contract.py            # Contrato Común v1.2
│   │   ├── providers.py           # Configuración de providers
│   │   ├── fallback.py            # Lógica de fallback
│   │   ├── logging_internal.py    # Buffer local
│   │   └── logging_external.py    # Flush a SYS_LOG
│   │
│   ├── modules/
│   │   ├── __init__.py
│   │   ├── base.py                # Clase base de módulo
│   │   │
│   │   ├── vision/
│   │   │   ├── image_processor.py
│   │   │   ├── pdf_scanner.py
│   │   │   └── ocr_core.py
│   │   │
│   │   ├── voice/
│   │   │   ├── asr.py
│   │   │   └── tts.py
│   │   │
│   │   ├── identity/
│   │   │   ├── face_vector.py
│   │   │   ├── id_consolidation.py
│   │   │   └── avatar_gen.py
│   │   │
│   │   ├── nlp/
│   │   │   ├── summarizer.py
│   │   │   ├── classifier.py
│   │   │   └── task_detector.py
│   │   │
│   │   ├── semantic/
│   │   │   ├── embeddings.py
│   │   │   └── similarity.py
│   │   │
│   │   └── structure/
│   │       ├── field_extractor.py
│   │       ├── hash_signer.py
│   │       ├── input_translator.py
│   │       ├── output_translator.py
│   │       └── lang_normalizer.py
│   │
│   └── providers/
│       ├── __init__.py
│       ├── tier1_local/
│       │   ├── tesseract.py
│       │   ├── whisper_local.py
│       │   ├── sentence_transformers.py
│       │   └── hashlib_provider.py
│       │
│       ├── tier1_gpu/
│       │   ├── runpod_client.py
│       │   ├── modal_client.py
│       │   └── replicate_client.py
│       │
│       └── tier2_premium/
│           ├── anthropic_client.py
│           ├── openai_client.py
│           ├── google_client.py
│           ├── elevenlabs_client.py
│           ├── deepgram_client.py
│           └── voyage_client.py
│
├── tests/
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
└── README.md

9.2 Clase Base de Módulo

# app/modules/base.py

from abc import ABC, abstractmethod
from typing import Any
from pydantic import BaseModel
import logging

from app.core.contract import Request, Response, Status
from app.core.providers import ModuleProviders, Tier
from app.core.fallback import FallbackManager
from app.core.logging_internal import InternalLogger

logger = logging.getLogger(__name__)

class ModuleBase(ABC):
    """Clase base para todos los módulos de GRACE."""
    
    def __init__(
        self,
        name: str,
        providers: ModuleProviders,
        internal_logger: InternalLogger
    ):
        self.name = name
        self.providers = providers
        self.fallback = FallbackManager(providers)
        self.logger = internal_logger
    
    async def execute(self, request: Request) -> Response:
        """Ejecuta el módulo con fallback automático."""
        
        # Log inicio
        await self.logger.log_start(request)
        
        # Intentar con cada provider en orden de fallback
        for attempt, provider_name in enumerate(self.fallback.get_chain(request)):
            try:
                provider = self.providers.providers[provider_name]
                
                # Ejecutar transformación específica del provider
                result = await self._execute_provider(
                    provider_name=provider_name,
                    request=request
                )
                
                # Construir response exitosa
                response = Response(
                    contract_version="1.2",
                    envelope=request.envelope.model_copy(
                        update={"timestamp_end": self._now()}
                    ),
                    status=Status(
                        code="SUCCESS" if attempt == 0 else "FALLBACK",
                        fallback_level_used=attempt,
                        tier_used=provider.tier.value,
                        provider_used=provider_name,
                        module_instance=f"{self.name}_{provider_name.upper()}"
                    ),
                    result=result,
                    quality=self._compute_quality(result),
                    metadata=self._build_metadata(provider, result)
                )
                
                # Log éxito
                await self.logger.log_success(request, response)
                return response
                
            except Exception as e:
                logger.warning(
                    f"Provider {provider_name} failed: {e}. "
                    f"Attempting fallback..."
                )
                await self.logger.log_error(request, provider_name, e)
                continue
        
        # Todos los providers fallaron
        response = Response(
            contract_version="1.2",
            envelope=request.envelope.model_copy(
                update={"timestamp_end": self._now()}
            ),
            status=Status(
                code="ERROR",
                fallback_level_used=len(self.fallback.get_chain(request)),
                tier_used="NONE",
                provider_used="NONE"
            ),
            errors=[{
                "code": "FALLBACK_EXHAUSTED",
                "message": "All providers failed"
            }]
        )
        
        await self.logger.log_failure(request, response)
        return response
    
    @abstractmethod
    async def _execute_provider(
        self,
        provider_name: str,
        request: Request
    ) -> dict[str, Any]:
        """Implementación específica del módulo para cada provider."""
        pass
    
    @abstractmethod
    def _compute_quality(self, result: dict) -> dict:
        """Calcula métricas de calidad del resultado."""
        pass
    
    def _build_metadata(self, provider, result) -> dict:
        """Construye metadata del procesamiento."""
        return {
            "model_id": getattr(result, "model_id", provider.name),
            "processing_ms": getattr(result, "processing_ms", 0),
            "cost_units": provider.cost_per_unit
        }
    
    def _now(self) -> str:
        from datetime import datetime
        return datetime.utcnow().isoformat() + "Z"

9.3 Ejemplo: OCR_CORE

# app/modules/vision/ocr_core.py

from typing import Any
from app.modules.base import ModuleBase
from app.core.contract import Request
from app.providers.tier1_local.tesseract import TesseractProvider
from app.providers.tier1_gpu.runpod_client import RunPodClient
from app.providers.tier2_premium.google_client import GoogleVisionClient

class OCRCore(ModuleBase):
    """Módulo de OCR con fallback multi-tier."""
    
    def __init__(self, *args, **kwargs):
        super().__init__("OCR_CORE", *args, **kwargs)
        
        # Inicializar providers
        self._providers = {
            "tesseract_local": TesseractProvider(),
            "runpod_got_ocr": RunPodClient("got-ocr"),
            "modal_qwen_vl": RunPodClient("qwen-vl"),  # o ModalClient
            "google_vision": GoogleVisionClient(),
        }
    
    async def _execute_provider(
        self,
        provider_name: str,
        request: Request
    ) -> dict[str, Any]:
        """Ejecuta OCR con el provider especificado."""
        
        provider = self._providers[provider_name]
        image_data = request.payload.content
        
        # Aplicar transformaciones si es retry
        if request.routing.get("apply_transforms"):
            image_data = await self._apply_transforms(
                image_data,
                request.routing["transforms"]
            )
        
        # Ejecutar OCR
        result = await provider.ocr(
            image=image_data,
            mode=request.context.get("mode", "strict"),
            lang=request.context.get("lang", "es")
        )
        
        return {
            "schema": "ocr_result_v1",
            "data": {
                "text": result.text,
                "blocks": result.blocks,
                "confidence": result.confidence
            }
        }
    
    def _compute_quality(self, result: dict) -> dict:
        """Calcula métricas de calidad del OCR."""
        data = result.get("data", {})
        return {
            "confidence": data.get("confidence", 0.0),
            "coverage": 1.0 if data.get("text") else 0.0,
            "validation_passed": data.get("confidence", 0) > 0.7
        }
    
    async def _apply_transforms(
        self,
        image_data: str,
        transforms: list[str]
    ) -> str:
        """Aplica transformaciones de imagen para mejorar OCR."""
        from app.modules.vision.image_processor import ImageProcessor
        
        processor = ImageProcessor()
        
        for transform in transforms:
            if transform == "resize":
                image_data = await processor.resize(image_data, max_width=800)
            elif transform == "binarize":
                image_data = await processor.binarize(image_data)
            elif transform == "deskew":
                image_data = await processor.deskew(image_data)
            elif transform == "upscale":
                image_data = await processor.upscale(image_data, factor=1.5)
        
        return image_data

9.4 Validador de Contrato

# app/core/contract.py

from pydantic import BaseModel, validator
from typing import Literal, Optional
from enum import Enum

class StatusCode(str, Enum):
    SUCCESS = "SUCCESS"
    PARTIAL = "PARTIAL"
    ERROR = "ERROR"
    TIMEOUT = "TIMEOUT"
    FALLBACK = "FALLBACK"

class ContractValidator:
    """Validador del Contrato Común v1.2"""
    
    REQUIRED_ENVELOPE = ['trace_id', 'step_id', 'idempotency_key']
    REQUIRED_ROUTING = ['module']
    
    @classmethod
    def validate_request(cls, request: dict) -> tuple[bool, list[str]]:
        errors = []
        
        # Contract version
        if request.get('contract_version') != "1.2":
            errors.append("contract_version must be '1.2'")
        
        # Envelope
        envelope = request.get('envelope', {})
        for field in cls.REQUIRED_ENVELOPE:
            if field not in envelope:
                errors.append(f"Missing envelope.{field}")
        
        # Routing
        routing = request.get('routing', {})
        for field in cls.REQUIRED_ROUTING:
            if field not in routing:
                errors.append(f"Missing routing.{field}")
        
        # Payload
        if 'payload' not in request:
            errors.append("Missing: payload")
        
        return len(errors) == 0, errors
    
    @classmethod
    def validate_response(cls, response: dict) -> tuple[bool, list[str]]:
        errors = []
        
        # Status
        status = response.get('status', {})
        if 'code' not in status:
            errors.append("Missing: status.code")
        elif status['code'] not in [s.value for s in StatusCode]:
            errors.append(f"Invalid status.code: {status['code']}")
        
        # Result (requerido si SUCCESS o PARTIAL)
        if status.get('code') in ['SUCCESS', 'PARTIAL', 'FALLBACK']:
            if 'result' not in response:
                errors.append("Missing: result")
        
        return len(errors) == 0, errors

Resumen

GRACE proporciona:

Característica Descripción
18 módulos Microservicios cognitivos especializados y desacoplados
Contrato Común v1.2 Interfaz universal para interoperabilidad total
Arquitectura 2-Tier TIER 1 autoalojado (local + GPU serverless) + TIER 2 APIs premium
Fallback chains Tolerancia a fallos con degradación elegante
Sistema de logging Buffer interno + SYS_LOG externo + SENTINEL dual
Pipelines oficiales Flujos pre-definidos para casos de uso comunes

Comparativa Jarvis → GRACE

Aspecto Jarvis (v4) GRACE (v5)
Providers Local + APIs remotas TIER 1 (autoalojado) + TIER 2 (premium)
GPU Dependía de APIs GPU Serverless (RunPod/Modal)
Logging Solo SYS_LOG Buffer interno + SYS_LOG + SENTINEL
Fallback Por provider Por tier + provider
Costo Variable Optimizado (TIER 1 primero)
Latencia Variable Predecible (local/GPU serverless)

Documento anterior: 05_ENTIDADES.md
Siguiente documento: 07_SEGURIDAD_TRAZABILIDAD.md