farm: anclar el store con bind-mount, no symlink — el `ln -s` rompía toda receta con zig_version
Regresión introducida ayer al mover el store al volumen persistente (`ln -sfn /mnt/cosecha/store
$REMOTE/store`). El síntoma se leía como deuda de la cascada GUI y era otra cosa.
hammer deriva el lab del PADRE DEL STORE: `BuildConfig::defaults_for_store` hace
`project_root = store_root.parent()` y de ahí `.dev-fs/{alpine,tools/zig,cache}`. Con el store
symlinkeado, resuelve a /mnt/cosecha/store ⇒ busca /mnt/cosecha/.dev-fs, que no existe, y muere con
"no encuentro el ejecutable zig en …" — un mensaje que apunta al lugar equivocado: el zig 0.13.0
está, y está bien, sólo que en /opt/hammer/.dev-fs/tools/.
Golpea SÓLO a las recetas que fijan `zig_version` (20 en el corpus), porque son las únicas que
resuelven un zig hermano del por defecto. Por eso la campaña del 05:41 dio 26 selladas / 11
fallidas y las 11 eran exactamente ésas (tllist pango gtk4 libadwaita gtksourceview fcft
*-hello hammer-edit dwarves), y por eso la de las 19:48 —que era justo la lista de deuda— dio 0/14.
El bind-mount mantiene las DOS invariantes a la vez: los datos siguen en el volumen (sellar =
persistir, que es la razón del volumen) y `$REMOTE/store` vuelve a ser una ruta real bajo $REMOTE
⇒ el padre es /opt/hammer y .dev-fs se encuentra. Verificado en el worker vivo: con el bind-mount
y SIN overrides de entorno, libinput pasa la resolución de zig y falla por su dep real de Python.
Se persiste en fstab para que sobreviva al reboot, y el chequeo de verificación pasa de `test -L`
a `mountpoint -q`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Semántico sayk'uy
Mana ima sutichaypas t'ikrakurqanchu: qillqalla, yachachiylla utaq willaylla t'ikrakurqan.
1 qillqakuna · +15 −3
- scripts/farm/farm-up.sh +15 −3
diff --git a/scripts/farm/farm-up.sh b/scripts/farm/farm-up.sh
index 414c648e..72099e95 100755
--- a/scripts/farm/farm-up.sh
+++ b/scripts/farm/farm-up.sh
@@ -96,9 +96,21 @@ for k in $(seq 1 "$N"); do
echo \" ✓ rescatados \$n artefactos horneados de la golden al volumen\"
rm -rf $REMOTE/store
fi
- ln -sfn /mnt/cosecha/store $REMOTE/store
- grep -q /mnt/cosecha /etc/fstab || echo '$dev /mnt/cosecha ext4 defaults,nofail 0 0' >> /etc/fstab" >/dev/null 2>&1
- if $SSH root@"$ip" 'mountpoint -q /mnt/cosecha && test -L '"$REMOTE"'/store' 2>/dev/null; then
+ # BIND-MOUNT, NO SYMLINK (2026-07-22). Anclar el store con \`ln -s\` rompía TODA receta con
+ # \`zig_version\` en el worker, y el síntoma se leía como deuda de la cascada GUI. Por qué:
+ # hammer deriva el lab del PADRE DEL STORE (BuildConfig::defaults_for_store ⇒
+ # project_root = store_root.parent(), de ahí .dev-fs/{alpine,tools/zig,cache}). Con el symlink
+ # el store resuelve a /mnt/cosecha/store ⇒ busca /mnt/cosecha/.dev-fs, que no existe, y muere
+ # con 'no encuentro el ejecutable zig en …' apuntando al lugar equivocado. Un bind-mount deja
+ # los datos en el volumen igual, pero \$REMOTE/store sigue siendo una ruta REAL bajo
+ # \$REMOTE ⇒ el padre vuelve a ser /opt/hammer y .dev-fs se encuentra. Mantiene las dos
+ # invariantes a la vez: sellar = persistir, y el lab donde hammer lo espera.
+ if [ -L $REMOTE/store ]; then rm -f $REMOTE/store; fi
+ mkdir -p $REMOTE/store
+ mountpoint -q $REMOTE/store || mount --bind /mnt/cosecha/store $REMOTE/store
+ grep -q /mnt/cosecha /etc/fstab || echo '$dev /mnt/cosecha ext4 defaults,nofail 0 0' >> /etc/fstab
+ grep -q \"$REMOTE/store\" /etc/fstab || echo '/mnt/cosecha/store $REMOTE/store none bind,nofail 0 0' >> /etc/fstab" >/dev/null 2>&1
+ if $SSH root@"$ip" 'mountpoint -q /mnt/cosecha && mountpoint -q '"$REMOTE"'/store' 2>/dev/null; then
echo " ✓ store anclado al volumen ($( $SSH root@"$ip" 'ls -d /mnt/cosecha/store/*/ 2>/dev/null | wc -l') artefactos ya presentes)"
else
echo " ⚠ el store NO quedó en el volumen ⇒ lo que construya se PIERDE al auto-borrarse. Revisar."