Files
hammer/scripts/juez.sh
T
sergioandClaude Opus 4.8 d99ed58850 harkaq: revertir busybox (era runtime base, rompía builds) + coordinar el §3 con Fable 5
DOS ERRORES MÍOS, uno de dirección y otro técnico, los dos en la cosecha automática:

1. DIRECCIÓN: declaró `busybox` como dep en 29 recetas — cuando la Etapa C lo está
   ELIMINANDO (USERLAND_COMPONENTS=[uutils,findutils,…], ya cerrada; joyas-reusables
   §5 lo confirma: "uutils… Ubuntu 25.10 los envía como default"). Estaba cimentando
   la deuda que el roadmap borra.
2. TÉCNICO: busybox YA está en el runtime base de harkaq (`ro /bin/busybox`, `ro
   /bin/sh` — el sandbox corre `sh -c` y /bin/sh→/bin/busybox). Es CONTRATO, no dep.
   Declararlo apila el busybox de hammer sobre el de Alpine y ROMPE el build:
   binutils daba "cannot run C compiled programs" en las DOS máquinas. Verificado:
   sin busybox declarado, binutils construye (b3:f4507dcd…). Y la cadena se explica:
   binutils roto ⇒ zlib (que lo declara) tampoco construía.

Auditoría de la cosecha (diff real, no la línea completa del +): añadió sólo 5 deps
distintas — make ×73, busybox ×29, perl ×8, pkgconf ×5, binutils ×1. Sólo busybox
estaba mal; las otras 4 son deps reales medidas. busybox revertido de 30 recetas
(queda sólo en busybox.toml, pre-existente).

Es el mismo error que ya me habían señalado con otro disfraz: MEDIR BIEN Y ACCIONAR
MAL. harkaq midió correcto (el build toca /bin/busybox: es el shell); la acción
correcta no era declararlo sino reconocerlo como contrato.

+ COORDINACIÓN del §3 con Fable 5 (mismo diseño, tareas repartidas):
  - Su lección casper queda CONFIRMADA y REFORZADA: la clausura de build no sólo le
    FALTAN las clases del mundo (offline) — también le SOBRA casi todo (headers, gcc).
    Medido: htop (estático, 0 NEEDED) no toca NADA al correr ⇒ política = su binario.
  - Su "la clase viaja como campo de la ConcesionCapacidad, sin formato nuevo" se
    cumple LITERALMENTE: lo firmado es format::Permisos = u32 bitmask en 36 bytes
    canónicos (Ring 0) ⇒ las clases SON los bits. La cripto no se toca.
  - Diseño unificado: frontera (clases, u32, declaradas) + detalle (paths, Landlock,
    medidos). D3 rige en ambos.
  - Reparto: clases→Fable 5; medición/harness→Opus. CONTACTO: runtime-policy.sh ahora
    emite la CLASE detectada (/etc/resolv.conf→dns, /etc/ssl/certs→tls-certs, …), no
    sólo el path: la medición alimenta la tabla, la tabla decide el bit.
  - Consumidor esperando: plan-jaula-juegos F1 (Steam que no puede leer ~/.ssh).

+ juez.sh (§10): nombre único por corrida (con uno fijo pega en caché ⇒ falso
  "sin evidencia"). Fue el juez quien destapó todo esto en su primera corrida real.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 23:14:19 -04:00

105 lines
5.3 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/sh
# juez.sh <receta> — JUEZ MECÁNICO del bucle agéntico (SDD 17 §10).
#
# agente propone receta → harkaq veredicto → granja reproduce ×2 → catálogo acepta
#
# Sin humano en el medio para la parte mecánica: el humano decide QUÉ construir; el juez decide
# si lo construido MERECE entrar al catálogo, y lo decide con evidencia, no con opinión.
#
# scripts/juez.sh recipes/zlib.toml
#
# Dos preguntas, dos veredictos, ninguno negociable:
# 1. ¿HERMÉTICO? harkaq (SDD 16): ¿usó algo que no declaró? El kernel responde.
# `denials=[]` no se cree, se GANA (el canario lo demuestra — D9).
# 2. ¿REPRODUCIBLE? consenso (SDD 17 §1): N builders independientes, ¿el mismo hash?
# Si sí, el artefacto es confiable SIN FIRMA.
#
# Si falla, el juez no dice "no" a secas: dice POR QUÉ y qué hacer.
# - Impuro → harkaq-suggest: "declarar dep: make" (arreglo mecánico)
# - Divergente → why-differs: qué fichero, qué causa (codegen/timestamp/build-id)
#
# Es el bucle que el SDD 08 §4 pide ("la IA propone, el sistema reproduce, el humano commitea")
# con la pieza que faltaba: un juez que la IA no puede convencer, sólo satisfacer.
set -eu
RECETA="${1:?uso: juez.sh <receta.toml>}"
HUB="$(cd "$(dirname "$0")/.." && pwd)"
cd "$HUB"
n=$(basename "$RECETA" .toml)
BUILDERS="${BUILDERS:-2}"
echo "══════ JUEZ MECÁNICO — $n"
echo
# ── 1. ¿HERMÉTICO? (harkaq)
echo "── 1/2 ¿usó algo que no declaró? [harkaq, SDD 16]"
if [ ! -x "${HARKAQ_BIN:-$HOME/.cache/harkaq}/harkaq-audit" ]; then
echo " ⊘ harkaq no está compilado ⇒ SIN EVIDENCIA. El juez NO afirma hermeticidad."
echo " (compilar scripts/harkaq/*.c y `setcap cap_audit_read` — ver scripts/harkaq/README.md)"
veredicto_h="sin-evidencia"
else
export HARKAQ=1 HARKAQ_BIN="${HARKAQ_BIN:-$HOME/.cache/harkaq}"
export HARKAQ_BASE="${HARKAQ_BASE:-$HARKAQ_BIN/base.policy}" HARKAQ_TIMEOUT="${HARKAQ_TIMEOUT:-200}"
# Nombre ÚNICO por corrida: con uno fijo, la 2ª vez `hammer build` pega en CACHÉ, no
# construye nada, no hay veredictos y el juez dice "sin evidencia" — un falso negativo que
# parece un problema de la receta. (Gotcha conocido; me mordió al probar el juez.)
uniq="$n-juez-$$"
tmp="$(dirname "$RECETA")/.juez-$n.toml"
sed -E "s/^(name\s*=\s*)\"$n\"/\1\"$uniq\"/" "$RECETA" > "$tmp"
out=$(timeout "${POR:-600}" ./target/debug/hammer build "$tmp" --store "$PWD/store" 2>&1 || true)
rm -f "$tmp"; rm -rf store/*-"$uniq" 2>/dev/null || true
veredictos=$(echo "$out" | grep '^\[harkaq\] {' | sed 's/^\[harkaq\] //')
deuda=""
if [ -z "$veredictos" ]; then
echo " ⊘ sin veredicto (¿caché? ¿el build ni arrancó?) ⇒ SIN EVIDENCIA"
veredicto_h="sin-evidencia"
else
veredicto_h="hermetico"
i=0
echo "$veredictos" | while IFS= read -r v; do :; done
printf '%s\n' "$veredictos" > /tmp/.juez-v
while IFS= read -r v; do
i=$((i + 1)); echo "$v" > /tmp/.juez-1
est=$(scripts/harkaq/harkaq-verdict.py /tmp/.juez-1 "$HARKAQ_BASE" --human 2>/dev/null | head -1 | sed 's/^ *estado: //;s/ .*//')
echo " fase $i: ${est:-?}"
[ "$est" = "Impuro" ] && { veredicto_h="impuro"; \
scripts/harkaq/harkaq-suggest.py /tmp/.juez-1 "$HARKAQ_BASE" "$PWD/store" "$PWD/recipes" "$RECETA" 2>/dev/null | sed 's/^/ /'; }
[ "$est" = "SinEvidencia" ] && veredicto_h="sin-evidencia"
done < /tmp/.juez-v
# el while corre en subshell: recuperar el peor veredicto por marcador
grep -q '"estado":"Impuro"' /tmp/.juez-v && veredicto_h="impuro"
grep -q '"estado":"SinEvidencia"' /tmp/.juez-v && veredicto_h="sin-evidencia"
fi
fi
echo
# ── 2. ¿REPRODUCIBLE? (consenso)
echo "── 2/2 ¿N builders independientes dan el mismo hash? [consenso, SDD 17 §1]"
if consenso=$(BUILDERS="$BUILDERS" timeout "${POR_CONSENSO:-1200}" scripts/consenso.sh "$RECETA" "$BUILDERS" 2>&1); then
echo "$consenso" | grep -E '✅|builder' | sed 's/^/ /'
veredicto_r="consenso"
else
rc=$?
echo "$consenso" | grep -E '⚠️|builder|SIN CONSENSO' | sed 's/^/ /'
[ "$rc" = 1 ] && veredicto_r="divergencia" || veredicto_r="sin-consenso"
if [ "$veredicto_r" = divergencia ]; then
echo " ── why-differs (SDD 17 §2) explicaría la divergencia:"
echo " scripts/why-differs.py <hashA> <hashB> --store ./store"
fi
fi
echo
# ── VEREDICTO
echo "══════ VEREDICTO"
if [ "$veredicto_h" = hermetico ] && [ "$veredicto_r" = consenso ]; then
echo " ✅ ACEPTAR — no usó nada sin declarar Y $BUILDERS builders lo reprodujeron bit a bit."
echo " El catálogo puede confiar en este artefacto sin firma y sin revisión humana del build."
exit 0
fi
echo " ❌ NO ACEPTAR"
[ "$veredicto_h" = impuro ] && echo " · hermeticidad: usa algo sin declarar (ver la sugerencia arriba: es una línea)"
[ "$veredicto_h" = sin-evidencia ] && echo " · hermeticidad: SIN EVIDENCIA — no se afirma nada (D9: un lector ciego y un build limpio son idénticos)"
[ "$veredicto_r" = divergencia ] && echo " · reproducibilidad: los builders NO coinciden ⇒ hay un canal impuro"
[ "$veredicto_r" = sin-consenso ] && echo " · reproducibilidad: no hubo suficientes builders con hash"
exit 1