diff --git a/docs/state/repro-verificado.tsv b/docs/state/repro-verificado.tsv new file mode 100644 index 00000000..ef797f07 --- /dev/null +++ b/docs/state/repro-verificado.tsv @@ -0,0 +1,19 @@ +# 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. +# +# recetahashfechaveredicto +libffi 1df7e7a3eac63694f8d094646cfc231f3843995f6f9f945cda138760f6bc9838 2026-09-05 reproduce +packaging 0378f4a8dba56e6519590778c2dad2291a99e92b7960d38960964f3fd52a7afc 2026-09-05 reproduce +itstool 158e4e38b2124e80856fbf64fdde1b0af39c1073de915d13a4a296f1ac8db0fd 2026-09-05 reproduce +markupsafe 9fcd3a2c0c442b4c9eb57683b6873dd47d227a681258bd8588f21d28327b4f06 2026-09-05 reproduce +musl-obstack 4a5b3327efb9cd5ec015d3f62e9ec85451deb08560d4963b2567d1e2a124acbb 2026-09-05 reproduce +hicolor-icon-theme 98ad44a5c02059b4cac576bbbf24195a229cda1c807f1eb6c7e80424ceab1e16 2026-09-05 reproduce +musl-fts b9681a5205197d51bb777efde1a271e9b189bf35d74091834c5f1aa43d82f16e 2026-09-05 reproduce +npth e5682fca87a9f591d533855b0056a07b5724304fb53402c940524d885908d980 2026-09-05 reproduce +poppler-render-check 0d29dc69792df003726252fbc381a0133df7654daafccf547f8d5a82e526c1fe 2026-09-05 reproduce +when 5b4048a23584aaaca41a7d8c0e50a92c469b1b1710f5d10b2dd7abd908fe57b6 2026-09-05 reproduce (tras poner al día un artefacto derivado) +doas 28bc42c24008f73d9541f407562cd4ed81e3788b95ab72fa00b5369ad606064a 2026-09-05 reproduce diff --git a/scripts/verificar-repro.sh b/scripts/verificar-repro.sh index a8698cce..40097162 100755 --- a/scripts/verificar-repro.sh +++ b/scripts/verificar-repro.sh @@ -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.' \ + '#' \ + '# recetahashfechaveredicto' > "$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