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 1572Shell 203Rust 109Markdown 993728 Definitions

repro: «la 2ª reconstrucción no construyó» NO es no-determinismo — mi propio bug, y lo pagó el libro

Corriendo una tanda con `MAX_SECONDS=45` se llenó el disco a mitad, los rebuilds empezaron a morir
por ENOSPC, y la rama que yo mismo había escrito para distinguir DERIVA de NO-DETERMINISMO metió
«falló» y «difiere» en la misma condición ⇒ **21 recetas sanas quedaron anotadas como
NO-DETERMINISMO** en un libro que pretende ser autoritativo. Un registro falso y persistente es peor
que no tener registro: el propósito del libro es que nadie tenga que volver a mirar, así que una
entrada equivocada se cree para siempre.

Es la trampa de siempre —un disco lleno se lee como receta rota, y la pista es que mueren varias
seguidas— y el script ORIGINAL ya la evitaba: «no es lo mismo «no reproduce» que «no construye
acá». Distinguirlos importa: mezclarlos inventaría un problema de determinismo». Lo rompí al añadir
la segunda reconstrucción. Restituido: si la 2ª no construye, se restaura el artefacto, se cuenta
como fallo y **no se anota nada** — sin veredicto es un estado legítimo.

Reparado además el daño: las 21 entradas falsas purgadas del libro (quedan 27 verificaciones
buenas), y `angle-grinder` repuesto desde `store/.divergen/`, donde lo había dejado la clasificación
errónea. Eso sí funcionó como debía: el ejemplar estaba guardado y entero, no perdido.

Y queda anotado en el propio script el límite del filtro por tiempo que provocó todo: el sidecar de
`store/.times/` lo escribe el WORKER, así que acota el build de esa receta EN LA MÁQUINA QUE LO
MIDIÓ. Una receta Rust de 40 s allá con la caché de cargo caliente son muchos minutos acá en frío
—`angle-grinder` y `amp` entraron por el filtro y se comieron el disco— y encima el número no cuenta
la CASCADA de deps que falten en el store local, que es la misma sorpresa que dio `gjs`. Con disco
justo conviene pasar las recetas a mano.

d7d9cf8fd2484e1092caa3267bcf88195d109205 · by Sergio · (1 month ago) · parent 118ba2e2c · browse the tree at this commit

Semantic delta

No definition changed: this change is text, documentation or data.

2 files · +73 −2

diff --git a/docs/state/repro-verificado.tsv b/docs/state/repro-verificado.tsv
index ef797f07..a6c48df7 100644
--- a/docs/state/repro-verificado.tsv
+++ b/docs/state/repro-verificado.tsv
@@ -17,3 +17,21 @@ npth	e5682fca87a9f591d533855b0056a07b5724304fb53402c940524d885908d980	2026-09-05
 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
+zstd	1ceb6215a5a3061ac385e036da642341da61a585abe62a1c904bd0c8c2f4d5fb	2026-09-05	reproduce
+actionlint	12e0640aa73729d170d992eb442bcca6b9d7b891a074d2d8b9f6583710717be3	2026-09-05	reproduce
+addlicense	e918fed592bc9eac2989262f030dba05e4dbdb32ab9ff715abe1f05bf9e688d3	2026-09-05	reproduce
+adwaita-cursors	22ae0ff6369e6f15cb6810ddd979d95ebe38307e8da668c1210d9434ef9b5b05	2026-09-05	reproduce
+adwaita-hello	09cf170c6a780bd09f46347c61aa48a16eccda81e27aee42184938242b026918	2026-09-05	reproduce
+age	b8ae28a4e360b61aa53667af7c6261951085285e62c2201f615173731ca36716	2026-09-05	reproduce
+agora-cli	e05c41f1d4e46974195fbfb76a3efb591217e6733be8e17b007ba5d9cc3a153d	2026-09-05	reproduce
+air	3761c6a516ab0bbcae825625e10c0fbd8015a15f25080e3b7dc36bfb7597d59f	2026-09-05	reproduce
+ali	9017cf46ef5dc33c726a2fe4adf91c7463bee749ce605a94757eeea51f260c06	2026-09-05	reproduce
+zoxide	83359c57babdd2e051b7c53bd63694d319969cd9bcb5a27922707655f7b572af	2026-09-05	reproduce
+alsa-lib	73fb200aae06b0743035dc9f961121fc94295e80a12d39dc358920d698b7bfe0	2026-09-05	reproduce
+alterx	415465a247da8489bfec54eac84d8bb2234e822423ba717974cbcbedfeb8905d	2026-09-05	reproduce
+amass	385b4a140f8e8fa04282494f01e7523625aff42ae90f6eb38cd0230e6914aa56	2026-09-05	reproduce
+amfora	10560630b5d8302979b7844a22d2e30696a046c834968bd713efa7fcbc2b993a	2026-09-05	reproduce
+amp	7b800350e79dda56eb1c3fca511700761cd91b2cd49ebf58f453fb4a01a62944	2026-09-05	reproduce (tras poner al día un artefacto derivado)
+anew	68ef0da2c17b474bee65caec2f61e4b24ccd5ea8e2d8357540ce572482bb5782	2026-09-05	reproduce
+npth	e5682fca87a9f591d533855b0056a07b5724304fb53402c940524d885908d980	2026-09-05	reproduce
+musl-fts	b9681a5205197d51bb777efde1a271e9b189bf35d74091834c5f1aa43d82f16e	2026-09-05	reproduce
diff --git a/scripts/verificar-repro.sh b/scripts/verificar-repro.sh
index 40097162..ea629f3a 100755
--- a/scripts/verificar-repro.sh
+++ b/scripts/verificar-repro.sh
@@ -143,6 +143,47 @@ 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).
+  # ── `MAX_SECONDS`: sortear sólo entre builds BARATOS ─────────────────────────────────────────
+  # Elegir muestra «por artefacto chico» es una trampa: el artefacto de `nodejs` pesa 0,2 MB y su
+  # build son horas de V8. Lo que hace cara una verificación es el TIEMPO DE CONSTRUIR, y ese dato
+  # ya existe — `scripts/farm/build-timed.sh` deja un sidecar por build en `store/.times/` y llega
+  # con la cosecha. Con `MAX_SECONDS=60` la muestra sale de ahí.
+  #
+  # Las recetas SIN medición quedan fuera cuando se pone el tope: no se puede prometer que algo es
+  # barato sin haberlo medido nunca. El modo de ampliar esa lista no es relajar el filtro sino
+  # correr builds instrumentados en el worker, que es donde el tiempo se mide.
+  #
+  # ⚠ DOS LÍMITES DEL NÚMERO, medidos el 2026-09-05 con `MAX_SECONDS=45` en el hub:
+  #   · El sidecar lo escribe el WORKER. Una receta Rust que allá tarda 40 s con la caché de cargo
+  #     caliente puede tardar muchos minutos acá en frío — `angle-grinder` y `amp` entraron por el
+  #     filtro y se comieron el disco. El tope acota el build DE ESA RECETA en LA MÁQUINA QUE LO
+  #     MIDIÓ, no acá.
+  #   · Y no cuenta la CASCADA: `hammer build` reconstruye las deps que falten en el store local, y
+  #     eso no está en el tiempo del sidecar. Es la misma sorpresa que dio `gjs`, cuyo grafo decía
+  #     «una receta» y se puso a rehacer spidermonkey entero.
+  # ⇒ con disco justo, mejor pasar las recetas a mano que confiar en el tope.
+  if [ -n "${MAX_SECONDS:-}" ]; then
+    TODOS=$(python3 - "$MAX_SECONDS" <<'PY'
+import glob, json, os, sys, re
+from statistics import median
+cap = float(sys.argv[1])
+m = {}
+for f in glob.glob("store/.times/*.json"):
+    try: d = json.load(open(f))
+    except Exception: continue
+    if d.get("name") and isinstance(d.get("seconds"), (int, float)):
+        m.setdefault(d["name"], []).append(d["seconds"])
+baratas = {k for k, v in m.items() if median(v) < cap}
+for ruta in glob.glob("recipes/*.toml") + glob.glob("recipes/incoming-wlr/*.toml"):
+    txt = open(ruta, encoding="utf8", errors="replace").read(4000)
+    mm = re.search(r'^name\s*=\s*"([^"]+)"', txt, re.M)
+    if mm and mm.group(1) in baratas:
+        print(ruta)
+PY
+)
+    [ -n "$TODOS" ] || { echo "── no hay recetas medidas por debajo de ${MAX_SECONDS}s (¿falta store/.times?)"; exit 0; }
+  fi
+
   # 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)
@@ -187,8 +228,20 @@ for f in $RECETAS; do
       # que estaba fuera de fecha era el guardado ⇒ deriva. Si no coinciden, es no-determinismo de
       # verdad. Sólo se paga el rebuild extra cuando ya hubo una diferencia.
       mv "$STORE/$D" "$GUARDA/$D.r1"; PENDIENTE="$PENDIENTE $D.r1"
-      if "$HAMMER" --store "$STORE" build "$f" >/dev/null 2>&1 && [ -d "$STORE/$D" ] \
-         && "$HAMMER" why-differs "$GUARDA/$D.r1" "$STORE/$D" >/dev/null 2>&1; then
+      # ⚠ «la segunda reconstrucción FALLÓ» NO es «difiere». Meterlas en la misma rama fue un error
+      # mío del 2026-09-05 y lo pagó el libro: se llenó el disco a mitad de una tanda, los rebuilds
+      # empezaron a morir por ENOSPC, y quedaron anotadas 21 recetas sanas como NO-DETERMINISMO —
+      # un registro falso y persistente, que es peor que no tener registro. Es la misma trampa de
+      # siempre: un disco lleno se lee como receta rota, y la pista es que mueren varias seguidas.
+      # El script original ya distinguía «no reproduce» de «no construye acá»; esto lo restituye.
+      if ! "$HAMMER" --store "$STORE" build "$f" >/dev/null 2>&1 || [ ! -d "$STORE/$D" ]; then
+        printf "  ⚠ %-26s la 2ª reconstrucción no construyó ⇒ SIN VEREDICTO (no lo anoto)\n" "$n"
+        fallo=$((fallo+1))
+        rm -rf "$STORE/$D"; mv "$GUARDA/$D" "$STORE/$D"; rm -rf "$GUARDA/$D.r1"
+        PENDIENTE=$(echo "$PENDIENTE" | sed "s| $D.r1||;s| $D||")
+        continue
+      fi
+      if "$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