3280 Commits
Author SHA1 Message Date
sergioandClaude Opus 4.8 5549330c94 selfhost-verify: RUST_EXPECT_REF=7fa6cb4e + swap --restore deja el toolchain prístino
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>
2026-06-17 01:17:24 -04:00
sergioandClaude Opus 4.8 9f7e75901b hammer-build: -C link-self-contained=no CONDICIONAL (Alpine rechaza la opción)
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>
2026-06-16 22:50:10 -04:00
sergioandClaude Opus 4.8 503e09aeed hammer-build: -C link-self-contained=no en el build rust nativo (zig provee crt1.o)
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>
2026-06-16 22:12:31 -04:00
sergioandClaude Opus 4.8 f06bfc7ee4 selfhost-verify: SWAP_RUST usa store dedicado (el input-hash no incluye el rustc)
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>
2026-06-16 22:03:18 -04:00
sergioandClaude Opus 4.8 fb71aca4be selfhost-verify: swap rust hammer-built 1.91.1 en /toolchain (SWAP_RUST, auto-consistencia)
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>
2026-06-16 21:59:38 -04:00
sergioandClaude Opus 4.8 526141a05b selfhost-verify: climb rust 1.90→1.91.0→1.91.1 COMPLETO (toolchain self-hosted)
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>
2026-06-16 11:32:53 -04:00
sergioandClaude Opus 4.8 0725bf3453 selfhost-verify: artefactos del climb rust 1.90→1.91 (bootstrap.toml + run-xpy.sh)
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>
2026-06-16 09:08:07 -04:00
sergioandClaude Opus 4.8 3e334ae0aa selfhost-verify: run_rustc all COMPLETO — toolchain rust stage-3 self-hosted (musl)
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>
2026-06-16 07:22:58 -04:00
sergioandClaude Opus 4.8 493a243762 selfhost-verify: parchea el hello_world final de run_rustc (snag #2 en Makefile:262)
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>
2026-06-16 01:38:48 -04:00
sergioandClaude Opus 4.8 4f0f5c7bc7 selfhost-verify: arregla el split OUT_DIR host/target de minicargo en build-stage0-musl
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>
2026-06-16 00:15:38 -04:00
sergioandClaude Opus 4.8 bf3f1166ec selfhost-verify: artefactos del frente rust (parche run_rustc + runners stage0-musl)
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>
2026-06-15 21:48:37 -04:00
sergioandClaude Opus 4.8 fc8bc906ea selfhost-verify: musl del toolchain con 256 TLS keys en bootstrap-devfs (frente rust)
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>
2026-06-15 09:02:59 -04:00
sergioandClaude Opus 4.8 aa31f04486 selfhost-verify: python3 también con gcc (mismo segfault zig que cmake)
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>
2026-06-14 18:15:35 -04:00
sergioandClaude Opus 4.8 f54683b44b selfhost-verify: corrige recipes cmake + python3 (diagnóstico de fallos zig)
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>
2026-06-14 18:04:27 -04:00
sergioandClaude Opus 4.8 2e1bc498b5 selfhost-verify: recipes cmake + python3 desde fuente (frente rust) — BORRADOR
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>
2026-06-14 17:45:41 -04:00
sergioandClaude Opus 4.8 f3ddad6bc0 selfhost-verify: recipe zlib desde fuente (frente rust, variante b)
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>
2026-06-14 17:28:51 -04:00
sergioandClaude Opus 4.8 5a18059b99 selfhost-verify: arranque del frente rust (variante b) — g++ en el devfs
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>
2026-06-14 09:02:39 -04:00
sergioandClaude Opus 4.8 6c8a307997 selfhost-verify: herramientas de toolchain extra desde fuente — patch, m4, pkgconf
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>
2026-06-14 05:40:53 -04:00
sergioandClaude Opus 4.8 a774552ead selfhost-verify: pieza 5 (coreutils swap) — SWAP_COREUTILS=1, musl+busybox byte-idénticos en host
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>
2026-06-14 02:23:28 -04:00
SergioandClaude Opus 4.8 a23630c50d feat(arje-link): transporte arje-bus → bus de agente, cierra B.2 end-to-end
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>
2026-06-14 03:30:04 +00:00
SergioandClaude Opus 4.8 f6b337f6cb feat(hydrate): hidratación dinámica real con patchelf (LinkMode::Dynamic)
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>
2026-06-14 03:23:12 +00:00
SergioandClaude Opus 4.8 8a5e75344a feat(swm): init_rule se materializa a /etc/hammer/init.d/{service}.rule
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>
2026-06-14 03:17:56 +00:00
SergioandClaude Opus 4.8 0f42c38106 feat(swm): source_patch modela tarballs además de git (Fase 4)
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>
2026-06-14 03:06:35 +00:00
SergioandClaude Opus 4.8 7c099afe4f feat(bus): B.2 sink del CRASHED — hammerd::crashes traduce eventos de arje
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>
2026-06-14 02:51:43 +00:00
sergioandClaude Opus 4.8 e9f535a1bb selfhost-verify: pieza 4 (bwrap swap) + materialización de build-deps en el lab
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>
2026-06-13 20:05:55 -04:00
sergioandClaude Opus 4.8 b05badee23 selfhost-verify: pieza 3 (linux-headers swap) — SWAP_LINUX_HEADERS=1, byte-idéntico a Alpine en host
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>
2026-06-13 19:35:01 -04:00
sergioandClaude Opus 4.8 26b10bd757 selfhost-verify: variante (b) ✓ REPRODUCIBLE in-VM con make+busybox swaps
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>
2026-06-13 18:51:50 -04:00
sergioandClaude Opus 4.8 0b97a85356 selfhost-verify: pieza 2 (busybox swap) — SWAP_BUSYBOX=1, validada en host
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>
2026-06-13 06:40:59 -04:00
sergioandClaude Opus 4.8 004a895829 selfhost-verify: fix CONFIRMADO + re-base EXPECT_REF a 9adefb82 (determinista)
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>
2026-06-13 05:05:25 -04:00
sergioandClaude Opus 4.8 be6f2e6e89 fix(sandbox): CARGO_BUILD_JOBS=1 para serializar el backend paralelo de rustc (determinismo)
[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>
2026-06-13 04:34:22 -04:00
sergioandClaude Opus 4.8 42c7f3b21d docs(roadmap): make-swap in-VM dio DIVERGENTE, pero el make es inocente
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>
2026-06-13 00:39:10 -04:00
sergioandClaude Opus 4.8 d71ef179eb fix(cli): --swap no debe confundir el : de b3: con el separador del rel_path
`--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>
2026-06-12 22:13:24 -04:00
sergioandClaude Opus 4.8 7bc2ee6019 builder: --swap del toolchain — montar make hammer sobre Alpine (variante b, pieza 1)
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>
2026-06-12 21:38:04 -04:00
sergioandClaude Opus 4.8 749ea9e797 recipes: GNU make 4.4.1 — pieza 1 del toolchain hammer-from-source (variante b)
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>
2026-06-12 14:55:30 -04:00
sergioandClaude Opus 4.8 44e04ca4a0 docs: Stage 2 — auto-alojamiento bit-a-bit confirmado in-VM (✓ REPRODUCIBLE)
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>
2026-06-12 09:01:19 -04:00
sergioandClaude Opus 4.8 818c157596 runbook: ✓ REPRODUCIBLE verificado end-to-end in-VM contra baseline 0039b2b9 (cu=1)
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>
2026-06-12 08:52:40 -04:00
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 4d8c1c754f gitignore: __pycache__/ (py_compile de los scripts)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 00:57:15 +00: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 9e3d6862ca docs: runbook §8c — store refrescado a baseline 4/4 + builder listo
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>
2026-06-11 21:00:11 +00:00
SergioandClaude Opus 4.8 4fe452848f bootstrap: -mcpu=baseline en zig cc — reproducibilidad CPU-independiente (Stage 2)
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>
2026-06-11 20:07:36 +00:00
SergioandClaude Opus 4.8 fd20e38d38 bootstrap: CA bundle para el TLS de cargo vendor en la VM
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>
2026-06-11 18:22:04 +00:00
SergioandClaude Opus 4.8 09034a5e2b bootstrap: red en el builder para el vendoring Rust (cargo vendor)
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>
2026-06-11 17:20:38 +00:00
SergioandClaude Opus 4.8 f6dcf1028d docs: runbook §8c — rebuild in-rootfs ejecutado, 2/4 sellados en la VM
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>
2026-06-11 17:04:33 +00:00
SergioandClaude Opus 4.8 890a37b473 bootstrap: empaquetar el builder con cpio --owner=root:root (copy-up de overlay)
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>
2026-06-11 15:29:17 +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 4a35dfb398 docs: runbook §8c — boot del builder confirmado end-to-end en QEMU
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>
2026-06-11 15:03:30 +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