SDD 28 §6.5: el muro derribado — de 23 binarios inertes a 1, y sin mover un ArtifactHash

Elegidas las salidas 1 y 2 del §6.4; hecha la 1, que resultó más barata de lo que parecía y desbloquea
la 2 en vez de competir con ella.

`musl-shared` publica `/usr/lib/libc.so` + `/lib/ld-musl-x86_64.so.1`. Como variante y no tocando la
canónica: `musl` es Stage 1 y su `of_tree` es el baseline del selfhost. Control: `takana hash
recipes/musl.toml` sigue en `b3:ce952f72…`. Y `musl` no es dep de nadie ⇒ cero re-hasheo del corpus.

En la caja: `sh: python3: not found` → `Python 3.12.10`. De 23 inertes quedó **1**, `sqlite3`, que
pedía `libz.so.1`; `zlib-shared` ya estaba sellado y sólo faltaba declararla en `base`.

La salida 2 (python/perl estáticos) sigue viva pero deja de ser urgente: con el cargador publicado el
sistema ya no cuelga del rootfs del lab.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RomoxEGZUhaT4pob1QSX5x
This commit is contained in:
Sergio
2026-09-11 02:00:51 +00:00
co-authored by Claude Opus 5
parent 7e86459738
commit 7e41ffd0e6
2 changed files with 51 additions and 0 deletions
+45
View File
@@ -582,6 +582,51 @@ Es decisión de ADR, y de las que conviene tomar mirando también el [SDD 27 §4
las dos preguntas —«¿el cliente reproduce o hidrata?» y «¿el cliente puede correr lo que le
mandamos?»— son la misma pregunta sobre qué es un sistema takana **sin laboratorio**.
### 6.5 ✅ El muro, derribado: el corpus publica su propio cargador *(2026-09-11)*
De las tres salidas del §6.4 el usuario eligió la 1 y la 2. Hecha la **1**, que resultó ser más barata
de lo que parecía y desbloquea la 2 en vez de competir con ella.
**`recipes/musl-shared.toml`** — variante dinámica de musl que publica `/usr/lib/libc.so` (4,2 M) y
`/lib/ld-musl-x86_64.so.1`. En musl el cargador Y la libc son el mismo objeto.
**Por qué una variante y no `--enable-shared` en la canónica**, con su control: `musl` es componente
de **Stage 1** y su `of_tree` es el baseline de `selfhost-verify`. Tocarla obliga a rehacer ese
baseline a propósito. Con el patrón `*-shared` —que el corpus ya usa 23 veces— la canónica no se
mueve: `takana hash recipes/musl.toml` sigue dando `b3:ce952f72…`, el mismo sellado de Stage 1. Y
además **`musl` no es dep de nadie** (medido: sólo de sí misma; el enlace estático lo resuelve el
musl que trae zig), así que esto **suma sin mover un solo ArtifactHash del corpus**.
#### ⚠ Y hubo que cambiar de compilador, medido
Con `zig-cc` el `libc.so` sale con **1586 símbolos dinámicos** contra los **1654** del musl de Alpine,
y los **68 que faltan son exactamente** los que musl implementa en ensamblador x86_64 — `memset`,
`memcpy`, `memmove`, `memcmp`, `strlen` y toda la familia matemática (`ceil floor sqrt fmod exp log
sin cos tan fma round trunc`) — más los `__stack_chk_*`.
No es que no se compilen: en el `libc.a` del musl canónico **están**. Lo que pasa es que **zig los
resuelve con su propio musl y los deja `FUNC LOCAL HIDDEN` de tamaño 0**, fuera de la tabla dinámica.
El síntoma es un cargador que arranca, reloca y muere con `memset: symbol not found` — que se lee
como «el binario está roto», no como «a la libc le faltan símbolos».
Con `compiler = "gcc"`: **1651 símbolos**, `memset` y `ceil` presentes.
#### El resultado, en la caja
| antes | después |
|---|---|
| `sh: python3: not found` (con `command -v` contestando `/usr/bin/python3`) | `Python 3.12.10` |
| 23 binarios inertes de 726 | **1** |
`perl 5.040002`, `readelf`/`objdump`/`nm` (GNU Binutils 2.45.1) y el resto corren. El único que
quedaba era **`sqlite3`**, con `Error loading shared library libz.so.1`: la zlib canónica también es
`--disable-shared` y nadie publicaba ese soname. `zlib-shared` ya existía sellado en el corpus —
sólo faltaba declararla en `base`.
**La salida 2 (python/perl estáticos) sigue viva y ahora es opcional, no urgente**: con el cargador
publicado el sistema ya no depende del rootfs del lab. Estático seguiría siendo mejor (un binario
menos que puede quedar colgado de un soname), pero es un frente propio y ya no bloquea la mudanza.
### 6.2 Lo que la mudanza tiene que producir, además de la mudanza
El usuario lo pidió explícito: **que este experimento saque recetas y las pruebe**. La caja vieja es
+6
View File
@@ -40,6 +40,12 @@ paquetes = [
# instrumental del proyecto. El síntoma era `sh: python3: not found` con `command -v python3`
# contestando `/usr/bin/python3`: no falta, no arranca. Ver SDD 28 §6.4.
"musl-shared",
# `zlib-shared` (2026-09-11): el único hueco que quedó tras publicar el cargador. Con
# `musl-shared`, 22 de los 23 binarios inertes de la imagen del servidor pasaron a correr; el 23º
# era `sqlite3`, que muere con `Error loading shared library libz.so.1`. La zlib canónica es
# `--disable-shared` y ningún artefacto publicaba ese soname — otra vez el rootfs del lab tapando
# el agujero. La variante ya existía en el corpus; sólo faltaba declararla.
"zlib-shared",
]
[perfil.cli]