tawasuyu

sergio/takana

> 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 co…

TOML 604Rust 56Shell 36Markdown 281227 Definiciones

harkaq: revertir busybox (era runtime base, rompía builds) + coordinar el §3 con Fable 5

DOS ERRORES MÍOS, uno de dirección y otro técnico, los dos en la cosecha automática:

1. DIRECCIÓN: declaró `busybox` como dep en 29 recetas — cuando la Etapa C lo está
   ELIMINANDO (USERLAND_COMPONENTS=[uutils,findutils,…], ya cerrada; joyas-reusables
   §5 lo confirma: "uutils… Ubuntu 25.10 los envía como default"). Estaba cimentando
   la deuda que el roadmap borra.
2. TÉCNICO: busybox YA está en el runtime base de harkaq (`ro /bin/busybox`, `ro
   /bin/sh` — el sandbox corre `sh -c` y /bin/sh→/bin/busybox). Es CONTRATO, no dep.
   Declararlo apila el busybox de hammer sobre el de Alpine y ROMPE el build:
   binutils daba "cannot run C compiled programs" en las DOS máquinas. Verificado:
   sin busybox declarado, binutils construye (b3:f4507dcd…). Y la cadena se explica:
   binutils roto ⇒ zlib (que lo declara) tampoco construía.

Auditoría de la cosecha (diff real, no la línea completa del +): añadió sólo 5 deps
distintas — make ×73, busybox ×29, perl ×8, pkgconf ×5, binutils ×1. Sólo busybox
estaba mal; las otras 4 son deps reales medidas. busybox revertido de 30 recetas
(queda sólo en busybox.toml, pre-existente).

Es el mismo error que ya me habían señalado con otro disfraz: MEDIR BIEN Y ACCIONAR
MAL. harkaq midió correcto (el build toca /bin/busybox: es el shell); la acción
correcta no era declararlo sino reconocerlo como contrato.

+ COORDINACIÓN del §3 con Fable 5 (mismo diseño, tareas repartidas):
  - Su lección casper queda CONFIRMADA y REFORZADA: la clausura de build no sólo le
    FALTAN las clases del mundo (offline) — también le SOBRA casi todo (headers, gcc).
    Medido: htop (estático, 0 NEEDED) no toca NADA al correr ⇒ política = su binario.
  - Su "la clase viaja como campo de la ConcesionCapacidad, sin formato nuevo" se
    cumple LITERALMENTE: lo firmado es format::Permisos = u32 bitmask en 36 bytes
    canónicos (Ring 0) ⇒ las clases SON los bits. La cripto no se toca.
  - Diseño unificado: frontera (clases, u32, declaradas) + detalle (paths, Landlock,
    medidos). D3 rige en ambos.
  - Reparto: clases→Fable 5; medición/harness→Opus. CONTACTO: runtime-policy.sh ahora
    emite la CLASE detectada (/etc/resolv.conf→dns, /etc/ssl/certs→tls-certs, …), no
    sólo el path: la medición alimenta la tabla, la tabla decide el bit.
  - Consumidor esperando: plan-jaula-juegos F1 (Steam que no puede leer ~/.ssh).

+ juez.sh (§10): nombre único por corrida (con uno fijo pega en caché ⇒ falso
  "sin evidencia"). Fue el juez quien destapó todo esto en su primera corrida real.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

d99ed588502194b110d400e79cd7c86d50e0bcd9 · por sergio · (hace 3 meses) · padre 2e85dfc8a · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

44 archivos · +697 −35

diff --git a/docs/17-cierres-frontera.md b/docs/17-cierres-frontera.md
index ebffad19..dffdaf78 100644
--- a/docs/17-cierres-frontera.md
+++ b/docs/17-cierres-frontera.md
@@ -84,6 +84,51 @@ dlopen de módulos NSS — la mitad de por qué casper existe no aplica:
 
 La clase viaja como campo de la `ConcesionCapacidad` — sin formato nuevo.
 
+**Medición que confirma y acota lo anterior (Opus 4.8, 2026-07-16).** Se probó el riel de punta
+a punta y salieron dos cosas que ajustan el diseño; la lección casper queda **confirmada y
+reforzada**:
+
+1. **El sujeto: la clausura de build no puede ser la política de runtime, ni siquiera de base.**
+   No es sólo que le falten las clases del mundo (casper): también le **sobra** casi todo. Un
+   build lee `zlib.h`, `make`, `gcc`; el binario resultante no abre ninguno. Medido con `htop`
+   (musl-estático, **0 `NEEDED`**): bajo la jaula con política mínima **no tocó un solo fichero**
+   fuera de sí mismo ⇒ su política de runtime es `ro <su binario>` y nada más. Derivarla del
+   build le habría concedido headers y compilador — permisos de más, firmados.
+   ⇒ **la política granular se MIDE corriendo el binario** (`scripts/harkaq/runtime-policy.sh`:
+   corre bajo la jaula y **resta el baseline del lanzador**, que si no se lleva el ruido del `sh`).
+   Para un estático la política *no puede* salir de las libs: sólo de correrlo.
+
+2. **La cripto ya es "frontera, no tabla" — y por eso las clases encajan sin tocarla.** Lo que la
+   `ConcesionCapacidad` firma **no** es `card-core::Permissions` (el struct) sino
+   `format::Permisos` = **`u32` bitmask**, dentro de `mensaje_capacidad` =
+   `hash(32) || permisos_le(4)` = **36 bytes canónicos, zero-alloc, con espejo `no_std` en Ring 0**
+   (`wawa-kernel/src/claves.rs:464`). Meterle una tabla de paths rompería **todas** las firmas y
+   contradiría el "capacidad = frontera física, no tabla" que este mismo §3 cita.
+   ⇒ **las clases de servicio SON los bits del `u32`** (`PERMISO_RED` ya es uno; `dns` sería otro).
+   "Sin formato nuevo" se cumple literalmente.
+
+**Diseño unificado (los dos niveles coexisten, cada uno donde cabe):**
+
+| nivel | qué | dónde | cómo se obtiene |
+|---|---|---|---|
+| **frontera** | clases de servicio (`dns`, `tls-certs`, `random`, `locale`, `syslog`) | `u32` firmado, verificado en Ring 0 | **declaradas por nombre** — no se pueden medir: el build es offline (casper) |
+| **detalle** | paths concretos (fs) | Landlock, userspace | **medidos** corriendo el binario bajo la jaula |
+
+El kernel verifica la frontera con 36 bytes; Landlock aplica el detalle. D3 rige en ambos: nada
+se ensancha en silencio.
+
+**Reparto de tareas (para no pisarnos):**
+- **Clases de servicio** (Fable 5): la tabla clase→permiso musl, el bit en el `u32`, y el cableado
+  con `ConcesionCapacidad`/`arje-absorb --attest-from`.
+- **Medición** (Opus 4.8): `runtime-policy.sh`, el harness harkaq (jaula, lector, canario D9) y el
+  baseline del lanzador.
+- **Punto de contacto acordado**: `runtime-policy.sh` emitirá también la **clase** detectada, no
+  sólo el path — si el binario toca `/etc/resolv.conf` ⇒ propone `dns`; si toca `/etc/ssl/certs/`
+  ⇒ `tls-certs`. La medición alimenta la tabla; la tabla decide el bit. Ninguno de los dos
+  ensancha por su cuenta.
+- **Consumidor esperándonos**: `plan-jaula-juegos.md` F1 («la jaula sellada con pressure-vessel +
+  política harkaq del runtime») — un Steam que no puede leer `~/.ssh` sale de este §3.
+
 ### 4. CVE por grafo
 
 `hammer affected CVE-X` exacto (grafo fuente→artefacto→instalado) + frontera mínima de
diff --git a/recipes/adwaita-hello.toml b/recipes/adwaita-hello.toml
new file mode 100644
index 00000000..10376968
--- /dev/null
+++ b/recipes/adwaita-hello.toml
@@ -0,0 +1,47 @@
+# adwaita-hello — app Adwaita mínima de VALIDACIÓN: prueba que libadwaita-1.a es linkeable de verdad.
+# AdwApplication + AdwApplicationWindow + AdwToolbarView. Link 100% estático vía pkg-config --static
+# libadwaita-1 + las privadas de gdk/gsk/appstream que el .pc no declara. Mismo patrón que gtk4-hello.
+name    = "adwaita-hello"
+version = "1.7.6"
+
+[source]
+tarball = "https://download.gnome.org/sources/libadwaita/1.7/libadwaita-1.7.6.tar.xz"
+sha256  = "5eacc5550f0bdbba6a1568aebf25a3d88f5ee07d6b558becc6fd9487579c9a29"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "static"
+
+[build.phases]
+configure = "true"
+compile = '''
+cat > adw_hello.c <<'CEOF'
+#include <adwaita.h>
+static void activate(GtkApplication *app, gpointer user_data) {
+  GtkWidget *win = adw_application_window_new(app);
+  gtk_window_set_title(GTK_WINDOW(win), "Adwaita en hammer");
+  gtk_window_set_default_size(GTK_WINDOW(win), 400, 260);
+  GtkWidget *toolbar = adw_toolbar_view_new();
+  adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(toolbar), adw_header_bar_new());
+  GtkWidget *status = adw_status_page_new();
+  adw_status_page_set_title(ADW_STATUS_PAGE(status), "libadwaita static-musl ✓");
+  adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(toolbar), status);
+  adw_application_window_set_content(ADW_APPLICATION_WINDOW(win), toolbar);
+  gtk_window_present(GTK_WINDOW(win));
+}
+int main(int argc, char **argv) {
+  AdwApplication *app = adw_application_new("org.hammer.adw", G_APPLICATION_DEFAULT_FLAGS);
+  g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
+  int status = g_application_run(G_APPLICATION(app), argc, argv);
+  g_object_unref(app);
+  return status;
+}
+CEOF
+export PKG_CONFIG_PATH=/usr/lib/pkgconfig
+zig cc -mcpu=baseline -static adw_hello.c -o adwaita-hello $(pkg-config --cflags --libs --static libadwaita-1 harfbuzz-subset epoxy xkbcommon wayland-client wayland-egl libtiff-4 libjpeg cairo-script-interpreter)
+'''
+install = "mkdir -p /out/usr/bin && cp adwaita-hello /out/usr/bin/adwaita-hello"
+
+[deps]
+build = ["pkgconf", "libadwaita", "appstream", "libyaml", "curl", "openssl", "libxmlb", "libxml2", "zstd", "gtk4", "pango", "gdk-pixbuf", "cairo", "graphene", "glib", "harfbuzz", "fribidi", "fontconfig", "freetype", "pixman", "libpng", "expat", "libjpeg-turbo", "libtiff", "libepoxy", "wayland", "libxkbcommon", "libdrm", "pcre2", "libffi", "zlib", "mesa"]
diff --git a/recipes/bash.toml b/recipes/bash.toml
index 461c21bf..d0a65972 100644
--- a/recipes/bash.toml
+++ b/recipes/bash.toml
@@ -45,4 +45,4 @@ _abuild_phase
 '''
 
 [deps]
-build = ["ncurses", "readline", "linux-headers", "busybox", "make"]
+build = ["ncurses", "readline", "linux-headers", "make"]
diff --git a/recipes/binutils.toml b/recipes/binutils.toml
index 22534b7b..47caf980 100644
--- a/recipes/binutils.toml
+++ b/recipes/binutils.toml
@@ -43,7 +43,7 @@ link        = "dynamic"
 zig_version = "0.13.0"
 
 [deps]
-build = ["busybox", "make"]
+build = ["make"]
 
 [build.phases]
 # --disable-nls: sin gettext (ausente en el toolchain hermético). --disable-werror: binutils promueve
diff --git a/recipes/coreutils.toml b/recipes/coreutils.toml
index e6b90a55..586ed17f 100644
--- a/recipes/coreutils.toml
+++ b/recipes/coreutils.toml
@@ -32,7 +32,7 @@ link     = "static"
 flags    = ["--enable-single-binary", "--disable-nls"]
 
 [deps]
-build = ["busybox", "make"]
+build = ["make"]
 
 [build.phases]
 # install por defecto (make install DESTDIR=/out) deja el multicall en /out/usr/bin/coreutils; lo
diff --git a/recipes/dosfstools.toml b/recipes/dosfstools.toml
index 296ab225..9653884d 100644
--- a/recipes/dosfstools.toml
+++ b/recipes/dosfstools.toml
@@ -43,4 +43,4 @@ _abuild_phase
 '''
 
 [deps]
-build = ["linux-headers", "busybox", "make"]
+build = ["linux-headers", "make"]
diff --git a/recipes/e2fsprogs.toml b/recipes/e2fsprogs.toml
index 942cfa68..b18fd76a 100644
--- a/recipes/e2fsprogs.toml
+++ b/recipes/e2fsprogs.toml
@@ -59,4 +59,4 @@ _abuild_phase
 '''
 
 [deps]
-build = ["linux-headers", "busybox", "pkgconf"]
+build = ["linux-headers", "pkgconf"]
diff --git a/recipes/flex.toml b/recipes/flex.toml
index 21a6ef25..9bf025df 100644
--- a/recipes/flex.toml
+++ b/recipes/flex.toml
@@ -24,9 +24,6 @@ link       = "dynamic"
 # bueno por-receta ⇒ gcc deja de hacer falta (toolchain 100% zig). No es input del 4/4. SDD 11 §7.2b.
 zig_version = "0.13.0"
 
-[deps]
-build = ["busybox"]
-
 [build.phases]
 configure = "./configure --prefix=/usr --disable-nls --disable-shared"
 compile   = "make -j\"$(nproc)\""
diff --git a/recipes/fontconfig.toml b/recipes/fontconfig.toml
index 17195d7c..eda899e1 100644
--- a/recipes/fontconfig.toml
+++ b/recipes/fontconfig.toml
@@ -15,4 +15,4 @@ install   = "make install DESTDIR=/out"
 # libpng+zlib: freetype se compila --with-png, así que freetype2.pc trae `Requires: libpng`
 # (y libpng.pc → zlib); sin ellos pkg-config no resuelve freetype2 y ./configure aborta.
 [deps]
-build = ["freetype", "expat", "pkgconf", "gperf", "python3", "libpng", "zlib", "busybox", "make"]
+build = ["freetype", "expat", "pkgconf", "gperf", "python3", "libpng", "zlib", "make"]
diff --git a/recipes/gawk.toml b/recipes/gawk.toml
index d3e11c2c..5c18555d 100644
--- a/recipes/gawk.toml
+++ b/recipes/gawk.toml
@@ -18,7 +18,7 @@ link     = "static"
 flags    = []
 
 [deps]
-build = ["busybox", "make"]
+build = ["make"]
 
 [build.phases]
 # de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):
diff --git a/recipes/gperf.toml b/recipes/gperf.toml
index d29952ab..3f847be9 100644
--- a/recipes/gperf.toml
+++ b/recipes/gperf.toml
@@ -9,7 +9,7 @@ compiler = "zig-cc"
 target   = "x86_64-linux-musl"
 link     = "static"
 [deps]
-build = ["busybox", "make"]
+build = ["make"]
 
 [build.phases]
 configure = "CXXFLAGS=\"$CXXFLAGS -std=c++14\" ./configure --prefix=/usr"
diff --git a/recipes/gtk4-hello.toml b/recipes/gtk4-hello.toml
new file mode 100644
index 00000000..017e29a5
--- /dev/null
+++ b/recipes/gtk4-hello.toml
@@ -0,0 +1,47 @@
+# gtk4-hello — app GTK4 mínima de VALIDACIÓN: prueba que libgtk-4.a (static) es linkeable de verdad.
+# Reutiliza el tarball de GTK4 solo como acarreo de [source] (lo ignora); escribe su propio hello.c y
+# lo linkea ESTÁTICO contra todo el cierre GTK4 vía `pkg-config --static gtk4`. Si sella, el toolkit
+# de GUI del lab es usable por apps, no solo "compila". deps = cierre .pc completo + gtk4.
+name    = "gtk4-hello"
+version = "4.18.6"
+
+[source]
+tarball = "https://download.gnome.org/sources/gtk/4.18/gtk-4.18.6.tar.xz"
+sha256  = "e1817c650ddc3261f9a8345b3b22a26a5d80af154630dedc03cc7becefffd0fa"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "static"
+
+[build.phases]
+# no-op: el tarball trae meson.build y el lab inyectaría `meson setup` por defecto si omito configure.
+configure = "true"
+compile = '''
+cat > hammer_hello.c <<'CEOF'
+#include <gtk/gtk.h>
+static void activate(GtkApplication *app, gpointer user_data) {
+  GtkWidget *win = gtk_application_window_new(app);
+  gtk_window_set_title(GTK_WINDOW(win), "Hola desde hammer");
+  gtk_window_set_default_size(GTK_WINDOW(win), 360, 220);
+  GtkWidget *label = gtk_label_new("GTK4 static-musl ✓ (zig cc)");
+  gtk_window_set_child(GTK_WINDOW(win), label);
+  gtk_window_present(GTK_WINDOW(win));
+}
+int main(int argc, char **argv) {
+  GtkApplication *app = gtk_application_new("org.hammer.hola", G_APPLICATION_DEFAULT_FLAGS);
+  g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
+  int status = g_application_run(G_APPLICATION(app), argc, argv);
+  g_object_unref(app);
+  return status;
+}
+CEOF
+# gtk4.pc NO declara Libs.private (asume link dinámico contra libgtk-4.so); para ESTÁTICO hay que sumar
+# las privadas que gdk/gsk linkean directo (harfbuzz-subset, epoxy, wayland, xkbcommon, tiff, jpeg).
+export PKG_CONFIG_PATH=/usr/lib/pkgconfig
+zig cc -mcpu=baseline -static hammer_hello.c -o gtk4-hello $(pkg-config --cflags --libs --static gtk4 harfbuzz-subset epoxy xkbcommon wayland-client wayland-egl libtiff-4 libjpeg cairo-script-interpreter)
+'''
+install = "mkdir -p /out/usr/bin && cp gtk4-hello /out/usr/bin/gtk4-hello"
+
+[deps]
+build = ["pkgconf", "gtk4", "pango", "gdk-pixbuf", "cairo", "graphene", "glib", "harfbuzz", "fribidi", "fontconfig", "freetype", "pixman", "libpng", "expat", "libjpeg-turbo", "libtiff", "libepoxy", "wayland", "libxkbcommon", "libdrm", "pcre2", "libffi", "zlib", "mesa"]
diff --git a/recipes/gtk4.toml b/recipes/gtk4.toml
new file mode 100644
index 00000000..e4b78d85
--- /dev/null
+++ b/recipes/gtk4.toml
@@ -0,0 +1,39 @@
+# gtk4 4.18.6 — el toolkit de GUI. meson static, backend SOLO wayland (sin X11/broadway/win/mac),
+# renderer GL vía libepoxy (vulkan disabled), todo lo opcional off (demos/tests/docs/cups/gstreamer/
+# introspection). Corona el stack gráfico C del lab: con esto el corpus puede producir apps GTK reales.
+# Deps = cierre transitivo .pc completo (pkg-config estático resuelve Requires.private).
+name    = "gtk4"
+version = "4.18.6"
+
+[source]
+tarball = "https://download.gnome.org/sources/gtk/4.18/gtk-4.18.6.tar.xz"
+sha256  = "e1817c650ddc3261f9a8345b3b22a26a5d80af154630dedc03cc7becefffd0fa"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "static"
+
+[build.phases]
+# GTK4 construye libgtk.a (static_library 'gtk') Y libgtk-4.so; las tools linkean la .so con libgtk_dep,
+# imposible en el lab static-musl. Parche: que las tools usen libgtk_static_dep (la .a). El sed es seguro:
+# "libgtk_dep" NO es substring de "libgtk_static_dep" ⇒ no toca las que ya usan el estático.
+configure = "sed -i 's/libgtk_dep/libgtk_static_dep/g' tools/meson.build && PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload --prefer-static -Ddefault_library=static -Dwayland-backend=true -Dx11-backend=false -Dbroadway-backend=false -Dwin32-backend=false -Dmacos-backend=false -Dvulkan=disabled -Dintrospection=disabled -Dbuild-demos=false -Dbuild-testsuite=false -Dbuild-tests=false -Dbuild-examples=false -Dmedia-gstreamer=disabled -Dprint-cups=disabled -Dprint-cpdb=disabled -Dcloudproviders=disabled -Dsysprof=disabled -Dtracker=disabled -Dcolord=disabled -Df16c=disabled -Ddocumentation=false -Dman-pages=false -Dc_args=-Wno-error=date-time"
+compile   = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
+# meson instala solo libgtk-4.so y genera convenience-libs THIN (gtk/gdk/gsk por separado, referencian
+# los .o por ruta → inútiles fuera del build dir). Fusiono los tres en UN archive GORDO libgtk-4.a (embebe
+# todos los .o) para que `-lgtk-4` + `-static` linkee de verdad en el lab static-musl.
+install = '''
+PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild
+rm -f /out/usr/lib/libgtk-4.a
+cd output
+objs=""
+for a in $(find . -name '*.a'); do
+  d=$(dirname "$a"); b=$(basename "$a")
+  for o in $(cd "$d" && zig ar t "$b"); do objs="$objs $d/$o"; done
+done
+zig ar rcs /out/usr/lib/libgtk-4.a $objs
+'''
+
+[deps]
+build = ["meson", "samurai", "python3", "pkgconf", "glib", "cairo", "pango", "gdk-pixbuf", "graphene", "libepoxy", "wayland", "wayland-protocols", "libxkbcommon", "libdrm", "fontconfig", "harfbuzz", "fribidi", "libpng", "pixman", "freetype", "expat", "libffi", "pcre2", "zlib", "libjpeg-turbo", "libtiff", "mesa"]
diff --git a/recipes/gtksourceview.toml b/recipes/gtksourceview.toml
new file mode 100644
index 00000000..0d8159d9
--- /dev/null
+++ b/recipes/gtksourceview.toml
@@ -0,0 +1,23 @@
+# gtksourceview 5.16.0 — widget de edición de código (resaltado, números de línea…) sobre GTK4.
+# Base de editores/IDEs (gnome-text-editor lo usa). meson static. introspection/vapi/docs/tests off.
+name    = "gtksourceview"
+version = "5.16.0"
+
+[source]
+tarball = "https://download.gnome.org/sources/gtksourceview/5.16/gtksourceview-5.16.0.tar.xz"
+sha256  = "ab35d420102f3e8b055dd3b8642d3a48209f888189e6254d0ffb4b6a7e8c3566"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "static"
+
+[build.phases]
+# gtksourceview 5.16 no tiene opción tests; los ejecutables de tests/testsuite linkean gtk4 estático y
+# fallan por las privadas (tiff/epoxy/cairo-script). La LIB sí construye → elimino esos subdirs con sed.
+configure = "sed -i \"/subdir('tests')/d;/subdir('testsuite')/d\" meson.build && PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload --prefer-static -Ddefault_library=static -Dintrospection=disabled -Dvapi=false -Ddocumentation=false -Dsysprof=false -Dc_args=-Wno-error=date-time"
+compile   = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
+install   = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
+
+[deps]
+build = ["meson", "samurai", "python3", "pkgconf", "gettext-tiny", "gtk4", "pango", "gdk-pixbuf", "cairo", "graphene", "glib", "harfbuzz", "fribidi", "fontconfig", "freetype", "pixman", "libpng", "expat", "libxml2", "libjpeg-turbo", "libtiff", "libepoxy", "wayland", "wayland-protocols", "libxkbcommon", "libdrm", "pcre2", "libffi", "zlib", "mesa"]
diff --git a/recipes/hammer-edit.toml b/recipes/hammer-edit.toml
new file mode 100644
index 00000000..175956d1
--- /dev/null
+++ b/recipes/hammer-edit.toml
@@ -0,0 +1,138 @@
+# hammer-edit — editor de código REAL para el distro: Adwaita + GtkSourceView, abrir/guardar/guardar-como
+# (GtkFileDialog), resaltado por extensión, números de línea, apertura de archivos desde la CLI. Link 100%
+# estático (gtk4+libadwaita+gtksourceview). No es una demo: es una app instalable y usable.
+name    = "hammer-edit"
+version = "1.0.0"
+
+[source]
+tarball = "https://download.gnome.org/sources/gtksourceview/5.16/gtksourceview-5.16.0.tar.xz"
+sha256  = "ab35d420102f3e8b055dd3b8642d3a48209f888189e6254d0ffb4b6a7e8c3566"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "static"
+
+[build.phases]
+configure = "true"
+compile = '''
+cat > hammer_edit.c <<'CEOF'
+#include <adwaita.h>
+#include <gtksourceview/gtksource.h>
+#include <string.h>
+
+typedef struct { GtkWindow *win; GtkSourceBuffer *buf; GFile *file; } App;
+
+static void set_title(App *a) {
+  char *name = a->file ? g_file_get_basename(a->file) : g_strdup("Sin título");
+  char *full = g_strdup_printf("%s — hammer-edit", name);
+  gtk_window_set_title(a->win, full);
+  g_free(name); g_free(full);
+}
+
+static void load_file(App *a, GFile *file) {
+  char *contents; gsize len;
+  if (!g_file_load_contents(file, NULL, &contents, &len, NULL, NULL)) return;
+  gtk_text_buffer_set_text(GTK_TEXT_BUFFER(a->buf), contents, len);
+  g_free(contents);
+  g_set_object(&a->file, file);
+  GtkSourceLanguageManager *lm = gtk_source_language_manager_get_default();
+  char *base = g_file_get_basename(file);
+  GtkSourceLanguage *lang = gtk_source_language_manager_guess_language(lm, base, NULL);
+  gtk_source_buffer_set_language(a->buf, lang);
+  g_free(base);
+  set_title(a);
+}
+
+static void open_cb(GObject *src, GAsyncResult *res, gpointer ud) {
+  App *a = ud;
+  GFile *file = gtk_file_dialog_open_finish(GTK_FILE_DIALOG(src), res, NULL);
+  if (file) { load_file(a, file); g_object_unref(file); }
+}
+static void on_open(GtkButton *b, gpointer ud) {
+  App *a = ud;
+  GtkFileDialog *d = gtk_file_dialog_new();
+  gtk_file_dialog_open(d, a->win, NULL, open_cb, a);
+  g_object_unref(d);
+}
+
+static void save_to(App *a, GFile *file) {
+  GtkTextIter s, e;
+  gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(a->buf), &s, &e);
+  char *text = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(a->buf), &s, &e, FALSE);
+  g_file_replace_contents(file, text, strlen(text), NULL, FALSE,
+                          G_FILE_CREATE_NONE, NULL, NULL, NULL);
+  g_free(text);
+  g_set_object(&a->file, file);
+  set_title(a);
+}
+static void save_cb(GObject *src, GAsyncResult *res, gpointer ud) {
+  App *a = ud;
+  GFile *file = gtk_file_dialog_save_finish(GTK_FILE_DIALOG(src), res, NULL);
+  if (file) { save_to(a, file); g_object_unref(file); }
+}
+static void on_save(GtkButton *b, gpointer ud) {
+  App *a = ud;
+  if (a->file) { save_to(a, a->file); return; }
+  GtkFileDialog *d = gtk_file_dialog_new();
+  gtk_file_dialog_save(d, a->win, NULL, save_cb, a);
+  g_object_unref(d);
+}
+
+static App *build_window(GtkApplication *app) {
+  App *a = g_new0(App, 1);
+  GtkWidget *win = adw_application_window_new(app);
+  a->win = GTK_WINDOW(win);
+  gtk_window_set_default_size(a->win, 820, 580);
+  GtkWidget *tv = adw_toolbar_view_new();
+  GtkWidget *hb = adw_header_bar_new();
+  GtkWidget *ob = gtk_button_new_from_icon_name("document-open-symbolic");
+  GtkWidget *sb = gtk_button_new_from_icon_name("document-save-symbolic");
+  gtk_widget_set_tooltip_text(ob, "Abrir");
+  gtk_widget_set_tooltip_text(sb, "Guardar");
+  g_signal_connect(ob, "clicked", G_CALLBACK(on_open), a);
+  g_signal_connect(sb, "clicked", G_CALLBACK(on_save), a);
+  adw_header_bar_pack_start(ADW_HEADER_BAR(hb), ob);
+  adw_header_bar_pack_end(ADW_HEADER_BAR(hb), sb);
+  adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(tv), hb);
+  a->buf = gtk_source_buffer_new(NULL);
+  gtk_source_buffer_set_highlight_syntax(a->buf, TRUE);
+  GtkWidget *view = gtk_source_view_new_with_buffer(a->buf);
+  gtk_source_view_set_show_line_numbers(GTK_SOURCE_VIEW(view), TRUE);
+  gtk_source_view_set_highlight_current_line(GTK_SOURCE_VIEW(view), TRUE);
+  gtk_source_view_set_auto_indent(GTK_SOURCE_VIEW(view), TRUE);
+  gtk_widget_add_css_class(view, "monospace");
+  GtkWidget *sc = gtk_scrolled_window_new();
+  gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sc), view);
+  adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(tv), sc);
+  adw_application_window_set_content(ADW_APPLICATION_WINDOW(win), tv);
+  set_title(a);
+  return a;
+}
+
+static void activate(GApplication *app, gpointer ud) {
+  App *a = build_window(GTK_APPLICATION(app));
+  gtk_window_present(a->win);
+}
+static void open_files(GApplication *app, GFile **files, gint n, const char *hint, gpointer ud) {
+  App *a = build_window(GTK_APPLICATION(app));
+  if (n > 0) load_file(a, files[0]);
+  gtk_window_present(a->win);
+}
+
+int main(int argc, char **argv) {
+  AdwApplication *app = adw_application_new("org.hammer.edit", G_APPLICATION_HANDLES_OPEN);
+  g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
+  g_signal_connect(app, "open", G_CALLBACK(open_files), NULL);
+  int status = g_application_run(G_APPLICATION(app), argc, argv);
+  g_object_unref(app);
+  return status;
+}
+CEOF
+export PKG_CONFIG_PATH=/usr/lib/pkgconfig
+zig cc -mcpu=baseline -static hammer_edit.c -o hammer-edit $(pkg-config --cflags --libs --static gtksourceview-5 libadwaita-1 harfbuzz-subset epoxy xkbcommon wayland-client wayland-egl libtiff-4 libjpeg cairo-script-interpreter)
+'''
+install = "mkdir -p /out/usr/bin && cp hammer-edit /out/usr/bin/hammer-edit"
+
+[deps]
+build = ["pkgconf", "gtksourceview", "libadwaita", "appstream", "libyaml", "curl", "openssl", "libxmlb", "libxml2", "zstd", "gtk4", "pango", "gdk-pixbuf", "cairo", "graphene", "glib", "harfbuzz", "fribidi", "fontconfig", "freetype", "pixman", "libpng", "expat", "libjpeg-turbo", "libtiff", "libepoxy", "wayland", "libxkbcommon", "libdrm", "pcre2", "libffi", "zlib", "mesa"]
diff --git a/recipes/incoming-clib/shared-libmandoc.patch b/recipes/incoming-clib/shared-libmandoc.patch
new file mode 100644
index 00000000..607934c9
--- /dev/null
+++ b/recipes/incoming-clib/shared-libmandoc.patch
@@ -0,0 +1,92 @@
+This patch links libmandoc dynamically instead of statically, this
+causes the package size to be reduced by roughly 50%.
+
+See also: https://inbox.vuxu.org/mandoc-tech/2L1YC2WD8JUE5.3QGU3CQ10EGCD@8pit.net/T/#u
+
+diff --git a/Makefile b/Makefile
+index 48c4741..252e11e 100644
+--- a/Makefile
++++ b/Makefile
+@@ -367,9 +367,13 @@ WWW_INCS	 = eqn.h.html \
+ 		   tbl_int.h.html \
+ 		   tbl_parse.h.html
+ 
++LIBMANDOC	= libmandoc.so
++MANDOCLIB	= -L. -lmandoc
++
+ # === USER CONFIGURATION ===============================================
+ 
+ include Makefile.local
++CFLAGS		+= -fPIC
+ 
+ # === DEPENDENCY HANDLING ==============================================
+ 
+@@ -392,7 +396,7 @@ distclean: clean
+ 	rm -f Makefile.local config.h config.h.old config.log config.log.old
+ 
+ clean:
+-	rm -f libmandoc.a $(LIBMANDOC_OBJS) $(ALL_COBJS)
++	rm -f $(LIBMANDOC) $(LIBMANDOC_OBJS) $(ALL_COBJS)
+ 	rm -f mandoc man $(MAIN_OBJS)
+ 	rm -f man.cgi $(CGI_OBJS)
+ 	rm -f mandocd catman catman.o $(MANDOCD_OBJS)
+@@ -432,11 +436,11 @@ base-install: mandoc demandoc soelim
+ 	$(INSTALL_MAN) makewhatis.8 \
+ 		$(DESTDIR)$(MANDIR)/man8/$(BINM_MAKEWHATIS).8
+ 
+-lib-install: libmandoc.a
++lib-install: $(LIBMANDOC)
+ 	mkdir -p $(DESTDIR)$(LIBDIR)
+ 	mkdir -p $(DESTDIR)$(INCLUDEDIR)
+ 	mkdir -p $(DESTDIR)$(MANDIR)/man3
+-	$(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR)
++	$(INSTALL_LIB) $(LIBMANDOC) $(DESTDIR)$(LIBDIR)
+ 	$(INSTALL_LIB) eqn.h man.h mandoc.h mandoc_aux.h mandoc_parse.h \
+ 		mdoc.h roff.h tbl.h $(DESTDIR)$(INCLUDEDIR)
+ 	$(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \
+@@ -485,7 +489,7 @@ uninstall:
+ 	rm -f $(DESTDIR)$(SBINDIR)/$(BINM_CATMAN)
+ 	rm -f $(DESTDIR)$(MANDIR)/man8/mandocd.8
+ 	rm -f $(DESTDIR)$(MANDIR)/man8/$(BINM_CATMAN).8
+-	rm -f $(DESTDIR)$(LIBDIR)/libmandoc.a
++	rm -f $(DESTDIR)$(LIBDIR)/$(LIBMANDOC)
+ 	rm -f $(DESTDIR)$(MANDIR)/man3/mandoc.3
+ 	rm -f $(DESTDIR)$(MANDIR)/man3/mandoc_escape.3
+ 	rm -f $(DESTDIR)$(MANDIR)/man3/mandoc_malloc.3
+@@ -515,23 +519,26 @@ Makefile.local config.h: configure $(TESTSRCS)
+ libmandoc.a: $(MANDOC_COBJS) $(LIBMANDOC_OBJS)
+ 	$(AR) rs $@ $(MANDOC_COBJS) $(LIBMANDOC_OBJS)
+ 
+-mandoc: $(MAIN_OBJS) libmandoc.a
+-	$(CC) -o $@ $(LDFLAGS) $(MAIN_OBJS) libmandoc.a $(LDADD)
++libmandoc.so: $(MANDOC_COBJS) $(LIBMANDOC_OBJS)
++	$(CC) $(LDFLAGS) -shared -o $@ $(MANDOC_COBJS) $(LIBMANDOC_OBJS) $(LDADD)
++
++mandoc: $(MAIN_OBJS) $(LIBMANDOC)
++	$(CC) -o $@ $(LDFLAGS) $(MAIN_OBJS) $(MANDOCLIB) $(LDADD)
+ 
+ man: mandoc
+ 	$(LN) mandoc man
+ 
+-man.cgi: $(CGI_OBJS) libmandoc.a
+-	$(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) libmandoc.a $(LDADD)
++man.cgi: $(CGI_OBJS) $(LIBMANDOC)
++	$(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) $(MANDOCLIB) $(LDADD)
+ 
+-mandocd: $(MANDOCD_OBJS) libmandoc.a
+-	$(CC) -o $@ $(LDFLAGS) $(MANDOCD_OBJS) libmandoc.a $(LDADD)
++mandocd: $(MANDOCD_OBJS) $(LIBMANDOC)
++	$(CC) -o $@ $(LDFLAGS) $(MANDOCD_OBJS) $(MANDOCLIB) $(LDADD)
+ 
+-catman: catman.o libmandoc.a
+-	$(CC) -o $@ $(LDFLAGS) catman.o libmandoc.a $(LDADD)
++catman: catman.o $(LIBMANDOC)
++	$(CC) -o $@ $(LDFLAGS) catman.o $(MANDOCLIB) $(LDADD)
+ 
+-demandoc: $(DEMANDOC_OBJS) libmandoc.a
+-	$(CC) -o $@ $(LDFLAGS) $(DEMANDOC_OBJS) libmandoc.a $(LDADD)
++demandoc: $(DEMANDOC_OBJS) $(LIBMANDOC)
++	$(CC) -o $@ $(LDFLAGS) $(DEMANDOC_OBJS) $(MANDOCLIB) $(LDADD)
+ 
+ soelim: $(SOELIM_COBJS) soelim.o
+ 	$(CC) -o $@ $(LDFLAGS) $(SOELIM_COBJS) soelim.o
diff --git a/recipes/incoming-clib/tests.patch b/recipes/incoming-clib/tests.patch
new file mode 100644
index 00000000..e83be096
--- /dev/null
+++ b/recipes/incoming-clib/tests.patch
@@ -0,0 +1,12 @@
+These tests only work with read/write access to /dev/tty0 (or similar)
+
+--- a/tests/testsuite.at
++++ b/tests/testsuite.at
+@@ -8,7 +8,6 @@
+ 
+ m4_include([unittest.at])
+ 
+-m4_include([utils.at])
+ m4_include([libcommon.at])
+ m4_include([libkeymap.at])
+ m4_include([libkbdfile.at])
diff --git a/recipes/incoming-clib/valgrind.patch b/recipes/incoming-clib/valgrind.patch
new file mode 100644
index 00000000..3ca04bc4
--- /dev/null
+++ b/recipes/incoming-clib/valgrind.patch
@@ -0,0 +1,11 @@
+Ref https://github.com/wismill/kbd/commit/0f410510f586e659fbdba9cfc3846be343b8dd30
+
+--- a/tests/unittest.at
++++ b/tests/unittest.at
+@@ -5,5 +5,5 @@
+ ]])
+ 
+ m4_define([UNITTEST_MEMCHECK],[
+-AT_CHECK([UNITTEST_RUN_MEMCHECK([$1])],[$2],[$3],[$4],[$5],[$6])
++AT_CHECK([$1],[$2],[$3],[$4],[$5],[$6])
+ ])
diff --git a/recipes/libadwaita.toml b/recipes/libadwaita.toml
new file mode 100644
index 00000000..e00a4a95
--- /dev/null
+++ b/recipes/libadwaita.toml
@@ -0,0 +1,22 @@
+# libadwaita 1.7.6 — los widgets modernos de GNOME sobre GTK4 (Adwaita). meson static.
+# Compila sus estilos SCSS con sassc en build. examples/tests/vapi/introspection/docs off.
+# deps = gtk4 + su cierre .pc completo + sassc.
+name    = "libadwaita"
+version = "1.7.6"
+
+[source]
+tarball = "https://download.gnome.org/sources/libadwaita/1.7/libadwaita-1.7.6.tar.xz"
+sha256  = "5eacc5550f0bdbba6a1568aebf25a3d88f5ee07d6b558becc6fd9487579c9a29"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "static"
+
+[build.phases]
+configure = "PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload --prefer-static -Ddefault_library=static -Dexamples=false -Dtests=false -Dvapi=false -Dintrospection=disabled -Dgtk_doc=false -Dc_args=-Wno-error=date-time"
+compile   = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
+install   = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
+
+[deps]
+build = ["meson", "samurai", "python3", "pkgconf", "sassc", "appstream", "libyaml", "curl", "openssl", "libxmlb", "libxml2", "zstd", "gtk4", "pango", "gdk-pixbuf", "cairo", "graphene", "glib", "harfbuzz", "fribidi", "fontconfig", "freetype", "pixman", "libpng", "expat", "libjpeg-turbo", "libtiff", "libepoxy", "wayland", "wayland-protocols", "libxkbcommon", "libdrm", "pcre2", "libffi", "zlib", "mesa"]
diff --git a/recipes/libarchive.toml b/recipes/libarchive.toml
index b368adee..272e95f4 100644
--- a/recipes/libarchive.toml
+++ b/recipes/libarchive.toml
@@ -25,7 +25,7 @@ target   = "x86_64-linux-musl"
 link     = "static"
 
 [deps]
-build = ["busybox", "make", "zlib"]
+build = ["make", "zlib"]
 
 [build.phases]
 # -fno-sanitize=undefined: mismo motivo que zlib — sin él, zig cc emite llamadas UBSan que el
diff --git a/recipes/libnl.toml b/recipes/libnl.toml
index d3a4e2e6..2f3deef8 100644
--- a/recipes/libnl.toml
+++ b/recipes/libnl.toml
@@ -23,7 +23,7 @@ link     = "static"
 
 [deps]
 # libnl 3.11 regenera sus parsers netlink ⇒ flex (lexer) + bison (parser) + m4 (bison lo invoca).
-build = ["flex", "bison", "m4", "busybox", "make"]
+build = ["flex", "bison", "m4", "make"]
 
 [build.phases]
 configure = "./configure --build=$CBUILD --host=$CHOST --prefix=/usr --libdir=/usr/lib --disable-shared --enable-static --disable-cli"
diff --git a/recipes/libusb.toml b/recipes/libusb.toml
index 746e969d..6732b385 100644
--- a/recipes/libusb.toml
+++ b/recipes/libusb.toml
@@ -38,4 +38,4 @@ make DESTDIR="/out" install
 '''
 
 [deps]
-build = ["linux-headers", "busybox", "make"]
+build = ["linux-headers", "make"]
diff --git a/recipes/linux-generic.toml b/recipes/linux-generic.toml
index 877e889d..ac77c56f 100644
--- a/recipes/linux-generic.toml
+++ b/recipes/linux-generic.toml
@@ -34,7 +34,7 @@ target   = "x86_64-linux-musl"
 link     = "dynamic"
 
 [deps]
-build = ["flex", "bison", "m4", "openssl", "elfutils", "busybox", "make"]
+build = ["flex", "bison", "m4", "openssl", "elfutils", "make"]
 
 [build.phases]
 configure = """
diff --git a/recipes/linux-metal.toml b/recipes/linux-metal.toml
index 1dfedda0..1ea90eaf 100644
--- a/recipes/linux-metal.toml
+++ b/recipes/linux-metal.toml
@@ -72,7 +72,7 @@ target   = "x86_64-linux-musl"
 link     = "dynamic"
 
 [deps]
-build = ["flex", "bison", "m4", "openssl", "elfutils", "busybox", "make"]
+build = ["flex", "bison", "m4", "openssl", "elfutils", "make"]
 
 [build.phases]
 configure = """
diff --git a/recipes/linux.toml b/recipes/linux.toml
index 694878a5..0216ce29 100644
--- a/recipes/linux.toml
+++ b/recipes/linux.toml
@@ -36,7 +36,7 @@
 #     integrity/dns_resolver, no apagable sin desarmar media config) ⇒ su host-tool certs/extract-cert
 #     #incluye openssl. Por eso libelf + openssl se proveen como BOOTSTRAP-LIBS apk en bootstrap-devfs.sh
 #     (status g++/zlib-dev; SEGUROS para el of_tree: hammerd no usa openssl, arje-zero va preseeded).
-#     deps.build=[flex,bison,m4] son hammer-built; libelf/openssl quedan de-Alpinizables luego con
+#     deps.build = [] son hammer-built; libelf/openssl quedan de-Alpinizables luego con
 #     recipes/{elfutils,openssl}.toml.
 #   - [DEUDA kikin, 2026-07-16] IO_URING + BPF_SYSCALL explícitos (contrato PLAN-KIKIN §4.bis) van
 #     en linux-metal/linux-generic; ACÁ NO todavía: este of_tree es LOAD-BEARING del selfhost-verify
diff --git a/recipes/mtools.toml b/recipes/mtools.toml
index 6660e0d9..55a78516 100644
--- a/recipes/mtools.toml
+++ b/recipes/mtools.toml
@@ -26,9 +26,6 @@ target      = "x86_64-linux-musl"
 link        = "static"
 zig_version = "0.13.0"
 
-[deps]
-build = ["busybox"]
-
 [build.phases]
 configure = "./configure --prefix=/usr --without-x CC='zig cc -mcpu=baseline -target x86_64-linux-musl' LDFLAGS=-static"
 compile   = "make -j\"$(nproc)\""
diff --git a/recipes/npth.toml b/recipes/npth.toml
index 5eaa2da1..8f2305cc 100644
--- a/recipes/npth.toml
+++ b/recipes/npth.toml
@@ -17,7 +17,7 @@ link     = "static"
 flags    = []
 
 [deps]
-build = ["busybox", "make"]
+build = ["make"]
 
 [build.phases]
 configure = '''
diff --git a/recipes/pango.toml b/recipes/pango.toml
new file mode 100644
index 00000000..2fab4f94
--- /dev/null
+++ b/recipes/pango.toml
@@ -0,0 +1,16 @@
+# pango 1.57.1 — layout/render de texto i18n (base de GTK). meson static.
+name    = "pango"
+version = "1.57.1"
+[source]
+tarball = "https://download.gnome.org/sources/pango/1.57/pango-1.57.1.tar.xz"
+sha256  = "e65d6d117080dc3aeeb7d8b4b3b518f7383aa2e6cfce23117c623cd624764c2f"
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "static"
+[build.phases]
+configure = "PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload --prefer-static -Ddefault_library=static -Dc_args=-Wno-error=date-time -Dintrospection=disabled -Dgtk_doc=false -Dbuild-testsuite=false -Dbuild-examples=false"
+compile   = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
+install   = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
+[deps]
+build = ["meson", "samurai", "python3", "pkgconf", "cairo", "harfbuzz", "fribidi", "glib", "freetype", "fontconfig", "pixman", "libpng", "expat", "libffi", "pcre2", "zlib"]
diff --git a/recipes/parted.toml b/recipes/parted.toml
index 16a62427..bf24bf1d 100644
--- a/recipes/parted.toml
+++ b/recipes/parted.toml
@@ -52,4 +52,4 @@ make DESTDIR="/out" install
 # lvm2 (device-mapper) ausente y opcional → --disable-device-mapper. libuuid real vía util-linux
 # (dep de build); pkgconf resuelve uuid.pc. bash/ncurses/readline innecesarios al binario estático.
 [deps]
-build = ["util-linux", "linux-headers", "pkgconf", "busybox", "make"]
+build = ["util-linux", "linux-headers", "pkgconf", "make"]
diff --git a/recipes/python3.toml b/recipes/python3.toml
index d34e3e20..5b53daf7 100644
--- a/recipes/python3.toml
+++ b/recipes/python3.toml
@@ -36,7 +36,7 @@ link        = "dynamic"
 zig_version = "0.13.0"
 
 [deps]
-build = ["zlib", "busybox", "pkgconf"]
+build = ["zlib", "pkgconf"]
 
 [build.phases]
 configure = "./configure --prefix=/usr --without-ensurepip --disable-test-modules --with-ensurepip=no CFLAGS=\"-Wno-error=date-time\""
diff --git a/recipes/readline.toml b/recipes/readline.toml
index 1b895652..f23f6709 100644
--- a/recipes/readline.toml
+++ b/recipes/readline.toml
@@ -13,4 +13,4 @@ configure = "./configure --prefix=/usr --disable-shared --enable-static --with-c
 compile   = "make"
 install   = "make install DESTDIR=/out"
 [deps]
-build = ["ncurses", "busybox", "make"]
+build = ["ncurses", "make"]
diff --git a/recipes/rsync.toml b/recipes/rsync.toml
index ed94ab11..cf989e34 100644
--- a/recipes/rsync.toml
+++ b/recipes/rsync.toml
@@ -54,4 +54,4 @@ make DESTDIR="/out" install
 # depends de runtime de Alpine (NO build-deps): python3
 
 [deps]
-build = ["zlib", "linux-headers", "busybox"]
+build = ["zlib", "linux-headers"]
diff --git a/recipes/sed.toml b/recipes/sed.toml
index d71bbb5c..72721e89 100644
--- a/recipes/sed.toml
+++ b/recipes/sed.toml
@@ -47,4 +47,4 @@ _abuild_phase
 
 # perl era build-dep de Alpine sólo para tests/docs; el tarball trae configure + sed.1 pregenerado.
 [deps]
-build = ["linux-headers", "busybox", "make"]
+build = ["linux-headers", "make"]
diff --git a/recipes/shadow.toml b/recipes/shadow.toml
index c49a5272..d4818b80 100644
--- a/recipes/shadow.toml
+++ b/recipes/shadow.toml
@@ -74,4 +74,4 @@ install -m644 /dev/null etc/subgid
 # deps de Alpine remapeadas al catálogo canónico. AUSENTES quitadas:
 # linux-pam, libbsd, setcap. Sin fcaps (setcap falla en el sandbox) ⇒ sin libcap.
 [deps]
-build = ["linux-headers", "busybox", "make"]
+build = ["linux-headers", "make"]
diff --git a/recipes/sourceview-hello.toml b/recipes/sourceview-hello.toml
new file mode 100644
index 00000000..c7426972
--- /dev/null
+++ b/recipes/sourceview-hello.toml
@@ -0,0 +1,57 @@
+# sourceview-hello — VALIDACIÓN del editor: ventana Adwaita con un GtkSourceView (resaltado C, números
+# de línea) editable. Junta libadwaita + gtksourceview + gtk4, link 100% estático. Es, de hecho, el
+# esqueleto de un editor de código real para el distro.
+name    = "sourceview-hello"
+version = "5.16.0"
+
+[source]
+tarball = "https://download.gnome.org/sources/gtksourceview/5.16/gtksourceview-5.16.0.tar.xz"
+sha256  = "ab35d420102f3e8b055dd3b8642d3a48209f888189e6254d0ffb4b6a7e8c3566"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "static"
+
+[build.phases]
+configure = "true"
+compile = '''
+cat > sv_hello.c <<'CEOF'
+#include <adwaita.h>
+#include <gtksourceview/gtksource.h>
+static void activate(GtkApplication *app, gpointer user_data) {
+  GtkWidget *win = adw_application_window_new(app);
+  gtk_window_set_title(GTK_WINDOW(win), "Editor hammer");
+  gtk_window_set_default_size(GTK_WINDOW(win), 640, 420);
+  GtkWidget *toolbar = adw_toolbar_view_new();
+  adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(toolbar), adw_header_bar_new());
+  GtkSourceBuffer *buf = gtk_source_buffer_new(NULL);
+  GtkSourceLanguageManager *lm = gtk_source_language_manager_get_default();
+  GtkSourceLanguage *lang = gtk_source_language_manager_get_language(lm, "c");
+  if (lang) gtk_source_buffer_set_language(buf, lang);
+  gtk_text_buffer_set_text(GTK_TEXT_BUFFER(buf),
+    "#include <stdio.h>\nint main(void){\n  printf(\"hola hammer\\n\");\n  return 0;\n}\n", -1);
+  GtkWidget *view = gtk_source_view_new_with_buffer(buf);
+  gtk_source_view_set_show_line_numbers(GTK_SOURCE_VIEW(view), TRUE);
+  gtk_widget_add_css_class(view, "monospace");
+  GtkWidget *scroll = gtk_scrolled_window_new();
+  gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), view);
+  adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(toolbar), scroll);
+  adw_application_window_set_content(ADW_APPLICATION_WINDOW(win), toolbar);
+  gtk_window_present(GTK_WINDOW(win));
+}
+int main(int argc, char **argv) {
+  AdwApplication *app = adw_application_new("org.hammer.editor", G_APPLICATION_DEFAULT_FLAGS);
+  g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
+  int status = g_application_run(G_APPLICATION(app), argc, argv);
+  g_object_unref(app);
+  return status;
+}
+CEOF
+export PKG_CONFIG_PATH=/usr/lib/pkgconfig
+zig cc -mcpu=baseline -static sv_hello.c -o sourceview-hello $(pkg-config --cflags --libs --static gtksourceview-5 libadwaita-1 harfbuzz-subset epoxy xkbcommon wayland-client wayland-egl libtiff-4 libjpeg cairo-script-interpreter)
+'''
+install = "mkdir -p /out/usr/bin && cp sourceview-hello /out/usr/bin/sourceview-hello"
+
+[deps]
+build = ["pkgconf", "gtksourceview", "libadwaita", "appstream", "libyaml", "curl", "openssl", "libxmlb", "libxml2", "zstd", "gtk4", "pango", "gdk-pixbuf", "cairo", "graphene", "glib", "harfbuzz", "fribidi", "fontconfig", "freetype", "pixman", "libpng", "expat", "libjpeg-turbo", "libtiff", "libepoxy", "wayland", "libxkbcommon", "libdrm", "pcre2", "libffi", "zlib", "mesa"]
diff --git a/recipes/sqlite.toml b/recipes/sqlite.toml
index 7bf41ae4..777bef07 100644
--- a/recipes/sqlite.toml
+++ b/recipes/sqlite.toml
@@ -9,7 +9,7 @@ compiler = "zig-cc"
 target   = "x86_64-linux-musl"
 link     = "static"
 [deps]
-build = ["busybox", "make"]
+build = ["make"]
 
 [build.phases]
 configure = "./configure --prefix=/usr --disable-shared --enable-static"
diff --git a/recipes/tar.toml b/recipes/tar.toml
index ede1baf2..b64c788e 100644
--- a/recipes/tar.toml
+++ b/recipes/tar.toml
@@ -18,7 +18,7 @@ link     = "static"
 flags    = []
 
 [deps]
-build = ["busybox", "make"]
+build = ["make"]
 
 [build.phases]
 # de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):
diff --git a/recipes/util-linux.toml b/recipes/util-linux.toml
index dcc866a0..babc2e78 100644
--- a/recipes/util-linux.toml
+++ b/recipes/util-linux.toml
@@ -73,4 +73,4 @@ make DESTDIR="/out" install
 # deps de Alpine/nix remapeadas al catálogo canónico. AUSENTES quitadas:
 # autoconf/automake/po4a/libxcrypt/sqlite/linux-pam/libcap-ng/systemd-minimal-libs.
 [deps]
-build = ["linux-headers", "busybox", "make"]
+build = ["linux-headers", "make"]
diff --git a/recipes/which.toml b/recipes/which.toml
index a11cbb5a..3110d2d5 100644
--- a/recipes/which.toml
+++ b/recipes/which.toml
@@ -18,7 +18,7 @@ link     = "static"
 flags    = []
 
 [deps]
-build = ["busybox", "make"]
+build = ["make"]
 
 [build.phases]
 # de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):
diff --git a/recipes/wpa_supplicant.toml b/recipes/wpa_supplicant.toml
index 54307c39..1eaa07f5 100644
--- a/recipes/wpa_supplicant.toml
+++ b/recipes/wpa_supplicant.toml
@@ -23,7 +23,7 @@ target   = "x86_64-linux-musl"
 link     = "static"
 
 [deps]
-build = ["libnl", "busybox", "make"]
+build = ["libnl", "make"]
 
 [build.phases]
 configure = '''
diff --git a/recipes/xorriso.toml b/recipes/xorriso.toml
index c559a94a..5a15d582 100644
--- a/recipes/xorriso.toml
+++ b/recipes/xorriso.toml
@@ -43,7 +43,7 @@ link        = "static"
 zig_version = "0.13.0"
 
 [deps]
-build = ["busybox", "make"]
+build = ["make"]
 
 [build.phases]
 configure = "./configure --prefix=/usr --disable-libreadline --disable-libedit --disable-libacl --disable-xattr --disable-zlib --disable-libbz2 --disable-libcdio CC='zig cc -mcpu=baseline -target x86_64-linux-musl' LDFLAGS=-static"
diff --git a/recipes/zlib.toml b/recipes/zlib.toml
index 126e5520..cc9cfd5a 100644
--- a/recipes/zlib.toml
+++ b/recipes/zlib.toml
@@ -25,7 +25,7 @@ target   = "x86_64-linux-musl"
 link     = "static"
 
 [deps]
-build = ["make"]
+build = ["make", "binutils"]
 
 [build.phases]
 # --static: sólo libz.a (sin .so; mrustc/rustc enlazan estático). --prefix=/usr: zlib.h→/usr/include,
diff --git a/scripts/harkaq/runtime-policy.sh b/scripts/harkaq/runtime-policy.sh
index 7019ac7f..01658ffb 100755
--- a/scripts/harkaq/runtime-policy.sh
+++ b/scripts/harkaq/runtime-policy.sh
@@ -62,6 +62,21 @@ if [ -z "$propios" ]; then
     echo "   ⇒ política Landlock: sólo \`ro $BIN\`. Es el caso de un estático que no abre ficheros."
 else
     echo "$propios" | sed 's/^/   ro /'
+    # CONTACTO con el §3 (clases de servicio, diseño de Fable 5): la medición no sólo lista
+    # paths — propone la CLASE. El path va a Landlock (detalle, userspace); la clase va al bit
+    # del u32 firmado (frontera, Ring 0). La medición ALIMENTA la tabla; la tabla decide el bit.
+    # Ninguno ensancha por su cuenta (D3).
+    clases=""
+    echo "$propios" | grep -qE '/etc/(resolv\.conf|hosts)'    && clases="$clases dns"
+    echo "$propios" | grep -qE '/etc/ssl/certs'                && clases="$clases tls-certs"
+    echo "$propios" | grep -qE '/usr/share/zoneinfo|/etc/TZ'   && clases="$clases tz"
+    echo "$propios" | grep -qE '/dev/log'                      && clases="$clases syslog"
+    if [ -n "$clases" ]; then
+        echo
+        echo "   ── clases de servicio detectadas (§3: van al u32 firmado, NO a Landlock):"
+        for c in $clases; do echo "      $c"; done
+        echo "      ⇒ declarar por nombre en la ConcesionCapacidad; el resto de arriba es Landlock."
+    fi
     echo
-    echo "   ⇒ pegar en la política Landlock del binario instalado."
+    echo "   ⇒ los `ro` van a la política Landlock del binario instalado."
 fi
diff --git a/scripts/juez.sh b/scripts/juez.sh
new file mode 100755
index 00000000..d10f551e
--- /dev/null
+++ b/scripts/juez.sh
@@ -0,0 +1,104 @@
+#!/bin/sh
+# juez.sh <receta> — JUEZ MECÁNICO del bucle agéntico (SDD 17 §10).
+#
+#   agente propone receta → harkaq veredicto → granja reproduce ×2 → catálogo acepta
+#
+# Sin humano en el medio para la parte mecánica: el humano decide QUÉ construir; el juez decide
+# si lo construido MERECE entrar al catálogo, y lo decide con evidencia, no con opinión.
+#
+#   scripts/juez.sh recipes/zlib.toml
+#
+# Dos preguntas, dos veredictos, ninguno negociable:
+#   1. ¿HERMÉTICO?     harkaq (SDD 16): ¿usó algo que no declaró? El kernel responde.
+#                      `denials=[]` no se cree, se GANA (el canario lo demuestra — D9).
+#   2. ¿REPRODUCIBLE?  consenso (SDD 17 §1): N builders independientes, ¿el mismo hash?
+#                      Si sí, el artefacto es confiable SIN FIRMA.
+#
+# Si falla, el juez no dice "no" a secas: dice POR QUÉ y qué hacer.
+#   - Impuro     → harkaq-suggest: "declarar dep: make" (arreglo mecánico)
+#   - Divergente → why-differs: qué fichero, qué causa (codegen/timestamp/build-id)
+#
+# Es el bucle que el SDD 08 §4 pide ("la IA propone, el sistema reproduce, el humano commitea")
+# con la pieza que faltaba: un juez que la IA no puede convencer, sólo satisfacer.
+set -eu
+
+RECETA="${1:?uso: juez.sh <receta.toml>}"
+HUB="$(cd "$(dirname "$0")/.." && pwd)"
+cd "$HUB"
+n=$(basename "$RECETA" .toml)
+BUILDERS="${BUILDERS:-2}"
+
+echo "══════ JUEZ MECÁNICO — $n"
+echo
+
+# ── 1. ¿HERMÉTICO? (harkaq)
+echo "── 1/2 ¿usó algo que no declaró?  [harkaq, SDD 16]"
+if [ ! -x "${HARKAQ_BIN:-$HOME/.cache/harkaq}/harkaq-audit" ]; then
+    echo "   ⊘ harkaq no está compilado ⇒ SIN EVIDENCIA. El juez NO afirma hermeticidad."
+    echo "     (compilar scripts/harkaq/*.c y `setcap cap_audit_read` — ver scripts/harkaq/README.md)"
+    veredicto_h="sin-evidencia"
+else
+    export HARKAQ=1 HARKAQ_BIN="${HARKAQ_BIN:-$HOME/.cache/harkaq}"
+    export HARKAQ_BASE="${HARKAQ_BASE:-$HARKAQ_BIN/base.policy}" HARKAQ_TIMEOUT="${HARKAQ_TIMEOUT:-200}"
+    # Nombre ÚNICO por corrida: con uno fijo, la 2ª vez `hammer build` pega en CACHÉ, no
+    # construye nada, no hay veredictos y el juez dice "sin evidencia" — un falso negativo que
+    # parece un problema de la receta. (Gotcha conocido; me mordió al probar el juez.)
+    uniq="$n-juez-$$"
+    tmp="$(dirname "$RECETA")/.juez-$n.toml"
+    sed -E "s/^(name\s*=\s*)\"$n\"/\1\"$uniq\"/" "$RECETA" > "$tmp"
+    out=$(timeout "${POR:-600}" ./target/debug/hammer build "$tmp" --store "$PWD/store" 2>&1 || true)
+    rm -f "$tmp"; rm -rf store/*-"$uniq" 2>/dev/null || true
+    veredictos=$(echo "$out" | grep '^\[harkaq\] {' | sed 's/^\[harkaq\] //')
+    deuda=""
+    if [ -z "$veredictos" ]; then
+        echo "   ⊘ sin veredicto (¿caché? ¿el build ni arrancó?) ⇒ SIN EVIDENCIA"
+        veredicto_h="sin-evidencia"
+    else
+        veredicto_h="hermetico"
+        i=0
+        echo "$veredictos" | while IFS= read -r v; do :; done
+        printf '%s\n' "$veredictos" > /tmp/.juez-v
+        while IFS= read -r v; do
+            i=$((i + 1)); echo "$v" > /tmp/.juez-1
+            est=$(scripts/harkaq/harkaq-verdict.py /tmp/.juez-1 "$HARKAQ_BASE" --human 2>/dev/null | head -1 | sed 's/^ *estado: //;s/ .*//')
+            echo "      fase $i: ${est:-?}"
+            [ "$est" = "Impuro" ] && { veredicto_h="impuro"; \
+                scripts/harkaq/harkaq-suggest.py /tmp/.juez-1 "$HARKAQ_BASE" "$PWD/store" "$PWD/recipes" "$RECETA" 2>/dev/null | sed 's/^/         /'; }
+            [ "$est" = "SinEvidencia" ] && veredicto_h="sin-evidencia"
+        done < /tmp/.juez-v
+        # el while corre en subshell: recuperar el peor veredicto por marcador
+        grep -q '"estado":"Impuro"' /tmp/.juez-v && veredicto_h="impuro"
+        grep -q '"estado":"SinEvidencia"' /tmp/.juez-v && veredicto_h="sin-evidencia"
+    fi
+fi
+echo
+
+# ── 2. ¿REPRODUCIBLE? (consenso)
+echo "── 2/2 ¿N builders independientes dan el mismo hash?  [consenso, SDD 17 §1]"
+if consenso=$(BUILDERS="$BUILDERS" timeout "${POR_CONSENSO:-1200}" scripts/consenso.sh "$RECETA" "$BUILDERS" 2>&1); then
+    echo "$consenso" | grep -E '✅|builder' | sed 's/^/   /'
+    veredicto_r="consenso"
+else
+    rc=$?
+    echo "$consenso" | grep -E '⚠️|builder|SIN CONSENSO' | sed 's/^/   /'
+    [ "$rc" = 1 ] && veredicto_r="divergencia" || veredicto_r="sin-consenso"
+    if [ "$veredicto_r" = divergencia ]; then
+        echo "   ── why-differs (SDD 17 §2) explicaría la divergencia:"
+        echo "      scripts/why-differs.py <hashA> <hashB> --store ./store"
+    fi
+fi
+echo
+
+# ── VEREDICTO
+echo "══════ VEREDICTO"
+if [ "$veredicto_h" = hermetico ] && [ "$veredicto_r" = consenso ]; then
+    echo "   ✅ ACEPTAR — no usó nada sin declarar Y $BUILDERS builders lo reprodujeron bit a bit."
+    echo "      El catálogo puede confiar en este artefacto sin firma y sin revisión humana del build."
+    exit 0
+fi
+echo "   ❌ NO ACEPTAR"
+[ "$veredicto_h" = impuro ]        && echo "      · hermeticidad: usa algo sin declarar (ver la sugerencia arriba: es una línea)"
+[ "$veredicto_h" = sin-evidencia ] && echo "      · hermeticidad: SIN EVIDENCIA — no se afirma nada (D9: un lector ciego y un build limpio son idénticos)"
+[ "$veredicto_r" = divergencia ]   && echo "      · reproducibilidad: los builders NO coinciden ⇒ hay un canal impuro"
+[ "$veredicto_r" = sin-consenso ]  && echo "      · reproducibilidad: no hubo suficientes builders con hash"
+exit 1