El lock lo sostiene la descripción de fichero abierta y los hijos la heredan: con 'exec 9>' +
'flock 9' cualquier descendiente que sobreviva al script retiene el lock para siempre, y el
siguiente que lo pida espera sin que nada falle. Medido hoy: dos firefox colgados de una caza
sobrevivieron al kill de su bwrap y dejaron a la granja hora y media sin poder compilar.
Dos formas de defecto ⇒ dos arreglos, y no son intercambiables:
· cosecha-cron, campana-deuda, harvest-harkaq — el lock cubre el script ENTERO, así que se
re-ejecutan bajo 'flock -o' (cierra el fd antes de ejecutar). Ir poniendo '9>&-' comando a
comando ahí es jugar a los topos. '-E 77' separa 'estaba ocupado' de 'el trabajo falló',
que con el 9> no se distinguían.
· farm-worker-loop, latido — el lock vive en un subshell / es a propósito el mecanismo de
vida, así que basta '9>&-' en los hijos. En latido NO se puede usar -o: ahí el fd retenido
ES como --status sabe que el latido vive sin pidfile. Su modo de fallo era el peor de
todos: un nieto fugado dejaba el latido MUERTO PERO APARENTANDO ESTAR VIVO.
Medido antes de elegir, no deducido del manual:
exec 9> + flock 9 → el nieto RETIENE (control negativo: reproduce el fallo)
exec {L}> (fd auto) → el nieto RETIENE (bash NO lo marca close-on-exec)
flock -o / 9>&- hijo → lock LIBRE
Y probados los cinco sobre el fichero real, no sobre una maqueta: copias truncadas justo tras
el bloque del lock, invocadas con RUTA RELATIVA DESDE OTRO DIRECTORIO (que es lo que rompe un
$0 sin resolver — de hecho la primera versión de harvest-harkaq calculaba YO después del cd y
habría fallado ahí). Los tres entran, ninguno deja el lock tomado por el nieto, y la exclusión
mutua sigue funcionando con su mensaje y su exit 0 — que es lo que un arreglo de locks puede
romper en silencio.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QPJteswQvP1L7zSBrQQe2
El latido vivía sólo en el crontab y eso resultó frágil: este laptop arranca a veces con
`init=/usr/local/sbin/arje-zero` y a veces con OpenRC (KDE), y no hay systemd en ninguno de los
dos. `cronie` es un servicio OpenRC ⇒ en el arranque arje no existe y el latido no late. Peor: no
late EN SILENCIO. Se destapó tras un corte sucio del 2026-07-22, en el que además se vio el
runlevel `default` quedar a medias (cronie/metalog/acpid caídos, NetworkManager/dbus arriba) ⇒ ni
siquiera arrancando OpenRC era garantía.
El costo del síntoma es caro y callado: sin latido el hub no siembra, el worker agota la cola y se
queda idle quemando € sin moler.
`latido.sh` cuelga el latido de la SESIÓN: cualquier terminal, en cualquier arranque, asegura que
haya exactamente un latido vivo (`--ensure` desde ~/.zshrc, ~5ms y mudo si ya hay uno). Sin root,
sin unidad de servicio, sin mantener lo mismo por duplicado en dos inits. Contra asumido: no late
sin sesión abierta — es un laptop, no un server, y el primer ciclo dispara al instante de abrir la
terminal (el cron esperaba hasta 30 min al próximo tick).
El lock va DENTRO de cosecha-cron.sh, no en el llamador, para que valga venga de donde venga. Eso
además tapa un bug latente que ya existía: nada impedía que dos ciclos se solaparan haciendo rsync
sobre el mismo store y `git commit`+`push` a la vez. Con el lock, el crontab puede quedarse: bajo
KDE dispara cron, bajo arje dispara la sesión, y nunca se pisan.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>