# /validate-app — Validar end-to-end una app del registry

Orquesta la cadena `fn-executor → fn-recopilador → fn-analizador → fn-mejorador` (fases 2-5 del bucle reactivo) sobre una app concreta. Devuelve veredicto pass/fail + IDs de proposals creadas si hay fallos.

## Argumento

`$ARGUMENTS` — `<app_id>` o `<dir_path>`. Ejemplos:
- `kanban_go_tools`
- `apps/kanban`
- `graph_explorer_cpp_viz`
- `projects/osint_graph/apps/graph_explorer`

Si vacio: detectar app desde `pwd` (si estas dentro de `apps/<X>/` o `projects/*/apps/<X>/`); si no, listar apps con `e2e_checks` declarado y pedir.

## Pasos

### 1. Resolver app objetivo

```bash
ROOT=/home/lucas/fn_registry
ARG="$ARGUMENTS"

if [ -z "$ARG" ]; then
  CWD="$(pwd)"
  case "$CWD" in
    "$ROOT"/apps/*|"$ROOT"/projects/*/apps/*)
      ARG="$(realpath --relative-to="$ROOT" "$CWD")"
      ;;
    *)
      sqlite3 "$ROOT/registry.db" "SELECT id, dir_path FROM apps ORDER BY id;"
      echo "Especifica app_id o dir_path"
      exit 1
      ;;
  esac
fi

# Resolver a (id, dir_path)
if echo "$ARG" | grep -q "^apps/\|^projects/"; then
  APP_DIR="$ARG"
  APP_ID=$(sqlite3 "$ROOT/registry.db" "SELECT id FROM apps WHERE dir_path = '$ARG';")
else
  APP_ID="$ARG"
  APP_DIR=$(sqlite3 "$ROOT/registry.db" "SELECT dir_path FROM apps WHERE id = '$ARG';")
fi

[ -z "$APP_ID" ] || [ -z "$APP_DIR" ] && { echo "App no encontrada: $ARG"; exit 1; }
```

### 2. Verificar contrato `e2e_checks`

```bash
HAS_CHECKS=$(awk '/^e2e_checks:/,/^[a-z_]+:|^---$/' "$ROOT/$APP_DIR/app.md" | grep -c "^  - id:")

if [ "$HAS_CHECKS" -eq 0 ]; then
  echo "App $APP_ID no tiene e2e_checks declarados."
  echo "Invocar fn-recopilador design-e2e para generar contrato:"
  echo ""
  echo "  Agent(subagent_type=fn-recopilador, prompt=\"design-e2e $APP_DIR\")"
  exit 0
fi
```

### 3. Fase 3 — RECOPILAR (auditar operations.db)

Invocar `fn-recopilador` para confirmar que los datos operativos estan integros antes de validar. Si recopilador reporta FAIL critical, NO continuar.

```
Agent(subagent_type=fn-recopilador,
      prompt="Auditar app $APP_DIR. Reportar OK/WARN/FAIL en formato corto.
              Si hay FAIL critical, advertirlo claramente. Solo lectura.")
```

Si reporta FAIL critical → abortar con mensaje y no llegar a fn-analizador.

### 4. Fase 4 — ANALIZAR (correr e2e_checks)

```
Agent(subagent_type=fn-analizador,
      prompt="Validar end-to-end la app $APP_ID (dir_path: $APP_DIR).
              Leer e2e_checks del app.md, ejecutar via e2e_run_checks_go_infra,
              evaluar assertions, calcular drift, persistir en e2e_runs.
              triggered_by: manual.
              git_sha: $(git rev-parse --short HEAD 2>/dev/null || echo '')

              Devolver veredicto caveman + run_id.")
```

Capturar `RUN_ID` del output. Capturar `STATUS` (`pass`|`partial`|`fail`).

### 5. Fase 5 — MEJORAR (proposals si hay fallos)

Solo si `STATUS != pass`:

```
Agent(subagent_type=fn-mejorador,
      prompt="App $APP_ID tuvo fallos en run_id $RUN_ID.
              Leer e2e_runs y summary_json de $APP_DIR/operations.db.
              Por cada fail critical: crear proposal kind=new_function|improve_function
              en registry.db con created_by=reactive_loop, evidence con run_id+check_id.
              Sugerir fix concreto en description.
              Devolver lista de proposal_ids creados.")
```

Capturar `PROPOSAL_IDS`.

### 6. Reporte final al usuario

Tabla resumen:

```
=== /validate-app: $APP_ID ===

Fase 3 RECOPILAR:  ✓ datos operativos integros
Fase 4 ANALIZAR:   <STATUS> (run_id: <RUN_ID>)
                   <P>/<T> checks pass, <W> warn, <F> fail
Fase 5 MEJORAR:    <N> proposals creadas: <PROPOSAL_IDS>

Detalle por check:
  build_frontend  ✓ 42s
  build_backend   ✓ 18s
  smoke_api       ✓ 1.2s
  tests_go        ✗ 12s — 3/45 fails

Siguientes pasos:
  - Revisar proposals: fn proposal list -s pending
  - Ver run completo: sqlite3 $APP_DIR/operations.db "SELECT * FROM e2e_runs WHERE id='<RUN_ID>'"
```

## Notas

- **fn-mejorador no existe todavia** (paso 6 del issue 0068). Mientras tanto, si STATUS != pass, solo imprime el detalle del fallo y sugerir crear proposal manual.
- Si un agente subagente devuelve respuesta ambigua (no extrae RUN_ID claramente), pedir clarificacion al usuario antes de continuar.
- Para apps sin `operations.db` (ej. kanban usa `kanban.db`), `e2e_runs` se persiste en `/tmp/<app>_e2e_runs.db` con la misma migracion 005.
- Caveman OK en stdout salvo en mensajes de error donde claridad supera brevedad.
- Tras correr la cadena, NO commitear nada automaticamente. La decision de mergear es del humano.
