Files
sergioandClaude Opus 4.8 d0c9cdfa33 harkaq: deuda declarable vs irreducible (§4.5) + primer barrido de Fase 2 (§4.6)
La métrica del §7 (<5% de recetas necesitan excepción) medía otra cosa. zlib
salió Impuro por /usr/bin/make y parecía runtime base: NO lo es. recipes/make.toml
existe, store/fbad44ac…-make está sellado y SWAP_MAKE es uno de los swaps del
selfhost-verify ⇒ a zlib le falta una LÍNEA en [deps], no una excepción.

  declarable   el store ya provee el path ⇒ arreglo mecánico    → NO cuenta
  irreducible  nadie lo provee ⇒ receta nueva o runtime base    → SÍ cuenta

harkaq-suggest.py cruza cada path de deuda contra el store (el mapeo de §4.1 al
revés: el path relativo dentro del artefacto ES el path del sandbox):
    /usr/bin/make          → declarar dep: make
    /usr/lib/libz.so.1.3.2 → irreducible (la zlib de hammer da libz.a estático,
                             no .so ⇒ NO se arregla declarando)
El diagnóstico deja de ser "algo pasó" y pasa a ser "hacé esto".

PRIMER BARRIDO (6 recetas C, fuentes cacheadas):
  Hermetico ............... 0
  sólo deuda DECLARABLE ... 5  ← y la deuda es EL MISMO path en las 5: /usr/bin/make
  con deuda IRREDUCIBLE ... 1  (brotli)

Lo que importa: la deuda de 5/6 es UN SOLO path y se arregla con una línea. No
hay cola larga de excepciones — que era el riesgo de muerte del §7.

Y el caso irreducible es la frontera CONOCIDA: brotli (C++) pide
/usr/lib/libstdc++.so.6.0.34 y /usr/lib/libgcc_s.so.1 — el runtime C++ del gcc de
Alpine, que hammer no construye. Es exactamente lo que la campaña "matar gcc" ya
tenía identificado. TERCERA vez que harkaq llega por su cuenta a una lista que
otro frente ya tenía: los swaps del selfhost-verify (§4.3), los binutils (§4.4)
y ahora el runtime C++.

Honestidad: 6 recetas no son 750 y son las fáciles. 1/6 = 17%, muy por encima del
<5% — pero el único caso es un problema conocido, nombrado y compartido con otros
dos frentes, no una cola de sorpresas. El barrido grande es trabajo de granja.

Bug del barrido encontrado por el propio barrido: copiar la receta a otro
directorio rompe la resolución de deps.build (son relativas al dir de la receta)
⇒ brotli fallaba con "no pude cargar la dep 'cmake'" y se descartaba EN SILENCIO
— o sea que se descartaban justo las recetas CON deps, las interesantes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:02:27 -04:00

79 lines
3.3 KiB
Bash
Executable File

#!/bin/sh
# Fase 2 — barrer el catálogo y medir la tasa de excepciones (SDD 16 §6).
#
# fase2-barrido.sh <receta.toml> [<receta.toml>...]
#
# El criterio de viabilidad del SDD (§7): "si el 30% de los builds necesita excepción manual,
# harkaq se desactiva y queda como decoración". Métrica: <5%.
#
# Pero "excepción" no es "denegación" (§4.5). Una deuda que el store YA PROVEE no es una
# excepción: es una línea en `[deps]` que falta, y el arreglo es mecánico. Sólo la deuda
# IRREDUCIBLE —nadie la provee— cuenta contra el <5%. Sin esa distinción la métrica mide
# ansiedad, no viabilidad.
#
# `hammer build` pega en la caché si el artefacto ya está sellado (no correría nada y el
# veredicto saldría vacío sin que sea un fallo). Se fuerza un build real copiando la receta con
# otro `name` — cambia hash_inputs sin tocar el store real ni la receta del repo.
set -eu
cd "$(dirname "$0")/../.."
BIN="${HARKAQ_BIN:-$HOME/.cache/harkaq}"
BASE="${HARKAQ_BASE:-$BIN/base.policy}"
OUT="${OUT:-work/harkaq-fase2}"
mkdir -p "$OUT"
export HARKAQ=1 HARKAQ_BIN="$BIN" HARKAQ_BASE="$BASE"
export HARKAQ_TIMEOUT="${HARKAQ_TIMEOUT:-120}"
total=0; limpias=0; solo_declarable=0; con_irreducible=0
: > "$OUT/deuda-cruda.txt"
for receta in "$@"; do
n=$(basename "$receta" .toml)
total=$((total + 1))
# La copia va AL LADO del original: las `deps.build` se resuelven relativas al directorio
# de la receta, así que copiarla a otro sitio rompe `cmake.toml` y compañía — y descartaba
# en silencio justo las recetas CON deps, que son las interesantes. Se limpia al salir.
tmp="$(dirname "$receta")/.harkaq-$n.toml"
sed "s/^name *= *\"$n\"/name = \"$n-hk\"/" "$receta" > "$tmp"
trap 'rm -f "$tmp"' EXIT
log="$OUT/$n.log"
timeout "${POR_RECETA:-300}" ./target/debug/hammer build "$tmp" --store "$PWD/store" \
> "$log" 2>&1 || true
# Un veredicto por fase (configure/compile/install son bwraps distintos ⇒ dominios distintos).
rm -f "$tmp"
grep '^\[harkaq\] {' "$log" | sed 's/^\[harkaq\] //' > "$OUT/$n.verdicts" || true
if [ ! -s "$OUT/$n.verdicts" ]; then
echo "?? $n — sin veredicto (¿caché? ¿fetch falló? ver $log)"
continue
fi
irr=0; dec=0
while IFS= read -r v; do
echo "$v" > "$OUT/.v.json"
s=$(scripts/harkaq/harkaq-suggest.py "$OUT/.v.json" "$BASE" "$PWD/store" 2>/dev/null || true)
echo "$s" | grep -q 'IRREDUCIBLE' && irr=1
echo "$s" | grep -q 'DECLARABLE' && dec=1
echo "$s" | sed -n 's/^ \(\/[^ ]*\)$/\1/p' >> "$OUT/deuda-cruda.txt"
done < "$OUT/$n.verdicts"
if [ "$irr" = 1 ]; then
con_irreducible=$((con_irreducible + 1)); echo "!! $n — deuda IRREDUCIBLE"
elif [ "$dec" = 1 ]; then
solo_declarable=$((solo_declarable + 1)); echo "~~ $n — sólo deuda declarable (falta [deps])"
else
limpias=$((limpias + 1)); echo "ok $n — Hermetico"
fi
done
echo
echo "════ FASE 2 — $total receta(s)"
echo " Hermetico ................... $limpias"
echo " sólo deuda DECLARABLE ....... $solo_declarable (arreglo mecánico: una línea en [deps])"
echo " con deuda IRREDUCIBLE ....... $con_irreducible ← lo que cuenta contra el <5%"
echo
echo " paths de deuda más frecuentes:"
sort "$OUT/deuda-cruda.txt" | uniq -c | sort -rn | head -12 | sed 's/^/ /'