tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 604Rust 56Shell 36Markdown 281227 Definiciones

repro: un libro de lo verificado, y por fin un número de cobertura — era 2 de 1157

`verificar-repro.sh` sorteaba una muestra y se olvidaba. Sin registro no había forma de contestar la
pregunta que importa —¿qué fracción del corpus se comprobó alguna vez que reproduce?— y encima las
mismas recetas salían sorteadas una y otra vez mientras otras no se miraban jamás. La primera medida
con el libro puesto: **2 de 1157**. El invariante central del proyecto no se había verificado de
forma acumulativa prácticamente en nada, y eso no se veía porque cada corrida daba «✅ PUERTA
SUPERADA» sobre su propia muestra.

`docs/state/repro-verificado.tsv` va con la misma clave auto-invalidante que el libro de fuzz:
(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. Un «ya lo verifiqué» que sobreviviera a un re-hash sería
una mentira; éste no puede serlo.

Con eso el muestreo pasa a sortear entre lo NO verificado, así que corridas sucesivas ACUMULAN
cobertura en vez de repetir (con `TODO=1` se sortea entre todas, para re-verificar a propósito), y
`--coverage` da el número sin construir nada.

Verificadas en esta tanda: itstool, markupsafe, musl-obstack, hicolor-icon-theme, musl-fts, npth,
poppler-render-check, doas, libffi y packaging REPRODUCEN; `when` derivaba y quedó al día. Cero
no-determinismos. Van 11 de 1157.

⚠ Y una trampa que casi me come, anotada acá porque el próximo la va a pisar: elegí candidatos «por
artefacto chico» y la lista empezó con **nodejs**, cuyo artefacto pesa 0,2 MB y cuyo build son horas
de V8. El tamaño del artefacto NO dice nada del costo de construirlo. Para elegir muestra barata hay
que mirar tiempos de build, no bytes de salida.

efe6e001d299cd52e45de5af3edc00493c780ee3 · por Sergio · (hace 1 mes) · padre d5863ae55 · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

2 archivos · +77 −1

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.
+#
+# receta<TAB>hash<TAB>fecha<TAB>veredicto
+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.' \
+  '#' \
+  '# 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