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 1389Shell 137Markdown 80Rust 802602 Definiciones

granja: el worker es el LXC PRESTADO (€0) — que no se vuelva a perder

El dato ya estaba en memoria y aun así se perdió dos veces, así que ahora vive en los sitios
que se leen sin buscarlos: regla 1 bis de CLAUDE.md (que carga todo agente en cada sesión) y
la skill 'granja' del repo. Se compila en dev.gioser.net PARA NO GASTAR HETZNER; no se
levantan cajas hcloud salvo petición explícita.

Y se arregla la fragilidad que salió al mirar: el reaper de cosecha-cron expulsa de .fleet
todo lo que no esté en hcloud, y el LXC se salvaba SÓLO porque su nombre contiene la subcadena
'gioser' y caía en una lista negra que existe para proteger al hub de Hetzner — no tiene nada
que ver con él. Medido con el bloque real del reaper contra un .fleet de juguete:

  nombre CON 'gioser'                    → 'en LISTA NEGRA ⇒ intocable'      sobrevive
  el MISMO host como 'pruebasia-lxc'     → 'ya no existe en hcloud'          .fleet VACÍO

O sea que la granja se mantenía conectada por una casualidad de nombre, y con otro nombre
volvía a 'flota vacía' en el primer ciclo sin que nada fallara. Ahora el reaper pregunta por
SSH si el host responde, que es preguntarle a la máquina en vez de al nombre. Verificado en
las dos direcciones, con control:

  host vivo, nombre sin 'gioser'  → 'no es de hcloud pero RESPONDE ⇒ se queda (€0)'
  host que no responde            → 'no responde ⇒ lo saco de .fleet'   (intención original)

Queda anotado también que .fleet está gitignored: un hub recién clonado nace con la flota
vacía y la granja queda desconectada en silencio — la cosecha dice 'flota vacía', los
artefactos no vuelven, y estado-granja.sh reporta 'no hay worker vivo' con el worker
compilando. Es como se descubrió esto hoy.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QPJteswQvP1L7zSBrQQe2

d45c0688e77d19131eb4fc27f7fc8611ac584df9 · por Sergio · (hace 1 mes) · padre c1d80ff8a · ver el árbol en este commit

Delta semántico

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

3 archivos · +96 −1

diff --git a/.claude/skills/granja/SKILL.md b/.claude/skills/granja/SKILL.md
new file mode 100644
index 00000000..e8cc76b1
--- /dev/null
+++ b/.claude/skills/granja/SKILL.md
@@ -0,0 +1,47 @@
+---
+name: granja
+description: Cómo se compila en este proyecto — dónde está el worker, cómo se enchufa, y por qué NO se levantan cajas de pago. Usar al empezar cualquier trabajo de build, cosecha o estado de la granja.
+---
+
+# La granja de hammer
+
+## Lo primero, porque cuesta dinero equivocarse
+
+**Se compila en `dev.gioser.net` — un LXC PRESTADO, coste €0.** 6 cores, 16 G RAM + 8 G swap, 196 G.
+Se usa exactamente **para no gastar Hetzner**.
+
+**NO levantar cajas hcloud** (`farm-up.sh`, `farm-run.sh`) salvo petición explícita del usuario. El
+modelo efímero de pago existe, funciona y está documentado, pero está SUPERADO como sitio de trabajo
+desde el 2026-09-05. Un `farm-up` por reflejo gasta euros que no hacen falta.
+
+```sh
+ssh -i ~/.ssh/github5 root@dev.gioser.net    # github5 está en su authorized_keys
+ssh -i ~/.ssh/sergio  root@dev.gioser.net    # la otra válida; NO hay entrada en ~/.ssh/config,
+                                             # por eso un `ssh` a secas da "Permission denied" y
+                                             # parece que la caja rechaza — no ofrece clave, nada más
+```
+
+## Antes de decir «no hay worker»
+
+`scripts/farm/.fleet` (`<nombre> <ip>` por línea) es lo que conecta hub y worker, y **está en
+`.gitignore`**. Un hub recién clonado nace con la flota vacía: la cosecha dice «flota vacía» cada
+30 minutos, los artefactos del worker no vuelven, y **nada falla**. `estado-granja.sh` dirá «no hay
+worker vivo» aunque el worker esté compilando. Comprobar el fichero antes de creerle al informe:
+
+    cat scripts/farm/.fleet || echo "dev.gioser.net 154.197.1.13" > scripts/farm/.fleet
+
+## Reglas que no son estilo
+
+1. **Todo `hammer build` bajo `flock -o work/.farm-build.lock`.** El `-o` no es opcional: sin él un
+   proceso fugado hereda el fd y deja la granja sin compilar, en silencio. Ver regla 1 de CLAUDE.md.
+2. **Un lock tomado sin build a la vista se diagnostica con `fuser -v work/.farm-build.lock`**, que
+   nombra al fugado. Pasó dos veces el mismo día.
+3. **Antes de contar nada del corpus, mirar `docs/state/build-state*.json`** — hay uno por cola
+   (corpus, kde, gnome, cosmic, wlr) y el cron los regenera los cinco cada 30 min. No recontar a mano.
+4. **Nada se borra por nombre.** `gioser` es el hub del usuario, fijo y sin backup.
+
+## Qué hace el latido
+
+`cosecha-cron.sh` cada 30 min: siembra código hub→worker (rsync `--delete`, excluye
+`work/store/target/.git`), baja el **manifiesto** de sellados del worker (no el store — bajarlo
+deshacía la poda cada media hora), regenera los cinco grafos, y commitea+pushea el estado.
diff --git a/CLAUDE.md b/CLAUDE.md
index afd38200..d574c84d 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -46,6 +46,37 @@ conocida, no barrida.
 que usarlo nos serializa con la granja además de entre nosotros. **No está dentro de `hammer build`
 a propósito**: esos scripts lo toman por fuera y hammer se bloquearía contra ellos.
 
+## 1 bis. El worker es el LXC PRESTADO, y es GRATIS: no se levanta nada en Hetzner
+
+**`dev.gioser.net` (154.197.1.13, hostname interno `PruebasIA`) es dónde se compila.** Es un LXC
+prestado en el Proxmox de gioser: 6 cores, 16 G RAM + 8 G swap, 196 G de disco, **coste €0**.
+Se usa exactamente por eso — **para no gastar Hetzner**.
+
+⇒ **No levantar cajas hcloud** (`farm-up.sh`, `farm-run.sh`) salvo que el usuario lo pida por su
+nombre. El modelo efímero de pago sigue documentado y funcionando, pero está SUPERADO como sitio de
+trabajo desde el 2026-09-05. Un `farm-up` por reflejo cuesta dinero real y no hace falta.
+
+```sh
+ssh -i ~/.ssh/github5 root@dev.gioser.net     # github5 está en su authorized_keys
+ssh -i ~/.ssh/sergio  root@dev.gioser.net     # la otra que entra; NO hay entrada en ssh/config
+```
+
+**Se enchufa por `scripts/farm/.fleet`** (`<nombre> <ip>` por línea), que **está en `.gitignore`**:
+o sea que un hub recién clonado nace con la flota VACÍA y la granja queda desconectada **sin que
+nada falle** — la cosecha dice «flota vacía» cada 30 min y los artefactos del worker no vuelven.
+Pasó, y se descubrió por casualidad. Si `estado-granja.sh` dice «no hay worker vivo», mirá `.fleet`
+antes de creerle.
+
+    echo "dev.gioser.net 154.197.1.13" > scripts/farm/.fleet
+
+⚠ **Y hasta el 2026-09-08 eso sobrevivía por una CASUALIDAD DE NOMBRE.** El reaper de
+`cosecha-cron.sh` saca de `.fleet` a todo lo que no esté en hcloud; el LXC se salvaba sólo porque su
+nombre contiene la subcadena `gioser` y caía en una lista negra que existe para proteger al HUB de
+Hetzner y no tiene nada que ver con él. Medido: el mismo host llamado `pruebasia-lxc` era expulsado
+en el primer ciclo. **Arreglado** — ahora el reaper pregunta por SSH si el host responde en vez de
+mirarle el nombre — pero la lección queda: *una protección que funciona por accidente se ve igual
+que una que funciona por diseño*.
+
 ## 2. Nunca `git add -A` — y acotar el COMMIT, no sólo el `add`
 
 Sólo rutas explícitas. Un `add -A` arrastra al commit los ficheros a medias de otro agente. Commits
diff --git a/scripts/farm/cosecha-cron.sh b/scripts/farm/cosecha-cron.sh
index 2a3e0e7c..b56f6db4 100755
--- a/scripts/farm/cosecha-cron.sh
+++ b/scripts/farm/cosecha-cron.sh
@@ -164,7 +164,24 @@ if [ -s "$FLEET" ] && command -v hcloud >/dev/null 2>&1; then
     # ¿el server siquiera existe? Si ya no está en hcloud (borrado a mano o por un ciclo previo),
     # NO cuesta € y no debe quedar en .fleet para siempre. Se dropea (no entra a `sobreviven`).
     if ! hcloud server describe "$name" -o format='{{.Name}}' >/dev/null 2>&1; then
-      echo "==> reaper: $name ya no existe en hcloud ⇒ lo saco de .fleet"; rm -f "$strike_f"; continue
+      # ⚠ «No está en hcloud» son DOS casos muy distintos, y antes se trataban igual (2026-09-08):
+      #   · un worker PERMANENTE que no es de Hetzner — hoy el LXC prestado `dev.gioser.net`, que
+      #     no cuesta € ⇒ NO HAY NADA QUE SEGAR, y sacarlo de .fleet desconecta la granja EN
+      #     SILENCIO: la cosecha pasa a decir «flota vacía» y los artefactos del worker dejan de
+      #     volver, sin que nada falle. Es el mismo fallo mudo que este fichero ya tuvo.
+      #   · un server efímero ya borrado a mano ⇒ ése sí sobra en .fleet para siempre.
+      # Se distinguen preguntándole a la MÁQUINA, no al nombre. Antes el LXC sólo se salvaba porque
+      # su nombre contiene la subcadena «gioser» y caía en la lista negra de arriba — una lista que
+      # existe para proteger al HUB de Hetzner y no tiene nada que ver con él. Medido: el mismo host
+      # llamado `pruebasia-lxc` era expulsado de .fleet en el primer ciclo.
+      if $SSH root@"$ip" true 2>/dev/null; then
+        echo "==> reaper: $name no es de hcloud pero RESPONDE ⇒ worker permanente, se queda (€0)"
+        sobreviven="${sobreviven}${name} ${ip}
+"
+      else
+        echo "==> reaper: $name no está en hcloud y no responde ⇒ lo saco de .fleet"; rm -f "$strike_f"
+      fi
+      continue
     fi
     if $SSH root@"$ip" 'pgrep -f "hammer build|campana-deuda|farm-worker-loop" >/dev/null 2>&1'; then
       echo 0 > "$strike_f"; sobreviven="${sobreviven}${name} ${ip}