--- id: "0068" title: "Cerrar bucle reactivo — fn-analizador (fase 4) y fn-mejorador (fase 5) con contrato e2e_checks" status: completado type: feature domain: - meta scope: multi-app priority: alta depends: [] blocks: [] related: - "22" - "23" - "0028" created: 2026-05-09 updated: 2026-05-17 tags: [] --- ## Cierre 2026-05-14 Toda infra implementada y operativa: - Migration `fn_operations/migrations/005_e2e_runs.sql` aplicada. - Funcion `e2e_run_checks_go_infra` (Cmd/Health/Ref con expect_exit/stdout_contains, background via `&`). Tipos `E2ECheck_go_infra` + `CheckResult_go_infra`. - Subagentes `fn-analizador` (Fase 4) y `fn-mejorador` (Fase 5) en `.claude/agents/`. - `fn-recopilador` extendido con modo `design-e2e `. - Skill `/validate-app ` orquesta cadena completa. - Regla `.claude/rules/e2e_validation.md` documenta contrato + patrones por stack. - Pilotos: `apps/kanban/app.md` y `projects/osint_graph/apps/graph_explorer/app.md` declaran `e2e_checks`. --- ## Contexto El bucle reactivo del registry (CONSTRUIR → EJECUTAR → RECOPILAR → ANALIZAR → MEJORAR) tiene agentes para fases 1-3: - **Fase 1 — CONSTRUIR**: `fn-constructor` (existe) - **Fase 2 — EJECUTAR**: `fn-executor` (existe) - **Fase 3 — RECOPILAR**: `fn-recopilador` (existe) - **Fase 4 — ANALIZAR**: falta agente - **Fase 5 — MEJORAR**: falta agente Sin fases 4 y 5 el bucle no cierra. Cada app sigue requiriendo iteracion manual: el humano lanza, mira, decide si funciona, y propone fixes. Objetivo: que apps lleguen a master correctas sin esa iteracion manual. ## Objetivo Disponer de un gate automatico pre-merge que valide end-to-end cualquier app del registry, y un mejorador que proponga cambios cuando la validacion falla. Capacidad reutilizable, no especifica de un proyecto. ## Diseno ### Contrato `e2e_checks` en `app.md` Cada app declara su validacion end-to-end en el frontmatter: ```yaml e2e_checks: - id: build cmd: "cd frontend && pnpm build && cd .. && CGO_ENABLED=1 go build -tags fts5 -o kanban ." timeout_s: 120 - id: smoke cmd: "./kanban --port 8095 --db /tmp/kanban_e2e.db &" health: "http://127.0.0.1:8095/api/board" timeout_s: 10 - id: ops_audit ref: "fn-recopilador:apps/kanban" - id: migrations cmd: "sqlite3 /tmp/kanban_e2e.db 'SELECT version FROM schema_migrations;'" expect_exit: 0 ``` Tipos de check: - `cmd` — comando shell, exit 0 = OK. - `health` — espera `cmd` en background, hace GET y verifica 200. - `ref` — apunta a otro agente/funcion del registry (ej. `fn-recopilador`, `fn-doctor`). - `expect_exit`, `expect_stdout_contains`, `expect_stdout_json` — predicados sobre la salida. ### fn-analizador (fase 4) Subagente nuevo. Input: `app_id`. Pasos: 1. Lee `e2e_checks` del `app.md`. 2. Ejecuta cada check en orden, captura stdout/stderr/exit/duration. 3. Eval assertions activas via `fn ops assertion eval --react`. 4. Compara `executions.metrics` actual vs ventana historica (drift > umbral = warning). 5. Diff golden outputs si app declara `tests/golden/`. 6. Persiste resultado en nueva tabla `e2e_runs` de `operations.db`. 7. Devuelve veredicto caveman: ``` build ✓ 42s smoke ✓ 0.8s ops_audit ✓ assertion:R1 ✗ warning duration drift +47% vs p50 ``` Tools: Read, Bash, Grep, Glob. Escribe SOLO `assertion_results`, `entity.status`, `e2e_runs`. NO toca registry.db. ### fn-mejorador (fase 5) Subagente nuevo. Input: salida de `fn-analizador` + `app_id`. Pasos: 1. Filtra fallos: `critical` → `kind=bug`, `warning` → `kind=optimization`. 2. Por cada fallo, busca contexto en registry: funciones tocadas, ultimas N proposals. 3. Crea proposal con `created_by=reactive_loop`, `evidence=[assertion_id, execution_id, e2e_run_id]`. 4. Sugiere fix concreto (parametro, funcion a partir, refactor) — texto, NO codigo. 5. Si fallo recurrente (>3 veces misma assertion) → `priority=high`. Tools: Read, Bash, Grep. Escribe SOLO `proposals` en registry.db. Nunca modifica funciones. ### Skill `/validate-app ` Orquesta cadena: `fn-executor` → `fn-recopilador` → `fn-analizador` → `fn-mejorador`. Devuelve tabla pass/fail + IDs de proposals creadas. ### Migracion `006_e2e_runs.sql` ```sql CREATE TABLE IF NOT EXISTS e2e_runs ( id TEXT PRIMARY KEY, app_id TEXT NOT NULL, started_at INTEGER NOT NULL, finished_at INTEGER, status TEXT NOT NULL, -- pass|fail|partial checks_total INTEGER NOT NULL, checks_pass INTEGER NOT NULL, checks_fail INTEGER NOT NULL, summary_json TEXT NOT NULL -- detalle por check ); CREATE INDEX IF NOT EXISTS e2e_runs_app_idx ON e2e_runs(app_id, started_at DESC); ``` ### Funciones nuevas del registry Delegables a `fn-constructor`: | ID | Domain | Que hace | |---|---|---| | `e2e_run_checks_go_infra` | infra | Ejecuta lista de checks, devuelve `[]CheckResult` | | `golden_diff_go_core` | core | Compara archivo vs golden con umbral | | `metrics_drift_go_datascience` | datascience | p50/p95 historico vs actual | | `proposal_from_failure_go_infra` | infra | Formatea evidencia → proposal | | `health_probe_go_infra` | infra | GET con timeout, retry, codigo esperado | Tipos: | ID | Que | |---|---| | `E2ECheck_go_infra` | struct check (id, cmd, ref, health, expect_*) | | `CheckResult_go_infra` | struct resultado (id, status, duration_ms, stdout, stderr, exit) | ### fn-recopilador como diseñador de checks `fn-recopilador` se extiende para **proponer e2e_checks por app** (modo design): - Inspecciona `app.md` (lang, framework, entry_point, uses_functions). - Detecta patrones conocidos: - Go service con frontend Vite → propone build (pnpm + go), smoke (puerto + endpoint health). - C++ ImGui app → propone build (cmake), smoke (`--self-test` o lanzar y matar tras N segundos). - Python pipeline → propone run con args dummy y verificar exit 0. - Audita `operations.db` y deriva `ops_audit` automatico. - Escribe propuesta en `app.md` como bloque `e2e_checks_suggested:` para que humano apruebe → renombre a `e2e_checks:`. Comando: `fn-recopilador design-e2e `. Asi `fn-analizador` recibe contratos completos de fabrica y solo necesita ejecutar. ## Plan de ejecucion | Paso | Tarea | Estado | |---|---|---| | 1 | Contrato `e2e_checks` en `docs/templates/app.md` + 2 apps piloto (kanban, graph_explorer) | en curso | | 2 | Funciones registry: `e2e_run_checks`, `golden_diff`, `metrics_drift`, `proposal_from_failure`, `health_probe` | pendiente | | 3 | Migracion `006_e2e_runs.sql` en `fn_operations/migrations/` | pendiente | | 4 | Subagente `fn-analizador` + skill `/validate-app` | pendiente | | 5 | Extender `fn-recopilador` con modo `design-e2e` | pendiente | | 6 | Subagente `fn-mejorador` | pendiente | | 7 | Gate opcional en `/git-push` para apps con `e2e_checks` declarado | pendiente | ## Criterios de aceptacion - [x] Template `docs/templates/app.md` con seccion `e2e_checks` documentada. - [x] `apps/kanban/app.md` declara `e2e_checks` (build_frontend + build_backend + smoke + tests + ops_audit). - [x] `projects/osint_graph/apps/graph_explorer/app.md` declara `e2e_checks` (build + self_test + pytest + enricher smoke). - [x] `fn-recopilador` puede sugerir `e2e_checks` para una app dada (modo `design-e2e`). - [x] `fn-analizador` corre los checks y devuelve veredicto caveman. - [x] `fn-mejorador` crea proposals con evidencia cuando hay fallos. - [x] Skill `/validate-app ` orquesta la cadena completa. - [x] Documentacion en `.claude/rules/e2e_validation.md`. ## Riesgos - **Golden tests para C++/UI son caros**. Empezar build+smoke+assertions; goldens solo donde aporten (graph_explorer ya tiene capture system). - **Apps sin operations.db** (kanban usa `kanban.db` propia, no `operations.db`). El check `ops_audit` debe aceptar BD alternativa o saltarse. - **Smoke tests con puertos en uso**. Los pilotos deben usar puertos efimeros (`--port 0` o range alto) y BDs en `/tmp/`. - **Adopcion gradual**. Apps sin `e2e_checks` no se validan (y no bloquean merge). Visible en `fn doctor`. ## Out of scope - Reemplazar `fn doctor` (que sigue siendo diagnostico read-only del estado). - Tests unitarios de funciones (siguen en `*_test.go`, `pytest`, etc.). - Performance benchmarks formales (los `metrics_drift` son aproximacion, no benchmark).