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

1666 lines
63 KiB
Markdown

# 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](#1-introducción)
2. [Modelo de Despliegue](#2-modelo-de-despliegue)
3. [Contrato Común v1.2](#3-contrato-común-v12)
4. [Envelope Universal](#4-envelope-universal)
5. [Sistema de Logging](#5-sistema-de-logging)
6. [Los 18 Módulos](#6-los-18-módulos)
7. [Arquitectura de Providers](#7-arquitectura-de-providers)
8. [Fallback Chains](#8-fallback-chains)
9. [Pipelines Oficiales](#9-pipelines-oficiales)
10. [Implementación de Referencia](#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:
- **G**enerativa — Produce outputs estructurados
- **R**eliable — Determinista y trazable
- **A**gnostic — Independiente del provider
- **C**ognitive — Capa de inteligencia
- **E**fficient — 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`:
```python
# 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
```json
{
"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
```json
{
"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
```sql
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
```python
# 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
```yaml
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
```yaml
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
```yaml
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)
```yaml
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)
```yaml
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
```yaml
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
```yaml
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
```yaml
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
```yaml
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
```yaml
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
```yaml
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
```yaml
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
```yaml
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
```yaml
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
```yaml
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
```yaml
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
```yaml
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
```yaml
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
```python
# 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
```json
{
"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
```python
# 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
```python
# 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
```python
# 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`