# A01.P009 - Evolución del Ecosistema ADN al Concepto de Dron > **Estado**: 🟢 Fase 1.5 completada > **Pertenece a**: [A01 - Ecosistema ADN](./A01_dtic-ADN.md) > **Fecha**: 2026-04-09 > **Responsable**: Lic. Ricardo MONLA > **Versión**: 3.2 — Fase 1.5 completada, sistema dual eliminado --- ## 📈 Progreso ``` Fase 0: ██████████ 100% Infraestructura de Datos (tablas internas) ✅ Fase 1: ██████████ 100% Atomicidad (bugs corregidos) ✅ Fase 1.5: ██████████ 100% Visibilidad Bitácora Web + Corrección Bugs ✅ Fase 2: ░░░░░░░░░░ 0% Composición — Orquestación de Flujos Fase 3: ░░░░░░░░░░ 0% Planificación — Drones Programados Fase 4: ░░░░░░░░░░ 0% Inteligencia de Colmena Fase 5: ░░░░░░░░░░ 0% Observabilidad — Dashboard y Métricas ``` --- ## 📋 Resumen Ejecutivo Este plan define la evolución del ecosistema ADN hacia una arquitectura de **Inteligencia de Colmena** basada en **AtomicDrones** — drones atómicos especializados que, compuestos, forman una maquinaria autónoma integral. **Filosofía de Diseño:** | Principio | Descripción | |-----------|-------------| | **🧬 AtomicDrones** | Cada dron hace UNA cosa y la hace bien. Sin monolitos. | | **🤖 Inteligencia de Colmena** | La solución emerge de la composición de drones simples. | | **⚙️ Engranajes Especializados** | Drones ejecutores, vigilantes, sanadores, planificadores. | | **🚫 No FrankenDrones** | Rechazar drones que intentan hacer todo mal. | **Concepto de Dron ADN:** - **Atómico**: Una responsabilidad única (Single Responsibility) - **Componible**: Se ensambla con otros drones para soluciones complejas - **Auto-bitácora**: Registra inicio/fin automáticamente - **Observable**: Estado visible vía `dron flota` y dashboard web - **Efímero**: Nace, ejecuta, muere (sin estado persistente innecesario) --- ## 🎯 Objetivo Evolucionar el ecosistema ADN hacia una **colonia de AtomicDrones** especializados que, compuestos, resuelven problemas complejos mediante inteligencia de colmena. **Meta:** Reducir la fricción operativa mediante drones atómicos que se especializan en una tarea única y se componen para flujos complejos. --- ## 🐝 Tipos de AtomicDrones (Especialización) Cada tipo de dron tiene una única responsabilidad. La composición de múltiples drones resuelve problemas complejos. | Tipo | Símbolo | Responsabilidad | Ejemplo | |------|---------|-----------------|---------| | **Ejecutor** | `🛠️` | Ejecuta un comando y reporta resultado | `dron_ejecutor` | | **Vigilante** | `👁️` | Monitorea estado de otros drones | `dron_vigilante` | | **Sanador** | `🩹` | Repara drones zombies/fallidos | `dron_sanador` | | **Planificador** | `📅` | Lanza drones según cron | `dron_planificador` | | **Mensajero** | `📨` | Notifica resultados (Slack, email) | `dron_mensajero` | | **Orquestador** | `🎼` | Compone múltiples drones en flujo | `dron_orquestador` | ### Ejemplo de Composición (Inteligencia de Colmena) **Problema:** Backup nocturno de SQL + sync a nube + notificación **Solución FrankenDron (❌ rechazar):** ```ruby # Un solo dron que hace todo (monolito frágil) dron_backup_nocturno.rb # 500 líneas, 7 responsabilidades ``` **Solución AtomicDrones (✅ adoptar):** ```bash # Orquestador compone 4 drones especializados dron_orquestador \ --step "dron_ejecutor --cmd 'vzdump 103'" \ --step "dron_ejecutor --cmd 'rclone sync /bkps oneDrive:'" \ --step "dron_vigilante --check exit_code" \ --step "dron_mensajero --notify slack 'Backup OK'" ``` --- ## 📡 Medio de Comunicación: Bitácora Web como Registro Central La **Bitácora Web** es el medio de comunicación donde los drones dejan registro de su actividad. El sistema sigue el principio **DB-First** con capas de visibilidad. ### Principio de Codificación: Atomisidad **Atomisidad** es el principio de código compartido que aplica "Menos es Más" a la implementación de drones: ``` ┌─────────────────────────────────────────────────────────────┐ │ Dron::Base (módulo compartido) │ │ - logger: Logger único para todos los drones │ │ - db_query: Ejecución de SQL con resultados │ │ - db_exec: Ejecución de SQL sin resultados │ │ - formato_duracion: Utilitario común │ │ - slice_safe: Manejo seguro de strings │ │ - blank?: Verificación de nil/empty │ └─────────────────────────────────────────────────────────────┘ │ ┌─────────────────┼─────────────────┐ │ │ │ ▼ ▼ ▼ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Ejecutor │ │ Vigilante │ │ Sanador │ │ extend Base │ │ extend Base │ │ extend Base │ └──────────────┘ └──────────────┘ └──────────────┘ ``` **Beneficios:** - Un solo lugar para corregir errores comunes - ~40% menos líneas de código - Nuevos drones heredan funcionalidad automáticamente ### Arquitectura de Registros ``` ┌─────────────────────────────────────────────────────────────────┐ │ DRONES (Ejecutores, Vigilantes, Sanadores, etc.) │ │ Cada dron deja registro al ejecutar │ └────────────┬────────────────────────────────────────────────────┘ │ registra ▼ ┌─────────────────────────────────────────────────────────────────┐ │ CAPA 1: Tablas Internas (NO visibles directamente) │ │ - bitacoras.dron_logs: Logs detallados de cada dron │ │ - bitacoras.dron_avances: Progreso paso-a-paso │ │ - bitacoras.dron_metricas: Métricas de rendimiento │ │ - bitacoras.dron_errores: Errores y reintentos │ └────────────┬────────────────────────────────────────────────────┘ │ │ dron_vigilante consolida ▼ ┌─────────────────────────────────────────────────────────────────┐ │ CAPA 2: Bitácora Web (Resumen visible) │ │ - events: Eventos consolidados por flujo/orquestación │ │ - Descripción: Resumen legible del progreso │ │ - Estado: ⏳ En ejecución | ✅ Completado | ❌ Fallido │ │ - URL: http://localhost:5174/bitacoras/ │ └─────────────────────────────────────────────────────────────────┘ ``` ### Tablas Internas (Esquema `bitacoras`) ```sql -- Logs detallados de cada dron (NO visible en web directamente) CREATE TABLE bitacoras.dron_logs ( id SERIAL PRIMARY KEY, dron_id VARCHAR(50) NOT NULL, -- ej: dron_083045_123 flujo_id VARCHAR(50), -- ID de orquestación (si aplica) tipo VARCHAR(20) NOT NULL, -- ejecutor|vigilante|sanador|planificador|mensajero estado VARCHAR(20) NOT NULL, -- pending|running|completed|failed|zombie cmd TEXT, -- Comando ejecutado output TEXT, -- Salida del comando exit_code INTEGER, -- Código de retorno started_at TIMESTAMP DEFAULT NOW(), completed_at TIMESTAMP, heartbeat TIMESTAMP DEFAULT NOW(), -- Último heartbeat reintentos INTEGER DEFAULT 0, metadata JSONB DEFAULT '{}'::jsonb -- Metadata adicional ); -- Avances paso-a-paso (para flujos multi-paso) CREATE TABLE bitacoras.dron_avances ( id SERIAL PRIMARY KEY, dron_id VARCHAR(50) NOT NULL, paso INTEGER NOT NULL, -- Número de paso en flujo descripcion TEXT NOT NULL, -- Qué se está haciendo estado VARCHAR(20) NOT NULL, -- pending|running|completed|failed started_at TIMESTAMP DEFAULT NOW(), completed_at TIMESTAMP, metadata JSONB DEFAULT '{}'::jsonb ); -- Métricas de rendimiento (agregaciones) CREATE TABLE bitacoras.dron_metricas ( id SERIAL PRIMARY KEY, fecha DATE NOT NULL, dron_tipo VARCHAR(20) NOT NULL, total_ejecuciones INTEGER DEFAULT 0, completados INTEGER DEFAULT 0, fallidos INTEGER DEFAULT 0, zombies INTEGER DEFAULT 0, tiempo_promedio INTERVAL, reintentos_total INTEGER DEFAULT 0, UNIQUE(fecha, dron_tipo) ); -- Índices para consultas eficientes CREATE INDEX idx_dron_logs_estado ON bitacoras.dron_logs(estado); CREATE INDEX idx_dron_logs_heartbeat ON bitacoras.dron_logs(heartbeat); CREATE INDEX idx_dron_logs_flujo ON bitacoras.dron_logs(flujo_id); CREATE INDEX idx_dron_avances_dron ON bitacoras.dron_avances(dron_id); ``` ### Dron Vigilante: El Monitor de Flotas El **`dron_vigilante`** es responsable de: 1. **Escanear flota**: Lee `bitacoras.dron_logs` para detectar drones activos 2. **Detectar zombies**: `heartbeat > 5min` → marca como zombie 3. **Registrar avances**: Inserta en `bitacoras.dron_avances` el progreso 4. **Consolidar resumen**: Crea/actualiza evento en `bitacoras.events` (visible en web) 5. **Alertar anomalías**: Si detecta >5 fallos en 1h → notifica ```ruby # Ejemplo: dron_vigilante escanea y registra avances class DronVigilante def escanear_flota drones_activos = DronDB.where("estado = 'running' AND heartbeat < ?", 5.minutes.ago) drones_activos.each do |dron| # Marcar como zombie dron.update(estado: 'zombie') # Registrar en avances DronAvance.create( dron_id: dron.id, paso: -1, descripcion: "Dron detectado como zombie (heartbeat > 5min)", estado: 'failed' ) # Consolidar resumen en events (visible en Bitácora Web) consolidar_resumen(dron.flujo_id) end end def consolidar_resumen(flujo_id) # Obtener todos los logs del flujo logs = DronLog.where(flujo_id: flujo_id) # Calcular estado consolidado estado = if logs.all? { |l| l.estado == 'completed' } 'completed' elsif logs.any? { |l| l.estado == 'failed' } 'failed' else 'running' end # Actualizar/crear evento resumen (visible en Bitácora Web) Evento.find_or_create_by(flujo_id: flujo_id).update( descripcion: "Flujo #{flujo_id}: #{logs.count} drones - #{estado}", estado: estado ) end end ``` ### Bitácora Web: Lo que el Usuario Ve La **Bitácora Web** (`http://localhost:5174/bitacoras/`) muestra: | Columna | Contenido | |---------|-----------| | **ID** | ID del evento resumen | | **I** | Hora de inicio del flujo | | **F** | Hora de fin (si completado) | | **Descripción** | Resumen consolidado (ej: "Backup nocturno: 4 drones completados") | | **J** | Modo (P=Presencial, R=Remoto, A=Automático) | | **E** | Estado (⏳, ✅, ❌) | | **Acc.** | Acciones (ver detalle, reintentar) | **Al hacer clic en "ver detalle"**: - Muestra tabla con drones individuales y su estado - Muestra avances paso-a-paso del flujo - Muestra métricas de rendimiento (tiempo, reintentos) --- ## 📊 Estado Actual (Línea Base — Auditoría 2026-04-09) ### Herramientas Existentes | Herramienta | Ubicación | Tipo | Estado | |-------------|-----------|------|--------| | `dron.rb` | `adn/tools/cli/dron.rb` | Dispatcher | ✅ Refactorizado | | `dron/ejecutor.rb` | `adn/tools/cli/dron/ejecutor.rb` | Ejecutor atómico | ⚠️ Bugs en bitácora web | | `dron/vigilante.rb` | `adn/tools/cli/dron/vigilante.rb` | Vigilante atómico | ⚠️ Bugs en consolidación | | `dron/sanador.rb` | `adn/tools/cli/dron/sanador.rb` | Sanador atómico | ⚠️ Bugs en reintentos | | `dron/bitacora.rb` | `adn/tools/cli/dron/bitacora.rb` | Bitácora atómica | ✅ Implementado | | `dron/base.rb` | `adn/tools/cli/dron/base.rb` | Módulo compartido | ✅ Implementado | | `dron_db.rb` | `adn/tools/db/core/dron_db.rb` | Acceso a DB | ⚠️ 3 bugs críticos | | `dispatcher.rb` | `adn/tools/cli/dron/dispatcher.rb` | Routing subcomandos | ⚠️ 1 bug crítico | ### Capacidades Actuales ```bash # Ejecutor (lanzar tarea con auto-bitácora) ./adn/tools/run dron lanzar --evento AUTO --nota "Backup" -- # Vigilante (ver flota) ./adn/tools/run dron flota ./adn/tools/run dron salud ./adn/tools/run dron estado # Sanador (health check + limpiar + reintentar) ./adn/tools/run dron sanear --dry-run ./adn/tools/run dron limpiar ./adn/tools/run dron reintentar ``` ### 🐛 Deuda Técnica Detectada (Auditoría 2026-04-09) #### Bugs Críticos (crashes directos) | # | Archivo | Línea | Bug | Impacto | |---|---------|-------|-----|---------| | B1 | `dispatcher.rb` | 214 | `BitacorasDB::BitacoraDB.ejecutar()` — método inexistente (debe ser `.with_connection { \|db\| db.execute() }`) | `dron estado ` crashea con NoMethodError | | B2 | `dron_db.rb` | 178-179 | `incrementar_reintentos` hace doble `.first` (`.first.to_h` → Hash, luego `.first` sobre Hash = par `[k,v]`) | Sanador crashea al reintentar drones | | B3 | `dron_db.rb` | 231-232 | `obtener_metricas` mismo patrón de doble `.first` | Consulta de métricas crashea | #### Bugs Medios (fallan en ciertos flujos) | # | Archivo | Línea | Bug | Impacto | |---|---------|-------|-----|---------| | B4 | `dron_db.rb` | 337-345 | `limpiar_antiguos` — DELETE sin RETURNING intenta leer `['count']` inexistente | Limpieza reporta 0 siempre | | B5 | `dron_db.rb` | 253 | `actualizar_metricas` — pasa Float donde PG espera INTERVAL | Error de tipo al guardar métricas | | B6 | `sanador.rb` | 27 | `Time.now - dron['completed_at']` — el campo viene como String, no Time | TypeError al calcular backoff | | B7 | `sanador.rb` | 41 | `Dron::Ejecutor.lanzar(...)` sin `require_relative 'ejecutor'` | NameError si se llama directamente | #### Bugs Bajos (edge cases) | # | Archivo | Línea | Bug | Impacto | |---|---------|-------|-----|---------| | B8 | `sanador.rb` | 41 | `dron.dig('metadata', 'nota')` — metadata es String JSON, no Hash | Nota de reintento siempre nil | | B9 | `ejecutor.rb` | 42-75 | Timeout nunca se aplica (falta `Timeout.timeout()` wrapping) | Drones largos nunca se frenan | | B10 | `vigilante.rb` | 141,143 | `BitacorasDB::BitacoraDB.crear_evento(...)` como método de clase (es de instancia) | Consolidación de flujos falla silenciosamente | | B11 | `ejecutor.rb` | 82-131 | `registrar_bitacora` con rescue genérico silencia todos los errores | Fallos de bitácora web invisibles | | B12 | `dron.rb` / `base.rb` | 30 / 27 | Logger: `.instance` (singleton) vs `.new` (instancia separada) | Logs inconsistentes | ### 🔍 Brecha Principal: Visibilidad en Bitácora Web **Problema crítico**: Los drones escriben en tablas internas (`dron_logs`) pero la **Bitácora Web** (`bitacoras.events`) no refleja su actividad. ``` CAPA 1 (dron_logs) CAPA 2 (events → Web) ┌─────────────────┐ ┌─────────────────┐ │ ✅ Drones │ ──?──→ │ ❌ La web no ve │ │ escriben acá │ │ nada │ └─────────────────┘ └─────────────────┘ ↑ La flecha "vigilante consolida" NO FUNCIONA por bugs B1, B10, B11 ``` **Causas raíz:** 1. El heartbeat solo actualiza `dron_logs.heartbeat` (tabla interna), nunca `events` 2. El ejecutor tiene lógica de bitácora web pero falla silenciosamente (B11) 3. El vigilante llama métodos de clase inexistentes (B10) 4. Coexiste un sistema antiguo de scripts `.sh` (que sí funcionaba) con el nuevo Ruby (que no) ### Limitaciones Futuras (post-corrección) | # | Limitación | Tipo | Impacto | Prioridad | |---|------------|------|---------|-----------| | 1 | Sin orquestación de flujos | Orquestador | No hay composición multi-paso | Media | | 2 | Sin planificación (cron) | Planificador | Requiere lanzamiento manual | Alta | | 3 | Sin notificaciones | Mensajero | Alertas manuales | Media | | 4 | Sin dashboard web dedicado | Observabilidad | Solo CLI + Bitácora Web | Baja | --- ## 🗺️ Fases de Implementación ### Fase 0: Infraestructura de Datos (Dron 0.5) — ✅ COMPLETA **Objetivo:** Crear tablas internas para registro detallado de drones. | ID | Tarea | Descripción | Estado | |:--:|-------|-------------|--------| | F0.T1 | Migración `003_dron_logs.sql` | Tabla `bitacoras.dron_logs` | ✅ Completa | | F0.T2 | Migración `004_dron_avances.sql` | Tabla `bitacoras.dron_avances` | ✅ Completa | | F0.T3 | Migración `005_dron_metricas.sql` | Tabla `bitacoras.dron_metricas` | ✅ Completa | | F0.T4 | `adn/tools/db/core/dron_db.rb` | Acceso a datos de drones | ✅ Completa | | F0.T5 | Hooks DB-First | Auto-registro en dron_logs al lanzar | ✅ Completa | **Criterio de éxito:** ✅ Drones registran actividad en tablas internas sin tocar events directamente. --- ### Fase 1: Atomicidad — Separación de Responsabilidades (Dron 1.0) — ⚠️ CON DEUDA TÉCNICA **Objetivo:** Refactorizar el monolito `dron.rb` en módulos atómicos especializados. | ID | Tarea | Tipo de Dron | Estado | |:--:|-------|--------------|--------| | F1.T1 | `dron/ejecutor.rb` | Ejecutor — lanza y monitorea comando | ⚠️ Bugs B9, B11 | | F1.T2 | `dron/vigilante.rb` | Vigilante — escanea flota, detecta zombies | ⚠️ Bug B10 | | F1.T3 | `dron/sanador.rb` | Sanador — re-intenta, limpia, notifica fallos | ⚠️ Bugs B6, B7, B8 | | F1.T4 | `dron/bitacora.rb` | Registrador — auto-bitácora (inicio/fin) | ✅ Completa | | F1.T5 | `dron/dispatcher.rb` | Dispatcher — routing de subcomandos | ⚠️ Bug B1 | | F1.T6 | `dron/base.rb` | Módulo compartido (atomisidad) | ✅ Completa | | F1.T7 | `dron_db.rb` | Capa de datos para drones | ⚠️ Bugs B2, B3, B4, B5 | **Criterio de éxito original:** ✅ Cada módulo tiene una única responsabilidad. ~40% menos código. **Criterio revisado:** ⚠️ La estructura atómica es correcta pero **12 bugs** impiden operación confiable. Corregidos en Fase 1.5. --- ### Fase 1.5: Visibilidad en Bitácora Web + Corrección de Bugs (Dron 1.1) — ✅ COMPLETA **Objetivo:** Que los drones sean **visibles desde la Bitácora Web** y corregir toda la deuda técnica de Fase 1. **Problema que resuelve:** Actualmente los drones son "fantasmas" — ejecutan tareas pero el usuario no puede ver su progreso desde la interfaz web principal. Solo escriben en tablas internas (`dron_logs`) pero nunca actualizan `bitacoras.events` de forma confiable. **Lo que el usuario debería ver en Bitácora Web:** ``` ┌─────┬───────┬───────┬─────────────────────────────────────────────┬───┬───┐ │ ID │ I │ F │ Descripción │ J │ E │ ├─────┼───────┼───────┼─────────────────────────────────────────────┼───┼───┤ │1420 │ 02:00 │ │ 🛸 Backup nocturno (dron_020000_123) │ A │ ⏳│ │ │ │ │ ├─ Ejecutando: vzdump 103 --mode stop │ │ │ │ │ │ │ └─ ❤️ Heartbeat: hace 45s │ │ │ ├─────┼───────┼───────┼─────────────────────────────────────────────┼───┼───┤ │1419 │ 01:30 │ 01:45 │ 🛸 Sync rclone (dron_013000_456) — ✅ 15m │ A │ ✅│ │ │ │ │ └─ Aterrizaje limpio — 2.3GB sincronizados │ │ │ └─────┴───────┴───────┴─────────────────────────────────────────────┴───┴───┘ ``` | ID | Tarea | Descripción | Estado | |:--:|-------|-------------|--------| | F1.5.T1 | Corregir bugs críticos | Bugs B1, B2, B3 — crashes directos en dispatcher y dron_db | ✅ | | F1.5.T2 | Corregir bugs medios | Bugs B4, B5, B6, B7 — fallos en sanador y métricas | ✅ | | F1.5.T3 | Simplificar `registrar_bitacora` | Reescribir el método del ejecutor: crear evento → heartbeat → cierre limpio | ✅ | | F1.5.T4 | Heartbeat visible en web | Que el heartbeat cada 30s actualice `events.descripcion` con progreso | ✅ | | F1.5.T5 | Eliminar sistema dual `.sh`/Ruby | `copiloto.rb` y `novato.rb` deprecados, `tmp/dron/` limpiado | ✅ | | F1.5.T6 | Corregir bugs bajos | Bugs B8-B12 — edge cases y consistencia | ✅ | **Flujo corregido del Ejecutor:** ``` Ejecutor.lanzar(cmd, nota) │ ├─ 1. Registrar en dron_logs (tabla interna) ──→ DronDB ├─ 2. Crear evento en events (Bitácora Web) ──→ 🌐 VISIBLE │ ├─ 3. Ejecutar comando con heartbeat thread: │ loop cada 30s: │ ├─ Actualizar dron_logs.heartbeat ──→ DronDB │ └─ Actualizar events.descripcion ──→ 🌐 VISIBLE │ ├─ 4. Comando finaliza ├─ 5. Registrar fin en dron_logs ──→ DronDB └─ 6. Cerrar evento en events (estado + hora fin) ──→ 🌐 VISIBLE ``` **Criterio de éxito:** - Cada dron lanzado aparece inmediatamente en la Bitácora Web como evento `⏳` - El heartbeat actualiza la descripción del evento en web cada 30 segundos - Al finalizar, el evento se cierra con `✅` o `❌`, hora de fin, y duración - `dron estado `, `dron flota`, y `dron salud` funcionan sin crashes - Cero bugs críticos, cero bugs medios --- ### Fase 2: Composición — Orquestación de Flujos (Dron 1.5) **Objetivo:** Permitir composición de drones para flujos multi-paso. | ID | Tarea | Descripción | Estado | |:--:|-------|-------------|--------| | F2.T1 | `dron/orquestador.rb` | Ejecuta pasos secuenciales (`--step`) | ⏳ | | F2.T2 | Condicionales | `--on-error continue\|abort\|retry` | ⏳ | | F2.T3 | Paralelismo | `--parallel` para pasos independientes | ⏳ | | F2.T4 | Contexto compartido | Variables entre pasos (`$DRON_OUTPUT_N`) | ⏳ | **Ejemplo:** ```bash ./adn/tools/run dron orquestar \ --step "dron_ejecutor --cmd 'vzdump 103'" \ --step "dron_ejecutor --cmd 'rclone sync /bkps oneDrive:'" \ --step "dron_mensajero --notify 'Backup OK'" \ --on-error abort ``` **Criterio de éxito:** Flujos complejos se expresan como composición de drones simples. --- ### Fase 3: Planificación — Drones Programados (Dron 2.0) **Objetivo:** Ejecución automática según cron. | ID | Tarea | Tipo de Dron | Estado | |:--:|-------|--------------|--------| | F3.T1 | `dron/planificador.rb` | Planificador — lee cron y lanza drones | ⏳ | | F3.T2 | Persistencia de schedules | `~/.claude/scheduled_tasks.json` | ⏳ | | F3.T3 | CLI schedules | `schedule add\|list\|remove` | ⏳ | | F3.T4 | Integración CronCreate | SDK de Claude Code | ⏳ | **Criterio de éxito:** Tareas recurrentes se lanzan automáticamente. --- ### Fase 4: Inteligencia de Colmena — Comunicación entre Drones (Dron 3.0) **Objetivo:** Drones se comunican y coordinan para resolver problemas. | ID | Tarea | Descripción | Estado | |:--:|-------|-------------|--------| | F4.T1 | Cola de eventos | Redis o archivo compartido para eventos | ⏳ | | F4.T2 | Publicar/ Suscribirse | Drones publican eventos, otros reaccionan | ⏳ | | F4.T3 | Patrones de reacción | `on failed → sanador`, `on completed → mensajero` | ⏳ | | F4.T4 | Feromonas digitales | Señales químicas virtuales (`/tmp/dron_pheromones/`) | ⏳ | **Ejemplo de flujo emergente:** ``` 1. Ejecutor falla → publica "failed" en cola 2. Sanador escucha → re-intenta (máx 3 veces) 3. Si falla → publica "critical" 4. Mensajero escucha → notifica por Slack ``` **Criterio de éxito:** Soluciones complejas emergen sin orquestador central. --- ### Fase 5: Observabilidad — Dashboard y Métricas (Dron 4.0) **Objetivo:** Visibilidad completa de la colonia. | ID | Tarea | Tipo de Dron | Estado | |:--:|-------|--------------|--------| | F5.T1 | API `/api/drones` | Endpoint para listar drones | ⏳ | | F5.T2 | API `/api/drones/:id/avances` | Endpoint para avances de un dron | ⏳ | | F5.T3 | Dashboard web | `http://localhost:5174/drones` | ⏳ | | F5.T4 | Gráficas | Tareas por día, tasa de éxito, tiempos | ⏳ | | F5.T5 | Alertas proactivas | `dron_vigilante` detecta anomalías | ⏳ | **Criterio de éxito:** Visibilidad completa vía web dashboard y métricas históricas. --- ## 🏗️ Arquitectura de Colmena ### Diagrama de Flujo (Inteligencia de Colmena) ``` ┌──────────────────────────────────────────────────────────────────┐ │ Dron::Base (módulo compartido - Atomisidad) │ │ - logger: Logger único │ │ - db_query/db_exec: Acceso a DB │ │ - utilidades: formato_duracion, slice_safe, blank? │ └─────────────┬────────────────────────────────────────────────────┘ │ extend Base (todos los drones) ┌─────────┼─────────┬─────────────────┐ │ │ │ │ ▼ ▼ ▼ ▼ ┌────────┐ ┌────────┐ ┌────────┐ ┌──────────┐ │EJECUTOR│ │VIGILANTE│ │SANADOR│ │BITÁCORA │ │🛠️ │ │👁️ │ │🩹 │ │📝 │ │lanzar │ │flota │ │sanear │ │iniciar │ │ │ │salud │ │limpiar│ │finalizar │ └───┬────┘ └───┬────┘ └───┬────┘ └────┬─────┘ │ │ │ │ │ │ │ │ registra │ │ │ ▼ │ │ │ ┌─────────────┐ │ │ │ │bitacoras. │ │ │ │ │events │ │ │ │ └─────────────┘ │ │ │ │ │ └─→ Re-intenta (máx 3, backoff) │ │ │ └─→ Detecta zombies (heartbeat > 5min) │ Consolida en events │ └─→ Ejecuta cmd Heartbeat cada 30s Registra en dron_logs + events ``` ### Principios de Diseño | Principio | Aplicación | |-----------|------------| | **Single Responsibility** | Cada dron hace UNA cosa | | **Composability** | Drones se ensamblan en flujos | | **Event-Driven** | Comunicación vía cola de eventos | | **Stateless** | Drones no guardan estado (efímeros) | | **Observable** | Todo evento se registra en DB | --- ## 🔧 Componentes Implementados ### Base Compartido (`adn/tools/cli/dron/base.rb`) — Atomisidad | Componente | Propósito | |------------|-----------| | `Base.logger` | Logger único para todos los drones | | `Base.db_query` | Ejecuta SQL y retorna resultados | | `Base.db_exec` | Ejecuta SQL sin retornar resultados | | `Base.formato_duracion` | Formatea segundos a "Xmin Ys" | | `Base.slice_safe` | Slice seguro de strings (evita nil) | | `Base.blank?` | Verifica si string es nil/vacío | ### Ejecutor (`adn/tools/cli/dron/ejecutor.rb`) | Componente | Propósito | |------------|-----------| | `Ejecutor.lanzar` | Ejecuta comando, heartbeat, reporta resultado | | `Ejecutor#heartbeat` | Actualiza heartbeat cada 30s | | `Ejecutor#registrar_bitacora` | Crea/actualiza evento en bitácora | ### Vigilante (`adn/tools/cli/dron/vigilante.rb`) | Componente | Propósito | |------------|-----------| | `Vigilante.escanear_flota` | Lee dron_logs, muestra resumen | | `Vigilante.salud` | Health check, detecta zombies y anomalías | | `Vigilante.dashboard` | Dashboard compacto de la flota | | `Vigilante.consolidar_flujo` | Consolidar estado de flujo en events | ### Sanador (`adn/tools/cli/dron/sanador.rb`) | Componente | Propósito | |------------|-----------| | `Sanador.reintentar_fallidos` | Re-lanza failed (máx 3, backoff exponencial) | | `Sanador.limpiar_antiguos` | Elimina completados > N días | | `Sanador.sanear` | Saneamiento completo (reintentar + limpiar) | ### Bitácora (`adn/tools/cli/dron/bitacora.rb`) | Componente | Propósito | |------------|-----------| | `Bitacora.iniciar` | Crea evento `⏳` en bitácora | | `Bitacora.finalizar` | Actualiza evento con `✅` o `❌` | | `Bitacora.auto` | Modo AUTO: inicia, ejecuta, finaliza | ### Persistencia | Archivo/Tabla | Tipo | Propósito | Visibilidad | |---------|---------|-----------|-------------| | `bitacoras.dron_logs` | Tabla DB | Logs detallados de cada dron | 🔒 Interna | | `bitacoras.dron_avances` | Tabla DB | Progreso paso-a-paso de flujos | 🔒 Interna | | `bitacoras.dron_metricas` | Tabla DB | Agregaciones y estadísticas | 🔒 Interna | | `bitacoras.events` | Tabla DB | Eventos consolidados (resumen) | ✅ Bitácora Web | | `/tmp/dron_flota/*.json` | Archivo | Estado de drones activos (runtime) | 🔒 CLI | | `/tmp/dron_queue/*.json` | Archivo | Cola de eventos (por tipo) | 🔒 Drones | | `/tmp/dron_pheromones/` | Directorio | Señales químicas virtuales | 🔒 Drones | | `~/.claude/scheduled_tasks.json` | Archivo | Schedules persistentes (cron) | 🔒 Planificador | ### Modificar | Archivo | Cambio | |---------|--------| | `adn/tools/cli/dron.rb` | Refactorizar → dispatcher que importa módulos | | `adn/tools/run` | Registrar subcomandos: `dron lanzar`, `dron orquestar`, etc. | | `adn/tools/db/core/bitacora_db.rb` | Hook para eventos AUTO (dron_bitacora) | --- ## 📝 Comandos por Tipo de Dron ### Ejecutor ```bash # Lanzar tarea simple (auto-bitácora) ./adn/tools/run dron lanzar --evento AUTO --nota "Backup SQL" -- vzdump 103 # Lanzar sin registro (efímero) ./adn/tools/run dron lanzar --no-bitacora --nota "Test rápido" -- echo hola # Lanzar con timeout ./adn/tools/run dron lanzar --timeout 300 --nota "Sync larga" -- rclone sync ... ``` ### Orquestador (Composición) ```bash # Flujo secuencial (backup → sync → notificar) ./adn/tools/run dron orquestar \ --step "dron lanzar --nota 'Backup' -- vzdump 103" \ --step "dron lanzar --nota 'Sync' -- rclone sync /bkps oneDrive:" \ --step "dron notificar --msg 'Backup completado'" \ --on-error abort # Flujo paralelo (múltiples backups simultáneos) ./adn/tools/run dron orquestar \ --parallel \ --step "dron lanzar --nota 'Backup SQL' -- vzdump 103" \ --step "dron lanzar --nota 'Backup DC' -- vzdump 100" \ --step "dron lanzar --nota 'Backup PCV' -- vzdump 104" ``` ### Planificador (Cron) ```bash # Agendar backup nocturno ./adn/tools/run dron schedule add \ --cron "0 2 * * *" \ --cmd "dron lanzar --evento AUTO --nota 'Backup nocturno' -- ./adn/tools/run bkps run C4 --batch" # Listar schedules ./adn/tools/run dron schedule list # Eliminar schedule ./adn/tools/run dron schedule remove ``` ### Vigilante (Monitoreo) ```bash # Dashboard de flota ./adn/tools/run dron flota # Estado detallado de un dron ./adn/tools/run dron estado # Métricas históricas ./adn/tools/run dron metricas [--desde 2026-04-01] [--hasta 2026-04-07] ``` ### Sanador (Reparación) ```bash # Health check (detecta zombies) ./adn/tools/run dron salud # Reintentar fallidos ./adn/tools/run dron sanear --reintentar # Limpiar completados ./adn/tools/run dron limpiar --mayor-a 24h ``` ### Mensajero (Notificaciones) ```bash # Notificar por Slack ./adn/tools/run dron notificar --slack "#backups" "Backup completado ✅" # Notificar por email ./adn/tools/run dron notificar --email "admin@frlr.utn.edu.ar" "Alerta de fallo" ``` --- ## 🎯 Criterios de Éxito ### Atomicidad (Fase 1) - ✅ Cada dron tiene una única responsabilidad (Single Responsibility) - ✅ Sin código duplicado entre módulos - ✅ Tests independientes por tipo de dron ### Composición (Fase 2) - ✅ Flujos multi-paso se expresan como composición de drones - ✅ Orquestador permite secuencial/paralelo/condicional ### Inteligencia de Colmena (Fase 4) - ✅ Drones se comunican vía cola de eventos - ✅ Patrones de reacción emergen (failed → sanador → notificar) - ✅ Sin orquestador central para reacciones automáticas ### Observabilidad (Fase 5) - ✅ Dashboard web muestra estado en tiempo real - ✅ Histórico consultable vía CLI y web - ✅ Alertas proactivas ante anomalías --- ## 📚 Referencias ### Internas (ADN) - **Herramienta actual**: [`adn/tools/cli/dron.rb`](../../../adn/tools/cli/dron.rb) - **A01.P006**: [Sensor de Mejora Continua](./A01.P006_Sensor-de-Mejora-Continua.md) — Dron como evolución del sensor - **A01 (dtic-ADN)**: [Manifiesto de Ámbito](./A01_dtic-ADN.md) — Marco de trabajo - **adn/06_gobernanza.md**: [Principios Rectores](../../../adn/06_gobernanza.md) — Menos es Más ### Externas (Inspiración) - **Swarm Intelligence**: Comportamiento emergente en colonias de insectos - **Unix Philosophy**: "Do one thing and do it well" - **Microservices**: Servicios pequeños, composables, independientes - **Event-Driven Architecture**: Comunicación asíncrona vía eventos - **CronCreate**: SDK de Claude Code para schedules persistentes ### DB-First - Todas las métricas se almacenan en PostgreSQL (`bitacoras.dron_logs`) - Dashboard web consume API → DB --- ## 🔄 Armonía Integral **Última actualización**: 2026-04-09 — Auditoría + Fase 1.5 planificada | Documento | Estado | Notas | |-----------|--------|-------| | `A01_dtic-ADN.md` | 📍 Pendiente | Agregar A01.P009 a tabla de planes | | `adn/07_proyectos.md` | 📍 Pendiente | Referenciar nuevo plan | | `docs/contexto/IA.md` | 📍 Pendiente | Actualizar sección de drones | | `adn/06_gobernanza.md` | ✅ Alineado | Principio "Menos es Más" — AtomicDrones + Atomisidad | --- ## 📦 Entregables ### Fase 1 (Estructura atómica — con deuda técnica) | Archivo | Líneas | Descripción | Estado | |---------|--------|-------------|--------| | `adn/tools/cli/dron/base.rb` | 66 | Módulo compartido (atomisidad) | ✅ | | `adn/tools/cli/dron/dispatcher.rb` | 284 | Routing de subcomandos | ⚠️ B1 | | `adn/tools/cli/dron/ejecutor.rb` | 171 | Ejecutor atómico | ⚠️ B9, B11 | | `adn/tools/cli/dron/vigilante.rb` | 151 | Vigilante atómico | ⚠️ B10 | | `adn/tools/cli/dron/sanador.rb` | 85 | Sanador atómico | ⚠️ B6, B7, B8 | | `adn/tools/cli/dron/bitacora.rb` | 76 | Bitácora atómica | ✅ | | `adn/tools/db/core/dron_db.rb` | 351 | Acceso a datos DB | ⚠️ B2-B5 | | `adn/tools/db/migrations/003_create_dron_tables.rb` | 232 | Migración DB | ✅ | ### Fase 1.5 (Pendiente — Visibilidad + Corrección) Entregables esperados: - Corrección de los 12 bugs detectados - Heartbeat visible en Bitácora Web - Eliminación del sistema dual `.sh`/Ruby - Flujo ejecutor→events→web funcional y probado