|
|
|
@@ -100,14 +100,66 @@ for d in "$GUARDA"/*; do
|
|
|
|
|
if [ -d "$STORE/$b" ]; then rm -rf "$d"; else mv "$d" "$STORE/$b"; echo " ↩ repuesto de una corrida anterior: $b"; fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# ── EL LIBRO DE LO YA VERIFICADO ───────────────────────────────────────────────────────────────
|
|
|
|
|
# Sin registro, cada corrida es una muestra aleatoria que se olvida: nadie puede decir qué fracción
|
|
|
|
|
# del corpus se verificó nunca, y las mismas recetas salen sorteadas una y otra vez mientras otras
|
|
|
|
|
# no se miran jamás. La clave es (receta, ArtifactHash) — el hash de HOY. Si la receta o cualquiera
|
|
|
|
|
# de sus deps cambia, el hash cambia, la entrada deja de casar y hay que volver a verificar. Un
|
|
|
|
|
# «ya lo verifiqué» que sobrevive a un re-hash sería una mentira; éste no puede.
|
|
|
|
|
LIBRO="${LIBRO:-docs/state/repro-verificado.tsv}"
|
|
|
|
|
[ -s "$LIBRO" ] || printf '%s\n' \
|
|
|
|
|
'# repro-verificado.tsv — qué artefactos se comprobaron que REPRODUCEN bit a bit, y cuándo.' \
|
|
|
|
|
'#' \
|
|
|
|
|
'# Clave = (receta, ArtifactHash). El hash resume la receta MÁS su cierre de deps, así que una' \
|
|
|
|
|
'# entrada deja de casar en cuanto algo aguas arriba cambia: no se puede dar por verificado lo' \
|
|
|
|
|
'# que ya no es lo mismo. Lo escribe scripts/verificar-repro.sh; se lee para medir cobertura y' \
|
|
|
|
|
'# para no volver a sortear lo ya hecho.' \
|
|
|
|
|
'#' \
|
|
|
|
|
'# receta<TAB>hash<TAB>fecha<TAB>veredicto' > "$LIBRO"
|
|
|
|
|
|
|
|
|
|
ya_verificado() { grep -qF "$(printf '%s\t%s\t' "$1" "$2")" "$LIBRO" 2>/dev/null; }
|
|
|
|
|
anotar() { printf '%s\t%s\t%s\t%s\n' "$1" "$2" "$(date -u +%F)" "$3" >> "$LIBRO"; }
|
|
|
|
|
|
|
|
|
|
# `--coverage`: qué fracción del corpus PRESENTE en este store se comprobó, al hash de hoy. Es la
|
|
|
|
|
# pregunta que el libro existe para poder contestar — antes no había forma de saberlo.
|
|
|
|
|
if [ "${1:-}" = "--coverage" ]; then
|
|
|
|
|
tot=0; hechas=0; sin_art=0
|
|
|
|
|
for f in recipes/*.toml recipes/incoming-*/*.toml; do
|
|
|
|
|
[ -f "$f" ] || continue
|
|
|
|
|
nn=$(awk -F'"' '/^name[[:space:]]*=/{print $2; exit}' "$f"); [ -n "$nn" ] || nn=$(basename "$f" .toml)
|
|
|
|
|
hh=$("$HAMMER" --store "$STORE" hash "$f" 2>/dev/null | tail -1 | sed 's/^b3://')
|
|
|
|
|
[ -n "$hh" ] || continue
|
|
|
|
|
[ -d "$STORE/$hh-$nn" ] || { sin_art=$((sin_art+1)); continue; }
|
|
|
|
|
tot=$((tot+1)); ya_verificado "$nn" "$hh" && hechas=$((hechas+1))
|
|
|
|
|
done
|
|
|
|
|
echo "── cobertura de reproducibilidad (contra el hash de HOY)"
|
|
|
|
|
echo " verificadas $hechas de $tot artefactos presentes en $STORE"
|
|
|
|
|
echo " sin artefacto $sin_art (selladas en otro lado, o en deuda: acá no hay qué comparar)"
|
|
|
|
|
exit 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [ $# -gt 0 ]; then RECETAS="$*"
|
|
|
|
|
else
|
|
|
|
|
# Muestra por CLASE de build: si sólo se verifican paquetes C con meson, el resultado no dice nada
|
|
|
|
|
# de Rust ni de Go, que son justamente donde el no-determinismo suele vivir (codegen paralelo,
|
|
|
|
|
# orden de símbolos, timestamps de módulos).
|
|
|
|
|
RECETAS=$(ls recipes/*.toml recipes/incoming-wlr/*.toml 2>/dev/null | shuf -n "$N" --random-source=/dev/zero | tr '\n' ' ')
|
|
|
|
|
# Se sortea entre lo que NO está en el libro, para que corridas sucesivas ACUMULEN cobertura en
|
|
|
|
|
# vez de repetir las mismas. Con `TODO=1` se sortea entre todas (para re-verificar a propósito).
|
|
|
|
|
TODOS=$(ls recipes/*.toml recipes/incoming-wlr/*.toml 2>/dev/null)
|
|
|
|
|
if [ -z "${TODO:-}" ]; then
|
|
|
|
|
PENDIENTES=""
|
|
|
|
|
for f in $TODOS; do
|
|
|
|
|
nn=$(awk -F'"' '/^name[[:space:]]*=/{print $2; exit}' "$f"); [ -n "$nn" ] || nn=$(basename "$f" .toml)
|
|
|
|
|
hh=$("$HAMMER" --store "$STORE" hash "$f" 2>/dev/null | tail -1 | sed 's/^b3://')
|
|
|
|
|
[ -n "$hh" ] || continue
|
|
|
|
|
ya_verificado "$nn" "$hh" || PENDIENTES="$PENDIENTES $f"
|
|
|
|
|
done
|
|
|
|
|
[ -n "$PENDIENTES" ] && TODOS="$PENDIENTES"
|
|
|
|
|
fi
|
|
|
|
|
RECETAS=$(printf '%s\n' $TODOS | shuf -n "$N" --random-source=/dev/zero | tr '\n' ' ')
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ok=0; dif=0; fallo=0; saltada=0; deriva=0; DIVERGEN=""
|
|
|
|
|
for f in $RECETAS; do
|
|
|
|
|
[ -f "$f" ] || continue
|
|
|
|
@@ -121,6 +173,7 @@ for f in $RECETAS; do
|
|
|
|
|
if "$HAMMER" --store "$STORE" build "$f" >/dev/null 2>&1 && [ -d "$STORE/$D" ]; then
|
|
|
|
|
if "$HAMMER" why-differs "$GUARDA/$D" "$STORE/$D" >/dev/null 2>&1; then
|
|
|
|
|
printf " ✓ %-26s REPRODUCE\n" "$n"; ok=$((ok+1))
|
|
|
|
|
anotar "$n" "$H" "reproduce"
|
|
|
|
|
rm -rf "$GUARDA/$D"
|
|
|
|
|
else
|
|
|
|
|
# ── DERIVA vs NO-DETERMINISMO: SE DECIDE ACÁ, NO EN LA CABEZA DE QUIEN LEE ──────────────
|
|
|
|
@@ -138,10 +191,14 @@ for f in $RECETAS; do
|
|
|
|
|
&& "$HAMMER" why-differs "$GUARDA/$D.r1" "$STORE/$D" >/dev/null 2>&1; then
|
|
|
|
|
printf " ~ %-26s DERIVA (el guardado era viejo; dos reconstrucciones coinciden)\n" "$n"
|
|
|
|
|
deriva=$((deriva+1))
|
|
|
|
|
# Se anota igual: las dos reconstrucciones coincidieron entre sí, que es justo lo que
|
|
|
|
|
# significa «reproduce». Lo viejo era el ejemplar guardado, no el determinismo.
|
|
|
|
|
anotar "$n" "$H" "reproduce (tras poner al día un artefacto derivado)"
|
|
|
|
|
rm -rf "$GUARDA/$D" "$GUARDA/$D.r1"
|
|
|
|
|
else
|
|
|
|
|
printf " ✗ %-26s NO-DETERMINISMO (dos reconstrucciones difieren entre sí)\n" "$n"
|
|
|
|
|
dif=$((dif+1)); DIVERGEN="$DIVERGEN $n"
|
|
|
|
|
anotar "$n" "$H" "NO-DETERMINISMO"
|
|
|
|
|
"$HAMMER" why-differs "$GUARDA/$D.r1" "$STORE/$D" 2>&1 | tail -4 | sed 's/^/ /'
|
|
|
|
|
# ⚠ NO se borran los ejemplares. Borrarlos destruía la evidencia justo en el único caso que
|
|
|
|
|
# este guardián existe para encontrar: decía «no reproduce» y tiraba las copias con las que
|
|
|
|
|