From 1d3d2f43b33c98e284ae43f91c891a97aec69241 Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Tue, 19 May 2026 00:43:09 +0200 Subject: [PATCH] feat(0121a): wave 2 e2e_checks proposals (8 apps) + README updated 8 fn-recopilador design-e2e paralelos: - services_api (Go service, schema custom operations.db) - registry_mcp (Go stdio MCP, JSON-RPC handshake test) - sqlite_api (Go service read-only HTTP, query_endpoint) - registry_dashboard (C++ ImGui, NO Go+React como yo supuse) - primitives_gallery (C++ build gate de toda API C++ del registry, 44 .cpp) - pipeline_launcher (Go TUI bubbletea) - docker_tui (Go TUI + go-duckdb) - fn_match (subcmd ./fn, hook helper, fuzzy match) 13/26 apps cubiertas. README documenta: - 6 bugs/drift descubiertos lateral (dag_engine x3, deploy_server, pipeline_launcher, docker_tui). - 3 correcciones de mi prompt (yo asumi stacks incorrectos). - Hallazgos arquitectonicos (primitives_gallery = build gate C++). Pendiente wave 3 (13 apps) + 0121b + 0121c. Co-Authored-By: Claude Opus 4.7 (1M context) --- dev/proposals_e2e_checks_0121/README.md | 55 +++++- dev/proposals_e2e_checks_0121/docker_tui.yaml | 132 +++++++++++++ dev/proposals_e2e_checks_0121/fn_match.yaml | 127 ++++++++++++ .../pipeline_launcher.yaml | 118 ++++++++++++ .../primitives_gallery.yaml | 148 ++++++++++++++ .../registry_dashboard.yaml | 181 ++++++++++++++++++ .../registry_mcp.yaml | 133 +++++++++++++ .../services_api.yaml | 130 +++++++++++++ dev/proposals_e2e_checks_0121/sqlite_api.yaml | 114 +++++++++++ 9 files changed, 1130 insertions(+), 8 deletions(-) create mode 100644 dev/proposals_e2e_checks_0121/docker_tui.yaml create mode 100644 dev/proposals_e2e_checks_0121/fn_match.yaml create mode 100644 dev/proposals_e2e_checks_0121/pipeline_launcher.yaml create mode 100644 dev/proposals_e2e_checks_0121/primitives_gallery.yaml create mode 100644 dev/proposals_e2e_checks_0121/registry_dashboard.yaml create mode 100644 dev/proposals_e2e_checks_0121/registry_mcp.yaml create mode 100644 dev/proposals_e2e_checks_0121/services_api.yaml create mode 100644 dev/proposals_e2e_checks_0121/sqlite_api.yaml diff --git a/dev/proposals_e2e_checks_0121/README.md b/dev/proposals_e2e_checks_0121/README.md index caa2cb01..351cd15b 100644 --- a/dev/proposals_e2e_checks_0121/README.md +++ b/dev/proposals_e2e_checks_0121/README.md @@ -1,8 +1,10 @@ # Propuestas e2e_checks — issue 0121a -Generadas por `fn-recopilador design-e2e` en wave 1, 2026-05-19. +Generadas por `fn-recopilador design-e2e` paralelo, 2026-05-19. -## Estado +## Estado (13/26 apps cubiertas) + +### Wave 1 (5 apps) | App | YAML | Lang | Stack | Checks | Severidad mix | Estado | |---|---|---|---|---|---|---| @@ -12,27 +14,64 @@ Generadas por `fn-recopilador design-e2e` en wave 1, 2026-05-19. | auto_metabase | [auto_metabase.yaml](auto_metabase.yaml) | py | httpx + CLI argparse | 4 | critical | propuesta | | dag_engine | [dag_engine.yaml](dag_engine.yaml) | go | net/http + vite/react + CGO+FTS5 | 6 | 5 critical + 1 warning | propuesta | -## Advertencias detectadas (laterales al objetivo) +### Wave 2 (8 apps) + +| App | YAML | Lang | Stack | Checks | Severidad mix | Estado | +|---|---|---|---|---|---|---| +| services_api | [services_api.yaml](services_api.yaml) | go | net/http + SSH cross-PC + sqlite custom schema | 6 | 3 critical + 3 warning | propuesta | +| registry_mcp | [registry_mcp.yaml](registry_mcp.yaml) | go | mcp-go stdio + CGO+FTS5 | 5 | 4 critical + 1 warning | propuesta | +| sqlite_api | [sqlite_api.yaml](sqlite_api.yaml) | go | net/http read-only + CGO+FTS5 | 7 | 4 critical + 2 warning + 1 (auth WIP) | propuesta | +| registry_dashboard | [registry_dashboard.yaml](registry_dashboard.yaml) | cpp | imgui + cpp-httplib + WS RFC6455 | 7 | 3 critical + 4 warning | propuesta | +| primitives_gallery | [primitives_gallery.yaml](primitives_gallery.yaml) | cpp | imgui + 44 .cpp registry (build gate de toda API C++) | 6 | 2 critical + 4 warning | propuesta | +| pipeline_launcher | [pipeline_launcher.yaml](pipeline_launcher.yaml) | go | bubbletea TUI + CGO+FTS5 | 5 | 3 critical + 2 warning | propuesta | +| docker_tui | [docker_tui.yaml](docker_tui.yaml) | go | bubbletea TUI + go-duckdb + docker CLI | 6 | 3 critical + 3 warning | propuesta | +| fn_match | [fn_match.yaml](fn_match.yaml) | go | subcmd de ./fn + FTS5 fuzzy match (hook helper) | 5 | 2 critical + 3 warning | propuesta | + +## Wave 3 (13 apps restantes, pendiente) + +apps/: +- altsnap_jitter_test, app_gestion, app_hub_launcher, footprint_geo_stack, metabase_registry, script_navegador, services_monitor, set_exe_icon, tables_qa, text_editor_smoke + +projects/*/apps/: +- element_agents/apps/element_matrix_chat, element_agents/apps/agents_and_robots, online_data_recopilation/apps/odr_console + +## Advertencias detectadas (laterales) + +### Bugs/drift descubiertos durante design-e2e - **dag_engine** — `apps/dag_engine/registry.db` (262 KB) viola `db_locations.md` (registry.db SOLO en raiz). Reaparicio tras borrado de 2026-05-16. Issue separado pendiente. - **dag_engine** — `pnpm build` roto por Mantine API drift (`StepTimeline.tsx:49` + `main.tsx:1`). Check `build_frontend` queda en `severity: warning` hasta arreglar. - **dag_engine** — falta flag `--migrate-only` en binario. Check `migrations_apply` usa `list` como proxy. - **deploy_server** — flag `--db` no expuesto en `cmdServe`. Check smoke usa BD por defecto del cwd hasta arreglar. +- **pipeline_launcher** — migracion `003_logs` falta en `operations.db`. Detectada por recopilador via PRAGMA table_info. +- **docker_tui** — `go.work` con path absoluto `/home/lucas/.local_agentes/backend` → build no portable. Check `build` queda en `severity: warning`. + +### Correcciones de stack en mis prompts (telemetria para mi) + +- **sqlite_api**: yo asumi Python, era Go. Recopilador corrigio. +- **registry_dashboard**: yo asumi Go+React+Vite, era C++ ImGui puro (cliente HTTP+WS). Recopilador corrigio + adapto checks. +- **fn_match**: yo asumi binario propio, es subcomando de `./fn`. Recopilador corrigio. + +## Hallazgos arquitectonicos + +- **primitives_gallery** es build gate de toda la API C++ del registry: 44 .cpp linkados (gfx + viz + core + 3d + sql + ...). Si una funcion C++ rompe su cabecera, falla aqui primero. Considerar moverlo a un job critico de CI. +- **services_api** usa schema custom en operations.db (no fn_operations standard: `service_state` + `service_transition`). `ops_audit` debe manejar schemas custom. +- **registry_mcp** test `mcp_handshake_stdio` arranca pipes in-process — replica el JSON-RPC que Claude Code usa al arrancar. Es el check de mayor valor por linea del wave 2. ## Siguiente paso -Wave 2 (16 apps restantes): app_gestion, app_hub_launcher, altsnap_jitter_test, docker_tui, fn_match, footprint_geo_stack, metabase_registry, pipeline_launcher, primitives_gallery, registry_mcp, script_navegador, services_api, services_monitor, set_exe_icon, tables_qa, text_editor_smoke + 5 en projects/*/apps (element_matrix_chat, agents_and_robots, sqlite_api, registry_dashboard, odr_console). +Wave 3 (13 apps restantes) → completar coverage propuestas. -Tras todas las propuestas → ejecutar 0121c: `/autonomous-task` por app aplicando el bloque al `app.md` correspondiente del sub-repo. +Despues: +- 0121b (`fn doctor e2e-coverage` via /autonomous-task tipo feature_app_simple) — apto para `/autopilot`. +- 0121c (aplicar propuestas: N /autonomous-task add_e2e_check) — paraleliza sub-repos. ## Como aplicar manualmente (sin orquestador) ```bash -# Editar el app.md del target cd apps/ -# Pegar el bloque e2e_checks: del yaml al frontmatter +# Pegar el bloque e2e_checks: del yaml al frontmatter de app.md $EDITOR app.md -# Commit en sub-repo git add app.md && git commit -m "feat: add e2e_checks (issue 0121)" git push ``` diff --git a/dev/proposals_e2e_checks_0121/docker_tui.yaml b/dev/proposals_e2e_checks_0121/docker_tui.yaml new file mode 100644 index 00000000..14c7cda1 --- /dev/null +++ b/dev/proposals_e2e_checks_0121/docker_tui.yaml @@ -0,0 +1,132 @@ +# e2e_checks proposal — docker_tui +# app_id: docker_tui +# lang: go +# stack: Bubble Tea (charmbracelet/bubbletea) + lipgloss + devfactory TUI framework +# dir_path: apps/docker_tui +# date: 2026-05-19 +# issue: 0121a wave 2 +# +# Generado por fn-recopilador modo design-e2e. +# NO copiar directamente al app.md — requiere revision humana (mismo flujo que proposals). +# +# --------------------------------------------------------------------------- +# DIAGNOSTICO +# --------------------------------------------------------------------------- +# lang=go, framework=bubbletea, entry_point=main.go +# Sin tests: no hay *_test.go en ningún paquete. +# Sin --help ni --version: el binario es TUI pura, requiere TTY. +# - timeout 2s ./docker-tui --help → exit 1 + "could not open a new TTY" +# - Eso es el comportamiento esperado de CI: sin TTY el proceso sale con error. +# CGO requerido: la dependencia devfactory (go.work local path +# /home/lucas/.local_agentes/backend) declara go-duckdb v1.6.5 que usa CGO. +# go vet pasa con CGO_ENABLED=1. Build sin CGO no es posible por la dep transitiva. +# Docker CLI: toda la logica llama al binario `docker` via shell.RunWithTimeout. +# No usa SDK de Docker ni abre /var/run/docker.sock directamente. +# Al fallar la invocación (socket ausente, daemon parado) devuelve error que +# la vista TUI muestra en pantalla — no hay panic ni exit(1). +# operations.db presente: 4 migraciones aplicadas (001-004). Sin entidades ni +# ejecuciones aun — la app es nueva (v0.1.0). Incluir ops_audit igualmente. +# go.work: referencia path absoluto /home/lucas/.local_agentes/backend. +# El build en CI necesita que ese path exista, o reemplazar con GOFLAGS/replace +# en el Makefile. El check build puede fallar en CI remoto si el path no monta. +# Se marca severity: warning para no bloquear gate mientras no hay CI remoto. +# --------------------------------------------------------------------------- + +e2e_checks_suggested: + + - id: build + # CGO_ENABLED=1 obligatorio — devfactory backend tiene go-duckdb (CGO). + # go.work en la raiz del app resuelve el replace local automaticamente. + # El binario resultante es ~42 MB con trimpath+ldflags. + cmd: "cd apps/docker_tui && CGO_ENABLED=1 go build -trimpath -ldflags='-s -w' -o /tmp/docker_tui_e2e ." + timeout_s: 120 + severity: warning + # warning porque el build depende de /home/lucas/.local_agentes/backend + # (path absoluto en go.work). En CI remoto puede no existir; pendiente + # resolver via GOFLAGS o módulo publicado en Gitea. + + - id: vet + # go vet detecta errores estaticos sin necesitar TTY ni docker daemon. + # Pasa con CGO_ENABLED=1 segun verificacion directa. + cmd: "cd apps/docker_tui && CGO_ENABLED=1 go vet ./..." + timeout_s: 60 + + - id: no_tty_exits_cleanly + # TUI pura sin --help. En ausencia de TTY (CI headless), el binario debe + # salir con exit != 0 y escribir un mensaje de error legible en stderr. + # Verificamos que: + # 1. Sale antes del timeout (no se queda colgado esperando input). + # 2. El stderr contiene "TTY" (mensaje de error conocido del framework). + # expect_exit: 1 porque tui.RunFullscreen devuelve error cuando no hay TTY. + cmd: "timeout 5s /tmp/docker_tui_e2e 2>&1 || true" + expect_stdout_contains: "TTY" + expect_exit: 0 + # expect_exit 0 porque usamos '|| true' para capturar stdout/stderr y + # verificar el mensaje. La condicion real es stdout_contains "TTY". + timeout_s: 10 + + - id: docker_cli_present + # Verifica que el binario docker esta en PATH antes de intentar operaciones. + # Sin docker instalado, todas las vistas muestran error — la TUI sigue + # funcionando (no crashea), pero el check avisa al operador en CI. + cmd: "docker --version" + expect_stdout_contains: "Docker version" + timeout_s: 5 + + - id: docker_socket_optional + # Simula socket de Docker ausente. Verifica que el CLI reporta el error + # correctamente y sale con codigo != 0 (comportamiento esperado). + # Este check es diagnostic: confirma que cuando el daemon no esta disponible + # el codigo de error es coherente. La TUI lo maneja gracefully (muestra + # el error en la lista en lugar de crashear). + cmd: "DOCKER_HOST=unix:///tmp/nonexistent_docker_e2e.sock docker ps 2>&1" + expect_stdout_contains: "failed to connect" + expect_exit: 0 + # expect_exit 0 porque la shell captura el stderr via 2>&1 y el check + # evalua stdout_contains. La condicion real es que docker reporta el error. + severity: warning + timeout_s: 5 + + - id: ops_audit + # operations.db presente con 4 migraciones aplicadas. + # Sin entidades aun (app nueva v0.1.0) — el audit valida que el schema + # esta completo y no hay referencias rotas. + ref: "fn-recopilador:apps/docker_tui" + +# --------------------------------------------------------------------------- +# JUSTIFICACION +# --------------------------------------------------------------------------- +# | check | razon | +# |------------------------|--------------------------------------------------| +# | build | CGO requerido por devfactory/go-duckdb. Sin | +# | | build verificado no hay binario que testear. | +# | | severity:warning por dependencia path absoluto. | +# | vet | Analisis estatico sin TTY ni daemon. Detecta | +# | | bugs de tipos y contextos antes de runtime. | +# | no_tty_exits_cleanly | CI es headless. Verificar que el binario sale | +# | | con error legible (no se cuelga) es el unico | +# | | gate posible para una TUI sin --self-test. | +# | docker_cli_present | Toda la logica wrappea el CLI `docker`. Si no | +# | | esta en PATH, las vistas muestran error pero | +# | | la causa raiz debe detectarse en CI. | +# | docker_socket_optional | Documenta el comportamiento cuando el daemon | +# | | no esta. La TUI debe degradar gracefully, no | +# | | crashear. severity:warning — ambiente dependiente.| +# | ops_audit | operations.db existe, 4 migraciones aplicadas. | +# | | Audita schema completo y coherencia de datos | +# | | (aunque este vacio en v0.1.0). | +# --------------------------------------------------------------------------- +# +# CHECKS OMITIDOS y razon: +# - tests: no hay *_test.go. Proponer agregar tests unitarios para +# views/docker.go (parseJSONLines, helpers) — candidato a issue futuro. +# - smoke con health URL: TUI sin servidor HTTP. No aplica. +# - --self-test flag: no implementado. Podria anadirse al main.go para +# verificar build de modelos sin lanzar el loop de bubbletea. +# - build_frontend: no hay frontend web. No aplica. +# +# NOTA CRITICA — go.work con path absoluto: +# El replace en go.work apunta a /home/lucas/.local_agentes/backend. +# Para que el check `build` funcione en cualquier maquina/CI, pendiente +# publicar devfactory como modulo en Gitea o agregar GONOSUMCHECK + replace +# via GOFLAGS. Hasta entonces build=warning, no critical. diff --git a/dev/proposals_e2e_checks_0121/fn_match.yaml b/dev/proposals_e2e_checks_0121/fn_match.yaml new file mode 100644 index 00000000..c0bbf55d --- /dev/null +++ b/dev/proposals_e2e_checks_0121/fn_match.yaml @@ -0,0 +1,127 @@ +# e2e_checks proposal — fn_match +# +# app_id: fn_match +# lang: go +# stack: hook helper — subcomando de fn CLI (cmd/fn/match.go), CGO+FTS5, +# reads registry.db read-write-open (WAL visibility), no service, +# invocado por PreToolUse hook en cada comando Bash interceptado +# date: 2026-05-19 +# issue: 0121a wave 2 (design-e2e fn-recopilador) +# +# Diagnostico del stack: +# - entry_point: cmd/fn/match.go — NO es un binario separado. Es el subcomando +# `fn match` del CLI principal compilado con `CGO_ENABLED=1 go build -tags fts5`. +# El binario resultante vive en la raiz del repo como `./fn`. +# - sin framework: proceso one-shot, sin servidor HTTP, sin health endpoint. +# - CGO_ENABLED=1 obligatorio (mattn/go-sqlite3 + FTS5 virtual table). +# - Lee registry.db abriendo conexion normal (no ?mode=ro) porque bm25() con +# WAL no checkpointed falla con "missing row from content table" en modo ro. +# Gotcha documentado en app.md. +# - no hay *_test.go especifico para match.go — solo cmd_vault_test.go en el +# mismo package. Check "tests" incluye vault tests (go test ./cmd/fn/...). +# - sin operations.db ni e2e_runs history => ops_audit omitido. +# - Performance critica: hook llama `fn match` en cada Bash command del agente. +# Latencia medida: 7-9ms en WSL2 (1255 funciones indexadas). Objetivo: <200ms. +# - high_confidence gate real del hook: raw_score >= 4.0 Y gap top1/top2 > 1.5 +# en raw scores. El normalizado siempre devuelve 1.0 para el top — no sirve +# como gate de confianza absoluto. +# +# Instrucciones de adopcion: +# 1. Copiar el bloque "e2e_checks:" al frontmatter de apps/fn_match/app.md +# (despues del bloque de params/output y antes de "## Ejemplo"). +# 2. Los checks asumen que ./fn existe en la raiz del repo. Si no: +# ejecutar primero el check "build" manualmente. +# 3. El check "latency_under_200ms" puede variar en CI (disco lento, cold start). +# Si falla consistentemente en CI pero pasa local, bajar a severity: warning. +# 4. El check "match_known_pattern" usa una consulta que produce deploy_cpp_exe_to_windows_bash_infra +# como top hit. Si esa funcion se renombra o borra, el check falla — actualizar +# expect_stdout_contains con el nuevo ID. +# +# Verificacion previa de las queries usadas en los checks (2026-05-19): +# $ ./fn match "taskkill.exe /IM registry_dashboard.exe /F" --format text +# [1.000] deploy_cpp_exe_to_windows_bash_infra raw=4.06 high_confidence=false +# $ ./fn match "echo hola" +# top: 3 hits, todos raw ~0.208 (< 4.0), high_confidence=false +# $ ./fn match "echo hola" | latency: 7-9ms +# +# NOTA: NO escribir directo al app.md — propuesta para revision humana. + +e2e_checks: + # --- build --- + # Compila el subcomando fn match (y todo el CLI) con CGO+FTS5. + # fn match no es binario separado: vive en cmd/fn/ junto al resto del CLI. + # El binario resultante es ./fn en la raiz del repo. + - id: build + cmd: "CGO_ENABLED=1 go build -tags fts5 -o fn ./cmd/fn/" + timeout_s: 120 + severity: critical + # por que: match.go usa go-sqlite3 (CGO) y FTS5 virtual tables. Sin -tags fts5 + # el indice FTS5 de registry.db no esta disponible y bm25() falla en runtime. + # Fallo de build indica dep rota o cambio de API en cmd/fn/main.go. + + # --- tests --- + # Corre el unico test suite del package cmd/fn (cmd_vault_test.go). + # No hay match_test.go dedicado — los tests de integracion del subcomando + # match estan cubiertos por match_known_pattern y match_no_false_positive abajo. + - id: tests + cmd: "CGO_ENABLED=1 go test -tags fts5 -count=1 ./cmd/fn/..." + timeout_s: 120 + severity: warning + # por que: los vault tests validan la plomeria del CLI (build, flags, JSON output). + # Severity warning porque no hay test unitario de match.go; si se anade + # match_test.go en el futuro, ascender a critical. + + # --- match_known_pattern --- + # Ejecuta fn match con un patron conocido que debe producir un hit de alta + # confianza. Usa "taskkill.exe /IM registry_dashboard.exe /F" porque: + # - token "taskkill" es un bashMarker (penaliza hits Python/bash cruzados) + # - "dashboard" y "exe" son tokens especificos con matches en el registry + # - resultado esperado top[0] = deploy_cpp_exe_to_windows_bash_infra (raw=4.06) + # Verifica que el pipeline de tokenize + FTS5 + scoring funciona end-to-end. + - id: match_known_pattern + cmd: "./fn match \"taskkill.exe /IM registry_dashboard.exe /F\"" + expect_stdout_contains: "deploy_cpp_exe_to_windows_bash_infra" + timeout_s: 15 + severity: critical + # por que: si este check falla, el hook PreToolUse no puede sugerir alternativas + # del registry para comandos taskkill — uno de los patrones mas comunes en + # sesiones de deploy C++. Indica regresion en tokenizer, FTS5 query builder, + # o scoring. También detecta si la funcion fue renombrada/borrada del registry. + + # --- match_no_false_positive --- + # Verifica que un comando trivial sin equivalente en el registry NO produce + # un hit de alta confianza. "echo hola" devuelve 3 hits con raw_score ~0.208 + # (todos < 4.0, threshold de high_confidence) y high_confidence=false. + # El hook solo inyecta un hint cuando high_confidence=true — esto valida que + # no hay spam de sugerencias para comandos inocuos. + - id: match_no_false_positive + cmd: "./fn match \"echo hola\"" + expect_stdout_contains: '"high_confidence": false' + timeout_s: 10 + severity: warning + # por que: un false positive en el hook interrumpe el flujo del agente con + # sugerencias irrelevantes. Severity warning porque la penalizacion es UX, + # no correctitud. Si el registro crece con funciones de "echo" / logging + # y el raw_score sube por encima de 4.0, revisar umbral minRawForHighConf + # en cmd/fn/match.go (actualmente 4.0). + + # --- latency_under_200ms --- + # Mide que una invocacion de fn match completa en < 200ms (proceso fresh, + # sin daemon). El objetivo documentado es < 50ms (medido 7-9ms en WSL2). + # El threshold de 200ms da margen para CI mas lento y disco frio. + # Se usa el patron known (taskkill) para medir un caso real con FTS5 activo. + - id: latency_under_200ms + cmd: > + START=$(date +%s%3N) && + ./fn match "taskkill.exe /IM registry_dashboard.exe /F" > /dev/null && + END=$(date +%s%3N) && + MS=$((END - START)) && + echo "latency=${MS}ms" && + [ "$MS" -lt 200 ] + timeout_s: 10 + severity: warning + # por que: fn match es llamado por el hook PreToolUse en CADA comando Bash + # del agente. Si la latencia supera 200ms, el hook se convierte en friccion + # perceptible (~40% del round-trip tipico de 500ms). Severity warning porque + # el threshold es conservador (10x el valor medido); solo alarma si hay + # regresion grave (disco frio, WAL grande no checkpointed, CGO rebuild). diff --git a/dev/proposals_e2e_checks_0121/pipeline_launcher.yaml b/dev/proposals_e2e_checks_0121/pipeline_launcher.yaml new file mode 100644 index 00000000..f231f955 --- /dev/null +++ b/dev/proposals_e2e_checks_0121/pipeline_launcher.yaml @@ -0,0 +1,118 @@ +# Propuesta e2e_checks para apps/pipeline_launcher +# Generada por fn-recopilador en modo design-e2e (2026-05-19) +# app_id: pipeline_launcher +# lang: go +# stack: TUI bubbletea + CGO + mattn/go-sqlite3 +# issue: 0121a wave 2 +# +# INSTRUCCIONES: copiar el bloque e2e_checks al frontmatter de +# apps/pipeline_launcher/app.md tras revision humana. +# NO modificar app.md automaticamente. +# +# Stack detectado: +# lang=go, framework=bubbletea v0.25.0 +# CGO_ENABLED=1 (mattn/go-sqlite3 v1.14.37 en go.mod) +# build tags: fts5 necesarios (importa fn-registry que usa fts5) +# NO frontend/ (TUI pura, sin assets web) +# NO tests/ ni *_test.go (check tests OMITIDO) +# entry_point: main.go → binario: pipeline_launcher +# config.Default() resuelve rutas via FN_REGISTRY_ROOT env var +# Sin flags --headless, --list, --version ni --help propios en main.go +# (la app es TUI pura; la unica salida "rapida" es abrir + cerrar con Ctrl+C) +# operations.db presente: tablas init (sin logs — migracion 003 NO aplicada) +# entities=0, relations=0, executions=0, assertions=0 +# registry.db: 30 pipelines con tag 'launcher' disponibles al momento de audit +# +# NOTAS IMPORTANTES: +# - La app no expone ningun modo headless ni flag CLI propio. Para un check +# "arranca bien y ve pipelines", la estrategia es: (a) go vet (compilacion +# y lint sin ejecutar TUI) + (b) query directa a registry.db via sqlite3 +# para verificar que existen pipelines con tag launcher (lo que la TUI +# mostraria). No se ejecuta el binario en modo TUI porque requiere TTY. +# - El check ops_init aplica las migraciones faltantes (especialmente 003_logs) +# sobre operations.db de e2e en /tmp, garantizando schema completo. +# - ops_audit invoca fn-recopilador sobre la operations.db real para validar +# integridad. Util como gate de regresion de schema/datos. +# - No hay tag 'service' → no se necesita smoke/health check HTTP. +# - Port e2e: N/A (no es service). + +e2e_checks: + # ----------------------------------------------------------------------- + # check: build + # Por que: gate primario. Valida que el modulo Go compila con CGO+fts5. + # CGO es obligatorio por mattn/go-sqlite3. fts5 es necesario + # porque el modulo fn-registry (replace local) usa FTS5 en sus + # queries sobre registry.db. Sin este tag el build falla con + # "undefined: fts5". + # El binario se escribe en /tmp para no contaminar el worktree + # y hacer el check idempotente. + # ----------------------------------------------------------------------- + - id: build + cmd: "cd /home/lucas/fn_registry/apps/pipeline_launcher && CGO_ENABLED=1 go build -tags fts5 -o /tmp/pipeline_launcher_e2e_bin ." + timeout_s: 120 + + # ----------------------------------------------------------------------- + # check: vet + # Por que: go vet con CGO+fts5 detecta errores semanticos que no bloquean + # la compilacion pero indican bugs (printf de tipo incorrecto, + # locks copiados, etc.). Complementa build — bajo coste, alta + # cobertura estatica. + # Se corre sobre el modulo completo (./...) para cubrir app/, + # config/ y views/ que el build check no ejercita separadamente. + # ----------------------------------------------------------------------- + - id: vet + cmd: "cd /home/lucas/fn_registry/apps/pipeline_launcher && CGO_ENABLED=1 go vet -tags fts5 ./..." + timeout_s: 60 + + # ----------------------------------------------------------------------- + # check: pipelines_list_loads + # Por que: valida la query central de la TUI — que registry.db contiene + # >=1 pipeline con tag 'launcher'. Si este check falla, la pantalla + # principal de la app mostraria "No pipelines found" que es el caso + # de fallo silencioso mas dificil de detectar sin correr la TUI. + # Query: buscar en functions donde kind='pipeline' y tags incluye + # 'launcher'. Equivalent a loadPipelines() en views/pipelines.go. + # No requiere el binario compilado — usa sqlite3 CLI directamente + # sobre registry.db (ya autorizado para queries en operations.db + # y uso diagnostico segun excepciones de registry_calls.md). + # ----------------------------------------------------------------------- + - id: pipelines_list_loads + cmd: > + COUNT=$(sqlite3 /home/lucas/fn_registry/registry.db + "SELECT COUNT(*) FROM functions WHERE kind='pipeline' AND tags LIKE '%launcher%';"); + [ "$COUNT" -ge 1 ] && echo "launcher_pipelines=$COUNT OK" || { echo "FAIL: no launcher pipelines found in registry.db"; exit 1; } + timeout_s: 10 + expect_stdout_contains: "OK" + + # ----------------------------------------------------------------------- + # check: ops_schema_complete + # Por que: la operations.db de pipeline_launcher no tiene la tabla logs + # (migracion 003_logs NO aplicada al momento de la auditoria). + # Este check aplica fn ops init sobre una copia en /tmp para + # verificar que las 3 migraciones (001_init, 002_executions_assertions, + # 003_logs) se aplican limpiamente sin errores. + # Idempotente: crea DB nueva en /tmp cada vez. + # ----------------------------------------------------------------------- + - id: ops_schema_complete + cmd: > + rm -f /tmp/pipeline_launcher_e2e_ops.db && + cp /home/lucas/fn_registry/apps/pipeline_launcher/operations.db /tmp/pipeline_launcher_e2e_ops.db && + FN_REGISTRY_ROOT=/home/lucas/fn_registry /home/lucas/fn_registry/fn ops init /tmp/pipeline_launcher_e2e_ops.db && + sqlite3 /tmp/pipeline_launcher_e2e_ops.db "SELECT name FROM sqlite_master WHERE type='table' AND name='logs';" | grep -q logs && echo "logs table OK" || { echo "FAIL: logs table missing after ops init"; exit 1; } + timeout_s: 30 + expect_stdout_contains: "logs table OK" + severity: warning + # NOTA: severity warning porque la migracion faltante no bloquea el uso + # normal de la TUI (no escribe logs todavia). Promover a critical cuando + # la app comience a usar la tabla logs activamente. + + # ----------------------------------------------------------------------- + # check: ops_audit + # Por que: invoca fn-recopilador sobre la operations.db real para detectar + # referencias rotas, tablas faltantes o datos inconsistentes. + # Es el gate del bucle reactivo fase 3 — sin este check el agente + # no tiene visibilidad sobre regresiones de schema/datos entre + # versiones del app. + # ----------------------------------------------------------------------- + - id: ops_audit + ref: "fn-recopilador:apps/pipeline_launcher" diff --git a/dev/proposals_e2e_checks_0121/primitives_gallery.yaml b/dev/proposals_e2e_checks_0121/primitives_gallery.yaml new file mode 100644 index 00000000..d58a72fd --- /dev/null +++ b/dev/proposals_e2e_checks_0121/primitives_gallery.yaml @@ -0,0 +1,148 @@ +# Propuesta e2e_checks para apps/primitives_gallery +# Generado por fn-recopilador modo design-e2e +# Issue: 0121a wave 2 +# Fecha: 2026-05-19 +# +# Diagnostico: +# lang=cpp, framework=imgui (fn::run_app), domain=gfx +# toolchain: mingw-w64 (cross-compile Windows desde WSL) +# modulos: main.cpp + capture.cpp + demo.cpp + 12 demos_*.cpp +# + 44 .cpp del registry (core + viz + gfx — el set mas grande del ecosistema) +# demos catalogadas: 43 entradas en k_demos[] (k_demo_count = 43) +# Core (20): button, icon_button, toolbar, modal_dialog, text_input, select, toast, +# tree_view, badge, empty_state, page_header, dashboard_panel, kpi_card, +# text_editor, file_watcher, process_runner, tween, bezier_editor, +# timeline, sql_workbench +# Viz (20): bar_chart, pie_chart, line_plot, scatter_plot, histogram, sparkline, +# graph_viewport, graph_styles, candlestick, gauge, heatmap, table_view, +# surface_plot_3d, scatter_3d, mesh_viewer, treemap, sankey, chord, +# contour, voronoi +# Gfx (3): shader_canvas, gl_texture, gl_info +# deps externas: SQLite::SQLite3, stb (vendor), imgui_text_edit (vendor) +# persistencia propia: ninguna (no BD, no state files) +# sin tests/ ni tests_*.py +# sin tag 'service': no expone HTTP (smoke con health: OMITIDO) +# operations.db: NO usa (ops_audit: OMITIDO) +# +# FLAG --capture: +# Confirmado en main.cpp (L186-215): rama headless que crea ventana GLFW +# GLFW_VISIBLE=FALSE + GL 3.3 core (deliberadamente baja para WSL Mesa/llvmpipe). +# Requiere contexto OpenGL real. En WSL sin GPU: LIBGL_ALWAYS_SOFTWARE=1 (Mesa). +# En WSL sin display (headless puro): GLFW requiere $DISPLAY o EGL offscreen. +# La severidad de capture_mode se marca WARNING (no critical) porque WSL2 sin +# libGL Mesa puede no entregar contexto GL valido — el check diagnostica pero +# no bloquea el build gate si el entorno no tiene driver GL. +# +# FLAG --list-demos: NO existe. main.cpp no tiene subcomando de listado. +# demos_count: OMITIDO — no hay forma de obtener el conteo sin invocar GL. +# Alternativa implementada: demos_count_static verifica el conteo en fuente. +# +# Patron: C++ ImGui app con modo --capture headless-GL + +app_id: primitives_gallery + +e2e_checks: + # Build del target completo para Windows via mingw-w64. + # primitives_gallery es el artefacto con mayor numero de .cpp del registry + # enlazados (44 archivos: core + viz + gfx). Si cualquier funcion del registry + # rompe su API de compilacion, este check lo detecta antes de que otro app falle. + # Actua como build gate del registry de funciones C++. + - id: build + cmd: "cmake --build /home/lucas/fn_registry/cpp/build/windows --target primitives_gallery -j" + timeout_s: 300 + severity: critical + + # Verifica que el artefacto .exe existe tras el build. + # El build puede reportar exit 0 con -j en builds parciales sin producir binario. + # Sin este check, capture_mode fallaria con un mensaje de error menos claro. + - id: binary_exists + cmd: "test -f /home/lucas/fn_registry/cpp/build/windows/apps/primitives_gallery/primitives_gallery.exe" + timeout_s: 5 + severity: critical + + # Modo --capture headless: crea ventana GLFW VISIBLE=FALSE + GL 3.3 core, + # renderiza las 43 demos en offscreen framebuffer y guarda PNG en /tmp/. + # Confirma que: (a) todas las demos compilan y se ejecutan sin crash, + # (b) el pipeline capture.cpp funciona hasta stbi_write_png, + # (c) ninguna demo provoca SIGSEGV/assertion al primer frame (warmup=3). + # + # Requiere contexto OpenGL real. En WSL sin GPU usar: + # LIBGL_ALWAYS_SOFTWARE=1 (Mesa/llvmpipe) — disponible si mesa-utils instalado. + # Si el entorno no puede entregar GL context, glfwCreateWindow retorna NULL y + # el binario sale con exit 1 (ver capture.cpp L62-68). + # Marcado WARNING porque la disponibilidad de GL en CI/WSL headless no esta + # garantizada sin configuracion extra del entorno. + # + # El check verifica que se genero al menos un PNG (button.png es el primero). + # Una suite completa de 43 PNGs indica que todas las demos son estables. + - id: capture_mode + cmd: > + mkdir -p /tmp/primitives_gallery_e2e && + /home/lucas/fn_registry/cpp/build/windows/apps/primitives_gallery/primitives_gallery.exe + --capture /tmp/primitives_gallery_e2e + timeout_s: 120 + severity: warning + # Nota: en WSL2 sin GPU puede necesitar LIBGL_ALWAYS_SOFTWARE=1 prefijado. + # Si el entorno tiene Mesa: prepend "LIBGL_ALWAYS_SOFTWARE=1" al cmd. + # Sin GL disponible, la demo gl_info y shader_canvas pueden fallar pero + # las demas (Core/Viz) deben seguir siendo capturadas si GL 3.3 esta disponible. + + # Verifica que el capture produjo PNGs para las 43 demos catalogadas en k_demos[]. + # Cada demo debe generar un PNG nombrado por su id (ej. button.png, bar_chart.png). + # Este check distingue "capture arranco y capturo algo" (capture_mode) de + # "capture completo todas las demos sin skip". Se puede ejecutar solo si + # capture_mode paso. + # Cuenta archivos .png en el dir de salida y compara con k_demo_count=43. + - id: capture_completeness + cmd: > + count=$(ls /tmp/primitives_gallery_e2e/*.png 2>/dev/null | wc -l); + echo "PNG count: $count"; + test "$count" -ge 43 + timeout_s: 10 + severity: warning + # Nota: depende de capture_mode. Si capture_mode fallo por falta de GL, + # este check tambien fallara (warning, no bloquea gate). + + # Verifica que el .ico esta presente junto al fuente de la app. + # add_imgui_app genera primitives_gallery_appicon.rc que windres incluye + # como recurso (.rsrc) en el .exe. Si appicon.ico falta, el build pasa + # pero el .exe queda sin icono embebido (visible en Explorer + taskbar). + - id: icon_exists + cmd: "test -f /home/lucas/fn_registry/apps/primitives_gallery/appicon.ico" + timeout_s: 5 + severity: warning + + # Verifica estaticamente que el conteo de demos en fuente es consistente. + # k_demo_count se deriva de sizeof(k_demos)/sizeof(k_demos[0]) en main.cpp. + # Cuenta las entradas de DemoEntry en k_demos[] usando grep en main.cpp + # como proxy — detecta si se añadio una demo al array pero no al modulo + # demos_*.cpp (lo que provocaria un linker error en build, pero este check + # da feedback mas temprano en el ciclo). + # Referencia esperada: 43 entradas (conteo manual de k_demos[] en main.cpp L37-84). + - id: demos_count_static + cmd: > + count=$(grep -c '^\s*{"' /home/lucas/fn_registry/apps/primitives_gallery/main.cpp); + echo "DemoEntry count in source: $count"; + test "$count" -ge 43 + timeout_s: 5 + severity: warning + # Nota: el grep cuenta lineas con '{"' en main.cpp — patron exclusivo de las + # entradas de k_demos[]. Si el formato de k_demos[] cambia, revisar el patron. + +# Justificacion por check: +# | check | razon | +# |----------------------|----------------------------------------------------------------------------| +# | build | 44 .cpp del registry enlazados — build gate de API C++ del registry entero | +# | binary_exists | confirma que cmake produjo .exe (no solo exit 0) | +# | capture_mode | --capture es headless-GL (GLFW invisible + GL 3.3); confirma no-crash 43 | +# | capture_completeness | distingue "algo capturado" de "todas las demos completas" | +# | icon_exists | .ico requerido para windres embeds — faltante no rompe build pero si deploy | +# | demos_count_static | detecta drift entre k_demos[] en fuente y modulos demos_*.cpp | +# +# checks OMITIDOS y razon: +# | check | razon de omision | +# |-------------|-----------------------------------------------------------------------------| +# | ops_audit | no usa operations.db | +# | smoke/health | no es service, no expone HTTP | +# | demos_count | --list-demos no existe en el binario; no hay forma headless sin GL | +# | self_test | fn::run_app no parsea --self-test; no implementado en main.cpp | diff --git a/dev/proposals_e2e_checks_0121/registry_dashboard.yaml b/dev/proposals_e2e_checks_0121/registry_dashboard.yaml new file mode 100644 index 00000000..c3bf85e0 --- /dev/null +++ b/dev/proposals_e2e_checks_0121/registry_dashboard.yaml @@ -0,0 +1,181 @@ +# e2e_checks proposal — registry_dashboard +# +# app_id: registry_dashboard +# lang: cpp +# stack: C++ ImGui (fn::run_app), SQLite directo + HTTP client (cpp-httplib) + +# WebSocket client (ws_client.cpp RFC6455), nlohmann/json, +# datos de registry.db via sqlite_api:8484 (fallback SQLite directo) +# date: 2026-05-19 +# issue: 0121a wave 2 (design-e2e fn-recopilador) +# +# Diagnostico del stack: +# - app.md: lang=cpp, framework=imgui, domain=tui, NO tiene tag 'service' +# - La app es un CLIENTE, no un servidor: no expone puerto propio. +# El puerto 8484 es de sqlite_api (dependencia externa), no de este binario. +# - entry_point: main.cpp -> fn::run_app(cfg, render) -> GUI loop +# - build: cmake --build cpp/build/linux --target registry_dashboard +# (el binario queda en cpp/build/linux/apps/registry_dashboard) +# En Windows: cpp/build/windows/apps/registry_dashboard.exe (cross-compile MinGW) +# - NO tiene --self-test implementado (sin argparse headless en main.cpp) +# - NO hay *_test.cpp ni tests/ con pytest en la app +# - NO hay frontend/ React/Vite (es C++ puro con ImGui, no Go+frontend) +# - NO tiene operations.db propia (usa registry.db via API o directo) +# - SIN health endpoint (no es service, no expone HTTP) +# - vendor/: solo nlohmann/json.hpp (cpp-httplib via vendor/httplib.h) +# - build Linux ya disponible: cpp/build/linux/apps/registry_dashboard +# - build Windows ya disponible: cpp/build/windows/apps/registry_dashboard.exe +# +# IMPORTANTE — por que no hay check "smoke" ni "api_endpoint_kpi": +# registry_dashboard no es un servidor — es una app GUI que CONSUME datos. +# Un smoke check al estilo "arrancar + health GET" no aplica porque no hay +# endpoint que consultar. La validacion de que los datos se cargan +# correctamente requiere que sqlite_api este corriendo (dependencia externa) +# o que se pase un registry.db directo. Ambos casos se cubren con el check +# 'integration_sqlite_direct' abajo, que es determinista y sin dependencias. +# +# El check 'api_endpoint_kpi' solicitado en el prompt del orquestador se +# implementa indirectamente via 'integration_sqlite_direct': se construye +# el binario con DISPLAY no seteado e invocacion headless no disponible. +# Ver 'ops_audit' para el camino alternativo via fn-recopilador. +# +# Instrucciones de adopcion: +# 1. Copiar el bloque "e2e_checks:" al frontmatter de +# projects/fn_monitoring/apps/registry_dashboard/app.md +# (antes del primer "##" de prosa). +# 2. El check 'build' asume que el directorio cpp/build/linux existe y cmake +# fue configurado previamente. Si no: anteponer +# "cmake -B /home/lucas/fn_registry/cpp/build/linux -S /home/lucas/fn_registry/cpp &&" +# al cmd o usar el check 'build_configure' (opcional, ver abajo). +# 3. El check 'integration_sqlite_direct' requiere que registry.db exista en +# la raiz del repo. En CI, puede copiarse de un fixture o generarse con +# 'fn index' antes de lanzar la suite. +# 4. Severity de 'build' puede bajarse a 'warning' si el binario Windows es +# el artefacto principal de deploy y el Linux build es solo CI-gate. +# +# NOTA: NO escribir directo al app.md — propuesta para revision humana. + +e2e_checks: + # --- build --- + # Compila el target registry_dashboard para Linux via cmake. + # Usa el build directory preexistente (cmake ya configurado). + # El binario queda en cpp/build/linux/apps/registry_dashboard. + # CGO no aplica (es C++, no Go). FTS5 se compila via SQLITE_ENABLE_FTS5 + # en la amalgamation vendoreada (CMakeLists.txt lo setea). + - id: build + cmd: "cmake --build /home/lucas/fn_registry/cpp/build/linux --target registry_dashboard -j$(nproc)" + timeout_s: 300 + severity: critical + # por que: la app enlaza ~20 funciones del registry C++ + sqlite + ws_client. + # Un fallo de build indica API break en fn_framework, funcion del registry + # con firma cambiada, o include roto. Es el gate mas importante para una + # app sin tests automaticos. + + # --- verify_binary --- + # Confirma que el binario existe y es ejecutable tras el build. + # Tambien verifica la version de symbols minimos esperados (sin linkage roto). + - id: verify_binary + cmd: "test -x /home/lucas/fn_registry/cpp/build/linux/apps/registry_dashboard && /home/lucas/fn_registry/cpp/build/linux/apps/registry_dashboard --help 2>&1 || true" + expect_exit: 0 + timeout_s: 5 + severity: critical + # por que: --help no esta implementado en la app, pero el binario debe poder + # cargarse sin segfault. exit != 139 (SIGSEGV) es suficiente. + # Detecta linkage roto (missing .so, wrong rpath) que el build paso por alto. + + # --- integration_sqlite_direct --- + # Verifica que el binario puede abrir registry.db via SQLite directo + # (sin sqlite_api corriendo) en modo headless usando timeout como proxy. + # La app imprime "SQLite fallback: " a stdout y luego entra en el + # GUI loop. timeout 3s mata el proceso antes de que el loop arranque pero + # DESPUES de que load_registry_data() ejecute la query SQL inicial. + # exit 124 = proceso terminado por timeout (exitoso para nuestro proposito). + # exit != 1 y != 139 indica que la carga SQL no crash. + - id: integration_sqlite_direct + cmd: > + DISPLAY="" timeout 3 + /home/lucas/fn_registry/cpp/build/linux/apps/registry_dashboard + /home/lucas/fn_registry/registry.db + 2>&1 | head -5 + expect_exit: 1 + timeout_s: 10 + severity: warning + # por que: valida la capa data.cpp (SQLite directo) sin depender de + # sqlite_api ni de un display X11. En headless, GLFW falla al abrir + # la ventana (exit 1) pero ANTES de eso load_registry_data() ya ejecuto + # las queries. Si el exit es 139 (SIGSEGV) o 134 (SIGABRT) -> regression + # en las queries SQL o en el parsing del schema. + # Severity warning porque el output exacto puede variar segun la version + # de GLFW en el CI. + # NOTA: si se implementa --self-test en la app, escalar a critical y + # usar ese flag en lugar de DISPLAY="" timeout 3. + + # --- data_schema_check --- + # Verifica que el schema de registry.db tiene las tablas que data.cpp + # espera: functions, types, apps, analysis, proposals, unit_tests. + # Este check no requiere el binario compilado — es SQL puro sobre la BD. + # Actua como pre-condicion para integration_sqlite_direct. + - id: data_schema_check + cmd: > + sqlite3 /home/lucas/fn_registry/registry.db + "SELECT COUNT(*) FROM sqlite_master WHERE type='table' + AND name IN ('functions','types','apps','analysis','proposals','unit_tests');" + expect_stdout_contains: "6" + timeout_s: 5 + severity: critical + # por que: si faltan tablas, data.cpp lanzara queries que retornan error. + # Detecta migraciones no aplicadas o registry.db corrupto antes de + # intentar el build + integration test. + + # --- call_monitor_schema_check --- + # Verifica que call_monitor.operations.db (consumida por la tab Monitor) + # tiene la tabla 'calls' que load_claude_usage_http() espera via sqlite_api. + # Este check valida la BD directamente — en produccion sqlite_api la expone + # via HTTP, pero aqui queremos detectar schema drift independientemente. + - id: call_monitor_schema_check + cmd: > + sqlite3 /home/lucas/fn_registry/projects/fn_monitoring/apps/call_monitor/operations.db + "SELECT COUNT(*) FROM sqlite_master WHERE type='table' + AND name IN ('calls','violations','sessions');" + expect_stdout_contains: "3" + timeout_s: 5 + severity: warning + # por que: la tab Monitor del dashboard se nutre de estas tablas. + # Si 'calls' no existe, la tab muestra placeholder vacio sin error visible. + # severity warning porque call_monitor.db puede estar vacia en un entorno + # nuevo (aun sin datos de telemetria). + + # --- ws_client_compile_check --- + # Verifica que ws_client.cpp compila sin warnings fatales. + # El cliente WebSocket es codigo propio (no libreria vendored) que implementa + # RFC6455 minimal — propenso a regresiones si se cambia la interfaz de + # WsClient sin actualizar todos los call sites. + - id: ws_client_compile_check + cmd: > + cmake --build /home/lucas/fn_registry/cpp/build/linux + --target registry_dashboard -j$(nproc) -- --warn-undefined-functions + 2>&1 | grep -i "ws_client" | grep -i "error" || true + expect_stdout_contains: "" + timeout_s: 60 + severity: warning + # por que: ws_client es la pieza mas fragil del stack (RFC6455 manual, + # sin tests dedicados). Buscar explicitamente errores en ws_client.cpp + # en el output de cmake da visibilidad sin duplicar el check build. + # expect_stdout_contains "" = la busqueda no encuentra errores (grep + # devuelve vacio). Si grep encuentra algo, el check falla con exit 0 + # pero stdout no vacio — revisar la logica si fn-analizador necesita + # el patron inverso. + + # --- ops_audit --- + # Invoca al fn-recopilador sobre el directorio de la app para verificar + # que app.md esta bien indexado en registry.db, que uses_functions son + # validos, y estructura general del artefacto. + # No hay operations.db propia en esta app — el recopilador auditara + # solo la estructura y las referencias cruzadas con registry.db. + - id: ops_audit + ref: "fn-recopilador:projects/fn_monitoring/apps/registry_dashboard" + severity: warning + # por que: registry_dashboard declara ~20 uses_functions en app.md. + # El recopilador verifica que cada ID existe en registry.db y detecta + # drift si alguna funcion fue renombrada o eliminada. + # severity warning porque la app puede funcionar correctamente aunque + # un ID en uses_functions este mal escrito (solo metadata). diff --git a/dev/proposals_e2e_checks_0121/registry_mcp.yaml b/dev/proposals_e2e_checks_0121/registry_mcp.yaml new file mode 100644 index 00000000..f61d0315 --- /dev/null +++ b/dev/proposals_e2e_checks_0121/registry_mcp.yaml @@ -0,0 +1,133 @@ +# e2e_checks proposal for apps/registry_mcp +# +# Generado por fn-recopilador en modo design-e2e. +# NO modifica app.md directamente — propuesta para revision humana. +# Copiar el bloque e2e_checks al frontmatter de apps/registry_mcp/app.md +# tras aprobar. +# +# Diagnostico: +# lang=go, framework=mcp (github.com/mark3labs/mcp-go) +# tag service → runtime=stdio (no puerto HTTP, no health endpoint) +# entry_point=main.go, build requiere CGO_ENABLED=1 -tags fts5 (sqlite + FTS5) +# tests: naming_test.go (TestValidateName/TestValidateDomain) +# fts_test.go (TestSanitizeFTS5/TestIsSnakeCase) +# format_test.go (TestRenderFunctionMarkdown/TestLangFence/TestTruncate) +# integration_test.go (TestIntegration_StdioListSearchShow/TestIntegration_SearchByTag) +# -> los integration tests arrancan el servidor en-proceso con pipes, NO +# requieren binario compilado, pero SI requieren registry.db accesible. +# operations.db: NO presente — la app no usa operations.db propia. +# frontend: NO. +# migrations/: NO (lee registry.db en modo ro, no escribe schema). +# gating flags: --enable-run y --enable-write — NO se testean aqui (requieren +# credenciales/estado externo). Solo se validan los tools read-only. +# +# Checks propuestos: +# build -> compilar con CGO+fts5. Gate critico: si no compila, nada mas importa. +# tests_unit -> go test ./... (unit tests puros: naming, fts, format). +# Los integration tests necesitan registry.db; se corre todo porque +# integration_test.go hace findRegistryRoot(t) y hace t.Skip si +# no lo encuentra. En el entorno de dev hay registry.db en la raiz, +# por tanto los integration tests CORREN. +# naming_reject -> smoke del validador de nombres: input invalido debe salir con +# exit != 0 o stdout/stderr con "naming:" / "action verb". +# Se implementa via go test -run TestValidateName directamente +# (mas simple y determinista que un binario auxiliar). +# mcp_handshake -> arranca el binario en modo stdio, envia initialize JSON-RPC +# por stdin, espera respuesta JSON valida con "result" en stdout. +# Usa FN_REGISTRY_ROOT explicito y timeout de 5s con bash+kill. +# Es el smoke mas util: prueba que el binario abre la BD, +# registra tools y responde al protocolo MCP correctamente. + +app_id: registry_mcp +dir_path: apps/registry_mcp +generated_by: fn-recopilador +generated_at: "2026-05-19" + +e2e_checks: + # ------------------------------------------------------------------- + # 1. BUILD — compilar con CGO + FTS5. Sin esto el resto no sirve. + # CGO_ENABLED=1 es obligatorio para go-sqlite3 (FTS5 tag lo exige). + # ------------------------------------------------------------------- + - id: build + cmd: > + cd /home/lucas/fn_registry/apps/registry_mcp && + CGO_ENABLED=1 go build -tags fts5 -o registry_mcp . + timeout_s: 120 + severity: critical + # por que: gate fundamental. Build roto = binario inexistente = nada funciona. + + # ------------------------------------------------------------------- + # 2. TESTS — unit + integration. Los integration_tests arrancan el + # servidor con pipes en-proceso; no necesitan binario pero si + # registry.db en la raiz del repo (findRegistryRoot hace t.Skip si + # no la encuentra). En dev siempre esta disponible. + # ------------------------------------------------------------------- + - id: tests + cmd: > + cd /home/lucas/fn_registry/apps/registry_mcp && + CGO_ENABLED=1 go test -tags fts5 -count=1 -timeout 60s ./... + timeout_s: 90 + severity: critical + # por que: cubre naming validator, FTS5 sanitizer, markdown renderer + # y el handshake stdio completo (tools/list + fn_search + fn_show) + # via TestIntegration_StdioListSearchShow. + + # ------------------------------------------------------------------- + # 3. NAMING_REJECT — el validator de nombres (naming.go) debe rechazar + # input invalido. Valida que la regla ids_naming.md esta codificada + # y activa. Se ejercita directamente via go test -run. + # Expected: PASS (el test Table case "Slice" espera err != nil). + # ------------------------------------------------------------------- + - id: naming_reject + cmd: > + cd /home/lucas/fn_registry/apps/registry_mcp && + CGO_ENABLED=1 go test -tags fts5 -count=1 -run TestValidateName -v 2>&1 | + grep -q "PASS" + timeout_s: 30 + severity: critical + # por que: fn_create_function llama al validator antes de escribir archivos. + # Si el validator acepta nombres invalidos (PascalCase, bare nouns), + # el registry se corrompe con IDs no-canonicos. Este check lo detecta. + + # ------------------------------------------------------------------- + # 4. MCP_HANDSHAKE_STDIO — smoke del protocolo JSON-RPC 2.0 real. + # Arranca el binario compilado en modo stdio, envia 'initialize', + # verifica que la respuesta tiene "result" (MCP ServerInfo valido). + # Usa timeout con kill para que no quede colgado. + # FN_REGISTRY_ROOT apunta a la raiz del repo donde esta registry.db. + # ------------------------------------------------------------------- + - id: mcp_handshake_stdio + cmd: | + BINARY=/home/lucas/fn_registry/apps/registry_mcp/registry_mcp + PAYLOAD='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"e2e_probe","version":"0"}}}' + RESPONSE=$(echo "$PAYLOAD" | timeout 5 "$BINARY" \ + --registry-root /home/lucas/fn_registry \ + --log-level error \ + 2>/dev/null | head -n1) + echo "response: $RESPONSE" + echo "$RESPONSE" | python3 -c " + import sys, json + r = json.load(sys.stdin) + assert 'result' in r, f'missing result key: {r}' + assert 'serverInfo' in r['result'] or 'protocolVersion' in r['result'], f'unexpected result: {r[\"result\"]}' + print('OK: MCP initialize handshake passed') + " + timeout_s: 15 + severity: critical + # por que: es el smoke mas real posible — el mismo protocolo que + # Claude Code usa al arrancar la sesion. Detecta regressions + # en: apertura de BD, registro de tools, serialization JSON-RPC. + # HTTP no se testea aqui (requiere --enable-run/--enable-write config). + + # ------------------------------------------------------------------- + # 5. OPS_AUDIT — auditoria de operations.db. + # registry_mcp no tiene operations.db propia (servicio stdio puro, + # no usa el ciclo reactivo). Este check queda como WARNING para + # documentar la decision y detectar si en el futuro se crea una BD. + # ------------------------------------------------------------------- + - id: ops_audit + ref: "fn-recopilador:apps/registry_mcp" + severity: warning + # por que: registry_mcp no usa operations.db hoy (runtime stdio sin + # entities/executions propias). Check WARNING para detectar + # si se anade en el futuro sin actualizar estos checks. diff --git a/dev/proposals_e2e_checks_0121/services_api.yaml b/dev/proposals_e2e_checks_0121/services_api.yaml new file mode 100644 index 00000000..1f8a7eac --- /dev/null +++ b/dev/proposals_e2e_checks_0121/services_api.yaml @@ -0,0 +1,130 @@ +# app_id: services_api +# lang: go (CGO_ENABLED=1, go-sqlite3, NO fts5 — no FTS5 features in this app) +# stack: net/http + SQLite (go-sqlite3) + SSH polling (ssh_exec_go_infra) +# dir_path: apps/services_api +# entry: main.go (--bind / --once / --registry / --db flags) +# service: port 8485, health /api/health, systemd-user +# ops.db: SI — service_state + service_transition (001_init.sql applied) +# sin entities/relations/executions del schema fn_operations +# tests: NO (*_test.go absent) — solo --once como smoke gate +# basicAuth: NO detectado en main.go / check.go +# ssh: SI — probeRemote usa infra.SSHExec (ssh_exec_go_infra) +# e2e port: 8585 (prod 8485 + 100, evita colision) +# issue: 0121a wave 2 — design-e2e services_api +# date: 2026-05-19 +# +# INSTRUCCIONES PARA EL HUMANO: +# 1. Revisar y ajustar comentarios; luego copiar el bloque e2e_checks: +# al frontmatter de apps/services_api/app.md (despues de service: block). +# 2. El check ops_audit invoca fn-recopilador sobre operations.db propia +# (NO usa el schema estandar fn_operations — solo service_state/service_transition). +# 3. El check smoke_once usa --once + --db efimera para no contaminar la BD +# de produccion ni necesitar registry.db real (usa /tmp/fn_e2e_sreg.db con +# un registry.db vacio). +# 4. smoke_health sube el binario como daemon real en puerto 8585 y verifica +# /api/health. Requiere que el check build haya producido el binario. +# 5. No hay go test porque no existen *_test.go. Si se añaden tests en el +# futuro, activar el check tests descomentando la entrada correspondiente. + +e2e_checks: + # ----------------------------------------------------------------------- + # 1. BUILD + # CGO_ENABLED=1 porque go-sqlite3 requiere cgo (no hay fts5 en este app, + # pero el flag no rompe nada y evita confusion futura si se añade FTS). + # ----------------------------------------------------------------------- + - id: build + cmd: "cd /home/lucas/fn_registry/apps/services_api && CGO_ENABLED=1 go build -o services_api ." + timeout_s: 120 + severity: critical + # por que: si no compila no hay nada que probar + + # ----------------------------------------------------------------------- + # 2. SMOKE --once + # Corre un ciclo completo de checks sin arrancar el HTTP server. + # Usa una BD efimera en /tmp y apunta el registry a fn_registry real + # (read-only); las queries a registry.db devuelven los targets reales del PC. + # Exit 0 = el loop no peta al cargar targets + persistir en ops_db. + # ----------------------------------------------------------------------- + - id: smoke_once + cmd: > + cd /home/lucas/fn_registry/apps/services_api && + FN_REGISTRY_ROOT=/home/lucas/fn_registry + ./services_api + --once + --registry /home/lucas/fn_registry + --db /tmp/services_api_e2e.db + --bind 127.0.0.1:8585 + timeout_s: 45 + severity: critical + # por que: valida que loadTargets + probeLocal + upsertState no panican + # Nota: SSH remotes daran no-route (sin config SSH en CI) — eso es correcto + # y no falla el check; el exit code del proceso es 0 si completo el ciclo. + + # ----------------------------------------------------------------------- + # 3. SMOKE HTTP + HEALTH + # Arranca el server en background en puerto 8585 con BD efimera, + # espera que /api/health responda 200. + # ----------------------------------------------------------------------- + - id: smoke_health + cmd: > + cd /home/lucas/fn_registry/apps/services_api && + ./services_api + --bind 127.0.0.1:8585 + --registry /home/lucas/fn_registry + --db /tmp/services_api_e2e_http.db + --interval 300s & + health: "http://127.0.0.1:8585/api/health" + timeout_s: 15 + severity: critical + # por que: verifica que el HTTP server arranca y responde en el puerto + # declarado en service.port (proxy: 8585 en lugar de 8485) + + # ----------------------------------------------------------------------- + # 4. ENDPOINT /api/services (warning — depende de datos del PC) + # Valida que el endpoint responde JSON bien formado con el campo self_pc. + # Es warning porque en un PC sin ~/.fn_pc o sin registry.db poblado + # puede devolver lista vacia pero eso no es un bug. + # ----------------------------------------------------------------------- + - id: check_services_endpoint + cmd: > + curl -sf http://127.0.0.1:8585/api/services | + python3 -c "import sys,json; d=json.load(sys.stdin); assert 'services' in d and 'self_pc' in d" + timeout_s: 10 + severity: warning + # por que: smoke de formato de respuesta del endpoint principal que + # services_monitor (C++) consume. Un cambio de schema JSON rompe el cliente. + + # ----------------------------------------------------------------------- + # 5. ENDPOINT /api/pcs (warning) + # Valida que /api/pcs responde con el campo pcs. + # ----------------------------------------------------------------------- + - id: check_pcs_endpoint + cmd: > + curl -sf http://127.0.0.1:8585/api/pcs | + python3 -c "import sys,json; d=json.load(sys.stdin); assert 'pcs' in d" + timeout_s: 10 + severity: warning + # por que: services_monitor usa /api/pcs para la barra lateral de PCs + + # ----------------------------------------------------------------------- + # 6. OPS AUDIT + # Invoca fn-recopilador sobre la operations.db propia. + # NOTA: esta BD tiene schema propio (service_state, service_transition), + # NO el schema estandar fn_operations (entities/relations/executions). + # El recopilador auditara estructura y datos vivos. + # ----------------------------------------------------------------------- + - id: ops_audit + ref: "fn-recopilador:apps/services_api" + severity: warning + # por que: detecta inconsistencias en service_state (ej. overall invalido, + # last_check_ts cero en todas las filas = --once nunca corrio) + + # ----------------------------------------------------------------------- + # OMITIDO: tests + # No existen *_test.go en apps/services_api. Activar cuando se añadan. + # + # - id: tests + # cmd: "cd /home/lucas/fn_registry/apps/services_api && CGO_ENABLED=1 go test -count=1 ./..." + # timeout_s: 120 + # severity: critical + # ----------------------------------------------------------------------- diff --git a/dev/proposals_e2e_checks_0121/sqlite_api.yaml b/dev/proposals_e2e_checks_0121/sqlite_api.yaml new file mode 100644 index 00000000..8e176f95 --- /dev/null +++ b/dev/proposals_e2e_checks_0121/sqlite_api.yaml @@ -0,0 +1,114 @@ +# e2e_checks proposal — sqlite_api +# app_id: projects/fn_monitoring/apps/sqlite_api +# lang: go +# stack: Go service, net/http, CGO_ENABLED=1, SQLite FTS5 +# module: fn-registry (go.mod en raiz del repo) +# binary: projects/fn_monitoring/apps/sqlite_api/sqlite_api (pre-compilado) +# systemd: sqlite_api.service (user scope, ExecStart usa el binario compilado) +# e2e port: 8684 (prod 8484 + 200) +# e2e db: /tmp/sqlite_api_e2e.db +# date: 2026-05-19 +# issue: 0121a wave 2 +# nota: service critico — caida 20h el 2026-05-17 por Restart=on-failure +# (ya corregido a Restart=always en el unit). Checks refuerzan +# que el binario arranca, responde, y ejecuta queries correctamente. + +e2e_checks: + # --- build ------------------------------------------------------------------ + - id: build + # Compila el binario del service con CGO+FTS5. + # El binario resultante es el mismo que usa el systemd unit. + # Correr desde la raiz del repo porque go.mod vive ahi. + cmd: > + cd /home/lucas/fn_registry && + CGO_ENABLED=1 go build -tags fts5 + -o projects/fn_monitoring/apps/sqlite_api/sqlite_api + ./projects/fn_monitoring/apps/sqlite_api/ + timeout_s: 120 + severity: critical + + # --- tests ------------------------------------------------------------------ + - id: tests + # Suite de tests unitarios Go existente (handlers_test.go). + # Cubre: /health, /api/databases, /api/databases/:db/query, + # ValidateQuery (whitelist SELECT/PRAGMA/WITH/EXPLAIN), + # DiscoverDatabases, /tables, /schema, 404 para DB inexistente. + # Usan DB en t.TempDir() — totalmente efimeros. + cmd: > + cd /home/lucas/fn_registry && + CGO_ENABLED=1 go test -tags fts5 -count=1 -v + ./projects/fn_monitoring/apps/sqlite_api/ + timeout_s: 60 + severity: critical + + # --- smoke ------------------------------------------------------------------ + - id: smoke + # Arranca el binario compilado con BD efimera y puerto alto. + # FN_REGISTRY_ROOT apunta a la raiz para que DiscoverDatabases + # encuentre registry.db real (necesario para /api/databases). + # El proceso queda en background; fn-analizador lo mata al terminar. + cmd: > + FN_REGISTRY_ROOT=/home/lucas/fn_registry + /home/lucas/fn_registry/projects/fn_monitoring/apps/sqlite_api/sqlite_api + --bind 127.0.0.1:8684 + --data-factory-db /tmp/sqlite_api_e2e_df.db & + health: "http://127.0.0.1:8684/api/databases" + timeout_s: 10 + severity: critical + + # --- query_endpoint --------------------------------------------------------- + - id: query_endpoint + # Valida que el endpoint POST /api/databases/:db/query funciona end-to-end: + # 1. Crea una BD SQLite efimera con una tabla trivial. + # 2. La registra como argumento de query via BD de registro en /api/databases. + # 3. Ejecuta SELECT 1 contra la BD "registry" (siempre disponible si hay + # FN_REGISTRY_ROOT correcto) y valida JSON con count>=1 y campo "columns". + # Alternativa mas simple: hit directo al endpoint con la BD ya registrada. + cmd: > + curl -sf -X POST http://127.0.0.1:8684/api/databases/registry/query + -H 'Content-Type: application/json' + -d '{"sql":"SELECT 1 AS ping"}' + | python3 -c " + import sys, json + r = json.load(sys.stdin) + assert r.get('count') == 1, f'count != 1: {r}' + assert 'columns' in r, f'no columns: {r}' + assert r['columns'][0] == 'ping', f'col != ping: {r}' + print('query_endpoint OK:', r) + " + timeout_s: 10 + severity: critical + + # --- write_rejection -------------------------------------------------------- + - id: write_rejection + # El service se declara read-only. Verifica que INSERT es rechazado con 400. + # Regresion directa del contrato de seguridad de sqlite_api. + cmd: > + STATUS=$(curl -s -o /dev/null -w "%{http_code}" + -X POST http://127.0.0.1:8684/api/databases/registry/query + -H 'Content-Type: application/json' + -d '{"sql":"INSERT INTO functions VALUES (\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\",\"x\")"}') && + [ "$STATUS" = "400" ] + timeout_s: 10 + severity: critical + + # --- auth_check ------------------------------------------------------------- + - id: auth_check + # Service actualmente NO requiere auth (bind 127.0.0.1 mitiga). + # Este check documenta el estado actual: cualquier cliente local puede + # hacer queries. Si en el futuro se añade X-Registry-Token, este check + # debe actualizarse para enviar el token correcto y esperar 401 sin token. + # Por ahora verifica que el endpoint responde sin auth header (comportamiento esperado). + cmd: > + curl -sf http://127.0.0.1:8684/health + | python3 -c "import sys,json; r=json.load(sys.stdin); assert r['status']=='ok'" + timeout_s: 5 + severity: warning + + # --- ops_audit -------------------------------------------------------------- + - id: ops_audit + # Invoca al fn-recopilador sobre las operations.db de apps de fn_monitoring. + # sqlite_api no tiene su propio operations.db pero es parte del proyecto + # fn_monitoring que sí tiene call_monitor con operations.db activa. + ref: "fn-recopilador:projects/fn_monitoring/apps/sqlite_api" + severity: warning