gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1385Shell 122Rust 77Markdown 682241 Definiciones

fix(granja): el cache de ZIG era el 91% de los inodos del worker, y nadie lo podaba

Cierra el agujero del commit anterior. Ahí se arregló que el watchdog mirara los inodos; faltaba
decir QUIÉN se los comía, y la respuesta estaba en el sitio que ningún podador visitaba:
`.dev-fs/cache/zig`, **~11,4 M de inodos de 12,5 M usados en el fs — el 91 %**. Ni `ls` terminaba
ahí, y por eso el censo a mano no lo encontró: tres intentos de `du`/`find` se colgaron en ese
subárbol y yo lo leí como «hay inodos fuera del alcance del contenedor, mirá el Proxmox». No había
nada que mirar afuera; estaba acá.

Es el punto ciego más caro posible: **zig es el compilador de TODO el corpus** (`compiler =
"zig-cc"`), su cache global crece con cada build, y no lo tocaba nadie — ni este watchdog, que
purgaba las caches Go y de zig no sabía nada, ni `poda-fuentes.sh`, ni la cosecha. Un montón que
sólo crece y que ningún guardián nombra no se descubre: se choca.

⚠ `mv` y DESPUÉS `rm -rf` en segundo plano, no `rm -rf` directo: borrar millones de ficheros tarda
minutos y un build que arranque en el medio escribiría dentro del árbol que se está borrando. El
rename es atómico — el build siguiente encuentra el sitio vacío y crea su cache nuevo mientras el
viejo se va en paralelo. Y va dentro de la misma guarda de «ningún build en vuelo» que protege a
las caches Go, por el motivo que ya estaba escrito ahí.

La ruta se resuelve como en `config.rs` (`cache_root = <proy>/.dev-fs/cache`) y respeta el mismo
override `CACHE` que acepta el build: si alguien lo mueve, el watchdog lo sigue.

Medido purgándolo a mano: 785 k → 989 k inodos libres y subiendo mientras borra, disco de 84% a 80%.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

1973d8111eef4997db3f3eb30c16d4b8ad3f7814 · por Sergio · (hace 15 d) · padre 1e75552c2 · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

1 archivos · +27 −2

diff --git a/scripts/farm/farm-worker-loop.sh b/scripts/farm/farm-worker-loop.sh
index 4a963ada..273cacba 100755
--- a/scripts/farm/farm-worker-loop.sh
+++ b/scripts/farm/farm-worker-loop.sh
@@ -30,7 +30,9 @@ mkdir -p "$HAMMER_DIR/work"
 
 # --- watchdog de disco: cada 3 min borra work/sources/* que ningún bwrap activo bind-monta
 # (seguro: sellada=store CAS, en-cola=se re-extrae sola). Evita que el vendoring llene el disco.
-# Además, si el disco supera DISK_HIGH%, purga los CACHES Go (GOMODCACHE ~/go/pkg/mod + gocache):
+# Además, si la presión (bytes o INODOS) supera DISK_HIGH%, purga los CACHES Go (GOMODCACHE
+# ~/go/pkg/mod + gocache) **y el cache global de zig** (`.dev-fs/cache/zig`), que es el más gordo de
+# los tres y el que nadie podaba: 11,4 M de inodos de 12,5 M usados, medido el 2026-10-07.
 # el `go mod vendor` de las recetas Go acumula ahí decenas de GB sin tope (el vendor/ local de cada
 # receta ya tiene lo que el build necesita; el modcache sólo se usa DURANTE el vendor). Si la purga
 # pisa un vendor en curso, esa receta reintenta el próximo ciclo (cache-hit el resto). Sin esto, una
@@ -120,8 +122,31 @@ SUELO_FRIO_MIN="${SUELO_FRIO_MIN:-120}"
       if pgrep -f 'go mod vendor' >/dev/null 2>&1 || pgrep -f 'release/(takana|hammer).* build ' >/dev/null 2>&1; then
         echo "$(date -u +%FT%TZ) watchdog: ${medidor} al ${use}% ≥ ${DISK_HIGH}% pero hay build en vuelo ⇒ difiero purga caches Go"
       else
-        echo "$(date -u +%FT%TZ) watchdog: ${medidor} al ${use}% ≥ ${DISK_HIGH}% ⇒ purgo caches Go"
+        echo "$(date -u +%FT%TZ) watchdog: ${medidor} al ${use}% ≥ ${DISK_HIGH}% ⇒ purgo caches Go y zig"
         go clean -modcache 2>/dev/null; go clean -cache 2>/dev/null
+        # ── Y EL CACHE DE ZIG, que es el que de verdad tumbó esta caja (2026-10-07) ──────────────
+        # Este watchdog purgaba Go y de zig no sabía nada, y **zig es el compilador de TODO el
+        # corpus** (`compiler = "zig-cc"`). Medido: `.dev-fs/cache/zig` tenía ~11,4 M de inodos de
+        # 12,5 M usados en el fs — el 91 %. Ni `ls` terminaba ahí. Es cache puro (zig lo rehace; la
+        # primera tanda después va más lenta y ya), y NADIE lo podaba nunca: ni este watchdog, ni
+        # `poda-fuentes.sh`, ni la cosecha.
+        #
+        # ⚠ Por qué `mv` y DESPUÉS `rm -rf`, y no `rm -rf` directo: borrar millones de ficheros
+        # tarda minutos, y un build que arranque en el medio escribiría DENTRO del árbol que se está
+        # borrando. El rename es atómico: el build siguiente encuentra el sitio vacío y crea su
+        # cache nuevo mientras el viejo se va en paralelo. Mismo motivo por el que esto va dentro de
+        # la guarda de «ningún build en vuelo» que protege a las caches Go.
+        #
+        # La ruta sale igual que en `config.rs` (`cache_root = <proy>/.dev-fs/cache`), con el mismo
+        # override `CACHE` que acepta el build: si alguien lo mueve, el watchdog lo sigue.
+        zcache="${CACHE:-$HAMMER_DIR/.dev-fs/cache}/zig"
+        if [ -d "$zcache" ]; then
+          zbasura="$(dirname "$zcache")/.zig-borrando-$$"
+          if mv "$zcache" "$zbasura" 2>/dev/null; then
+            rm -rf "$zbasura" &
+            echo "$(date -u +%FT%TZ) watchdog: cache de zig apartado y borrándose en segundo plano"
+          fi
+        fi
       fi
     fi
   done