#!/bin/sh # juez.sh — 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 }" 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 `takana 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 --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