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 1561Shell 203Rust 109Markdown 993728 Definiciones

bootstrap: busybox reproducible — fixes destapados por la verificación de Stage 2

La verificación de reproducibilidad de Stage 2 (dos builds + diff de bytes) probó
que musl reconstruye bit-idéntico pero busybox NO, y cazó dos no-determinismos:

1. Config interactiva: tras editar .config, silentoldconfig prompea por opciones
   NEW leyendo stdin → set de applets variable (build no-determinista y flaky).
   Fix en busybox.toml: `yes '' | make oldconfig` (defaults, determinista;
   1.36.1 no tiene olddefconfig).
2. Headers UAPI del kernel: el config determinista habilita console-tools, que
   exige linux/kd.h (zig no la bundlea). Fix: linux-headers en bootstrap-devfs.sh
   (zig cc nativo la halla en /usr/include).

Con ambos, musl y busybox reconstruyen bit-idéntico. Runbook §8b documenta la
verificación y deja pendiente: reproducibilidad de los componentes Rust y el
rebuild dentro de un builder rootfs (auto-alojamiento pleno).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

01d5a02b4d0d6118ad187e1d8fc8d13090934fcc · por Sergio · (hace 4 meses) · padre 79ad2cad6 · ver el árbol en este commit

Delta semántico

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

3 archivos · +41 −2

diff --git a/docs/runbooks/stage1-vm-boot.md b/docs/runbooks/stage1-vm-boot.md
index 904cdb59..cc1dbf34 100644
--- a/docs/runbooks/stage1-vm-boot.md
+++ b/docs/runbooks/stage1-vm-boot.md
@@ -235,6 +235,35 @@ Detecta la muerte **con su `ExitStatus`** (`Killed(SIGTERM)`), programa el resta
 que [ADR 0007](../adr/0007-arje-como-init-propio.md) prometía y la Fase 5 había diferido. Exponerlo
 a la capa de IA por `agent.sock` es B.2 (bus único).
 
+## 8b. Stage 2 — verificación de reproducibilidad (pre-rebuild-in-rootfs)
+
+El `stage2` de hammer ancla el **content-hash** (`ArtifactHash::of_tree`, los bytes reales) del
+rootfs y lo compara con un rebuild. El rebuild **dentro** del rootfs usando *sólo* las herramientas
+de Stage 1 (auto-alojamiento pleno) necesita un **builder rootfs** — el Stage 1 mínimo es un
+*runtime* (no trae zig/make/cargo), así que ese paso es un hito aparte. Lo que **sí** se verificó
+acá: la **bit-reproducibilidad del build** (dos builds independientes del mismo componente →
+`diff -r`):
+
+| Componente | Reproducible | Notas |
+|---|---|---|
+| **musl** 1.2.5 | ✅ byte-idéntico | el build C con zig cc es determinista de fábrica |
+| **busybox** 1.36.1 | ✅ tras dos fixes | (ver abajo) |
+| hammerd / arje-zero (Rust) | ☐ pendiente | rust bit-reproducible es más duro; el rebuild de arje-zero es caro (monorepo) |
+
+**La verificación cazó dos no-determinismos reales en busybox** (justo lo que [SDD 09 §2](../09-trust-model.md) pide):
+
+1. **Config interactiva.** Tras editar `.config`, el compile corre `silentoldconfig`, que ante
+   opciones NEW (WERROR, etc.) **prompea leyendo stdin** → el set de applets salía distinto por
+   corrida (build no-determinista *y* flaky). Fix: `yes '' | make oldconfig` (acepta defaults,
+   determinista; busybox 1.36.1 no tiene `olddefconfig`).
+2. **Headers del kernel.** Con el config determinista, los applets de `console-tools` exigen
+   `linux/kd.h` (UAPI) que zig **no** bundlea → `linux-headers` en el lab (`bootstrap-devfs.sh`);
+   zig cc nativo los encuentra en `/usr/include`.
+
+Con ambos, `musl` y `busybox` reconstruyen **bit-idéntico**. El próximo paso de Stage 2 es el
+rebuild *dentro* de un builder rootfs y, antes, verificar/forzar la reproducibilidad de los
+componentes Rust.
+
 ## 9. Cross-check opcional — `arje-packager`
 
 arje trae su propio empaquetador (`03_ukupacha/arje/init/arje-packager`):
diff --git a/recipes/busybox.toml b/recipes/busybox.toml
index 3a44b97a..368fcbcd 100644
--- a/recipes/busybox.toml
+++ b/recipes/busybox.toml
@@ -31,7 +31,13 @@ link     = "static"
 # `zig cc`, manteniendo la hermeticidad zig-only (ADR 0003) sin meter gcc al rootfs.
 # El link final asume GNU ld y pasa flags que `zig cc` valida y rechaza (`--warn-common`, `-Map`,
 # `--verbose`); los quitamos de scripts/trylink. Es la incompatibilidad GNU-ld↔zig/lld esperada.
-configure = "make CC='zig cc' HOSTCC='zig cc' defconfig && sed -i -e 's/^# CONFIG_STATIC is not set/CONFIG_STATIC=y/' -e 's/^CONFIG_TC=y/# CONFIG_TC is not set/' -e 's/^CONFIG_FEATURE_TC_INGRESS=y/# CONFIG_FEATURE_TC_INGRESS is not set/' .config && sed -i -e 's/-Wl,--warn-common//g' -e 's/-Wl,-Map,[^ ]*//g' -e 's/-Wl,--verbose//g' scripts/trylink"
+#
+# `yes '' | make oldconfig` tras editar .config: sin esto, el compile corre `silentoldconfig`, que
+# al ver opciones NEW (p.ej. WERROR) **prompea interactivamente** leyendo stdin — build
+# no-determinista y flaky (lo destapó la verificación de reproducibilidad de Stage 2). `yes ''`
+# acepta el default de cada NEW ⇒ config resuelta y determinista (busybox 1.36.1 no tiene el target
+# `olddefconfig`, así que usamos `oldconfig` alimentado por `yes`).
+configure = "make CC='zig cc' HOSTCC='zig cc' defconfig && sed -i -e 's/^# CONFIG_STATIC is not set/CONFIG_STATIC=y/' -e 's/^CONFIG_TC=y/# CONFIG_TC is not set/' -e 's/^CONFIG_FEATURE_TC_INGRESS=y/# CONFIG_FEATURE_TC_INGRESS is not set/' .config && yes '' | make CC='zig cc' HOSTCC='zig cc' oldconfig && sed -i -e 's/-Wl,--warn-common//g' -e 's/-Wl,-Map,[^ ]*//g' -e 's/-Wl,--verbose//g' scripts/trylink"
 compile   = "make -j\"$(nproc)\" CC='zig cc' HOSTCC='zig cc'"
 # busybox instala en CONFIG_PREFIX (no DESTDIR): bin/busybox + symlinks de cada applet.
 install   = "make CC='zig cc' HOSTCC='zig cc' CONFIG_PREFIX=/out install"
diff --git a/scripts/bootstrap-devfs.sh b/scripts/bootstrap-devfs.sh
index b82b68c5..7a9e15f4 100755
--- a/scripts/bootstrap-devfs.sh
+++ b/scripts/bootstrap-devfs.sh
@@ -113,7 +113,11 @@ else
     # y Alpine no trae ese std (no hay rustup). Falta resolver el toolchain Rust del lab (plan C.2)
     # — ver docs/runbooks/stage1-vm-boot.md §8. Hasta entonces, los componentes C (musl, busybox)
     # sí construyen end-to-end.
-    NEEDED="make autoconf automake m4 patch coreutils libtool pkgconf bash binutils rust cargo"
+    # `linux-headers`: UAPI del kernel (linux/kd.h, etc.) que zig cc NO bundlea; busybox y otros
+    # paquetes la necesitan. zig cc nativo la encuentra en /usr/include. (Lo destapó la
+    # verificación de reproducibilidad de Stage 2: con el config determinista, los applets de
+    # console-tools la exigen.)
+    NEEDED="make autoconf automake m4 patch coreutils libtool pkgconf bash binutils rust cargo linux-headers"
     missing=""
     for pkg in $NEEDED; do
         # apk info -e devuelve el paquete si está instalado, vacío si no.