Commit Graph
10 Commits
Author SHA1 Message Date
sergioandClaude Opus 4.8 4c9bcc016b sandbox: CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1 — arje-zero reproducible (Stage 2 no-det #3)
El rebuild in-VM daba ✗ DIVERGENTE (of_tree host 984e002f ≠ VM 94b93585) pese a
que los 4 componentes sellaban bajo el mismo key of_inputs. Bisección por componente
en el host: musl, busybox y hammerd reconstruyen byte-idéntico, y la ensambladura del
rootfs (of_tree) es determinista e independiente del entorno. El culpable era arje-zero:
dos builds del MISMO host daban binarios distintos (Δ ~9.6 KB por .text/.rodata/.eh_frame/
.gcc_except_table) — firma del codegen paralelo de rustc.

Raíz: el workspace de hammer pinea [profile.release] codegen-units=1 (por eso hammerd
reproducía), pero el monorepo tawasuyu no declara perfil → cargo default codegen-units=16,
cuyo reparto del crate en N objetos varía build-a-build.

Fix: el sandbox impone codegen-units=1 para TODAS las crates Cargo (el var de cargo gana
sobre el profile del repo fuente). El lab elimina el no-determinismo en vez de confiar en
upstream (SDD 09 §2). Verificado: dos builds cu=1 de arje-zero → byte-idénticos.

Nueva referencia reproducible 4/4: of_tree(stage1)=b3:0039b2b9… (reemplaza 198f209f… de
cu=16). Actualizados EXPECT_REF (selfhost-verify.sh) y runbook §8b/§8c.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 04:31:51 -04:00
sergioandClaude Opus 4.8 1ab53a650f selfhost-verify: módulos del kernel booteado + build a stderr (E2BIG)
Dos bugs latentes que sólo aparecían en un build real (in-VM); en el host
quedan tapados porque todo sale de caché.

1. scripts/selfhost-verify.sh: los módulos se sacaban de /lib/modules/$(uname -r)
   pero la VM bootea $KERNEL (/boot/vmlinuz-linux), que puede ser otra versión.
   Mismatch de version-magic ⇒ overlay.ko no carga ⇒ bwrap muere "No such device".
   Ahora la versión se deriva del bzImage booteado (file -bL "$KERNEL"; fallback uname -r).

2. crates/hammer-build/src/sandbox.rs: spawn_pump teeaba el stdout del build al
   stdout del padre. rebuild-stage1 hace PRIME=$(hammer ... bootstrap stage1); en
   un build real son miles de líneas de configure/make capturadas en $PRIME ⇒ el
   paso siguiente --rootfs "$PRIME" exec con un arg gigante ⇒ E2BIG (Argument list
   too long). Ahora el tee va a stderr; stdout queda para el hash legible-por-máquina.

Con esto el verify corre end-to-end in-VM: los 4 componentes reproducen bit a bit,
pero of_tree(stage1) diverge (host vs VM vs baseline) — no-determinismo del ensamblado
a cazar (SDD 09 §2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 03:04:45 -04:00
SergioandClaude Opus 4.8 7025f93bcd scripts: tarea selfhost-verify end-to-end (correr el 4/4 in-VM en KVM)
El veredicto pleno 4/4 in-VM pide KVM + RAM holgada; el host de dev (7.6 GB, sin KVM)
colgó por presión de RAM bajo TCG a los ~17 min del make de musl. Esta tarea traslada
la verificación a una máquina capaz (laptop) en un solo comando.

- scripts/selfhost-verify.sh: pipeline completo — stage0 → stage1 baseline → stage2
  (ancla la ref of_tree) → inyecta overlay.ko/e1000.ko del kernel local al toolchain →
  ensambla el builder con la ref embebida → empaqueta (cpio --owner=root:root) →
  bootea + driver no-interactivo → veredicto. KVM auto-detect; PRESEED=hammerd para el
  camino barato (preseed C+arje, sólo hammerd in-VM). Cross-check entre máquinas:
  compara su of_tree(stage1) contra EXPECT_REF (198f209f… conocida-buena del dev).
- scripts/drive-rebuild.py: driver no-interactivo parametrizado (env: BUILDER_CPIO,
  KERNEL, MEM, CPU, KVM, NET, DEADLINE, LOG). Bootea, espera la shell de arje-zero,
  manda rebuild-stage1 y sale 0 si REPRODUCIBLE / 1 si DIVERGENTE. (Versión de repo del
  driver ad-hoc que vivía en work/.)
- scripts/boot-builder-vm.sh: añade la NIC e1000 (NET=1 por defecto) — el vendoring Rust
  necesita red.
- runbook §8c: documenta la tarea y el muro de RAM del host de dev.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 00:57:07 +00:00
SergioandClaude Opus 4.8 cf15995623 bootstrap: builder carga overlay.ko — el sandbox de build lo exige en la VM
El run en la VM avanzó hasta `configure` y ahí bwrap falló: `Can't make overlay
mount … No such device`. Causa raíz: el kernel trae overlay como MÓDULO
(CONFIG_OVERLAY_FS=m) y el initramfs arranca sin módulos cargados ⇒ ENODEV. El
sandbox de hammer-build usa `bwrap --tmp-overlay` (raíz efímera sobre el
toolchain), así que necesita overlayfs.

Fix: rebuild-stage1 hace `insmod /toolchain/lib/overlay.ko` tras el shim del
loader (overlay no tiene deps; vermagic del kernel destino). El toolchain suma
`kmod` (insmod/modprobe). El `overlay.ko` es específico del kernel (no de Alpine):
se inyecta aparte en el builder (.dev-fs/alpine/lib/overlay.ko), documentado en
bootstrap-devfs.sh.

Progreso del run: shim OK ⇒ bwrap/git/curl corren ⇒ fetch OK ⇒ configure arranca;
overlay era el siguiente muro. 28 tests verdes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 15:20:06 +00:00
SergioandClaude Opus 4.8 64894d863c bootstrap: builder ejecutable — toolchain con bwrap/git/curl + shim del loader
Correr el rebuild EN la VM destapó dos faltantes reales del builder (justo lo que
la verificación de Stage 2 debe cazar):

1. El toolchain (variante a, desde Alpine) traía compiladores (cargo/make/zig)
   pero NO las herramientas de orquestación del lab — bwrap (anida el sandbox),
   git (git archive del mirror) y curl (tarballs). En el host las aporta el
   sistema; en la VM el toolchain es el único userland capaz, así que deben vivir
   ahí. bootstrap-devfs.sh las añade (paquete `bubblewrap`, no `bwrap`).

2. Esos binarios son Alpine *dinámicos* y no corren desde el userland Stage 1
   *estático* (musl --disable-shared ⇒ no hay loader en /lib). rebuild-stage1
   ahora instala un shim del loader musl (cp a /lib) + LD_LIBRARY_PATH/PATH al
   toolchain antes de invocar hammer; el sandbox de build sigue anidando en
   /toolchain. El hammer estático corre por ruta absoluta.

El builder boot end-to-end ya estaba probado; esto lo hace además *capaz de
reconstruirse*. 28 tests verdes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 15:13:32 +00:00
SergioandClaude Opus 4.8 66d4df4f57 bootstrap: script de boot del builder en QEMU (rebuild in-rootfs)
scripts/boot-builder-vm.sh empaqueta el último eslabón operacional del SDD 11 §7:
bootea work/builder.cpio.gz (el builder rootfs como initramfs cpio+gzip) con
arje-zero como PID 1; en la consola se corre `rebuild-stage1` para reconstruir
stage1' con el toolchain de adentro y comparar con la referencia.

- Defaults: KERNEL=/boot/vmlinuz-linux, MEM=6144, CPU=Broadwell (AVX2 bajo TCG).
- KVM=1 usa -enable-kvm -cpu host si hay /dev/kvm (mucho más rápido).
- Documenta la tensión de RAM: el rootfs vive en tmpfs (~1.2 GB) + el rebuild Rust
  necesita varios GB más, todo en RAM; con host ~7 GB y sin KVM va justo/lento.

El initramfs (410 MB gz, 26776 entradas) se verificó: sbin/init→arje-zero, el
hammer estático, rebuild-stage1, rebuild.env y el toolchain/cargo presentes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 15:01:11 +00:00
SergioandClaude Opus 4.8 01d5a02b4d 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>
2026-06-11 12:11:42 +00:00
SergioandClaude Opus 4.8 5a1088d5ce bootstrap: fixes de la primera corrida real de Stage 1 (musl+busybox ✓ con zig cc)
Primera ejecución del runbook en el host. El userland C builda end-to-end; el
camino Rust queda bloqueado por una decisión de toolchain. Hallazgos verificados:

recipes/busybox.toml — tres incompatibilidades GNU-toolchain ↔ zig, resueltas:
- gcc hardcodeado (CC/HOSTCC = gcc con `=` ignora el env): pasar CC='zig cc'
  HOSTCC='zig cc' en línea de comando de make
- flags GNU-ld que zig cc valida y rechaza (--warn-common, -Map, --verbose):
  quitarlos de scripts/trylink con sed
Con esto musl 1.2.5 y busybox 1.36.1 compilan, linkean y se sellan.

scripts/bootstrap-devfs.sh — añade rust+cargo al rootfs (las recetas Cargo
corren cargo en el sandbox), con CAVEAT: el rust de Alpine es
x86_64-alpine-linux-musl pero BuildSys::Cargo pide x86_64-unknown-linux-musl
(no instalado, sin rustup) → bloquea hammerd/arje-zero. Decisión de toolchain
abierta (plan C.2).

docs/runbooks/stage1-vm-boot.md §8 — bitácora con la tabla de etapas, los fixes
y las opciones para resolver el triple Rust.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 02:21:18 +00:00
SergioandClaude Opus 4.7 1fc8c97617 Fase 0+1 cerradas: GNU grep 3.12 real construido e hidratado
Cierra el primer entregable del roadmap. Cambios:

- `Source`: ahora admite dos modos mutuamente excluyentes — `git` (repo+commit) o
  `tarball` (url+sha256). El hash de entrada del artefacto usa el commit en modo
  git y el sha256 en modo tarball; ambos son identificadores inmutables del
  contenido fuente. Validación en `Source::kind()` con error claro.
- `fetch`: dispatch por modo. Tarball cacheado en `work/tarballs/<sha>.tar`,
  descarga vía `curl -fL`, verificación sha256 con `sha2`, extracción con
  `--strip-components` (default 1, GNU-style).
- `recipes/grep.toml`: GNU grep 3.12 desde el tarball release de gnu.org
  (sha256 fijado, sin patches, `--disable-perl-regexp --disable-nls`).
- Bootstrap: añade `binutils` al rootfs Alpine — configure de autotools mira
  ld/ar/ranlib incluso cuando el compilador real es zig cc.
- `.gitignore`: `/work/` (artefactos transitorios del build).
- `docs/10-roadmap.md`: Fase 0 y Fase 1 marcadas ; entregable cerrado.

Nota sobre v3.11 vs v3.12: probé primero v3.11 y el binario producido daba
"memory exhausted" en cualquier regex (bug conocido de grep+musl static al
inicializar DFA). v3.12 corrige y funciona limpio dentro del rootfs Alpine.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 14:11:46 +00:00
SergioandClaude Opus 4.7 e53877a532 Caché persistente de zig + bootstrap reproducible del .dev-fs
- `BuildConfig.cache_root` (override `HAMMER_CACHE`): bindea `/cache` al sandbox
  y exporta `ZIG_GLOBAL_CACHE_DIR=/cache/zig`. Evita ~30s de recompilación de
  musl en cada build.
- `scripts/bootstrap-devfs.sh`: idempotente, descarga+verifica alpine-minirootfs
  3.23.4 y zig 0.16.0 con sha256 fijo, instala build tools en el rootfs vía apk
  bajo bwrap.
- `make_tree_read_only`: solo archivos regulares pierden `w`; los directorios
  conservan 0o755 para no estorbar GC ni `rm -rf` administrativo. La
  inmutabilidad estricta del store se delega al mount RO de la distro propia.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 13:56:10 +00:00