feat(infra): auto-commit con 6 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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`.
|
||||
Reference in New Issue
Block a user