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…
granja: cuatro sondas quedaron ciegas tras el renombre — el informe decía «idle» compilando
1#!/usr/bin/env bash
2# estado-granja.sh — foto RÁPIDA de la granja, on-demand (no depende del cron). Corre cuando quieras
3# ver dónde va sin esperar al latido: salud del worker, qué muele, avance KDE, y si el cron corrió.
4# scripts/farm/estado-granja.sh
5set -uo pipefail
6ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
7SSH_KEY="${SSH_KEY:-$HOME/.ssh/github5}"
8FLEET="$ROOT/scripts/farm/.fleet"
9SSH="ssh -i $SSH_KEY -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o BatchMode=yes -o LogLevel=ERROR -o ConnectTimeout=12"
10
11echo "══ WORKERS ($(date '+%H:%M:%S')) ══"
12if [ -s "$FLEET" ]; then
13 while read -r name ip; do
14 [ -n "${name:-}" ] || continue
15 echo "▶ $name ($ip)"
16 $SSH "root@$ip" '
17 echo " $(uptime | sed "s/.*load average/load/")"
18 n=$(ls /opt/takana/store 2>/dev/null | wc -l); echo " store: $n artefactos"
19 # ⚠ LOS DOS NOMBRES. El renombre hammer→takana (ADR 0016) dejó esta sonda ciega: el worker
20 # invoca `./target/release/takana` y acá se buscaba `release/hammer`, así que «moliendo»
21 # decía «(nada — idle)» CON EL WORKER CONSTRUYENDO. Comprobado el 2026-09-14: el informe
22 # decía idle mientras allá corría `takana --store ./store build recipes/centrifugo.toml`.
23 # Un informe que miente sobre si hay trabajo es peor que no tenerlo — leyendo ese «idle» se
24 # concluye que la granja está seca. El binario `hammer` sigue existiendo (cargo lo compila
25 # como alias), así que se aceptan los dos.
26 b=$(pgrep -af "release/(takana|hammer)" | grep -E "release/(takana|hammer) (build|--store|hash)" | grep -oE "[^ /]+\.toml" | sort -u | tr "\n" " ")
27 echo " moliendo: ${b:-(nada — idle o entre colas)}"
28 ' 2>/dev/null || echo " ⚠ sin respuesta (¿dead-man lo mató? ¿aún arrancando?)"
29 done < "$FLEET"
30else
31 echo " flota vacía (scripts/farm/.fleet) — no hay worker vivo"
32fi
33
34echo; echo "══ AVANCE KDE (grafo local) ══"
35if [ -f docs/state/build-state-kde.json ]; then
36 python3 - <<'PY'
37import json,os,time
38f="docs/state/build-state-kde.json"
39d=json.load(open(f)); q=d["by_queue"].get("incoming-kde",{})
40tot=sum(q.values()); s=q.get("sealed",0)
41age=int(time.time()-os.path.getmtime(f))
42bar=int(30*s/tot) if tot else 0
43print(f" [{'#'*bar}{'.'*(30-bar)}] {s}/{tot} sellado "
44 f"(deuda {q.get('debt',0)}, nunca {q.get('never',0)})")
45print(f" grafo regenerado hace {age//60}m {age%60}s (lo actualiza el cron o `scripts/build-state.py --kde`)")
46PY
47else
48 echo " (sin grafo — corré scripts/build-state.py --kde)"
49fi
50
51echo; echo "══ CRON DE COSECHA ══"
52line=$(crontab -l 2>/dev/null | grep cosecha-cron | grep -v '^#')
53[ -n "$line" ] && echo " instalado: $line" || echo " ⚠ NO instalado en el crontab"
54if [ -f work/cosecha-cron.log ]; then
55 echo " último ciclo (tail):"
56 grep -E 'cosecha-cron (arranca|fin)|siembra|cosecha ✓|estado commit' work/cosecha-cron.log | tail -6 | sed 's/^/ /'
57else
58 echo " (aún no corrió — no hay work/cosecha-cron.log; el cron dispara en :00 y :30)"
59fi