docs: runbook del cierre del auto-alojamiento (variante b) + cross-refs
Toda la variante (b) del SDD 11 §7.2 vivía sólo en scripts/rust-frontier/README y notas dispersas; el SDD §7.2 y el runbook §8c quedaban en "Pendiente: linux-headers → bwrap → rust/llvm". Nuevo runbook docs/runbooks/ self-hosting-toolchain.md documenta el end-state: - las dos categorías de swap y los dos anclajes de of_tree (9adefb82 rustc Alpine / 7fa6cb4e hammer-rust auto-consistente); - tabla de las piezas from-source (make/busybox/coreutils/bwrap/linux-headers /rust/binutils + patch/m4/pkgconf) con hash, flag y si están en-camino; - las 3 corridas verify (5-swap, rust, capstone 6-swap) con comandos y resultados ✓ REPRODUCIBLE in-VM; - el mecanismo --swap (archivo/directorio/rust-overlay); - gotchas reusables (zig miscompila→gcc, musl 256 TLS keys, CARGO_BUILD_JOBS=1, zsh :u / word-splitting); - binutils inerte verificado por bisección. SDD §7.2 y runbook §8c ahora marcan variante (b) cerrada y enlazan el runbook. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+10
-2
@@ -227,8 +227,16 @@ recetas, la **semilla** (`zig`, ya un artefacto sellado), `make`+autotools, `car
|
||||
(ThinLTO) divergía ~62 KB en `arje-zero` a >1 CPU. Fix: `CARGO_BUILD_JOBS=1` en el sandbox
|
||||
serializa el jobserver ⇒ reproducible e independiente del nº de CPUs (SDD 09 §2). El baseline
|
||||
reproducible verdadero es `of_tree=9adefb82…` (el viejo `0039b2b9…` era un build paralelo no-fiable).
|
||||
**Pendiente:** correr Stage 2 in-VM con los swaps para el `✓ REPRODUCIBLE` end-to-end; luego
|
||||
linux-headers → bwrap → el gran tramo rust/llvm.
|
||||
- **✅ VARIANTE (b) CERRADA** (ver [runbook self-hosting-toolchain.md](runbooks/self-hosting-toolchain.md)):
|
||||
se completaron todas las piezas en-camino — make, busybox, **coreutils, bwrap, linux-headers** y
|
||||
el gran tramo **rust/cargo 1.91.1** (cadena purista mrustc→1.90→1.91.0→1.91.1, LLVM 20.1.8 externo
|
||||
reusado; ver [`scripts/rust-frontier/`](../scripts/rust-frontier/README.md)). El **capstone** corrió
|
||||
los 6 swaps juntos in-VM (`SWAP_{MAKE,BUSYBOX,COREUTILS,BWRAP,LINUX_HEADERS,RUST}=1`) dando
|
||||
`✓ REPRODUCIBLE` con `of_tree(stage1')=7fa6cb4e…` bit a bit. Dos anclajes de `of_tree`: `9adefb82…`
|
||||
(rustc Alpine, los 5 tools lo mantienen) y `7fa6cb4e…` (hammer-rust, auto-consistente — el
|
||||
compilador emite los bytes). binutils desde fuente (`recipes/binutils.toml`, 2.45.1) cierra la
|
||||
provenance pero es **inerte** al `of_tree` (zig provee as/ld; verificado por bisección). No quedan
|
||||
piezas del toolchain por de-Alpinizar.
|
||||
|
||||
### 7.3 Enganche con lo ya hecho
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
# Runbook — auto-alojamiento del toolchain (variante b, cerrada)
|
||||
|
||||
Cierre de la **variante (b)** del SDD 11 §7.2: el toolchain del builder ya no es "todo Alpine" —
|
||||
cada pieza genuinamente en-camino se construye **desde fuente con hammer** y el auto-alojamiento de
|
||||
Stage 1 sigue siendo **bit a bit** (`of_tree(stage1') == of_tree(stage1)`).
|
||||
|
||||
Este runbook documenta el end-state. Para el mecanismo base (rebuild in-rootfs, builder, QEMU) ver
|
||||
[stage1-vm-boot.md](stage1-vm-boot.md) §8c; para el detalle del frente rust ver
|
||||
[`scripts/rust-frontier/README.md`](../../scripts/rust-frontier/README.md).
|
||||
|
||||
## 0. Qué demuestra / qué no
|
||||
|
||||
- **SÍ:** el builder reconstruye los 4/4 de Stage 1 (musl, busybox, hammerd, arje-zero) con un
|
||||
toolchain **construido por hammer desde fuente** (make, busybox, coreutils, bwrap, linux-headers
|
||||
**y** rustc/cargo), y el `of_tree(stage1')` reproduce la referencia **bit a bit** dentro de la VM.
|
||||
- **NO:** no afirma igualdad byte-a-byte con el toolchain de Alpine. El criterio es
|
||||
**auto-consistencia** (el toolchain hammer reproduce SU propio sello), no equivalencia con Alpine
|
||||
(ver §3, los dos anclajes de `of_tree`).
|
||||
|
||||
## 1. Las dos categorías de swap (clave conceptual)
|
||||
|
||||
| categoría | piezas | efecto en `of_tree` |
|
||||
|-----------|--------|---------------------|
|
||||
| **herramientas que orquestan/copian** | make, busybox, coreutils, bwrap, linux-headers, binutils | producen **bytes idénticos** ⇒ `of_tree` NO cambia |
|
||||
| **el compilador que EMITE bytes** | rustc/cargo | un rustc distinto ⇒ bytes distintos de hammerd/arje-zero ⇒ `of_tree` DIVERGE |
|
||||
|
||||
Por eso hay **dos anclajes** de `of_tree(stage1)`:
|
||||
|
||||
- **`b3:9adefb82…`** — baseline con **rustc de Alpine** 1.91.1 (los 5 tools de sandbox lo mantienen).
|
||||
- **`b3:7fa6cb4e…`** (`RUST_EXPECT_REF`) — con **hammer-rust** 1.91.1 (mrustc→1.90→1.91.0→1.91.1).
|
||||
≠ 9adefb82 porque el compilador emite los bytes; es auto-consistente (reproducido en host y VM).
|
||||
|
||||
## 2. Piezas del toolchain construidas desde fuente
|
||||
|
||||
Todas estáticas musl con `zig cc` salvo donde se note. "En-camino" = la usan los `make`/`cargo` del 4/4.
|
||||
|
||||
| pieza | receta | hash sellado | flag verify | en-camino | nota |
|
||||
|-------|--------|--------------|-------------|-----------|------|
|
||||
| GNU make 4.4.1 | `make.toml` | `fbad44ac…` | `SWAP_MAKE` | sí | herramienta base autotools |
|
||||
| busybox 1.36.1 | `busybox.toml` | `56664d70…` | `SWAP_BUSYBOX` | sí | `sh/sed/grep/awk/tar/find` |
|
||||
| GNU coreutils 9.8 | `coreutils.toml` | `b116944c…` | `SWAP_COREUTILS` | sí | multicall, `cp/mkdir/install` |
|
||||
| bwrap 0.11.0 (+libcap) | `bwrap.toml` | `f89e7160…` | `SWAP_BWRAP` | sí | el sandbox del propio lab |
|
||||
| linux-headers 6.16.12 | `linux-headers.toml` | `da3d714b…` | `SWAP_LINUX_HEADERS` | sí | swap-directorio (13 subdirs UAPI) |
|
||||
| rustc/cargo 1.91.1 | `scripts/rust-frontier/` | prefix `rust-1.91.1-prefix` | `SWAP_RUST` | sí | **compilador**, cambia `of_tree` |
|
||||
| binutils 2.45.1 | `binutils.toml` | `61400d05…` | — (`SWAPS=`) | **no (inerte)** | CC=gcc; ver §6 |
|
||||
| patch / m4 / pkgconf | `{patch,m4,pkgconf}.toml` | — | — (`SWAPS=`) | no | provenance autotools |
|
||||
|
||||
`binutils` y `patch/m4/pkgconf` no están en el camino mínimo del 4/4 (zig provee as/ld/ar; ningún
|
||||
4/4 corre `autoreconf`), así que NO tienen flag dedicado — se swapean con el escape
|
||||
`SWAPS="name=hash:rel …"`.
|
||||
|
||||
## 3. Corridas de verificación (todas ✓ REPRODUCIBLE in-VM)
|
||||
|
||||
Prerrequisitos: `./scripts/bootstrap-devfs.sh` (devfs Alpine + zig + g++ + musl 256-TLS-keys), KVM, y
|
||||
para `SWAP_RUST` el prefix hammer-rust en `.scratch/rust-1.91.1-prefix` (ver el README del frente).
|
||||
|
||||
```sh
|
||||
# (a) 5 tools de sandbox acumulados (rustc = Alpine) → of_tree 9adefb82
|
||||
SWAP_MAKE=1 SWAP_BUSYBOX=1 SWAP_LINUX_HEADERS=1 SWAP_BWRAP=1 SWAP_COREUTILS=1 \
|
||||
KVM=1 MEM=24576 ./scripts/selfhost-verify.sh
|
||||
|
||||
# (b) compilador hammer-rust solo → of_tree 7fa6cb4e
|
||||
SWAP_RUST=1 KVM=1 MEM=16384 PRESEED=hammerd ./scripts/selfhost-verify.sh
|
||||
|
||||
# (c) CAPSTONE — los 6 juntos (todo el toolchain en-camino hammer-built) → of_tree 7fa6cb4e
|
||||
SWAP_MAKE=1 SWAP_BUSYBOX=1 SWAP_LINUX_HEADERS=1 SWAP_BWRAP=1 SWAP_COREUTILS=1 \
|
||||
SWAP_RUST=1 KVM=1 MEM=12288 PRESEED=hammerd ./scripts/selfhost-verify.sh
|
||||
```
|
||||
|
||||
Resultados verificados:
|
||||
- **(a)** 2026-06-14, ~46 min, sobrevive presión de memoria fuerte.
|
||||
- **(b)** 2026-06-18, of_tree `7fa6cb4e` bit a bit (host y VM).
|
||||
- **(c)** 2026-06-19, builder `8ac23664` (17 entradas `--swap` + overlay rust), hammerd reconstruido
|
||||
in-VM `d08fd273` byte-idéntico, `of_tree(stage1')=7fa6cb4e == RUST_EXPECT_REF`, ~7 min in-VM.
|
||||
Demuestra que las dos categorías de swap **componen sin interferencia**.
|
||||
|
||||
### `PRESEED=hammerd` es OBLIGATORIO con `SWAP_RUST`
|
||||
|
||||
arje-zero (monorepo tawasuyu) vendorea ~1973 crates; un rebuild in-VM completo (`PRESEED=all`)
|
||||
desborda el rootfs en RAM de la VM (ENOSPC en `cargo vendor`). `PRESEED=hammerd` preseedea el
|
||||
arje-zero host-built (hammer-rust, `--locked`) y sólo reconstruye hammerd in-VM (vendor chico). Con
|
||||
esto la corrida (c) cabe en `MEM=12288` **sin swap del host**.
|
||||
|
||||
### Reproducibilidad de arje-zero (drift cerrado)
|
||||
|
||||
arje-zero deriva si su fuente no committea `Cargo.lock` (vendor sin `--locked` → deps no pineadas).
|
||||
Cerrado fijando el `Cargo.lock` del workspace en tawasuyu (`recipes/arje-zero.toml` → commit
|
||||
`9967b02c`): el fetch detecta el lock y vendorea `--locked` ⇒ bit-reproducible.
|
||||
|
||||
## 4. El mecanismo de swap
|
||||
|
||||
`hammer bootstrap builder --swap name=<hash>[:rel_path]` (repetible; `rel_path` default
|
||||
`usr/bin/<name>`) monta el artefacto sellado sobre el path del toolchain Alpine y lo ancla en el
|
||||
**hash lógico** del builder (`swaps_digest`), haciendo la procedencia auditable. Variantes:
|
||||
- **archivo** (make, busybox, coreutils, bwrap): estático musl ⇒ sin shim del loader.
|
||||
- **directorio** (linux-headers): un `rel_path` directorio reemplaza el árbol entero (remove+copy,
|
||||
borra huérfanos Alpine) — `assemble_builder` en `hammer-bootstrap`.
|
||||
- **rust** (`swap-rust-into-toolchain.sh`): overlay aditivo+reversible de `.scratch/rust-1.91.1-prefix`
|
||||
sobre `.dev-fs/alpine`; sólo reemplaza `/usr/bin/{rustc,cargo}` (el rustlib y `.so` de hammer no
|
||||
chocan con los de Alpine). `--restore` deja el devfs prístino. Como el input-hash del store NO
|
||||
incluye el rustc, `SWAP_RUST` usa un **store dedicado** (`store-rust`) para forzar el rebuild.
|
||||
|
||||
## 5. Gotchas clave (reusables)
|
||||
|
||||
- **zig 0.16 miscompila binarios musl grandes** ⇒ python3/cmake/binutils con `zig cc` SEGFAULTEAN al
|
||||
correr. Fix: `CC=gcc CXX=g++` en las fases (gcc nativo, como Alpine). El compilador da igual para
|
||||
una herramienta mientras corra.
|
||||
- **musl `PTHREAD_KEYS_MAX` 128→256:** el rustc booteado por mrustc agota los pthread keys de musl
|
||||
("out of TLS keys"). El `bootstrap-devfs.sh` reconstruye el loader del toolchain con 256 keys (es
|
||||
el musl del TOOLCHAIN, no el target del 4/4 — no afecta `of_tree`).
|
||||
- **`CARGO_BUILD_JOBS=1` en el sandbox:** `codegen-units=1` NO basta — el backend paralelo de
|
||||
rustc/LLVM (ThinLTO) divergía ~62 KB en arje-zero a >1 CPU. Serializar el jobserver lo vuelve
|
||||
CPU-count-independiente (SDD 09 §2).
|
||||
- **`--swap` en zsh interactivo:** `$HASH:usr` se parsea como el modificador `:u` (uppercase). Bracear
|
||||
`${HASH}:usr`. (El verify es bash, ahí es literal.)
|
||||
- **`for x in $VAR` en zsh** NO hace word-splitting — usar arrays o lista literal.
|
||||
|
||||
## 6. binutils — inerte, verificado empíricamente
|
||||
|
||||
`recipes/binutils.toml` (2.45.1, misma versión que Alpine) cierra la de-Alpinización del toolchain,
|
||||
pero es **inerte al `of_tree`**: el lab compila con `zig cc` (ensamblador interno + lld + `zig
|
||||
ar`/`ranlib`/`objcopy`), así que los 4/4 nunca invocan el `ld`/`as` de binutils.
|
||||
|
||||
Verificado por bisección (host, sin VM, 2026-06-19): superponer hammer-binutils (`61400d05`) sobre
|
||||
`.dev-fs/alpine/usr/bin` (confirmando que el `ld` activo pasa a NEEDED `libc.so` sin `libbfd`) y
|
||||
reconstruir musl+busybox → **byte-idénticos** al baseline (`57b66a2e`, `56664d70`). El swap no mueve
|
||||
`of_tree`. (CC=gcc por el gotcha de zig; `link=dynamic` porque libtool descarta el `-static` del exe.)
|
||||
|
||||
## 7. Estado
|
||||
|
||||
**Frente de auto-alojamiento CERRADO.** Todo el toolchain en-camino es hammer-from-source y el
|
||||
auto-alojamiento está verificado bit a bit con todas las piezas juntas (capstone (c)). No quedan
|
||||
piezas del toolchain por de-Alpinizar (gcc nativo se usa sólo como bootstrap-compiler de las
|
||||
herramientas grandes, igual status que zig; el veto purista era sobre un *rustc* prebuilt, ya
|
||||
eliminado por el frente mrustc).
|
||||
@@ -269,6 +269,11 @@ pleno, un hito propio (el Stage 1 mínimo es runtime, sin compilador).
|
||||
|
||||
## 8c. Builder rootfs — el rebuild in-rootfs (auto-alojamiento, SDD 11 §7)
|
||||
|
||||
> **Variante (b) — auto-alojamiento puro — CERRADA.** Este §8c cubre el mecanismo con toolchain
|
||||
> Alpine (variante a). Para el toolchain construido por hammer desde fuente (make/busybox/coreutils/
|
||||
> bwrap/linux-headers + rust + binutils) y la verificación capstone de los 6 swaps juntos in-VM, ver
|
||||
> [self-hosting-toolchain.md](self-hosting-toolchain.md).
|
||||
|
||||
El **ensamblado** del builder ya está implementado (`hammer bootstrap builder`, [SDD 11 §7.4](../11-bootstrap.md);
|
||||
variante a, toolchain desde Alpine). Produce, sobre el Stage 1 rootfs, una imagen con el toolchain
|
||||
adentro lista para reconstruirse a sí misma. Receta operacional:
|
||||
|
||||
Reference in New Issue
Block a user