Auto-consistencia de hammer-rust VERIFICADA en host (2026-06-17): of_tree(stage1)
construido con hammer-rust 1.91.1 = b3:7fa6cb4e… reproducido 2× (store-rust y store-rust2,
builds frescos independientes). Es el nuevo EXPECT_REF para SWAP_RUST (criterio elegido:
auto-consistencia, ≠ el 9adefb82 de Alpine). Cableado como default de RUST_EXPECT_REF.
swap-rust-into-toolchain.sh --restore: ahora también elimina lo AÑADIDO por el swap
(rustlib x86_64-unknown-linux-musl + librustc_driver de hammer), no sólo restaura
rustc/cargo. Round-trip apply→restore deja el devfs prístino (verificado: sólo
x86_64-alpine-linux-musl + driver de Alpine). Antes dejaba ~350 MB de cruft.
Nota: los leftovers NO afectaban el of_tree (un build Alpine con/ sin ellos diverge igual
del baseline Jun13 — ver hallazgo de drift abajo); la limpieza es higiene/reversibilidad.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fix de 503e09a, que añadía el flag SIEMPRE: el rust de Alpine (host x86_64-alpine-linux-
musl) NO sólo tiene self-contained apagado — PARCHEA la opción para que sea un error
("option `-C link-self-contained` is not supported on this target"), así que pasarla
rompía el build baseline (verificado: baseline-check falló en el build-script de
proc-macro2). Un rust vanilla (host x86_64-unknown-linux-musl, p. ej. hammer-rust) SÍ la
soporta y la NECESITA (su musl trae self-contained/rcrt1.o que choca con el crt1.o de zig
⇒ duplicate _start).
Ahora condicional por host-triple del rustc: se añade el flag SÓLO si el host NO es
`-alpine-`. Para Alpine ⇒ comando idéntico al pre-503e09a (sin flag) ⇒ 9adefb82 intacto
por construcción. Para hammer-rust ⇒ con flag ⇒ linkea con zig sin duplicar _start.
(`--print`/`--version` no validan -C; sólo el link real lo hace — por eso se discrimina
por host-triple, no por probe.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
El link de las recetas Cargo nativas lo hace `zig cc` (un driver de compilador completo
que ya aporta sus startfiles crt1.o). El target musl vanilla `x86_64-unknown-linux-musl`
trae CRT AUTOCONTENIDO (self-contained/rcrt1.o) y lo pasaría también al linker ⇒
`ld.lld: duplicate symbol: _start` (rcrt1.o vs crt1.o de zig). Añadir
`-C link-self-contained=no` a RUSTFLAGS hace que rustc NO aporte startfiles propios y
deje que zig los provea — para TODAS las unidades (deps, build-scripts, proc-macros y la
crate top; RUSTFLAGS las alcanza a todas, los bin_flags de `cargo rustc --` sólo a la top).
No-op para el rust de Alpine (host x86_64-alpine-linux-musl): su self-contained ya está
APAGADO — de hecho el baseline 9adefb82 linkea sin chocar con zig, lo que sólo es posible
si Alpine NO aporta startfiles self-contained. Imprescindible para un rust vanilla, p. ej.
el hammer-rust del frente self-host (SWAP_RUST): con él, hammerd YA compila y sella con
hammer-rust (antes fallaba en el build-script de proc-macro2).
Verificación baseline (of_tree(stage1) sin swap == 9adefb82 con este hammer) en cola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
recipe.hash_inputs = source+compiler+target+link+patches+flags+phases+deps; NO incluye
el binario rustc del toolchain. En el ./store compartido, arje-zero/hammerd quedarían
cacheados con los bytes de Alpine ⇒ el swap de rust sería un no-op (REF seguiría 9adefb82).
SWAP_RUST=1 ahora usa un store dedicado (store-rust, override RUST_STORE) para forzar el
rebuild de los 4/4 con hammer-rust, sin tocar el ./store baseline. Así of_tree refleja el
compilador nuevo (auto-consistencia).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pieza rust del auto-alojamiento "variante b" (la última del frente). A DIFERENCIA de
make/busybox/bwrap/coreutils/linux-headers (herramientas que orquestan/copian ⇒ bytes
idénticos ⇒ of_tree 9adefb82 por construcción), **rustc EMITE los binarios del 4/4**
(arje-zero, hammerd) ⇒ un rustc distinto diverge of_tree. Criterio elegido: AUTO-
CONSISTENCIA (REF recomputado con hammer-rust = nuevo EXPECT_REF; la VM reproduce ESE),
no igualdad byte-a-byte con el baseline Alpine.
- swap-rust-into-toolchain.sh: overlay aditivo y reversible de .scratch/rust-1.91.1-prefix
sobre /toolchain. El rustlib x86_64-unknown-linux-musl de hammer y sus .so con hash propio
NO chocan con el x86_64-alpine-linux-musl de Alpine ⇒ sólo se reemplazan /usr/bin/{rustc,
cargo} (Alpine guardado en *.alpine; --restore deshace). Los 4/4 compilan NATIVO (target
x86_64-linux-musl == SANDBOX_NATIVE_TARGET, sin --target) ⇒ hammer-rustc emite para su
triple nativo x86_64-unknown-linux-musl.
- selfhost-verify.sh: SWAP_RUST=1 aplica el swap en $TOOLCHAIN antes del build de stage1
(así el REF host se computa con hammer-rust) y restaura al salir (trap). Sirve TANTO al
REF host COMO al toolchain in-VM (--toolchain $TOOLCHAIN). EXPECT_REF pasa a RUST_EXPECT_REF
(no el 9adefb82 de Alpine). Vars: RUST_PREFIX, RUST_EXPECT_REF.
VALIDADO: el swap aplica/restaura limpio; hammer-rust 1.91.1 (host x86_64-unknown-linux-musl)
compila+corre un crate NATIVO (sin --target) en el devfs — el camino exacto de los 4/4.
NEXT: computar el nuevo RUST_EXPECT_REF (bootstrap stage1+stage2 con SWAP_RUST) y verify in-VM.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ambos hops del climb construidos con el bootstrap real (x.py) en el sandbox devfs,
reusando LLVM 20.1.8 externo en todo (gate >=19) — sin rebuild de LLVM:
mrustc → rustc 1.90.0 → rustc 1.91.0 → rustc 1.91.1
- hop 1 (1.90.0→1.91.0): bootstrap.toml, stage0 = prefix run_rustc musl-host
1.90.0. stage-2 + install → rust-1.91.0-prefix relocatable (rpath).
- hop 2 (1.91.0→1.91.1): bootstrap-1.91.1.toml, stage0 rustc = el 1.91.0 instalado
(bind ro /stage0 vía STAGE0), stage0 cargo = el 1.90.0 (pasa el check minor-1).
extended+cargo. FIX cargo-native-static=true → feature all-static (openssl/curl/
libgit2/libz vendored desde fuente vía gcc), el devfs hermético no tiene OpenSSL.
- run-xpy.sh: añade bind ro opcional /stage0 (env STAGE0) para el stage0 del hop.
VERIFICADO: rust-1.91.1-prefix/bin/{rustc,cargo} corren standalone (solo prefix
montado, rpath). rustc 1.91.1 (ed61e7d7e) host x86_64-unknown-linux-musl LLVM
20.1.8; cargo 1.91.1. Smoke-test compila+corre. Es la versión EXACTA de Alpine,
auto-alojada desde la cadena mrustc. Cada hop ~45min (LLVM reusado).
NEXT: swap rust 1.91.1 en /toolchain + criterio de auto-consistencia (EXPECT_REF).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Frente rust, fase climb: la toolchain mrustc-bootstrapped 1.90.0 (host musl) ya
sirve de stage0 para construir rust 1.91.0 con el bootstrap real (x.py).
- bootstrap.toml: build/host/target=x86_64-unknown-linux-musl, stage0 rustc/cargo
= prefix run_rustc 1.90.0 host-musl, LLVM 20.1.8 reusado vía llvm-config (pasa
el gate >=19, sin rebuild de LLVM), crt-static=false (link dinámico contra el
musl del devfs, como Alpine y la toolchain de run_rustc), rpath=true.
- run-xpy.sh: corre x.py en el sandbox devfs (bind /src, /out, /mrustc) para que
resuelvan los paths de stage0 + llvm-config del bootstrap.toml.
- README: documenta ambos.
dry-run de x.py VALIDADO (stage0 pasa el version-check minor+1, LLVM hallado,
target ok). Build stage-2 de 1.91.0 EN MARCHA en background.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Con el stage0 musl-host, run_rustc all terminó: rustc stage-3 (host=musl, LLVM 20.1.8,
1.90.0-stable-mrustc) + cargo 1.90.0 + sysroot (294 rlibs) construidos y verificados
corriendo. El muro de proc-macros quedó roto (tinystr/displaydoc/icu nativos).
Dos snags finales arreglados (en run_rustc.patch, vs be69c74):
- Makefile:262 (hello_world FINAL): mismos flags CRT que la 172 (--target +
-C target-feature=-crt-static -C link-self-contained=no); solo aflora al completar
stage-2/3.
- Makefile:235 (cargo FINAL): --features vendored-openssl (openssl-sys no halla openssl
del sistema en el devfs hermético; openssl-src lo compila desde fuente). README
documenta ambos como snags #4 y #2(262).
NEXT: climb 1.90 -> 1.91.0 -> 1.91.1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Con el muro de proc-macros roto (stage0 musl-host), run_rustc avanzó por primera vez
hasta el smoke-test hello_world del prefix FINAL (Makefile:262) y falló igual que el
de stage-1: usa el default musl -static-pie + CRT self-contained ausente
(rcrt1.o/crti.o/crtbeginS.o/crtendS.o/crtn.o + -lunwind estático) -> ld: cannot find.
Fix idéntico al de la línea 172: añade --target $(RUSTC_TARGET) -C target-feature=
-crt-static -C link-self-contained=no a la regla del hello final. run_rustc.patch
regenerado (vs be69c74) e incluye ahora ambas reglas; README snag #2 documenta las dos.
Verificado parcialmente: stage-2 rustc, stage-3 rustc y cargo se construyeron OK antes
del fallo (proc-macros nativos: tinystr/displaydoc/icu compilan). Rebuild en curso.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Al construir el cargo del stage0 musl-host, minicargo (con RUSTC_TARGET seteado,
aunque host==target==musl) corre los build-scripts bajo cargo-build/host/build_X/
pero el crate target hace include!/include_bytes!(OUT_DIR/..) apuntando a
cargo-build/build_X/ (vacío) -> mrustc aborta con signal 6. Rompió en libsqlite3-sys
(bindgen.rs) y en el binario cargo (man.tgz).
Fix: symlink_outdirs() enlaza cada dir target -> host (salidas bit-idénticas porque
host==target), aplicado en un bucle de reintento alrededor del build incremental de
cargo (los sys-crates tardíos -cargo/curl/openssl/libgit2-sys/libssh2-sys- corren sus
scripts al final, así que un solo pase no basta). Documentado como snag #4 en el README.
Verificado: stage0 musl-host rustc 1.90.0 + cargo 1.90.0 construyen y corren con
host=x86_64-unknown-linux-musl; desbloquea proc-macros nativos en run_rustc.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rastrea las correcciones del frente rust que vivían en .scratch/ (gitignored):
- run_rustc.patch (vs mrustc be69c74): minicargo/hello con --target musl;
RUSTFLAGS + sitios de link con link-self-contained=no (CRT vía gcc Alpine,
link dinámico contra musl); proxy host-units con crt-static off (sin inject
de --target, host==target==musl con el stage0 musl-host).
- build-stage0-musl.sh: rebuild del stage0 rustc+cargo con host triple musl
(CFG_COMPILER_HOST_TRIPLE vía RUSTC_TARGET, --target vía MRUSTC_TARGET),
reusa LLVM + bin/mrustc. Gotcha OUTDIR_SUF documentado.
- run-runrustc.sh: corre targets de run_rustc en el sandbox devfs apuntando
al stage0 musl-host.
- README: diagnóstico de los 3 snags acoplados (std-gnu mmap64/open64,
CRT self-contained ausente, host-triple gnu + proc-macros) y el workflow.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
El rustc booteado por mrustc agota los pthread keys de musl al correr
("fatal runtime error: out of TLS keys" — gotcha #4 de mrustc issue #388).
Es el musl del TOOLCHAIN (el loader /lib/ld-musl-x86_64.so.1 que toda tool
del rootfs linkea), NO el musl target del 4/4 (recipes/musl.toml, estático,
intacto). Se añade a bootstrap-devfs.sh un paso idempotente que reconstruye
musl 1.2.5 con PTHREAD_KEYS_MAX=256 (sed en limits.h, build gcc lib/libc.so)
y reemplaza el loader (backup .orig128). ABI-compat: gcc/make siguen
corriendo. Seguro para of_tree: el loader runtime de las tools no cambia los
bytes que emiten; el 4/4 es estático contra hammer-musl.
Verificado a mano: run_rustc pasó el punto donde moría (build de libstd
musl) y avanza (27%+).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
El rebuild de python3 con zig cc pasó el date-time pero el intérprete
`_bootstrap_python` (zig cc) SEGFAULTEÓ en el paso de "freeze modules" —
mismo fallo que cmake: zig 0.16 miscompila binarios musl grandes (un
hello-world dinámico zig sí corre). Fix idéntico: CC=gcc/CXX=g++ en las
fases (gcc nativo del toolchain, como compila Alpine). Con gcc además
-Wdate-time deja de molestar (gcc honra SOURCE_DATE_EPOCH).
NOTA: rebuild gcc EN CURSO (fase compile, ya pasó configure) al commitear;
aún no sellado. zlib (f3ddad6) validado.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Primer intento de ambas falló; correcciones tras diagnóstico con probes aislados:
- cmake: el cmake mínimo que `./bootstrap` compila con `zig c++` SEGFAULTEA al
correr ("Problem while running initial CMake") — interacción libc++/musl de
zig. Fix: forzar CC=gcc/CXX=g++ en las fases (Alpine compila cmake con gcc;
el toolchain ya trae gcc/g++, nativos y funcionales en el sandbox).
- python3: Modules/getbuildinfo.c usa __DATE__/__TIME__ y la build habilita
-Wdate-time; zig (clang) lo promueve a ERROR. Probé que SOURCE_DATE_EPOCH=1
(que el sandbox ya exporta) fija el VALOR a 1970-01-01 (determinista) pero
clang NO silencia -Wdate-time vía SDE (eso es sólo-GCC). Fix:
CFLAGS="-Wno-error=date-time" — degrada a warning, valor sigue determinista.
NOTA: ambos rebuilds estaban EN CURSO al commitear (aún no sellados en store);
si fallan otra vez, commit de seguimiento. zlib (f3ddad6) sí validado.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Dependencias de build que rustc usa para construir su LLVM bundled (mrustc
README: cmake ≥3.4.3 + python3). De-Alpinizan el camino de bootstrap de rust;
hoy satisfechas por apk de arranque.
- cmake 3.31.6: build vía ./bootstrap (zig cc/c++), enlace dinámico, OpenSSL OFF.
- python3 3.12.10: ./configure autotools (zig cc), deps.build=[zlib],
--without-ensurepip --disable-test-modules, enlace dinámico.
NOTA: ambos están EN VALIDACIÓN — sus builds estaban en fase `configure` (sin
errores, zig cc aceptado) al commitear, todavía NO sellados en store. Si la
compilación/instalación falla, requerirán ajuste en un commit de seguimiento.
zlib (f3ddad6) sí está validado y sellado.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
zlib 1.3.1 estática (zig cc) — primera dependencia de build de la cadena rust
construida desde fuente. mrustc enlaza -lz y el toolchain Alpine sólo trae el
.so runtime (sin zlib.h/libz.a/zlib.pc); esta receta sella libz.a + headers +
zlib.pc en /usr (mismo patrón que libcap → materialize_build_deps los overlaya
en el sandbox), reemplazando el zlib-dev de arranque cuando se cablee como
deps.build de la receta mrustc/rust.
Validada: build+sello OK (store cf716586…-zlib). configure de zlib es a mano
(rechaza flags autotools) ⇒ fases override como musl (./configure --static).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Inicia la última pieza del toolchain hammer-from-source: reemplazar el
rustc/cargo de Alpine por una cadena purista vía mrustc (mrustc → rustc
1.90.0 → 1.91.1, sólo 2 saltos). mrustc es C++14 y DEBE compilarse con g++
(clang/zig rompen sus macros tagged_union, ver mrustc issue #388) y enlaza
-lz; el toolchain traía libstdc++ runtime pero no cc1plus/headers ni
zlib-dev. Se añaden `g++` y `zlib-dev` a la lista NEEDED del devfs como
herramientas de arranque (mismo status que make/zig/gcc — el veto purista
es sobre un *rustc* prebuilt, no sobre un compilador C++; zlib-dev quedará
reemplazado por recipes/zlib.toml al avanzar el frente).
.gitignore: ignora .scratch/ (clone de mrustc + fuentes de rustc, multi-GB).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Más de-Alpinización del builder (variante b, SDD 11 §7.2b): recetas para construir desde fuente
tres build-tools del toolchain que hoy vienen de Alpine.
- recipes/patch.toml (GNU patch 2.8): lo invoca apply_patches (hammer-build/fetch.rs) cuando una
receta trae source.patches, p.ej. el overlay de linux-headers.
- recipes/m4.toml (GNU m4 1.4.20): base de la cadena autotools.
- recipes/pkgconf.toml (pkgconf 2.5.1): lee los .pc que materialize_build_deps deja en el sandbox.
Las 3 estáticas musl con zig cc (AutoconfReady), validadas: corren, versión correcta y funcionales
(patch aplica, m4 expande, pkgconf resuelve). El 4/4 mínimo no las invoca ⇒ sin flag SWAP_* dedicado
(swapeables con el escape SWAPS="name=hash:rel"); avanzan "builder reconstruible al completo".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Quinta pieza del toolchain hammer-from-source (variante b, SDD 11 §7.2b): GNU coreutils 9.8
(cp/mkdir/ln/chmod/mv/install…), que el `make install` de musl y busybox invocan.
- recipes/coreutils.toml: empaquetada multicall (--enable-single-binary), mismo layout que el
paquete de Alpine (un /bin/coreutils + ~100 symlinks que despachan por argv[0]). Estática musl
con zig cc, vainilla sin patches (es tool del toolchain, no input compilado del 4/4).
- scripts/selfhost-verify.sh: SWAP_COREUTILS=1 construye la receta y monta el único binario sobre
/toolchain/bin/coreutils — los symlinks del toolchain (cp/mkdir/install/…) lo siguen, un solo --swap.
Bisección host fuerte: con hammer-coreutils pisando el de Alpine (trap-restore en .dev-fs), musl Y
busybox rebuildearon BYTE-IDÉNTICO (57b66a2e, 56664d70). Pendiente: corrida in-VM acumulando swaps.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
hammerd::arje_link se suscribe al bus del init (ENTE_BUS_SOCK), relee el frame
postcard de arje-bus con un mirror mínimo de suscriptor (sin arrastrar el
crate-graph de arje ⇒ hammer sigue standalone) y reenvía cada BusEvent →
crashes → Event::Crashed → agent.sock. Wire verificado byte-a-byte contra
arje-bus real (ulid string, frame Subscribe=[00,01,00,0d]); 2 tests de round-trip
local + frame. Se lanza en thread si ENTE_BUS_SOCK está definido (no-op si no).
Roadmap B.2 marcado ✅ (resta sólo el smoke contra init vivo).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deja de ser un error "pendiente": hydrate(.., DynamicSpec{interpreter,rpath})
detecta ELF por magic, copia los que necesitan parcheo (no hardlink: patchelf
mutaría el store) y aplica --set-interpreter/--set-rpath atómicamente
(copy→patch→rename); no-ELF y spec vacío siguen hardlinkeando. ensure_patchelf
falla limpio antes de tocar el FHS si falta la herramienta. HydrateReport.patched
cuenta los reescritos. Callers (bus/cli/bootstrap/e2e) pasan None=estático.
4 tests nuevos (incl. camino de error sin patchelf y real gated). Doc §4.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deja de ser un no-op "pendiente fase 5": apply::apply_init_rule escribe una
regla TOML por servicio (service/action/command); enable/start/restart la
escriben, disable/stop la retiran (idempotente), con guardas de nombre y acción.
CLI y orchestrator la aplican (rebaseando con prefix/overlay). Es el contrato
on-disk que el init (arje) lee para supervisar. 3 tests + doc del formato.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mutation::SourcePatch y RecipeInline ganan campos repo/commit XOR tarball/sha256
(Option, serde-default ⇒ compat con .swm git existentes), resueltos por
swm::swm_source_kind con la misma regla que recipe::Source::kind. swm_bridge
sintetiza la receta según el modo; hammer export reconstruye fuentes tarball
como source_patch en vez de caer a file_drop (provenance fina recuperada).
Prompt del traductor y roadmap actualizados. Tests nuevos para tarball + XOR.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nuevo módulo hammerd::crashes: traduce la señal de ciclo de vida normalizada
(fuente = arje-bus BusEvent) a proto::Event::Crashed y la bombea al EventBus →
agent.sock (capa de IA). Traducción + bucle de bombeo desacoplados del
transporte y testeados (3 tests). Resta sólo el adaptador de transporte
arje-bus ↔ hammerd. Roadmap B.2 actualizado.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cuarta pieza del toolchain hammer-from-source (variante b, SDD 11 §7.2b): bubblewrap, el
sandbox del propio lab. Binario estático ⇒ swap de archivo sobre /toolchain/usr/bin/bwrap.
Como herramienta del toolchain (no input del 4/4) no necesita casar byte-a-byte con Alpine,
sólo aislar igual.
Tres piezas:
- recipes/libcap.toml (2.78): dep obligatoria de bwrap; el toolchain Alpine no trae el -dev
(libcap.a / sys/capability.h). Build estático musl con zig cc, sin patches (es tool, no input).
- materialización de build-deps (hammer-build): deps.build ahora se CONSTRUYE recursivamente
(build() llama build() por cada dep) y cada artefacto sellado se apila como capa --overlay-src
bajo el rootfs del sandbox, dejando usr/{include,lib,lib/pkgconfig} en /usr. pkgconf y zig cc
las hallan sin plumbing de flags. Recetas sin deps: sandbox byte-igual (baseline intacto).
Tests nuevos: no_deps_emits_single_overlay_src, deps_stack_as_overlay_layers_under_rootfs.
- recipes/bwrap.toml (0.11.0): el toolchain no trae meson/ninja/python, así que bypaseamos meson
compilando los 4 .c de bubblewrap directo con zig cc (+config.h trivial). deps.build=["libcap"].
Validación host fuerte: hammer-bwrap es estático, corre --version y sandboxea, y musl rebuildeó
BYTE-IDÉNTICO usándolo de sandbox (bisección). Expuesto con SWAP_BWRAP=1. Tests verdes.
Pendiente: corrida in-VM acumulando swaps para el sello ✓ REPRODUCIBLE.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tercera pieza del toolchain hammer-from-source (variante b, SDD 11 §7.2b): los headers
UAPI del kernel 6.16.12 que musl/busybox #include, hoy tomados del paquete linux-headers
de Alpine.
- recipes/linux-headers.toml: `make headers` (no `headers_install` — su rsync final falta
en el toolchain hermético) + unifdef vía HOSTCC=zig cc; .tar.gz (busybox-tar lo
descomprime sin xz). Sella los 13 subdirs kernel-owned de usr/include.
- assemble_builder: el swap ahora soporta rel_path de DIRECTORIO (reemplaza el árbol
entero: remove + copy), no sólo binarios. Cubierto por test nuevo
(builder_rootfs_swaps_toolchain_header_tree_from_source, incl. borrado de huérfanos).
- recipes/linux-headers-alpine-compat.patch: el paquete de Alpine no es el `make headers`
crudo. Aporta content-pinned 5 archivos que difieren de la salida vainilla; 3 son
REQUERIDOS (scsi/{scsi,scsi_ioctl,sg}.h — legacy userspace, NO UAPI) porque el applet
`eject` de busybox los incluye y sin ellos no compila. install los pisa sobre /out y
limpia el junk (.cmd/Makefile/headers_check.pl/drm) que `cp -a` arrastra.
- scripts/selfhost-verify.sh: SWAP_LINUX_HEADERS=1 construye la receta y emite un --swap
por subdir kernel-owned (auto-derivado del artefacto sellado).
Criterio de éxito fuerte: `diff -r` del header-tree de hammer contra el de Alpine = VACÍO
⇒ el toolchain swapeado es byte-idéntico al baseline ⇒ reproducibilidad por construcción.
Ensamblado end-to-end en host OK (13 swaps, musl bits/sys intactos). 133 tests verdes.
Pendiente: corrida in-VM para el sello ✓ REPRODUCIBLE.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
KVM=1 MEM=24576 SWAP_MAKE=1 SWAP_BUSYBOX=1 ./scripts/selfhost-verify.sh en libre:
la VM reconstruyó los 4/4 con el /toolchain hammerizado (make fbad44ac… +
busybox 56664d70… pisando los de Alpine, busybox compilándose a sí mismo con
hammer-busybox de shell). of_tree(stage1')==EXPECT_REF 9adefb82… ⇒
✓ REPRODUCIBLE: stage1' == stage1, DRIVER_RC=0 (~54 min, arje-zero cu=1 in-VM).
La procedencia del builder deja de ser "todo Alpine" y el auto-alojamiento
sigue bit-a-bit. Siguiente pieza: linux-headers → bwrap → rust/llvm.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Variante (b) pieza 2: el sh+coreutils que el build usa del /toolchain. El /toolchain
de Alpine es mixto — busybox para sh/sed/grep/awk/tar/find (symlinks → /bin/busybox),
GNU coreutils para cp/mkdir/install. El swap monta el busybox estático de hammer
sobre /toolchain/bin/busybox: los applets busybox-backed pasan a usarlo, coreutils
GNU queda intacto. Sin código nuevo — el mecanismo --swap ya soporta rel_path
(--swap busybox=<hash>:bin/busybox).
Validado en host (sin VM): con make+busybox de hammer swapeados, los 4/4 componentes
construyen — incl. busybox compilándose a sí mismo con hammer-busybox de shell — y el
of_tree del rootfs ensamblado da 9adefb82 (el baseline determinista). Las piezas 1 y 2
son reproducibilidad-neutrales: el toolchain es intercambiable sin perturbar el byte-output.
selfhost-verify.sh: SWAP_BUSYBOX=1 (paralelo a SWAP_MAKE). Docs 10/11 actualizadas.
Pendiente: verify in-VM con los swaps para el ✓ REPRODUCIBLE end-to-end.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Verificado: arje-zero con CARGO_BUILD_JOBS=1 y TODAS las CPUs del host sale
byte-idéntico al build serial ⇒ el jobserver serializa el backend paralelo de
rustc/LLVM (ThinLTO) independientemente del nº de CPUs. La pieza que faltaba para
la reproducibilidad host↔VM (codegen-units=1 no bastaba).
- EXPECT_REF re-baseado: 0039b2b9 (build paralelo no-fiable) → 9adefb82 (serial,
determinista, = lo que produce la VM con 1 vCPU).
- Baseline del host refrescado: store/ re-sellado con el arje-zero determinista.
- docs/10-roadmap.md: causa raíz documentada (make inocente; arje-zero/ThinLTO).
Pendiente: re-correr el verify in-VM con el fix para cerrar el ✓ REPRODUCIBLE y
validar de paso la pieza 1 (swap del make).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
[VERIFICACIÓN EN CURSO — no confirmado aún] Stage 2 variante (b) destapó que
codegen-units=1 NO basta para reproducibilidad: el backend paralelo de rustc/LLVM
(ThinLTO + codegen) dimensiona su pool de hilos por el paralelismo disponible y sus
decisiones varían build-a-build a >1 hilo.
Evidencia: arje-zero divergía ~62 KB entre dos builds host idénticos (mismo rustc
1.91.1, mismo commit fijado, mismos flags), mientras un build serial (la VM tiene
1 vCPU, o taskset -c 0 en host) reproducía bit-a-bit a of_tree=9adefb82. El baseline
0039b2b9 se construyó en paralelo ⇒ referencia no-fiable. make/musl/busybox/hammerd
están limpios (descartados uno a uno); el único flaky es arje-zero por paralelismo.
CARGO_BUILD_JOBS=1 limita el jobserver a 1 token para serializar el backend. Test
in-flight: rebuild de arje-zero con todas las CPUs + JOBS=1 debe dar 9adefb82. Si el
pool de LLVM ignora el jobserver (usa affinity), habrá que fijar afinidad o LTO.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stage 2 in-VM con SWAP_MAKE=1 dio of_tree(stage1')=9adefb82 ≠ 0039b2b9. El
diagnóstico en host exonera al make: musl+busybox construidos con hammer-make
salen byte-idénticos al baseline (diff -r limpio) y el ensamblado completo da
of_tree EXACTO 0039b2b9. La divergencia es no-determinismo in-VM (coincidió con
swap thrashing: 97 min wall para ~27 min compute), no el swap del toolchain.
Pendiente: re-correr el verify sin swap (control) para aislar la flakiness in-VM.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`--swap make=b3:fbad…` se parseaba como hash=`b3`, rel_path=`fbad…` porque el
split del rel_path opcional (`name=hash[:rel_path]`) corría ANTES de quitar el
prefijo `b3:`. Resultado: el assemble del builder fallaba con "no existe en el
artefacto sellado b3:b3" (lo cazó el primer intento de SWAP_MAKE=1 in-VM, antes
de bootear la VM ⇒ cero tiempo de máquina perdido).
Fix: quitar `b3:` del hash antes de buscar el `:` del rel_path. Extraje el parseo
inline a `parse_swap()` y le puse 4 tests de regresión (b3:+default, hash pelado+
rel explícito, b3:+rel explícito, falta '=').
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Segundo paso del auto-alojamiento *puro* (SDD 11 §7.2b): tras sellar GNU make
4.4.1 desde fuente (commit 749ea9e), ahora el builder puede *usarlo*. El swap
reemplaza una a una las piezas que el builder toma de Alpine por recetas hammer,
con Stage 2 reverificando que el byte-output no cambia.
- `BuilderSpec.swaps: Vec<ToolchainSwap{name,artifact,rel_path}>`: monta el binario
sellado sobre el path Alpine en /toolchain (estático musl ⇒ sin shim del loader).
- `swaps_digest` (ordenado por nombre) entra al hash lógico del builder ⇒ la
procedencia deja de ser "todo Alpine" y se vuelve auditable para el log de
transparencia. Vacío ⇒ digest "" (compat hacia atrás: builder pura-Alpine
conserva su hash previo).
- CLI: `hammer bootstrap builder --swap make=<hash>[:rel_path]` (repetible;
rel_path por defecto usr/bin/<name>).
- selfhost-verify.sh: opt-in `SWAP_MAKE=1` (construye recipes/make.toml y lo
swapea) + `SWAPS="name=hash …"` para swaps extra. Default off ⇒ corrida
pura-Alpine idéntica a la baseline conocida-buena.
Validado en el host contra el store real: pura `b3:8a370f5d…` vs swapped
`b3:e7e2282c…`, y /toolchain/usr/bin/make queda hardlinkeado al artefacto
fbad44ac… (ELF estático, no el dinámico de Alpine). 3 tests nuevos
(swap aplica, hash cambia, error si falta el binario). 37 tests verdes.
Pendiente: correr Stage 2 in-VM con el swap y confirmar que of_tree(stage1') == ref
(el make hammer compila los 4/4 idéntico al de Alpine ⇒ toolchain intercambiable).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Arranca el auto-alojamiento *puro* (SDD 11 §7.2b): reemplazar una a una las
piezas que el builder toma de Alpine (/toolchain) por recetas hammer desde
fuente, con Stage 2 reverificando cada paso.
make es la pieza base de toda receta autotools. Build estático musl con zig cc
(mismo camino que grep: tarball release con configure → AutoconfReady), sellado
b3:fbad44ac… y reproducible bit-a-bit (dos builds en stores distintos ⇒ árbol
idéntico). Pendiente: swap al /toolchain del builder + Stage 2.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cierra la deriva entre los docs y lo ya probado/commiteado (818c157):
el rebuild in-rootfs corrió end-to-end (host↔VM) y of_tree(stage1')=
0039b2b9… igualó la referencia ⇒ ✓ REPRODUCIBLE.
- roadmap §track posterior: Stage 2 ☐→✅; "Siguiente" reapunta al
auto-alojamiento puro (variante b) + ítems Stage 1 (bus único, atestación).
- SDD 11 §5/CLI: marcadores stage2 ◑→✅; §7 (intro/7.4/8) el rebuild in-VM
deja de ser "lo que falta" y queda la variante (b) como corte pleno.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Corrida KVM=1 MEM=24576 ./scripts/selfhost-verify.sh en el host (libre/cachyos):
la VM reconstruyó los 4/4 con el toolchain de adentro (arje-zero cu=1 compiló en
27m32s in-VM), of_tree(stage1')=b3:0039b2b9… igualó la referencia ⇒
✓ REPRODUCIBLE: stage1' == stage1 (auto-alojado bit a bit), DRIVER_RC=0.
Cierra el hunt de codegen-units (commit 4c9bcc0): la reproducibilidad de arje-zero
queda confirmada en el bucle completo host↔VM, no sólo host↔host.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
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>
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>
Refresca los 4 componentes (musl, busybox, hammerd, arje-zero — éste re-vendorea el
monorepo) con el toolchain baseline en un store limpio y lo promueve a ./store (el
nativo queda en store-native-bak, gitignored). arje-zero baseline difiere del nativo
⇒ el fix -mcpu=baseline alcanza también al monorepo. Referencia CPU-independiente
full-4/4: of_tree(stage1)=
b3:198f209f5e2c9d3a37411823b2ea42a09074d4e482f044278958b1b86f232dbb (rootfs key
b3:2bd7c91b…, idéntico al del preseed-nativo: el cambio de bytes de arje no movió su
key of_inputs — la escotilla C.2 de nuevo).
Builder re-ensamblado con ese toolchain + hammer baseline + --ref-content 198f209f
(embebida en /etc/hammer/rebuild.env) y repackado a work/builder.cpio.gz (415 MB,
27027 entradas, --owner=root:root). Queda listo para bootear: adentro rebuild-stage1
debe reproducir 198f209f ⇒ ✓ REPRODUCIBLE cerraría el auto-alojamiento 4/4 bit a bit.
.gitignore: ignora /store-*/ (stores scratch/backup) — evita commitear el store.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
El rebuild in-rootfs de Stage 2 cazó un no-determinismo real: stage1 reconstruido
en la VM divergía del host (of_tree host=b3:94a4f1… vs VM=b3:ab615b…), aun con el
seal hash idéntico (el seal es of_inputs: mismo key ≠ mismos bytes).
Diagnóstico (control en el host, sin VM): un rebuild de hammerd en el host es
byte-idéntico al cacheado, así que la receta es determinista host-a-host y el cache
no está stale. La divergencia es del entorno de build de la VM: `zig cc` default a
`-mcpu=native` y hornea la ISA del builder en el C/asm de los build-scripts (blake3,
curve25519-dalek). El host tiene SHA-NI+AVX2; `-cpu Broadwell` (VM bajo TCG) no tiene
SHA-NI ⇒ codegen distinto ⇒ bytes distintos ⇒ of_tree distinto. Misma raíz que el
SIGILL de AVX del runbook §7 (binarios al CPU del builder, no a un baseline genérico).
Fix: `-mcpu=baseline` en TODOS los sitios zig cc — CC/CXX del sandbox, los dos
wrappers Cargo (.hammer-zig-cc) y CC/HOSTCC de la receta de busybox. Las rutas SIMD
del runtime (blake3/sha2) son asm con dispatch en runtime: siguen presentes. Bonus:
cierra el AVX/SIGILL del §7 (corre en qemu64 sin -cpu Broadwell).
Validado en el host: con baseline hammerd cambia de bytes (1672448 vs 1677584 —
confirma que el default no era baseline) y los 3 componentes rebuildan limpio
(stage1 rc=0). Nueva referencia CPU-independiente of_tree(stage1-baseline)=
b3:4408e44e2ec51c3769deffcd64dd1f6c2010d414418937c3fa7930a0ded3f845. Runbook §8c
documenta el cruce del muro Rust-offline (cargo vendor por la NIC, hammerd sellado
in-VM en 74m35s) y este diagnóstico+fix.
Nota (plan C.2): el flag de CPU no entra en of_inputs ⇒ cambio de toolchain/flags da
cache-hit con bytes viejos; cerrar ese "pin de toolchain al hash" es trabajo aparte.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Con red, `cargo vendor` resolvió crates.io (DNS OK) pero el TLS falló: la VM no
tenía CA bundle en /etc/ssl/certs/ca-certificates.crt ([77] SSL CA cert). El
toolchain trae el bundle de Alpine; rebuild-stage1 lo copia a la ruta estándar y
exporta SSL_CERT_FILE/CURL_CA_BUNDLE/GIT_SSL_CAINFO (cargo usa libcurl/openssl
según el build). Penúltimo eslabón del vendoring Rust offline-asistido.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Los componentes Rust hacen `cargo vendor` (baja de crates.io); la VM no tenía red
⇒ `failed to sync`. rebuild-stage1 ahora levanta una NIC e1000 (qemu user-mode
10.0.2.0/24): insmod del módulo e1000.ko (como overlay, =m y no cargado), config
estática de eth0 (10.0.2.15, gw 10.0.2.2) y DNS de slirp (10.0.2.3). Best-effort:
sin NIC es no-op (los componentes C no necesitan red). El workspace no tiene deps
git, así que crates.io basta. e1000.ko se inyecta en el builder (.dev-fs/alpine).
Driver de boot: añade `-netdev user -device e1000` y sube el techo a 4h (builds
Rust bajo TCG).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Registra la corrida real (QEMU TCG): la cadena de muros que sólo el rebuild
DENTRO de la VM destapó y que se arreglaron en orden — toolchain sin
bwrap/git/curl, binarios dinámicos vs userland estático (shim del loader), overlay
como módulo no cargado (insmod), y ownership del initramfs (cpio --owner=root).
Resultado: musl y busybox se reconstruyeron y SELLARON dentro de la VM con el
toolchain de adentro (~35-38 min/componente bajo TCG) — auto-alojamiento probado
sobre builds reales. hammerd abortó en `cargo vendor` (deps crates.io no
provistas offline; la VM no tiene red). El 4/4 pleno necesita red en la VM o
crates vendoreadas + un host con KVM/más RAM (idealmente builder desde disco).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
El run en la VM, ya con overlay cargado, fallaba en `bwrap: Can't mkdir /opt/zig:
Permission denied`. Diagnóstico (el rootfs resultó ser tmpfs, no ramfs, así que
no era el fs): los ficheros del builder viajaban con el uid del que lo armó
(1000). En la VM corren como root (0); el userns de bwrap mapea sólo 0→0, así que
el 1000 queda SIN mapear y el copy-up de overlay no puede preservar el owner del
/opt copiado ⇒ EACCES. En el host funciona porque bwrap mapea 1000→0.
Fix: empaquetar el initramfs con `cpio --owner=root:root` (runbook §8c). Revierte
el staging-a-tmpfs (era una hipótesis ramfs equivocada); rebuild-stage1 vuelve a
HAMMER_ROOTFS=/toolchain y documenta el requisito de ownership. 28 tests verdes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
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>
Smoke test real (qemu -cpu Broadwell, initramfs 410 MB gz): el builder rootfs
bootea hasta la shell. arje-zero como PID 1 carga+valida la seed card, instancia
hammerd (pid 60) + console-getty (pid 61), hammerd levanta watcher fanotify +
agent.sock, y la getty deja `~ #` en consola. Mismo boot que Stage 1 pero con el
toolchain adentro — listo para `rebuild-stage1`.
Actualiza la receta de §8c: script boot-builder-vm.sh, MEM=6144, kernel real,
nota de RAM (tmpfs + rebuild en RAM va justo sin KVM).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>