From d45c0688e77d19131eb4fc27f7fc8611ac584df9 Mon Sep 17 00:00:00 2001 From: Sergio Date: Tue, 8 Sep 2026 18:41:16 +0000 Subject: [PATCH] =?UTF-8?q?granja:=20el=20worker=20es=20el=20LXC=20PRESTAD?= =?UTF-8?q?O=20(=E2=82=AC0)=20=E2=80=94=20que=20no=20se=20vuelva=20a=20per?= =?UTF-8?q?der?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) Claude-Session: https://claude.ai/code/session_014QPJteswQvP1L7zSBrQQe2 --- .claude/skills/granja/SKILL.md | 47 ++++++++++++++++++++++++++++++++++ CLAUDE.md | 31 ++++++++++++++++++++++ scripts/farm/cosecha-cron.sh | 19 +++++++++++++- 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 .claude/skills/granja/SKILL.md 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` (` ` 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`** (` ` 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}