--export-dynamic venia del .pc de gmodule, y estatico destapo un bug de upstream
Los 8 ejecutables decian static y enlazaban musl dinamicamente. La huella que lo
delata sin mirar el build: `readelf --dyn-syms` daba 21475 entradas contra ~2700
de un binario dinamico normal — eso es --export-dynamic, no un enlace corriente.
NO venia del meson de gtk (ahi no aparece la palabra) sino de un .pc DE
DEPENDENCIA: `gmodule-2.0.pc` trae literalmente `Libs: -Wl,--export-dynamic`, y
`meson.build:426` pedia `dependency('gmodule-2.0')`. El wrapper de cc del lab
(`sandbox.rs:597`) tira el `-static` ante --export-dynamic ⇒ lo ponia el lab y
lo sacaba el lab, por un flag heredado de una dep.
No hace falta parchear el .pc de glib: upstream ya publica la misma libreria sin
el flag. `gmodule-no-export-2.0.pc` trae el `-lgmodule-2.0 -pthread` de verdad y
los otros dos solo hacen Requires sobre el añadiendo --export-dynamic. Es la
palanca prevista, no un apaño — de hecho `gio-2.0.pc` de la propia glib ya usa
la variante no-export.
REGLA GENERAL: cualquier receta que enlace gmodule hereda --export-dynamic y
pierde el -static SIN AVISO. Si link=static no pega y hay glib de por medio,
mirar los .pc de las deps antes que el build del proyecto.
Y entonces aparecio un bug que SOLO existe en estatico: los 8 morian con SIGSEGV
hasta en `--help`. Backtrace con gdb:
g_module_symbol (module=0x0, symbol_name="gtk_progress_get_type")
_gtk_module_has_mixed_deps (module_to_check=0x0) at gtk/gtkmain.c:474
do_pre_parse_initialization () at gtk/gtkmain.c:498
gtk_init_check () at gtk/gtkmain.c:635
`_gtk_module_has_mixed_deps(NULL)` hace `g_module_open(NULL,0)` y pasa el
resultado a `g_module_symbol` sin comprobarlo. En musl ESTATICO `dlopen(NULL)`
devuelve NULL siempre ⇒ deref de nulo en el offset 8, en el arranque. Con libc
dinamica el bug no se ve nunca. Cuarto parche de la receta: la comprobacion que
falta. Devolver FALSE es correcto ademas de seguro — en un estatico no hay
modulos cargables, asi que no puede haber simbolos de GTK 2/3 mezclados.
Control: 423 ficheros intactos, NEEDED=0 en los ocho, .dynsym de 21475 a 0, los
ocho arrancan, gtk4-path-tool hace trabajo real, y `builder-tool validate`
devuelve EXACTAMENTE el mismo «Could not initialize windowing system» que daba
el binario dinamico anterior.
Cae en cascada el re-hash de 7 dependientes; se reconstruyen a continuacion.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACUcwo9mZsE5ocYVE9npih
hammer
Una distribución Linux construida con un laboratorio funcional y hermético en el sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada desde el suelo para que una IA programadora entienda, modifique y comparta el sistema.
hammer no es otro gestor de paquetes inmutable. Es una arquitectura de dos mundos:
- El laboratorio compila desde fuentes upstream (commits fijados), de forma
determinista y aislada (
bubblewrap+zig cc+ musl estático), y direcciona cada artefacto por su hash (BLAKE3) en un content-addressed store. - El userland es un Linux clásico, mutable, con FHS de verdad (
/bin,/lib,/etc). Los binarios se hidratan desde el store por hardlinks. Puedes pisar archivos en caliente, romper cosas con unrm -rf, y revertir cuando quieras.
Entre ambos mundos viven las tres piezas que hacen a hammer distinto:
- Overlay de experimentación — prueba cambios sobre el sistema real con red de
seguridad;
hammer try/commit/discard. - Diario de mutaciones — un daemon
fanotifyregistra todo lo que tú (o la IA) cambiáis a mano. Vives imperativamente; el sistema genera el delta contra la base limpia. El diario es tu configuración — sin ser declarativa. - Manifiesto
.swm— compartes la receta de la mutación (parche de fuente + flags + ediciones de config), no el binario cocinado. El receptor reproduce y verifica; no confía en tu binario.
Encima de todo corre el bus de agente (/run/agent.sock): la IA habla un protocolo
pequeño y legible, dispara compilaciones, inyecta en el overlay, escucha fallos y reacciona.
Tú tienes la última palabra.
Estado
Fase de arranque. Validamos la capa AI-nativa sobre Alpine (musl + FHS ya cocidos)
antes de bajar a distro propia. Ver docs/10-roadmap.md.
Documentación de diseño (SDD)
Toda la arquitectura está en docs/. Empieza por
docs/00-vision.md y docs/01-architecture.md.
Estructura
crates/
hammer-core tipos compartidos: Recipe, Swm, hashing CAS, store
hammer-build el laboratorio: sandbox + compilación + hidratación
hammer-cli el binario `hammer` (build, hydrate, try, commit, apply, export…)
hammerd daemon: bus de agente + diario de mutaciones
docs/ SDDs y ADRs
Stack
| Capa | Decisión |
|---|---|
| Base de validación | Alpine (musl + FHS mutable) |
| Tooling / daemons | Rust (estático-musl) |
| Compilador del lab | zig cc por defecto, pluggable por receta |
| Sandbox de build | bubblewrap (namespaces) |
| Direccionamiento | BLAKE3 content-addressed store |
| Despliegue | Hidratación por hardlinks + patchelf |
Filosofía
La automatización es mi empleada en el sótano, pero en el piso de arriba mando yo.
Eficiencia matemática en la manufactura, libertad biológica en la ejecución.