docs(SDD 23): §10 — la misma herida reabierta por el renombre, y el gocryptfs sin causa

Deja escrito lo de hoy donde ya vivía el diagnóstico de esta clase de fallo (§9):
el aprovisionamiento de `go` en el worker SE HIZO el 2026-08-28 y el renombre lo
deshizo el 2026-09-09 sin que nada fallara. Con el método de detección (varias
muriendo en segundos = sistémico; leer el error de UNA antes de contar deuda), la
comprobación en los dos sentidos, y las cuatro sondas de `pgrep` que el mismo
renombre dejó ciegas.

Incluye el no-determinismo de `gocryptfs` con la hipótesis REFUTADA anotada como
tal: no es el `cgo` (sq y usql también lo usan y reproducen) ni la ruta aleatoria
del temporal (las cadenas son idénticas y difieren 1.874.136 bytes, desde .rodata).
Queda abierto y sin causa; no está en ningún perfil, así que no bloquea imágenes.
This commit is contained in:
Sergio
2026-09-14 14:32:04 +00:00
parent cb101fd70b
commit 642c170b6a
+67
View File
@@ -351,3 +351,70 @@ habla del rootfs DEL SANDBOX.
**Es una decisión de aprovisionamiento, no de arquitectura**, y desbloquea tres cuartas partes del
catálogo para la granja.
## 10. 🔁 La misma herida, reabierta por el renombre (2026-09-14)
El §9 cerró con «es una decisión de aprovisionamiento, no de arquitectura». **Se tomó**: el
2026-08-28 `bootstrap-devfs.sh` enlazó `go` en `~/.cargo/bin` del worker, que es lo que el fetch
mira. Funcionó.
Y volvió a romperse **sin que nada fallara**. El enlace guardaba una ruta ABSOLUTA
`/opt/hammer/.dev-fs/tools/go/bin/go`— y el renombre hammer→takana (ADR 0016, 2026-09-09) movió el
directorio. `ln -sfn` había dejado un enlace colgado, y el script imprimía «go enlazado ✓» sin
comprobar nada. **Del 2026-09-09 al 2026-09-14 el worker no pudo construir ninguna receta Go.**
### Cómo se encontró, que es la parte reutilizable
Por casualidad, verificando reproducibilidad: **16 de 25 recetas Go murieron en SEGUNDOS**. Esa es
la firma de un fallo SISTÉMICO, nunca la de 16 recetas rotas — es la misma pista que el disco lleno.
El error lo decía entero:
Error: spawn go mod vendor: No such file or directory (¿está `go` en el PATH del host?)
pero `verificar-repro.sh` manda la salida del build a `/dev/null`, así que el informe sólo decía
«no construyó». ⇒ **Ante un «no construyó», reproducir UNA a mano y leer el error** antes de
escribir un número de deuda.
### Comprobado en los dos sentidos
Repuesto el enlace, `gron` pasó de no construir a construir **y reproducir bit a bit**
(`why-differs`: 5 entradas idénticas, 0 divergen), y `checkmake` —que la tanda anterior había dado
por «no construyó»— reproduce. No estaban rotas: faltaba el binario.
`cargo`, `git`, `patch`, `tar` y `curl` del worker se revisaron a la vez y están sanos: `cargo` es
una instalación de rustup de verdad, no un enlace al repo, y por eso el renombre no lo tocó.
### Lo que se cambió para que no se repita
`bootstrap-devfs.sh` ya no da el enlace por bueno: repone el que esté colgado (avisando de a dónde
apuntaba) y **comprueba que RESUELVE ejecutando `go version` a través de él**; si no ejecuta, sale 1
con el síntoma escrito. Probado con un control que tiene que pasar y con dos roturas a propósito
(enlace colgado a `/opt/hammer` ⇒ lo repone; destino inexistente ⇒ falla ruidoso).
Y de paso, el mismo renombre había dejado **ciegas cuatro sondas de proceso** que buscaban
`release/hammer`: `estado-granja.sh` informaba «moliendo: (nada — idle)» con el worker compilando
`centrifugo`, y el `hay_trabajo` del dead-man tampoco veía el build — en una caja hcloud eso es un
worker borrado a mitad de un build. Las cuatro aceptan ahora los dos nombres.
> **La lección, que es nueva respecto de las tres del §7:** un renombre no rompe sólo lo que
> compila. Rompe las cadenas que alguien escribió a mano —enlaces absolutos, patrones de `pgrep`,
> rutas en scripts— y ésas no las mira ningún compilador. Lo que las encuentra es un guardián que
> comprueba el EFECTO (¿corre `go`?, ¿veo el build?) en vez del gesto (¿creé el enlace?).
### Rendimiento de la campaña ese día
Con el worker devuelto al frente Go y el hub en la familia KDE Frameworks:
| frente | familia | reproducen | deriva | no-determinismo | no construyeron |
|---|---|---|---|---|---|
| hub | KF6 tier 13 (CMake) | 36 | 0 | 0 | 0 |
| worker | Go | 17 | 2 | 1 | 0 |
El único no-determinismo real es `gocryptfs`, con los dos ejemplares guardados en
`store/.divergen/`. **La hipótesis obvia se midió y salió FALSA**: se atribuyó al `cgo = true`
—porque el temporal `go-build<aleatorio>` queda en el DWARF— pero las otras dos recetas con cgo del
corpus, `sq` y `usql`, **reproducen**. Y mirado de cerca, la ruta aleatoria tampoco es la causa: los
dos binarios tienen cadenas IDÉNTICAS salvo esas dos rutas, y sin embargo difieren en **1.874.136
bytes** empezando dentro de `.rodata`. O sea que hay algo de orden/direcciones debajo, no una cadena
horneada. Queda ABIERTO y sin causa; `gocryptfs` no está en ningún perfil y no tiene dependientes,
así que no bloquea ninguna imagen.