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) <noreply@anthropic.com>
This commit is contained in:
2026-05-19 00:43:09 +02:00
parent b8f8b8ff3c
commit 68bb9fbdae
9 changed files with 1130 additions and 8 deletions
+47 -8
View File
@@ -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/<app>
# 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
```
@@ -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.
+127
View File
@@ -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).
@@ -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"
@@ -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 |
@@ -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: <path>" 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).
@@ -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.
@@ -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
# -----------------------------------------------------------------------
@@ -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