Commit Graph
27 Commits
Author SHA1 Message Date
Sergio 476168bb07 takana etapa 5c: comentarios de scripts, MOTD, y un BUG que introdujo la etapa 4
250 líneas de comentario en 151 scripts. Control verificado: el diff no toca
NI UNA línea que no empiece por #, y la sintaxis de los 151 pasa.

El barrido saltea heredocs y cadenas triples, y el guardián DISPARÓ 3 veces:
las tres eran el MOTD que el script escribe DENTRO de la imagen construida —
texto del producto, no comentario del script. Se cambiaron aparte y a
propósito, que es rebranding, no limpieza.

Y el hallazgo caro:  casaba contra ,
que es el TARGET de tracing — o sea el module_path!, o sea el nombre del crate.
La etapa 4 lo movió a  y el script quedó casando NADA. No fallaba:
imprimía cero atribuciones, indistinguible de un log sin problemas. Comprobado
con el binario (RUST_LOG=info sobre zlib), no deducido. Ahora acepta las dos, y
tiene que seguir aceptándolas porque los logs viejos en disco dicen la vieja.

Además 14 rutas de módulo  en docs, que el barrido anterior no tocó
porque  no es frontera de palabra.
2026-09-09 19:28:48 +00:00
Sergio 24bcf1783c takana etapa 4: los 10 crates de librería y el CLI pasan a takana-*
hammer-{core,build,bootstrap,overlay,journal,mirror,upgrade,agent,recover,cli}
→ takana-*, con sus deps de workspace, sus identificadores en el fuente y las
referencias -p de los scripts.

VERIFICADO que no mueve nada del corpus: `takana hash recipes/zlib.toml`
devuelve b3:dc363f26… , idéntico a antes del renombre. Los nombres de crate no
entran en hash_inputs, pero eso se comprueba, no se supone. 600 tests en verde.

DOS BINARIOS SE CONGELAN, y no por prolijidad:

- `hammerd` — paquete Y binario. Es componente de Stage 1 de la distro (musl,
  busybox, hammerd, arje-zero), lo supervisa arje-zero en el sistema arrancado,
  `PRESEED=hammerd` lo nombra en selfhost-verify y sus bytes anclan el baseline
  of_tree. El nombre del crate va en los símbolos ⇒ renombrarlo mueve los bytes.

- `hammer-recover` — el PAQUETE se renombra a takana-recover, el BINARIO no.
  hammer-live-install.sh lo copia a /usr/sbin/hammer-recover en sistemas ya
  instalados y hornea un hook de arranque que lo invoca por ese nombre:
  renombrarlo rompe máquinas instaladas, no el repo.

Consecuencia que hay que anotar igual: al renombrar hammer-core, los bytes de
hammerd cambian de todos modos porque linkea contra un crate con otro nombre.
El baseline of_tree del selfhost hay que rehacerlo — es efecto de la etapa 4,
no de un cambio de hammerd.

Las referencias en comentarios de recetas y docs (rutas hammer-core/src/…)
quedan para la etapa 5: son texto, no mueven hash.
2026-09-09 18:46:41 +00:00
Sergio 442a319499 lab re-pineado con lld (d1e341d5) — y el sha «determinista» lo ensuciaba un log
Al ir a re-pinear la imagen para propagar el `lld` a la granja, hub y worker empaquetaron a shas
DISTINTOS. La imagen se creó para que el sha VERIFIQUE, así que un desacuerdo ahí no se pinea: se
mide.

Los dos rootfs son idénticos: 9550 entradas con la misma lista de ficheros, los mismos tamaños, y
CERO diferencias de metadato (modo, nlink, destino de symlink) en las 8778 entradas de fichero y
symlink. La única diferencia de contenido en todo el rootfs era `var/log/apk.log`, donde apk anota
la FECHA de cada operación — o sea que dos labs equivalentes empaquetaban distinto sólo porque las
instalaciones ocurrieron en momentos distintos. Un sha que no se puede reproducir desde un rootfs
equivalente no verifica nada, que es justo lo que este fichero existe para dar.

Se excluye ese log del tar (no todo `var/log`: cambio mínimo; apk lo recrea solo). Con la exclusión,
hub y worker dan el MISMO tar: 179d04f054f28d8dafe7c626d6b8c686a33a00a96715ee544a9bcf6f62cf586d.

⇒ LA GRANJA YA ESTABA SINCRONIZADA Y AHORA SE PUEDE DEMOSTRAR, sin correr `--traer` en un worker que
está construyendo firefox — reemplazarle el rootfs a mitad de build habría sido la forma cara de
descubrir lo mismo.

Nueva imagen publicada: hammer/lab/lab-d1e341d5….tar.zst (310 M), pin actualizado en
bootstrap-devfs.sh. Queda en el comentario cómo comparar dos máquinas: se compara el TAR y no el
`.tar.zst`, porque el sha comprimido depende de la versión de zstd de cada máquina y dos labs
idénticos con zstd distintos darían un falso desacuerdo.
2026-09-05 03:49:56 +00:00
Sergio cb3ecd5a00 firefox pasa a clang+lld con LTO: la puerta de las optimizaciones costaba apk add lld, no una receta de LLVM
El SDD 26 estimó que habilitar PGO/LTO exigía una receta `llvm-toolchain` (clang+lld+libc++ desde
fuente). ERA CARO DE MÁS. Al mirar el lab en vez de suponerlo:

- `.dev-fs/alpine` YA TRAE clang22 + llvm22 22.1.8 — la MISMA major que usa el APKBUILD de Alpine
  para este mismo Firefox (`_llvmver=22`).
- `Compiler::Clang` YA EXISTE en hammer, cableado de punta a punta: `parse_compiler` lo acepta y
  `hammer-build/src/lib.rs` pone CC=clang, CXX=clang++ y AR=llvm-ar. NINGUNA receta lo usaba.
- Lo único que faltaba era `ld.lld`. `apk add lld` ⇒ lld22 22.1.8, dos paquetes, cero upgrades.

CON ESO CAEN LOS TRES MUROS QUE OBLIGABAN A gcc, sin perder lo que gcc daba: el sondeo de linker se
satisface con `--enable-linker=lld`, el `ar` lo pone hammer solo, y el `NEEDED` de la stdlib de C++
existe porque clang++ de Alpine usa la libstdc++ COMPARTIDA — la prueba no es teórica, Alpine
construye este Firefox con clang22 y sin libcxx en sus makedepends.

LA HUELLA DEL LAB NO SE MOVIÓ, Y SE MIDIÓ ANTES DE TOCAR NADA. `lld` no casa ningún prefijo de
TOOLCHAIN_PREFIXES (hammer-core/src/lab.rs), así que los 43 paquetes que entran en `hash_inputs`
salieron idénticos ⇒ los 837 artefactos sellados quedan intactos. Eso es lo que hace barato el
cambio HOY, y a la vez es un agujero escrito en los dos sitios: la versión de lld no es parte de la
identidad del artefacto, y sólo expone a las recetas `compiler="clang"`, que hoy es una. Meter
"lld" en la lista de prefijos es lo correcto y cuesta re-hashear el corpus entero: próxima campaña.

En el mozconfig entran, además de lld: `--enable-lto=cross`, `--enable-packed-relative-relocs` y
`--with-unsigned-addon-scopes=app,system`. El último no es cosmético: sin él un Firefox de release
rechaza las extensiones que la distro deja en distribution/extensions/, así que la capacidad de atuq
de shipear su propio `sct` se decide ACÁ, en la base, y no en el overlay del derivado.

PGO no entra en esta pasada y el porqué queda escrito en la receta: el perfil se junta corriendo el
navegador (Alpine y Arch usan xvfb-run; nosotros no tenemos X11 ⇒ sway headless) y el profdata NO es
determinista, así que tiene que sellarse como artefacto propio y consumirse por hash.

ThinLTO se capa con la misma cuenta que -j y por la misma razón que ella no es un literal: un número
fijo ataría el ArtifactHash a la RAM de quien escribió la receta.

Nuevo ArtifactHash: b3:6f2a3b2f6db4452ed0d2d3f4e2ff7cd6562a86878d4360653859720be1c3d94d
(el firefox 154.0 sellado con gcc queda SUPERADO, no perdido).
2026-09-05 03:13:38 +00:00
SergioandClaude Opus 5 fe9e06de9e lab: musl-libintl — el rootfs traia los runtimes pero no libintl.h
Decision del usuario. La reconstruccion en la granja destapo que toda la zona
grafica del corpus muere en cadena con

    /usr/include/glib-2.0/glib/gi18n-lib.h:25:10: fatal error: 'libintl.h' file not found

y con ella gdk-pixbuf, appstream, gjs, gdm, mutter, gnome-shell, wireplumber,
sway, swaybg, swaylock, xdg-desktop-portal... El header no estaba en NINGUNA de
las dos maquinas (labs identicos, mismo sha256), asi que no era divergencia de
worker: era el corpus.

En Alpine `libintl.h` NO lo trae musl-dev: lo trae `musl-libintl`, que es
justo lo que faltaba. Verificado: `checking for libintl.h... yes`, y glib,
python3, meson y el resto de la base ya sellan contra el lab nuevo.

El apk va contra EDGE, que es rodante, asi que lo que importa no es solo que
funcione sino que NO ARRASTRE: el lock del toolchain cambia en UNA linea
(+musl-libintl-1.2.6-r2), ni una version movida. La vez anterior un `apk add`
se llevo de propina ncurses 6.5→6.6 y readline 8.3.1→8.3.3.

Se eligio `musl-libintl` y no `gettext-dev` a proposito: el segundo mete `.pc`
que compiten con los del store en la resolucion de pkg-config, que es
exactamente como freetype autodetecto bzip2 y tumbo fontconfig con 27 recetas
detras. Este no trae ninguno.

`openssl-dev` sigue FUERA, respetando el veto de 6ab29b1: el host-tool del
kernel enlaza el openssl del corpus desde el overlay. python3 sigue sin `_ssl`
⇒ gjs/gdm/spidermonkey siguen cayendo por esa via, que es otro frente.

Coste asumido: el corpus se re-hashea otra vez.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xd5DComN9Nu47TBpYMBHBn
2026-08-21 13:08:49 +00:00
SergioandClaude Opus 5 248cd5b270 lab: pinear la imagen nueva (con los -dev de CPython)
sha256 3c9c1ef3... reemplaza a db8a3252... La anterior producia un python3 sin
_ctypes ni _curses y con el se caia la familia GNOME/KDE entera.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 01:01:57 +00:00
SergioandClaude Opus 5 1940a94a11 lab: los -dev al rootfs — es el unico sitio donde _curses se puede resolver
Decision del usuario. CPython construye sus modulos opcionales como .so
COMPARTIDOS y las .a del corpus NO son PIC («relocation R_X86_64_PC32 against
symbol 'stdscr'»), asi que declararlas en [deps] NO funciona: se probo una
por una. Las libs del rootfs son compartidas y si sirven.

Añadidos: libffi-dev ncurses-dev readline-dev sqlite-dev bzip2-dev xz-dev
expat-dev. Resultado VERIFICADO: el guardian de python3 importa los OCHO
modulos (_ctypes _curses readline sqlite3 bz2 lzma zlib pyexpat) y pasa. De
paso `libffi` sale de [deps]: ya lo aporta el lab.

openssl-dev NO va, deliberado: se de-Alpinizo porque el host-tool del kernel
enlaza el openssl del corpus desde el overlay; devolverlo podria cambiar el
artefacto del kernel. python3 sigue sin `ssl`.

Y SE CIERRA EL AGUJERO QUE ESTO ABRIA. Esas libs del rootfs ahora entran en
el CONTENIDO de un artefacto, asi que su version es parte de su identidad ⇒
van a TOOLCHAIN_PREFIXES. Sin eso habriamos reabierto en pequeño el mismo
fallo que 58d3161 cerro: instalar los -dev subio ncurses 6.5→6.6 y readline
8.3.1→8.3.3 —sin tocar gcc/rust/musl, lo confirmo el lock— y ese salto habria
cambiado el python3 producido SIN mover su direccion.

Coste: la huella del lab cambia ⇒ el corpus se re-hashea otra vez. Se hace
AHORA a proposito, con 194 artefactos, no con el corpus a medio construir.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 00:55:01 +00:00
SergioandClaude Opus 5 0de4bf08aa lab: el rootfs se ANCLA en una imagen pineada — deja de resolverse con apk
Al entrar el toolchain en hash_inputs (58d3161) se abrio un agujero
operativo: los repos del rootfs apuntan a Alpine edge, que es RODANTE, asi
que dos maquinas que corran bootstrap-devfs.sh en fechas distintas resuelven
toolchains distintos y NO COMPARTEN NI UN ARTEFACTO. Ni cosecha de granja, ni
mirror pull, ni un cache-hit. Cada worker efimero nacia con un lab propio.

`apk add` contra edge es irrepetible por diseno (edge sirve solo la ultima
version). La salida no es repetir la resolucion, es no repetirla: el rootfs
se construye UNA vez y se TRAE pineado por sha256 — el mismo trato que ya
reciben alpine-minirootfs y zig en este script.

  imagen: 294 M comprimida (1,1 G extraida)
  sha256: db8a32526ad41fbcc76223842dbb4eb65c8ed576570b82152dc7c5691fc2a349

EL TAR ES DETERMINISTA A PROPOSITO (--sort=name --mtime=@1 --owner=0
--numeric-owner): sin eso el sha depende del orden del directorio y del uid
de quien empaqueta, dos empaquetados del MISMO rootfs darian imagenes
distintas y no habria forma de verificar que una imagen es la que dice ser.
Comprobado: dos pasadas, mismo sha.

EL REEMPLAZO ES POR ROTACION, no extrayendo encima: a medias quedaria una
MEZCLA de dos rootfs, que es justo lo que esto existe para evitar.

VERIFICADO de punta a punta: bajada del box, sha intacto tras el viaje,
extraida, y la huella de lab que produce es IDENTICA a la del rootfs vivo
(zlib -> b3:c7a7338f... en las dos). O sea que una maquina que arranque de
esta imagen comparte store.

--from-scratch conserva el camino viejo: es como se FABRICA una imagen nueva.
Reconstruir el corpus es el precio de ese cambio, y ahora es explicito.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 18:57:13 +00:00
SergioandClaude Opus 5 39873fd86e lab: el TODO mandaba a pinear un snapshot de edge que no existe
Alpine no publica snapshots datados de edge y el repo sólo sirve la última
versión, así que ese camino no estaba pendiente: estaba cerrado. Apunta al
lock del paso 3a-quater, que es lo que sí se puede hacer hoy.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 13:05:08 +00:00
SergioandClaude Opus 5 a8f77acc9e lab: lock del toolchain, porque edge es rodante y la deriva no se veia
Los repos del rootfs apuntan a Alpine edge (bump deliberado por el techo
MSRV). Es RODANTE: el mismo script en dos fechas da compiladores distintos.
Medido el 2026-08-10 al bootstrapear gioser — el laptop tenia rust 1.96 y
aqui edge resolvio 1.97.0-r0. Para un proyecto cuyo invariante es reproducir
eso es deriva del LAB, y no aparece en build-state.json.

No es un pin y no puede serlo: edge sirve solo la ultima version (`apk policy
rust` lista unicamente 1.97.0-r0), asi que `apk add rust=1.96.0-r0` rompe en
cuanto edge avanza, y Alpine no publica snapshots datados de edge. Anclar de
verdad pide espejar APKINDEX + los .apk, que es un frente aparte.

Lo que si se puede hoy: registrar los 92 paquetes resueltos en
docs/state/lab-toolchain.lock —que viaja por git, que es como los dos hubs lo
comparan— y AVISAR con el diff delante cuando la maquina difiere. Aceptar el
cambio es deliberado: --relock. Un lock que no se puede imponer sigue
valiendo si al menos nombra lo que cambio.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 13:04:45 +00:00
sergioandClaude Opus 4.8 9a028ba04f gnome: SPIDERMONKEY (mozjs 128) SELLA en el hub — keystone caído
El motor JS de Mozilla, keystone del frente GNOME (gjs→gnome-shell cuelgan de él),
sella b3:c48dbd10: libmozjs-128.so + libjs_static.a + shell js128 + mozjs-128.pc +
550 headers. Compiló el C++ entero a -O3 -j8 sin OOM en el hub (31GB/0 swap, al filo).

Seis capas iteradas desde el borrador:
  1-2. FIX DE INFRA: el rootfs builder tenía clang pero NO el paquete  (Alpine
       separa los binutils LLVM del compilador). Sin llvm-ar/llvm-objdump/llvm-profdata
       configure aborta. bootstrap-devfs.sh: +llvm22 en NEEDED + paso 3a-ter que
       symlinkea la suite llvm-* a /usr/bin (Alpine la deja en /usr/lib/llvm22/bin sin
       exponerla). Aplicado ya al rootfs real (.dev-fs/alpine).
  3. triple: mozjs no traduce vendor ; 4. debe COINCIDIR con el host de rustc
     (); fijado ese exacto.
  5. venv de mach: cada fase es un bwrap con /tmp fresco ⇒ el venv no sobrevivía de
     configure a compile. Anclado a /src/.mozbuild (persiste, es scratch).
No re-hashea artefactos (el rootfs no entra al hash). OJO: el worker golden también
necesita llvm22 (ya cubierto por bootstrap-devfs.sh para la próxima provisión).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 14:17:13 -04:00
sergioandClaude Opus 4.8 4291b2adeb Etapa G frente Go: vendoring integrado en fetch — amfora construye, repro
Cierra el muro del frente Go (vendoring) replicando el patron de Rust:
vendorear in-situ en el fetch (host, con red), no tarball-al-mirror.

- fetch.rs: vendor_go_deps() analoga a vendor_cargo_deps — corre go mod vendor
  en el host si hay go.mod; el sandbox compila offline con -mod=vendor.
- lib.rs: engancha vendor_go_deps tras los patches cuando el arbol trae go.mod
  (sin BuildSys::Go; el compile lo fija la receta en build.phases).
- bootstrap-devfs.sh: instala el toolchain go del host (1.26.4, estatico) en
  .dev-fs/tools/go + symlink en ~/.cargo/bin (PATH del worker via .cargo/env).
- amfora: PRIMERA receta Go del corpus. Build end-to-end validado (repo+commit
  -> fetch vendorea -> sandbox offline -> binario estatico que corre, Amfora
  v1.11.0). REPRODUCIBLE bit-a-bit: dos stores independientes dan of_tree
  b3:9ec1d5fe (trimpath + buildid= en el compile). Promovida al repo (282).

Quedan 12 recetas Go en tandas/staged-2026-06-26/ (cheat/dnsx/croc/dyff/csvtk/
git-town/miller/jump/gron/qrcp/walk/gtrash): mecanico, copiar el patron de
amfora ajustando el nombre del binario.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 04:34:56 -04:00
sergioandClaude Opus 4.8 f9a60ed469 Etapa G: fixes del kit de granja distribuida (validados en VPS Hetzner real)
Tres frentes que aparecieron al provisionar un CCX13 (Ubuntu 24.04) de verdad:
- bootstrap-devfs §3b: el loader musl-256-keys ahora DETECTA la versión del
  rootfs (apk db) en vez de hardcodear 1.2.5. Alpine edge avanzó a musl 1.2.6 ⇒
  un loader 1.2.5 vs coreutils 1.2.6 da `renameat2: symbol not found` → chmod
  roto en el sandbox → el wrapper zig-cc no queda +x → EACCES. case con sha de
  1.2.5 y 1.2.6, die si aparece una nueva.
- vps-setup §2b: compila bubblewrap 0.11.2 si el de la distro no soporta
  --overlay-src (Ubuntu 24.04 trae 0.9.0 sin overlayfs; el sandbox lo necesita).
- farm-sync: excluye /.scratch (44G de fuentes mrustc/rustc) + *.png/content*
  del rsync al worker (casi copia 44G de más).

Smoke test en el VPS: builds compilan código real (pasan cc/chmod), rustc 2
cores al 93%, RAM holgada. Worker funcional.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 04:35:57 -04:00
sergioandClaude Opus 4.8 2032df4085 Etapa G: MITIGA scudo (alias libscudo→musl) → destraba trippy/jnv/presenterm (119→122)
El edge rust depende de scudo-malloc y los shims rustc/cargo lo linkean como primer NEEDED ⇒
scudo interpone malloc en todo el proceso y CRASHEA a rustc en ciertos proc-macros (corrupted
chunk header / SIGSEGV). No se puede apk-del (rust depende). Mitigación: aliasar
/usr/lib/libscudo.so → la libc musl ⇒ el NEEDED resuelve pero malloc cae a musl, sin scudo.
Los shims no usan símbolos scudo-específicos (sólo querían el override), seguro y reversible
(.orig-scudo). bootstrap-devfs.sh lo reproduce (paso 3a-bis).

Destrabados+promovidos: trippy (trip 0.13.0), jnv (0.7.1), presenterm (0.16.1) — antes
crasheaban rustc, ahora construyen+corren static-musl.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 16:01:37 -04:00
sergioandClaude Opus 4.8 e393c6bd4d Etapa G: BUMP de toolchain del catálogo 1.91.1→1.96 (destraba MSRV) + oxlint/ruff (101→103)
El usuario aprobó subir el rustc del sandbox. El rootfs de build (.dev-fs/alpine) migró a
repos Alpine edge: rust/cargo 1.96.0 (+ gcc 15.2/musl 1.2.6/llvm22) + clang-dev/clang-libs
(libclang p/bindgen de los *-sys). bootstrap-devfs.sh actualizado para reproducirlo. El 4/4
NO se afecta (usa SWAP_RUST con el rust hammer-built 1.91.1); esto es el toolchain del CATÁLOGO.

Destrabados+promovidos: oxlint (1.94) y ruff (1.94) construyen+sellan static-musl. ouch lleva
gueto gcc pero queda staged: sus deps C++ (unrar-ng-sys/libbzip3-sys) chocan en el link final
(-lstdc++ vs la libc++ de zig). Frontera C++ = ortogonal al MSRV.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 12:48:24 -04:00
sergioandClaude Opus 4.8 b37f11b666 kernel-from-source: de-Alpinizar flex/bison (recetas reales, no eclipsadas)
flex/bison estaban en el devfs base (apk) Y como recipes/{flex,bison}.toml en
deps.build del kernel — pero las capas de deps van BAJO el rootfs, así que el
Alpine flex/bison eclipsaba a los hammer y las recetas eran decorativas. Quito
flex/bison del devfs/bootstrap-devfs.sh; ahora el kernel los toma de deps.build
(hammer). Validado: rebuild en store fresco → kconfig compila con flex/bison
hammer (lexer.lex.o/parser.tab.o), HAMMER_KERNEL=1 verify → ✓ REPRODUCIBLE.
(El bzImage difiere en 1 byte del Alpine-flex/bison build: el timestamp embebido
UTS_VERSION, no flex/bison; el kernel no es input del of_tree del 4/4.)

m4 (que bison invoca) se deja en el base como tool autotools general. Con esto
los build-deps ESPECIALIZADOS del kernel (flex/bison/openssl/elfutils) son todos
hammer-from-source; sólo quedan las libs base/runtime (m4, libz/libzstd de libelf,
gcc) como capa de arranque, igual status que libc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 14:47:57 -04:00
sergioandClaude Opus 4.8 5937f746e5 recipes/elfutils: de-Alpinizar libelf (último build-dep Alpine del kernel)
tools/objtool del kernel enlaza -lelf (libelf+gelf.h); venía de `apk add
elfutils-dev`. Ahora recipes/elfutils.toml construye SÓLO libelf (0.194, lo que
objtool necesita — no libdw/libdwfl/src) desde fuente, wired como deps.build del
kernel. Con esto NINGÚN build-dep del kernel viene de Alpine: el camino del
kernel es 100% hammer-from-source.

elfutils es glibc-céntrico; musl no trae <error.h>/<argp.h>/<libintl.h>/fts/
obstack/rawmemchr. En vez del parche completo de Alpine, shims mínimos en compat/
(vía CPPFLAGS/-include): error.h y argp.h (sólo los usan color.c/printversion.c,
cuyos .o van en libeu.a pero objtool NO referencia ⇒ basta que compilen); libintl
no-op (+ --disable-nls); rawmemchr inline; y libargp/libfts/libobstack.a stubs
para pasar los AC_SEARCH_LIBS del configure (símbolos inertes para libelf). CC=gcc.

bootstrap-devfs.sh: elfutils-dev fuera del NEEDED. Validado: purgué elfutils-dev
del devfs, rebuild → objtool linkea el libelf hammer (sin gelf.h Alpine), y
HAMMER_KERNEL=1 verify → ✓ REPRODUCIBLE bit a bit, DRIVER_RC=0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 13:51:15 -04:00
sergioandClaude Opus 4.8 7304eb3381 recipes/openssl: de-Alpinizar el build-dep openssl del kernel
certs/extract-cert (host-tool del kernel, lo arrastra CONFIG_SYSTEM_DATA_
VERIFICATION=y) enlaza -lcrypto; venía de `apk add openssl-dev`. Ahora
recipes/openssl.toml (OpenSSL 3.5.4, CC=gcc, libcrypto/libssl ESTÁTICAS vía
no-shared) lo construye desde fuente, wired como deps.build del kernel
(materializado como capa overlay en /usr: libcrypto.a + headers + pkgconfig).

bootstrap-devfs.sh: openssl-dev fuera del NEEDED. El runtime libcrypto3/libssl3
(que curl/git necesitan) lo sigue trayendo Alpine aparte — no es openssl-dev.

Validado: purgué openssl-dev del devfs, rebuild del kernel → certs/extract-cert
compila con el libcrypto hammer (sin Alpine openssl), y HAMMER_KERNEL=1 verify →
✓ REPRODUCIBLE bit a bit, DRIVER_RC=0. libelf (objtool) sigue como bootstrap-lib
apk (elfutils-en-musl es el difícil; de-Alpinizable luego).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 12:25:40 -04:00
sergioandClaude Opus 4.8 f108cc626d kernel-from-source: resolver build-deps (libelf+openssl) + refinar config
Avance del frente kernel: el build pasó objtool y certs.
- bootstrap-devfs.sh: +flex +bison +elfutils-dev +openssl-dev al NEEDED.
  * elfutils-dev (libelf/gelf.h): objtool lo exige — en x86_64 las mitigaciones
    seleccionan CONFIG_OBJTOOL aunque se use frame-pointer unwinder.
  * openssl-dev: el host-tool certs/extract-cert lo #incluye — el defconfig
    fuerza CONFIG_SYSTEM_DATA_VERIFICATION=y vía KEYS←NFS/integrity/dns_resolver
    (no apagable sin desarmar media config).
  Ambas son build-libs de arranque (status g++/zlib-dev), SEGURAS para el of_tree
  del self-host: hammerd no usa openssl (Cargo.lock limpio) y arje-zero va
  preseeded/cacheado (no se reconstruye). De-Alpinizables luego con
  recipes/{elfutils,openssl}.toml.
- linux.toml: quité los -d de keyring que no pegan (olddefconfig/syncconfig los
  revierten por el select-chain); openssl resuelve extract-cert. Comentario
  actualizado con el diagnóstico.

Estado: build compila el kernel completo (objtool+certs OK); defconfig es grande
(GPU/wireless), pendiente el bzImage + boot-test + optimización de config.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 08:19:47 -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 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 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 01d5a02b4d bootstrap: busybox reproducible — fixes destapados por la verificación de Stage 2
La verificación de reproducibilidad de Stage 2 (dos builds + diff de bytes) probó
que musl reconstruye bit-idéntico pero busybox NO, y cazó dos no-determinismos:

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

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

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

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

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

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

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

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

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

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

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