Renombrado el directorio del worker y la unit, con las tres units del repo
(farm, deadman service y timer). Todas las rutas /opt/hammer del hub pasan a
/opt/takana: eran defaults REMOTE= y HAMMER_DIR=, mas los systemctl/journalctl
que nombraban la unit sin el sufijo .service, que el primer sed no casaba.
Orden, para que no quedara partido: el hub siembra por rsync a una ruta fija,
asi que se saco el cron ANTES de mover. Si se movia el worker con el hub
apuntando a la ruta vieja, la siguiente cosecha recreaba /opt/hammer y quedaban
dos arboles.
Verificado de punta a punta:
- el worker cerro un ciclo de build REAL desde /opt/takana (dunst sellado, 1/1)
- una cosecha completa del hub contra la ruta nueva: siembra, manifiesto, los
nueve grafos, static-audit (691 estaticos, MIENTEN 0) y estado pusheado
- la unit vieja quedo deshabilitada y borrada; /opt tiene una sola entrada
NO se tocan dos referencias a /opt/hammer que siguen siendo CORRECTAS:
docs/23-plan-rehasheo.md describe rutas EMBEBIDAS en artefactos ya construidos
—que literalmente dicen /opt/hammer/work en sus secciones .debug— y el HANDOFF
de la noche de KDE es registro. Cambiarlas haria que los documentos mientan.
Era la cola de staging de las tandas base-system/foot y sus recetas ya se
habian PROMOVIDO a canonicas commit a commit ("promover 7 tier-2", "promover
cadena crypto", "promover tllist/utf8proc/scdoc/fcft/foot"). Lo que quedaba
eran 0 .toml y 26 .patch: 5 copias byte a byte de la version canonica de
recipes/ y 21 de recetas que ya no viven ahi.
No eran "probablemente inutiles": son inalcanzables POR CONSTRUCCION.
`fetch::apply_patches` resuelve `recipe.base_dir.join(nombre)` y `base_dir` es
el directorio de la receta, sin fallback a `recipes/` — un parche en una cola
sin recetas no lo puede pedir nadie.
⚠ El corolario queda escrito en farm-worker-loop.sh: al promover una cola, los
`.patch` NO viajan con la receta, y la cola queda en un estado que PARECE vivo
(tiene ficheros) sin moler nada.
Sale de QUEUES en farm-worker-loop.sh y de la lista de promote de farm-down.sh.
`incoming-go` se queda en las dos aunque el directorio no exista: es la cola
aislada del frente Go y el guard `ls $Q/*.toml` salta las vacias; quitarla seria
dejarla muerta el dia que ese frente la recree.
Verificado con la regla ESTRICTA de resolucion de parches sobre todo el corpus:
94 referencias resuelven, 0 rotas. (El chequeo que use al jubilar onda-2 era mas
laxo que hammer — aceptaba recipes/<parche> como fallback; su conclusion se
sostiene, pero el metodo queda corregido.)
Gate --check OK, grafo CIERRA, corpus 786/787.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LykB7vw38b4Ck1Zij15RQ4
Podé el store por tercera vez hoy: 363 artefactos superados, 24 G. Comparado con la poda de la
tarde: **362 en común**. Volvieron otra vez, pese al arreglo de esta tarde.
LA CAUSA de que el arreglo no sirviera: puse el `--exclude-from` del registro de podados sólo en
`farm-sync.sh`, y el latido NO usa ese script. `cosecha-cron.sh` tiene su PROPIO rsync del store
(línea 71), y corre cada 30 minutos por cron ⇒ una poda de 24 G quedaba deshecha en menos de una
hora. Los tres commits de «cosecha granja» de la madrugada son exactamente eso.
Y al ir a arreglarlo, en vez de parchear y seguir, busqué si había más: **son CUATRO** las rutas
que bajan el store del worker — `cosecha-cron.sh`, `farm-sync.sh`, `harvest-go.sh` y
`farm-down.sh`. Tenía protegida una de cuatro.
El error de método vale más que el bug: arreglar una de varias copias y declarar victoria es
PEOR que no arreglar, porque el síntoma se atenúa lo justo para dejar de mirar. Lo que lo
delató fue comparar los manifiestos de dos podas (`comm -12`), no leer código. Dos podas con el
mismo número no son coincidencia — ya está anotado como regla, y hoy la regla pagó dos veces.
Las cuatro llevan ahora el mismo `--exclude-from` y una nota que dice que son cuatro, para que
la quinta —si aparece— nazca protegida.
Disco: 112 G → 136 G tras la poda de ahora.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Las 7 recetas del stack gráfico (libdrm/mesa/meson/samurai/seatd/wayland/wayland-protocols) +
6 patches eran imports crudos de Alpine, redundantes: las 7 ya tienen receta CANÓNICA en recipes/
(mesa pineada a 24.0.9 iris-only A PROPÓSITO, no la 26.1.1 cruda con FIXME-sha256). Su trabajo
aterrizó por la vía canónica (7131cd4) hace 3 semanas; la cola quedó de cruft rompiendo cada ciclo.
fa45978 las sacó de QUEUES creyéndolas de 'otro agente' (5126a8b). Confirmado que NO hay otro
agente ⇒ borradas. recipes/incoming/ vuelve a ser cola de staging general y REGRESA a QUEUES; el
guard ls-vacío la salta si no hay nada. recipes/incoming/.deferred/ (24 recetas aparcadas con
diagnóstico, git con muro en libgit.a) NO se toca: el glob de QUEUES es top-level, no la muele.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
recipes/incoming/ es la cola del stack gráfico tawasuyu, de otro agente. Sus 7 recetas son
imports crudos de Alpine con sha256='FIXME-sha256' y deps sin expandir (clang$_llvmver, _dev,
py3-gpep517) ⇒ NO construibles por construcción. El worker las fallaba en CADA vuelta (CPU
pagada) y farm-down repetía los 6 errores al bajar, con pinta de ser nuestros.
Su trabajo YA aterrizó por la vía canónica (7131cd4 'MESA iris-only CONSTRUIDA — stack gráfico
COMPLETO'), así que la cola quedó obsoleta. Pero NO es nuestra para borrarla: 370e7b7 ya la
parqueó una vez como cruft y 5126a8b tuvo que revertirlo. Dejamos sus ficheros en paz y sólo
los sacamos de QUEUES.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Petición explícita del usuario: gioser.net es FIJO y NO TIENE BACKUP. Vive en el
MISMO proyecto hcloud que los workers, y Hetzner no da tokens por-recurso: el
token que el dead-man switch necesita para auto-borrarse puede borrar CUALQUIER
server del proyecto. farm-down era peor: borraba por NOMBRE leído de .fleet sin
verificar NADA — un nombre equivocado en esa lista y adiós.
Dos capas, porque una sola no basta cuando el fallo es irreversible:
1. LISTA NEGRA por nombre (gioser*) — explícita y legible.
2. LABEL role=hammer-worker — sólo se borra lo que NACIÓ de farm-up. Ésta es la
capa fuerte: no depende de mantener una lista al día. Un server que no es
worker no se borra, punto.
VERIFICADO contra los servers vivos, no en teoría:
gioser labels=map[] ⛔ PROTEGIDO
hworker-4 labels=map[role:hammer-worker] BORRABLE
Y .fleet sólo contiene hworker-4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
dalfox/templ/errcheck/ineffassign/unconvert (Go) + dprint (Rust) + kyverno (Go),
construidos en un worker efímero hcloud, cosechados y firmados. Binarios musl-static
verificados: dalfox 3.1.2, templ v0.3.1020, dprint 0.55.1, ineffassign, y los
analizadores Go corren. feroxbuster/jless/mdcat/mise quedan staged (frontera *-sys:
openssl-sys/xcb desde fuente).
Fix farm-down: el promote final ahora recorre TODAS las colas del worker
(incoming/incoming-go/incoming-clib), no sólo recipes/incoming — los artefactos de
las otras colas se cosechaban pero no se firmaban.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Los workers efímeros reciclan IPs de Hetzner. accept-new RECHAZA una clave de host
cambiada ⇒ el 'until ssh true' de farm-up colgaba para siempre en una IP reusada.
Como el modelo es hub-and-spoke (worker sin secretos, compute descartable) no hay
superficie MITM: saltamos verificación de host y no ensuciamos known_hosts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Migración del worker pet-24/7 a workers efímeros on-demand. farm1 (ccx23 persistente que
idleaba quemando plata) → snapshot golden 'hammer-golden-2026-07-05' (img 405120842: toolchain
+ store sellado horneados) → destruido. Baseline ahora 0 cajas / €0.
- farm-up.sh [N]: crea N workers desde el snapshot (cache-hit instantáneo del catálogo baked),
los alinea con la cola actual del laptop, registra la flota en scripts/farm/.fleet (gitignored).
- farm-down.sh [name...]: cosecha el store (CAS, merge seguro) al laptop y DESTRUYE; promueve+firma.
Orden seguro: sólo destruye si el pull de store salió bien.
- Validado punta a punta: up 1 → boot+cache+toolchain OK → down (cosecha+destruye) OK.
- Cron laptop harvest-go contra farm1 removido (la cosecha ahora la hace farm-down).
El worker sigue sin secretos (hub-and-spoke): compute puro y descartable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>