gioser

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 Definiciones

⎇ ba1fb2d3a8ada748984dceeb0f58e6b3e67772b8 scripts/verificar-repro.sh Shell · 88 líneas · 5.5 KB Historia crudo

SEGUNDA corrección: lo que medía el test era DERIVA, no no-determinismo — el corpus SÍ reproduce 102aabd1f · sergio ·

1#!/usr/bin/env bash
2# verificar-repro.sh — ¿reproducen los artefactos bit a bit? Reconstruye y COMPARA. Etapa 1 del SDD 23.
3#
4# ── POR QUÉ ESTE SCRIPT Y NO UN GREP ───────────────────────────────────────────────────────────
5# El no-determinismo se mide RECONSTRUYENDO Y COMPARANDO, no buscando cadenas sospechosas en los
6# binarios. El plan heredado daba 92 paquetes por «no-deterministas probables» porque tenían rutas
7# `/src` en `.debug_*`; al mirarlo resultó que `/src` es un bind CONSTANTE del lab, y que las únicas
8# rutas realmente ajenas venían de terceros (la ruta de compilación de Alpine horneada en el musl
9# prebuilt, cadenas literales del fuente, rutas de autores en assets SVG). Un grep sobre binarios da
10# CANDIDATOS, no veredictos. Ver SDD 23 §1.
11#
12# ── ⚠ QUÉ MIDE ESTE SCRIPT, EXACTAMENTE (leer antes de sacar conclusiones) ─────────────────────
13# Compara el artefacto GUARDADO en el store contra una reconstrucción de hoy. Eso NO es lo mismo que
14# medir no-determinismo, y confundirlos costó dos conclusiones equivocadas en el SDD 23:
15#   · si el artefacto guardado es viejo, se construyó con OTRO estado del lab ⇒ una diferencia es
16#     DERIVA («el mundo se movió»), no no-determinismo;
17#   · el no-determinismo es: mismas entradas, MISMO lab, salidas distintas.
18# ⇒ Para medir NO-DETERMINISMO hay que correr el script DOS VECES: la primera pone el artefacto al
19#   día con el lab actual, y es la SEGUNDA la que contesta la pregunta. Medido: anew, gron y age
20#   divergían en la primera corrida y REPRODUCEN en la segunda.
21#
22# ── EL MÉTODO, Y POR QUÉ ES BARATO ─────────────────────────────────────────────────────────────
23# Se APARTA el artefacto (no se borra) y se reconstruye. Como las DEPS siguen en el store, el rebuild
24# es sólo el paquete en cuestión, no su cadena — que es lo que hace viable verificar decenas. Después
25# `hammer why-differs` compara los dos árboles y nombra la causa si divergen.
26#
27# ── LA RED DE SEGURIDAD ────────────────────────────────────────────────────────────────────────
28# Si el rebuild FALLA (y fallará en alguna: hay recetas que sólo construyen en ciertas máquinas), el
29# artefacto original se RESTAURA. Un verificador que destruye lo que verifica es peor que no tenerlo.
30# Por eso se aparta a un directorio temporal en vez de borrar, y hay `trap` para restaurar todo lo
31# pendiente si se interrumpe.
32#
33# Uso:   scripts/verificar-repro.sh [receta.toml ...]      (sin args: muestra por clase)
34# Env:   STORE (def ./store)   N (def 30, tamaño de la muestra)
35set -uo pipefail
36ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
37STORE="${STORE:-./store}"; HAMMER="${HAMMER:-./target/release/hammer}"; N="${N:-30}"
38GUARDA="$(mktemp -d)"; PENDIENTE=""
39
40restaurar_todo() {
41  for h in $PENDIENTE; do
42    [ -d "$GUARDA/$h" ] && [ ! -d "$STORE/$h" ] && mv "$GUARDA/$h" "$STORE/$h" && echo "  ↩ restaurado $h"
43  done
44  rm -rf "$GUARDA"
45}
46trap restaurar_todo EXIT INT TERM
47
48if [ $# -gt 0 ]; then RECETAS="$*"
49else
50  # Muestra por CLASE de build: si sólo se verifican paquetes C con meson, el resultado no dice nada
51  # de Rust ni de Go, que son justamente donde el no-determinismo suele vivir (codegen paralelo,
52  # orden de símbolos, timestamps de módulos).
53  RECETAS=$(ls recipes/*.toml recipes/incoming-wlr/*.toml 2>/dev/null | shuf -n "$N" --random-source=/dev/zero | tr '\n' ' ')
54fi
55
56ok=0; dif=0; fallo=0; saltada=0; DIVERGEN=""
57for f in $RECETAS; do
58  [ -f "$f" ] || continue
59  n=$(awk -F'"' '/^name[[:space:]]*=/{print $2; exit}' "$f"); [ -n "$n" ] || n=$(basename "$f" .toml)
60  H=$("$HAMMER" --store "$STORE" hash "$f" 2>/dev/null | tail -1 | sed 's/^b3://')
61  [ -n "$H" ] || { saltada=$((saltada+1)); continue; }
62  D="$H-$n"
63  [ -d "$STORE/$D" ] || { saltada=$((saltada+1)); continue; }
64
65  mv "$STORE/$D" "$GUARDA/$D"; PENDIENTE="$PENDIENTE $D"
66  if "$HAMMER" --store "$STORE" build "$f" >/dev/null 2>&1 && [ -d "$STORE/$D" ]; then
67    if "$HAMMER" why-differs "$GUARDA/$D" "$STORE/$D" >/dev/null 2>&1; then
68      printf "  ✓ %-26s REPRODUCE\n" "$n"; ok=$((ok+1))
69      rm -rf "$GUARDA/$D"
70    else
71      printf "  ✗ %-26s DIVERGE\n" "$n"; dif=$((dif+1)); DIVERGEN="$DIVERGEN $n"
72      "$HAMMER" why-differs "$GUARDA/$D" "$STORE/$D" 2>&1 | tail -4 | sed 's/^/       /'
73      rm -rf "$GUARDA/$D"
74    fi
75  else
76    # El rebuild falló: restaurar y NO contarlo como divergencia (no es lo mismo «no reproduce» que
77    # «no construye acá»). Distinguirlos importa: mezclarlos inventaría un problema de determinismo.
78    printf "  ⚠ %-26s no construyó (artefacto restaurado)\n" "$n"; fallo=$((fallo+1))
79    rm -rf "$STORE/$D"; mv "$GUARDA/$D" "$STORE/$D"
80  fi
81  PENDIENTE=$(echo "$PENDIENTE" | sed "s| $D||")
82done
83
84echo "════════════════════════════════════════════════════════════"
85echo "  REPRODUCEN: $ok · DIVERGEN: $dif · no construyeron: $fallo · sin artefacto: $saltada"
86[ "$dif" -gt 0 ] && echo "  ⚠ divergen:$DIVERGEN"
87[ "$dif" -eq 0 ] && [ "$ok" -gt 0 ] && echo "  ✅ PUERTA SUPERADA: 0 divergencias sobre $ok verificadas"
88exit $(( dif > 0 ? 1 : 0 ))