feat(infra): auto-commit con 6 cambios

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 16:16:36 +02:00
parent ea6a3ec8a5
commit 6aec0413bb
6 changed files with 541 additions and 0 deletions
@@ -0,0 +1,130 @@
---
id: "0167"
title: "fn run de library function Go ejecuta go test del paquete entero (arrastra tests flaky vecinos)"
status: pendiente
type: enhancement
domain:
- registry-quality
scope: registry-only
priority: media
depends: []
blocks: []
related: ["0077"]
created: 2026-06-03
updated: 2026-06-03
tags: [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:
- `TestSSHTunnelOpenClose``bind [127.0.0.1]:19876: Address already in use`
- `TestDockerContainerExec``listen 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`.