INCIDENTE (2026-07-23): un worker quedó 3.5h idle quemando € mientras el usuario
dormía. El dead-man del worker estaba "activo" (timer disparando cada 10 min)
pero FALLABA con exit 1 en cada tick: llegaba a matarse pero su
/etc/hammer-deadman.env no tenía token válido ⇒ salía 1 "sin HCLOUD_TOKEN" y
nunca se borraba. Verificaron que el timer DISPARA, no que puede BORRAR —
firing ≠ can-delete.
Causa de fondo: la garantía dependía de que CADA worker se auto-provisione bien
un token, y eso falla EN SILENCIO. Un invariante que depende de una provisión
frágil no es un invariante.
FIX en dos capas (defensa en profundidad):
1. REAPER HUB-SIDE (cosecha-cron.sh): el hub tiene un token que funciona y el
latido corre cada 30 min aunque no haya sesión (setsid). Un worker sin trabajo
activo REAPER_MAX=2 ciclos (~1h) se BORRA desde el hub, con el MISMO blindaje
de label role=hammer-worker (gioser jamás pasa). Cubre "dead-man del worker
roto". El dead-man del worker sigue cubriendo "hub caído".
2. farm-up verifica CAN-DELETE, no sólo firing: que el token del worker vea su
propio id en la API (lo mismo que hace al morir). Si no puede, LO GRITA al
provisionar en vez de descubrirlo 3.5h tarde.
Acción inmediata tomada: worker borrado a mano (label verificado), €0 baseline
restaurado — sólo queda gioser (protegido, fijo). Todo estaba cosechado.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>