base 51/51 · cli 74/74 · escritorio-sway 121/121. Cosecha verificada: cero artefactos en el
worker que el hub no tenga.
De la tanda: 25 de 30 selladas. Los 5 fallos, ninguno causado por el split:
· cargo-audit, cargo-hack, git-absorb — 'spawn cargo vendor': el grafo las clasifica como clase
`c` porque declaran compiler=gcc para sus deps de C, pero por dentro son Cargo. Filtrar por la
clase del grafo NO basta.
· hammerd — git privado por SSH (HUB-ONLY, como las de tawasuyu).
· coreutils — 'you should not run configure as root'. Esto NO lo causó el split: es DERIVA. La
receta llevaba tiempo sin poder construirse en el lab actual y nadie lo sabía porque su
artefacto viejo seguía en el store. Es exactamente lo que la campaña destapa.
⚠ Y de ahí sale un riesgo que conviene nombrar: cada receta que deja de reconstruir convierte su
artefacto viejo en un REHÉN — store-gc no puede podarlo (es el único ejemplar) y nadie puede
regenerarlo. Hoy son ~12 G inmovilizados, y crecen con cada receta que se rompe en silencio.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`base`, `cli` y `escritorio-sway` bajaron a 50/51, 73/74 y 120/121 después de la cascada del
split, y los tres fallaban por LA MISMA receta: dbus.
EL ERROR NO MENCIONABA LA RED POR NINGÚN LADO:
meson.build:372:11: ERROR: Unhandled python exception
Y arriba, enterrado entre reintentos:
<urlopen error unknown url type: https>
WARNING: failed to download with error: name 'ssl' is not defined
dbus declara subproyectos con `.wrap` y meson intenta DESCARGARLOS. En el sandbox no hay red y
python no trae ssl ⇒ «Unhandled python exception», que se lee como un bug de meson y es
simplemente que no hay salida a internet. Y no debe haberla: el build es hermético a propósito.
`--wrap-mode=nodownload` obliga a usar las deps del sistema (nuestros artefactos, vía
pkg-config) y deja los wraps inertes. Mismo caso que `wl-clipboard` anoche.
⇒ base 51/51 · cli 74/74 · escritorio-sway 121/121. Los tres cierran otra vez.
ESTADO DE LA REPARACIÓN DE LA CASCADA: de las 54 que quedaron sin artefacto, 42 reconstruidas.
Las 12 restantes son EXACTAMENTE las que ya estaban en deuda antes de la campaña:
· 6 el muro del PIC (gtk4 y su cadena estática — duplicado superado de la dinámica de GNOME);
· 3 HUB-ONLY (mirada-*, llimphi-counter: git privado / commit en ceros);
· dwarves (libdw/musl), y adwaita-hello (error 39 = la carrera del ADR 0012).
O sea que la campaña no dejó deuda nueva.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Declarado en targets.toml y verificado con el grafo: **121 nodos, 121 sellados, falta 0**. Es
una imagen construible hoy, no una intención.
Nueve raíces (sway, yambar, fuzzel, swaybg, swaylock, swayidle, grim, slurp, wl-clipboard) más
`hereda = ["cli"]`, porque un WM sin userland debajo no se usa: hacen falta la terminal y las
herramientas. `foot` no se lista porque ya entra por la clausura de `cli`. El resto de la
imagen —wlroots, mesa, wayland, libinput, seatd, cairo, pango, fcft…— lo calcula el grafo
siguiendo las aristas: escribir la clausura a mano es justo lo que targets.toml existe para
evitar.
LA COMPARACIÓN QUE VALE: KDE y GNOME fueron campañas de semanas porque debajo tienen una torre
de C (Qt entero, GTK, la cascada de mesa). Esto es una decena de binarios pequeños sobre
wlroots y salió en una noche. Ya estaba escrito en el SDD 20 como hipótesis —«los WMs ligeros
son la mejor relación esfuerzo/resultado que queda»—; ahora está medido.
`--wlr` en build-state.py, con su flag propio por la misma razón que COSMIC: sin él el frente
es INVISIBLE para el khipu, y `yupana radio` sobre una receta compartida (wayland, libinput,
pixman, mesa, libxkbcommon…) no reportaría la imagen sway entre las afectadas — o sea que el
próximo que toque una de ésas mediría de menos y creería que no rompe nada.
Queda lo que no puede decidir el grafo: probarlo en QEMU CON PANTALLA. La regla ya pagada cara
es que las imágenes de escritorio no se validan con `-nographic`, porque el compositor puede
«arrancar» en los logs y no pintar nada.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
b3:b8f3baf0, selló a la primera. Arranca desde cosmic-start ("wireplumber OK (pid
192) — hay gestor de sesión"), se conecta al grafo (dos clientes en wpctl status) y
wpctl pasa a mostrar una sección Video que antes no existía.
Y el Start de ScreenCast SIGUE sin Response a los 60s. Mismo resultado exacto.
LA HIPÓTESIS QUEDA MATADA POR MEDICIÓN. "Falta el gestor de sesión que mueva el nodo
de Paused a Streaming" era mía y era razonable; no era cierta. Queda escrita junto a
su refutación porque una hipótesis descartada CON EVIDENCIA vale más que una lista de
sospechosos: acota el próximo paso a lo que queda, que es el backend mismo.
El dato nuevo, que es por dónde seguir: con wireplumber corriendo, `wpctl status`
lista `Video → Streams` VACÍO durante el handshake. O sea que el nodo
`cosmic-screencast` que SÍ existe en `pw-cli ls Node` no llega a wireplumber como
stream gestionado. Próximo movimiento: RUST_LOG=trace sobre screencast_thread, no
otra dep.
── por qué receta propia y no la de GNOME ──────────────────────────────────────
La de incoming-gnome funciona pero NEEDea libglib/libgobject/libpipewire de la ISLA
DINÁMICA de GNOME: traerla metería una segunda glib y una segunda pipewire en la
imagen. De 19 deps, 14 dan hash idéntico; las que divergen divergen a propósito —
sobre todo `pipewire`, que acá apunta a la de COSMIC (338d1d8c), la que el escritorio
realmente ARRANCA. Un gestor de sesión contra otra pipewire que la que corre no
gestiona nada.
El cambio de fondo es glib → glib-shared. COSMIC usa la glib ESTÁTICA del corpus, que
le alcanza al portal porque es un ejecutable. Acá no: wireplumber produce un .so y 17
módulos, y libglib-2.0.a tiene 44.275 reubicaciones R_X86_64_32/32S ⇒ no es PIC. La
regla del frente GNOME (readelf -r ANTES de gastar el build) ahorró uno.
Y la salida no fue una campaña nueva sino una MEDICIÓN: incoming-kde/glib-shared
copiada a esta cola resuelve al MISMO hash (0584ce1f) y ya estaba sellada ⇒ cero
rebuild. Idem pcre2-shared, lua y libelogind. Las dos glib coexisten sin pisarse (.a
y .so son ficheros distintos) y el portal conserva sus 3 NEEDED.
escritorio-cosmic: 84 → 89 recetas, 0 faltantes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
La receta de la sonda (b3:af49d32d) y lo que midió. Es la única receta de la campaña
cuyo producto no es una pieza del escritorio sino un instrumento para medirlo: entra
a la imagen porque un handshake de portal sólo se puede ejercer DESDE la sesión, con
bus y compositor vivos, y sale ESTÁTICA (0 NEEDED) porque un instrumento no debe
depender de aquello que mide.
[1/4] CreateSession → Response 0, session_handle ✓
[2/4] SelectSources → Response 0 ✓
[3/4] Start → el backend ABRE "Share your screen", con
miniatura EN VIVO del framebuffer y el output
Virtual-1; se elige, se pulsa Share…
y NO llega Response en 60s ✗
El log del backend da la línea exacta:
screencast_thread: state-changed 'Connecting' -> 'Paused'
Y `pw-cli ls Node` durante la espera da el veredicto INDEPENDIENTE:
node.name = "cosmic-screencast" media.class = "Video/Source"
EL NODO DE VIDEO EXISTE EN EL GRAFO DE PIPEWIRE. La cadena entera —cliente →
frontend → backend → compositor → demonio— funciona hasta crear y negociar el stream.
Lo único que no ocurre es el Response de vuelta tras quedar en `Paused`. Eso es un
lugar muy distinto del de esta mañana ("no hay demonio con quien negociar").
Sospecha para el próximo paso, y es HIPÓTESIS no medición: falta `wireplumber`. Sin
gestor de sesión nadie mueve el nodo de Paused a Streaming y el backend parece
esperarlo. Construirlo la confirma o la mata.
Gotchas que costaron corridas y quedan escritos:
· matar el backend se lleva puesto al frontend (ambos pierden dueño del bus);
· el lanzador busca por NOMBRE VISIBLE: `cosmic-term` no matchea, `Terminal` sí —
escribir el nombre del binario abre otra app;
· `| head -N` bufferiza y deja la terminal en blanco: parece colgada y está esperando;
· pkg-config OMITE los -L de dirs "estándar" y zig cc cross NO los busca ⇒
`-ldbus-1` pelado da "unable to find static system library", que suena a librería
faltante cuando lo que falta es la ruta.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
69 min. NEEDED: libgbm, libpipewire, libxkbcommon, libc. Instala el binario
en /usr/libexec, el .service de D-Bus con @libexecdir@ sustituido, el
cosmic.portal que declara las cinco interfaces
(Access/FileChooser/Screenshot/Settings/ScreenCast) y sus iconos.
clang18 se construyó en la granja y se cosechó al laptop (b3:62c6bfb5), pero
el backend NO se pudo construir allá: el worker no tiene la cola COSMIC
horneada —el snapshot golden es del 2026-07-15 y toda esta cola es
posterior— así que intentó reconstruir pipewire y murió buscando glib. Es la
regla de «rootfs laptop ≠ worker» pero con el STORE: lo que en el laptop es
cache-hit, en el worker es un build entero con sus propias deps.
Y destapó que la receta de pipewire NO lleva --wrap-mode=nodownload: ante
una dep faltante intenta bajarse un subproyecto de internet y, sin red, el
error que sale no es «te falta glib» sino «Unhandled python exception / This
is a Meson bug». Queda anotado como deuda.
--offline SIN --locked, y no es descuido: el sed del parche corre en la fase
compile, o sea DESPUÉS del cargo vendor, así que cargo ve el Cargo.toml
cambiado y con --locked se niega. Quitar una feature sólo puede ENCOGER el
conjunto de crates, así que lo que haga falta ya está vendorizado; la
hermeticidad la da --offline + el árbol vendorizado, no el --locked.
Dos raíces en el perfil y en la hidratación, porque son DOS procesos que se
encuentran por D-Bus en runtime y ningún [deps] los relaciona. Imagen en 83
recetas (eran 74).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>