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.
140 lines
7.2 KiB
Bash
Executable File
140 lines
7.2 KiB
Bash
Executable File
#!/bin/sh
|
|
# harvest-harkaq.sh — COSECHA-ONLY de la campaña harkaq (modo desatendido, para cron en el hub).
|
|
# Determinista, sin IA. Hermano de harvest-go.sh y con la misma disciplina: no elige, no diagnostica,
|
|
# no compila en el hub; sólo convierte en commit lo que el worker YA midió.
|
|
#
|
|
# Uso (cron): cd /home/sergio/hammer && scripts/farm/harvest-harkaq.sh root@<ip> >>work/harvest-harkaq.log 2>&1
|
|
#
|
|
# POR QUÉ EXISTE ASÍ: la lista de "recetas a las que les falta declarar make" NO se puede sacar de
|
|
# un regex. Se intentó y falló dos veces en la misma tarde: `\bmake\b` colaba `cargo-make` (el guión
|
|
# es límite de palabra) y la versión estrecha perdía LAS CINCO recetas donde harkaq había medido la
|
|
# deuda de verdad (`compile = "make …"`: el carácter previo es una comilla). El número bailó 69→45→99
|
|
# según el retoque. La fuente de verdad es la MEDICIÓN, no la conjetura — que es exactamente para lo
|
|
# que existe harkaq. Este script sólo aplica lo que el kernel denunció.
|
|
#
|
|
# Ciclo (idempotente, seguro de re-correr):
|
|
# 1. git pull --rebase (otro agente pushea al mismo main)
|
|
# 2. baja los veredictos del worker
|
|
# 3. por cada veredicto: harkaq-suggest contra el store COMPLETO del hub (el del worker es parcial
|
|
# y marcaría como irreducible lo que sí es declarable — el worker MIDE, el hub CLASIFICA)
|
|
# 4. si la deuda es DECLARABLE ⇒ añade la dep a la receta. Si es IRREDUCIBLE ⇒ NO la toca: va a
|
|
# tandas/needs-review-harkaq/ con el motivo. Declarar algo que el store no provee rompería el
|
|
# build en vez de arreglarlo.
|
|
# 5. commit + push con `git add` EXPLÍCITO (nunca -A: respeta al otro agente)
|
|
set -u
|
|
|
|
HUB="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
# Ruta absoluta a MÍ MISMO capturada ANTES del `cd`: se usa para re-ejecutarse bajo el lock, y un
|
|
# `$0` relativo dejaría de resolver en cuanto cambiamos de directorio.
|
|
YO="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
|
|
cd "$HUB"
|
|
WORKER="${1:?uso: harvest-harkaq.sh root@<ip>}"
|
|
|
|
# LOCK: dos cosechas a la vez editarían recetas y harían `git commit` en paralelo = árbol
|
|
# corrupto. El harvest es lento (re-indexa el store por veredicto), así que un ciclo puede pisar
|
|
# al siguiente. flock con -n: si ya hay una corriendo, esta sale limpia en vez de solaparse.
|
|
LOCK="$HUB/work/.harvest-harkaq.lock"
|
|
# ⚠ `flock -o` y re-exec, NO `exec 9>` (medido 2026-09-08): el lock lo sostiene el fd y los hijos
|
|
# lo heredan, así que un `ssh` o un `rsync` fugado de esta cosecha lo retendría DESPUÉS de que el
|
|
# script termine y todas las cosechas siguientes saldrían por «otra cosecha en curso» — mudas y
|
|
# para siempre. Con `-o` el fd se cierra antes de ejecutar y sólo el proceso `flock` lo sostiene.
|
|
# `-E 77` separa «estaba ocupado» de «el trabajo falló». Ver la regla 1 de CLAUDE.md.
|
|
if [ -z "${HARVEST_HARKAQ_CON_LOCK:-}" ]; then
|
|
export HARVEST_HARKAQ_CON_LOCK=1
|
|
rc=0; flock -n -E 77 -o "$LOCK" "$YO" "$@" || rc=$?
|
|
if [ "$rc" = 77 ]; then
|
|
echo "$(date -u +%FT%TZ) otra cosecha en curso, salto este ciclo"
|
|
exit 0
|
|
fi
|
|
exit "$rc"
|
|
fi
|
|
SSH_KEY="${SSH_KEY:-$HOME/.ssh/github5}"
|
|
REMOTE="${REMOTE:-/opt/takana}"
|
|
SSH="ssh -i $SSH_KEY -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes"
|
|
REVIEW="tandas/needs-review-harkaq"
|
|
mkdir -p "$REVIEW" work
|
|
|
|
echo "═══ $(date -u +%FT%TZ) cosecha harkaq desde $WORKER"
|
|
git pull --rebase -q 2>/dev/null || echo " (pull falló; sigo con lo local)"
|
|
|
|
VERD=work/harkaq-verdicts
|
|
rm -rf "$VERD"; mkdir -p "$VERD"
|
|
rsync -az -e "$SSH" "$WORKER:$REMOTE/work/harkaq-campana/" "$VERD/" 2>/dev/null || {
|
|
echo " sin veredictos que cosechar (¿el worker sigue midiendo?)"; exit 0; }
|
|
|
|
tocadas=""
|
|
for v in "$VERD"/*.verdicts; do
|
|
[ -f "$v" ] || continue
|
|
n=$(basename "$v" .verdicts)
|
|
[ -f "recipes/$n.toml" ] || continue
|
|
|
|
deps=""; irr=0
|
|
while IFS= read -r j; do
|
|
[ -n "$j" ] || continue
|
|
echo "$j" > /tmp/.hkv.json
|
|
s=$(scripts/harkaq/harkaq-suggest.py /tmp/.hkv.json "$HOME/.cache/harkaq/base.policy" \
|
|
"$HUB/store" "$HUB/recipes" 2>/dev/null) || true
|
|
echo "$s" | grep -q IRREDUCIBLE && irr=1
|
|
# "→ declarar dep: X" (el store lo provee y sabe cuál artefacto es).
|
|
d=$(echo "$s" | sed -n 's/.*→ declarar dep: \([a-zA-Z0-9._-]*\).*/\1/p')
|
|
deps="$deps $d"
|
|
done < "$v"
|
|
|
|
deps=$(echo "$deps" | tr ' ' '\n' | grep -v '^$' | sort -u | tr '\n' ' ')
|
|
[ -n "$deps" ] || continue
|
|
|
|
if [ "$irr" = 1 ]; then
|
|
# NO se toca: declarar algo que el store no provee rompe el build en vez de arreglarlo.
|
|
cp "$v" "$REVIEW/$n.verdicts"
|
|
echo " ?? $n — deuda irreducible ⇒ a needs-review (deps declarables vistas:$deps)"
|
|
continue
|
|
fi
|
|
|
|
if python3 scripts/farm/harkaq-add-deps.py "recipes/$n.toml" $deps; then
|
|
echo " ++ $n — declaradas:$deps"
|
|
tocadas="$tocadas recipes/$n.toml"
|
|
fi
|
|
done
|
|
|
|
# Recoger también las recetas editadas por un ciclo ANTERIOR que no llegó a commitear (el proceso
|
|
# murió, SIGPIPE, la máquina se apagó). Sin esto quedan huérfanas para siempre: al re-correr,
|
|
# add-deps dice "ya estaban declaradas", `tocadas` sale vacío y nadie las commitea nunca. Pasó en
|
|
# el primer ciclo real: 13 recetas editadas y sin committear. Se filtra por `recipes/*.toml` y por
|
|
# que el diff SÓLO toque la línea `build = [...]`, para no arrastrar trabajo de otro agente.
|
|
for f in $(git diff --name-only -- 'recipes/*.toml' 2>/dev/null); do
|
|
case " $tocadas " in *" $f "*) continue ;; esac
|
|
# ¿el diff toca SÓLO `[deps]`/`build =`? Se ignoran las líneas en blanco añadidas/quitadas
|
|
# (`^[+-]\s*$`): add-deps mete un `\n` tras el bloque y ese `+` vacío hacía que el filtro
|
|
# rechazara recetas legítimas (flex, gawk…) como "de otro agente". Y el mensaje usa comillas
|
|
# SIMPLES: con dobles, el `[deps].build` entre backticks se ejecutaba como comando.
|
|
if git diff -U0 -- "$f" | grep -E '^[-+]' | grep -vE '^(---|\+\+\+)' \
|
|
| grep -vE '^[-+]\s*$' | grep -qvE '^[-+]\s*(build\s*=|\[deps\])'; then
|
|
echo ' ·· '"$f"' — el diff toca algo que no es [deps].build: NO lo toco (¿otro agente?)'
|
|
else
|
|
tocadas="$tocadas $f"
|
|
echo " ↻ $f — pendiente de un ciclo anterior, se commitea ahora"
|
|
fi
|
|
done
|
|
|
|
if [ -n "$tocadas" ]; then
|
|
# `git add` EXPLÍCITO por rutas: el repo lo comparte otro agente (cola gráfica/Go).
|
|
# shellcheck disable=SC2086
|
|
git add $tocadas
|
|
git commit -q -m "harkaq: declarar deps medidas por el kernel (cosecha automática)
|
|
|
|
Cosecha desatendida de la campaña harkaq. Cada dep de acá la denunció el audit de
|
|
Landlock en un build real: el kernel vio al build usarla sin declararla, y el
|
|
store del hub confirma qué artefacto la provee (deuda DECLARABLE, §4.5).
|
|
|
|
Recetas:$(echo "$tocadas" | tr ' ' '\n' | grep -v '^$' | sed 's|recipes/||;s|\.toml||' | tr '\n' ' ')
|
|
|
|
No se tocó ninguna receta con deuda IRREDUCIBLE: declarar algo que el store no
|
|
provee rompería el build en vez de arreglarlo. Esas van a $REVIEW.
|
|
|
|
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>" && git push -q 2>/dev/null || {
|
|
git pull --rebase -q && git push -q; }
|
|
echo " ✓ commit+push de $(echo "$tocadas" | wc -w) receta(s)"
|
|
else
|
|
echo " nada que declarar en este ciclo"
|
|
fi
|