paso 7: muon MEDIDO — el problema no es la cobertura de meson, es UNA bandera del enlazador
El plan pedía medir 10 recetas antes de adoptar muon, porque «no cubre el 100% de meson». Medido con
muon 0.6.0 (construido acá: una sola compilación C del amalgama en 6,7 s, y el muon completo en 4,7 s
con su samu embebido; dice «meson compatibility version 1.7.99») sobre una muestra SISTEMÁTICA —una
cada 10,7 de las 107 ordenadas, no elegida a dedo— que incluye mesa.
COBERTURA DEL LENGUAJE: 9 de 10 sin un solo hueco de sintaxis. El único gap real es de TIPOS:
graphene hace `conf.set10('HAVE_MEMALIGN', 1)` y muon exige bool donde meson acepta int. Las otras 7
fallas son deps del entorno (pkg-config, un módulo de python) y una es artefacto de mi arnés.
EL HALLAZGO TRANSVERSAL: muon añade `-Wl,--fatal-warnings` a las sondas que compilan Y ENLAZAN
(functions/compiler.c:210) y zig la rechaza de plano ⇒ `cc.sizeof()` devuelve -1 y
`cc.has_function()` false PARA TODO. dbus abortaba con «Could not find a 64-bit integer type» y
graphene con «No aligned malloc function» por sondas que nunca llegaron a correr. Con un cc que
descarta esa bandera, las mismas sondas dan 8 y true.
⚠ Y mi primer «control» no era un control: `CC=$(command -v gcc || command -v cc)` resolvió al MISMO
envoltorio de zig porque en esta jaula no hay gcc. Lo que aisló la causa fue sacar muon del medio.
La causa raíz está en muon y su código lo sabe: toolchains.meson detecta `zig ld` y lo trata como
`lld` → `ld` (GNU), con un TODO que pide exactamente que zig ld sea su propio tipo. Registrarlo así
NO toma efecto: el camino real es «linker: lld (passed-through)», que no pasa por ese detect. Es
trabajo aguas arriba.
VEREDICTO: NO-GO hoy. El gate son dos defectos nombrados, no una campaña. Y filtrar la bandera en el
envoltorio del lab NO es la salida: el lab no entra en hash_inputs, así que dos labs sellarían bytes
distintos en la misma dirección del store. Tampoco se commitea recipes/muon.toml: una receta sin
sellar ensucia el grafo con un nodo `never`; los comandos quedan medidos en el plan.
Delta semántico
Ninguna definición cambió: el cambio es de texto, documentación o datos.
1 archivos · +95 −0
diff --git a/docs/plan-que-sigue-tras-busybox.md b/docs/plan-que-sigue-tras-busybox.md
index 4251de3f..1dcc3f1c 100644
--- a/docs/plan-que-sigue-tras-busybox.md
+++ b/docs/plan-que-sigue-tras-busybox.md
@@ -838,3 +838,98 @@ esta clase de máquina ya provocó un `global_oom`. Lo que cambia es que el lím
disco —medibles, con watchdog— en vez de la corrupción silenciosa de un árbol compartido. Y el
`flock` de `CLAUDE.md` §1 sigue haciendo falta por otra razón: serializa contra los scripts de la
granja, que es control de RECURSOS.
+
+---
+
+# Paso 7 — MEDIDO: `muon` es viable, pero hoy es NO-GO por dos defectos nombrados (2026-09-22)
+
+El paso 7 del plan pedía explícitamente **medir 10 antes de adoptar**, porque «muon no cubre el 100 %
+de meson». Se midió. El resultado no es el que la frase sugería: **el problema no es la cobertura del
+lenguaje meson — es una bandera del enlazador.**
+
+## Cómo se midió
+
+- `muon 0.6.0` (tag, commit `1c825e41e2266be1bead999f7f65d9c763a7ca18`) construido acá: **una sola
+ compilación C** de `src/amalgam.c` (6,7 s con el `cc` del lab) da el `muon-bootstrap`, y ése
+ configura y compila el muon completo en **4,7 s / 156 objetivos**, usando su `samu` embebido. Dice
+ **«meson compatibility version 1.7.99»**. Como receta sería trivial.
+- **Muestra SISTEMÁTICA, no elegida a dedo**: de las 107 recetas que declaran `meson`, ordenadas
+ alfabéticamente, una cada 10,7 ⇒ 10 repartidas por todo el alfabeto. Salieron
+ `accountsservice dbus-shared geocode-glib graphene iso-codes libgweather mesa pango-shared swaybg
+ wl-clipboard` — incluida **`mesa`**, que es el proyecto meson más retorcido del corpus.
+- Fuente bajada de la URL/commit que pinea cada receta, y `muon setup` en el árbol.
+
+## El hallazgo transversal: UNA bandera rompe TODAS las sondas del compilador
+
+Primera corrida: 9 de 10 fallan. Dos con un síntoma que no era de deps —dbus: «Could not find a
+64-bit integer type»; graphene: «No aligned malloc function could be found»— y la causa estaba dos
+capas más abajo:
+
+```
+dbg executing cc … '-Wl,--fatal-warnings'
+dbg compiler stderr: 'error: unsupported linker arg: --fatal-warnings'
+c compiler: sizeof long long: -1
+```
+
+muon añade `-Wl,--fatal-warnings` a las sondas que **compilan y ENLAZAN**
+(`src/functions/compiler.c:210`), y **zig lo rechaza de plano**. Entonces `cc.sizeof()` devuelve
+**-1** y `cc.has_function()` devuelve **false para todo** — y los proyectos que ramifican sobre eso
+abortan diciendo cualquier cosa menos la verdad.
+
+⚠ **Y mi primer «control» no era un control**: puse `CC=$(command -v gcc || command -v cc)` y en esta
+jaula no hay gcc, así que `cc` resolvió al MISMO envoltorio de zig. Daba idéntico, y por un momento
+pareció que el defecto era de muon en cualquier compilador. Lo que lo aisló fue sacar muon del medio:
+
+```
+/work/sergio/bin/cc x.c -o x -Wl,--fatal-warnings ⇒ error: unsupported linker arg
+/work/sergio/bin/cc x.c -o x ⇒ compila y enlaza OK
+```
+
+**La causa raíz está en el propio muon, y su código lo sabe.** `src/script/runtime/toolchains.meson`
+detecta `zig ld` y lo trata como `lld`, que hereda de `ld` (GNU), con este TODO textual: «we need to
+support a way for the compiler to return a list of linkers to check, and then we can specify zig ld
+as its own linker type». Intenté justamente eso —registrar `zig-ld` con `fatal_warnings: []`— y **no
+toma efecto**: el camino real es «linker: lld (passed-through)», que no pasa por el `detect` del
+registro. Es trabajo aguas arriba, no un parche de una línea.
+
+**Lo que SÍ prueba que la bandera es todo el problema**: con un `cc` que la descarta, las mismas
+sondas dan los valores correctos (`sizeof(long long) = 8`, `aligned_alloc = true`).
+
+⚠ **Y ese envoltorio NO es la solución**, aunque funcione: el lab **no entra en `hash_inputs`**
+([[lab-fuera-de-hash-inputs]]), así que filtrar la bandera ahí haría que dos labs sellaran bytes
+distintos en la MISMA dirección del store. El arreglo tiene que estar donde el hash lo cubra.
+
+## La muestra, con la bandera filtrada (o sea: lo que muon puede de verdad)
+
+| receta | resultado | clase |
+|---|---|---|
+| `dbus-shared` | **setup complete** | ✓ |
+| `iso-codes` | **setup complete** | ✓ |
+| `geocode-glib` | `program not found` (módulo gnome) | dep del entorno |
+| `libgweather` | módulo python `gi` ausente | dep del entorno |
+| `mesa` | pkg-config `vdpau` ausente | dep del entorno |
+| `pango-shared` | pkg-config `gobject-introspection` ausente | dep del entorno |
+| `swaybg` · `wl-clipboard` | pkg-config `wayland-client` ausente | dep del entorno |
+| `accountsservice` | su script de versión exige un clone git | artefacto de MI arnés |
+| **`graphene`** | **`conf.set10('HAVE_MEMALIGN', 1)` ⇒ «expected type bool, got int»** | **GAP de muon** |
+
+**Cobertura del lenguaje: 9 de 10 sin un solo hueco de sintaxis** — `mesa` incluida, que llega hasta
+resolver dependencias. El único gap real es de TIPOS, no de una función que falte: meson acepta un
+`int` en `configuration_data.set10()` y muon 0.6.0 exige `bool`.
+
+## Veredicto: NO-GO hoy, y el gate son dos defectos, no una campaña
+
+1. **`zig ld` tratado como GNU `ld`** ⇒ todas las sondas de enlace rotas. Es el TODO de muon; hay que
+ hacerlo aguas arriba (o parchear el camino «passed-through», que es donde de verdad se decide).
+2. **`conf.set10()` rechaza `int`.** Extrapolando la muestra, ~10 de las 107 tendrían algo de esta
+ clase; cada uno es un arreglo chico aguas arriba o un parche por receta.
+
+Mientras 1 no esté, **el swap re-hashearía 107 recetas para obtener binarios configurados con sondas
+que mienten** — que es peor que no hacerlo. Y el premio tampoco es el que parecía: con el paso 1 hecho
+`python3` ya NO viaja en las imágenes, así que lo que compra el cambio es **la cadena de build**, no
+bytes de imagen.
+
+**No se commiteó `recipes/muon.toml` a propósito:** una receta sin sellar ensucia el grafo con un nodo
+`never` que el drenaje cuenta como deuda. Cuando el gate se cierre, la receta es de quince líneas y
+los comandos están medidos acá: `sh bootstrap.sh build-boot` → `build-boot/muon-bootstrap setup -Dlibcurl=disabled
+-Dlibarchive=disabled -Dlibpkgconf=disabled build` → `muon-bootstrap -C build samu`.