Files
fn_registry/dev/issues/0167-fn-run-library-go-paquete-entero.md
T
egutierrez 6aec0413bb feat(infra): auto-commit con 6 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-03 16:16:36 +02:00

6.2 KiB
Raw Blame History

id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
id title status type domain scope priority depends blocks related created updated tags
0167 fn run de library function Go ejecuta go test del paquete entero (arrastra tests flaky vecinos) pendiente enhancement
registry-quality
registry-only media
0077
2026-06-03 2026-06-03
fn-run
go
testing
flaky
dag-engine
reliability

0167 — fn run de library function Go ejecuta go test del paquete entero

APP Metadata

Campo Valor
ID 0167
Estado pendiente
Prioridad media
Tipo enhancement — dispatcher de fn run

Contexto

Cuando fn run <id> recibe una library function Go sin main.go que tiene tests declarados (tested: true + test_file_path), el dispatcher (cmd/fn/run.go:171-181) ejecuta:

go test -v -count=1 -tags fts5 ./functions/<domain>   # el PAQUETE ENTERO

Es decir, no ejecuta "la función" (no se puede: no tiene main), sino que corre todos los tests del paquete. Consecuencia: el éxito de fn run miFuncion depende de que pasen los tests de todas las demás funciones del mismo paquete, no solo los suyos.

Cómo se manifestó

Los DAGs daily-registry-audit y weekly-deep-scan del dag_engine invocaban funciones *_go_infra (find_unused_functions, artefact_doctor, etc.) como function: steps. Cada step disparaba go test ./functions/infra (paquete completo), que contiene tests impuros con recursos fijos:

  • TestSSHTunnelOpenClosebind [127.0.0.1]:19876: Address already in use
  • TestDockerContainerExeclisten unix .../docker_exec_test.sock: bind: invalid argument (path de socket > 108 chars con TMPDIR largo)

Al correr dos function: steps en paralelo (ambos depends del mismo padre), las dos invocaciones de go test ./functions/infra colisionaban en el puerto fijo 19876 → una pasaba y la otra fallaba de forma no determinista. Resultado: el DAG fallaba sin auditar nada, y el fallo parecía "la auditoría encontró un problema" cuando en realidad era un test de red vecino.

Nota: el síntoma operativo en los DAGs ya se resolvió por otra vía (2026-06-03): los steps ahora usan audit_doctor_snapshot_bash_infra (Bash), que ejecuta fn doctor <sub> real en vez de go test del paquete. Este issue es la causa raíz general del dispatcher, que sigue afectando a cualquier fn run <library_go_fn_con_tests>.

Problema

  1. fn run de una library function NO ejecuta la función — corre el paquete de test entero.
  2. Los tests impuros de un paquete (puertos/sockets/red fijos) no son seguros para ejecuciones concurrentes ni reproducibles en cualquier entorno (TMPDIR, CI).
  3. Un único test flaky en functions/infra rompe fn run de las ~N funciones testeadas del paquete, y por extensión cualquier DAG/cron que las invoque.

Opciones de solución (decidir en implementación)

Opción A — library Go sin main → siempre compile-check (go vet/go build)

fn run <lib_fn> significa "verifica que la función va"; para código sin main eso es "compila". Testear es responsabilidad de go test / CI, no de fn run en un cron.

  • Pro: determinista, rápido, elimina el flaky de raíz.
  • Contra: rompe el comportamiento documentado en CLAUDE.md ("fn run filter_slice_go_core → Go function con tests → go test -v"). Perderíamos la capacidad de correr los tests de una función vía fn run.

Opción B — go test acotado con -run a los tests de la función

Si la función declara sus tests, ejecutar solo esos:

go test -v -count=1 -tags fts5 -run '^(TestX|TestY)$' ./functions/<domain>
  • Pro: aísla del flaky vecino manteniendo "fn run corre mis tests".
  • Contra / RIESGO: si los nombres de fn.Tests (frontmatter YAML, registry/parser.go:32) tienen drift respecto al código, -run no matchea y go test sale 0 con "no tests to run" → falso-verde en una primitiva crítica de todo el ecosistema. Mitigación obligatoria si se elige B: reconciliar fn.Tests con los tests extraídos por el indexer (registry/test_parser.go::parseGoTests, que ya puebla unit_tests) y/o detectar "0 tests ejecutados" parseando el output y tratarlo como fallo.

Opción C — aislar los tests impuros del paquete

Hacer robustos los tests culpables: puerto efímero (:0 en vez de 19876), socket en path corto bajo /tmp con nombre acotado, t.Parallel-safe. No cambia el dispatcher pero reduce la probabilidad de colisión.

  • Pro: no toca fn run (cero blast radius sistémico).
  • Contra: no resuelve el problema conceptual (sigue corriendo el paquete entero); otros paquetes pueden introducir tests impuros nuevos y reincidir.

Recomendación

Combinar C (saneamiento inmediato de TestSSHTunnelOpenClose y TestDockerContainerExec, bajo riesgo) con B endurecida (acotar -run + guard anti-falso-verde apoyado en unit_tests extraídos, no en el frontmatter manual). La Opción A es la más limpia conceptualmente pero rompe comportamiento documentado; evaluar si ese comportamiento ("fn run corre los tests") aún se usa de verdad o puede deprecarse hacia go test directo.

Definition of Done

Escenario Tipo Comando / evidencia Resultado esperado
Golden: fn run de library fn testeada e2e ./fn run find_unused_functions_go_infra exit 0 sin depender de tests de funciones vecinas
Edge: dos fn run concurrentes del mismo paquete e2e dos invocaciones en paralelo de funciones de functions/infra ambas exit 0, sin colisión de puerto/socket
Error: nombres de test con drift (si se elige B) unit fn.Tests con un nombre inexistente NO produce falso-verde (se detecta "0 tests run" → fallo)
Tests impuros saneados unit go test -run 'TestSSHTunnelOpenClose|TestDockerContainerExec' ./functions/infra repetido 5× 5/5 PASS deterministas

Notas

  • Archivos clave: cmd/fn/run.go (dispatcher, líneas 145-194), registry/parser.go (campo Tests), registry/test_parser.go (extracción de nombres de test), functions/infra/ssh_tunnel_open_close_test.go y functions/infra/docker_container_exec_test.go (tests culpables).
  • Relacionado con 0077 (fn-run-bash-output-mudo): familia de issues sobre la semántica y observabilidad de fn run.