libva sube al corpus y la copia de incoming-kde se JUBILA (git mv, no copia: dos
ficheros para un artefacto es el cuadro de las dos glib esperando a derivar). La
mudanza fue gratis y medida antes: las cinco deps de libva viven sólo en el
corpus, así que incoming-kde ya las resolvía por caída al padre y hammer hash dio
el MISMO ArtifactHash en las dos rutas (b3:405c6211).
libva pasa a -Dwith_wayland=yes, que eso SÍ cambia el hash. La razón está en
mpv/meson.build:1464: el feature `vaapi` se requiere contra
`vaapi-drm or vaapi-wayland or vaapi-x11 or vaapi-win32` ⇒ -Dvaapi=enabled a
secas no habilita NADA. De los cuatro backends, x11/win32 están fuera por
Wayland-only y vaapi-drm exige features[drm] de mpv, apagado porque vo=drm pide
libdisplay-info. Queda vaapi-wayland, que pide libva-wayland.pc.
Evidencia, no sólo sello: meson lista «vaapi vaapi-wayland» entre los features
habilitados, y el binario sellado trae NEEDED libva.so.2 + libva-wayland.so.2.
Radio medido antes de tocar: 2 dependientes (kpipewire, spectacle), los dos
reconstruidos. Las 7 imágenes siguen en 0 en deuda.
⚠ El driver es RUNTIME (intel-media-driver / gallium VA por dlopen): que esto
selle y que --hwdec=vaapi funcione en una máquina son cosas distintas.
La receta llevaba --disable-x86asm heredado de cuando ffmpeg entró SÓLO para
kpipewire (codificar un stream de escritorio, donde da igual). Para el
reproductor era decodificar sin SIMD.
Dos recetas —ffmpeg.toml y mpv.toml— prohibían tocarlo con la misma razón: un
hash distinto dejaría DOS ffmpeg peleando por las mismas rutas en una imagen KDE,
y el arreglo correcto sería «promover una sola y jubilar la de la cola». Eso ya
había pasado: incoming-kde/ffmpeg.toml no existe y hay UNA sola receta ffmpeg en
todo el disco. La prohibición sobrevivió a la condición que la justificaba.
--x86asmexe=nasm explícito y nasm (2.16.03) a [deps].build: sin ensamblador
declarado configure apagaría x86asm en SILENCIO, sellando un artefacto con otro
hash y sin la SIMD que dice traer.
Evidencia, no sólo sello: configure imprime «x86 assembler nasm», compila los
objetos X86ASM, y libavcodec.so pasa de 12.685.744 a 14.454.288 bytes (+1,77 MB).
Radio medido antes de tocar (yupana radio ffmpeg): 4 dependientes, ninguno
transitivo de más — mpv, wf-recorder, kpipewire, spectacle. Los 4 reconstruidos y
sellados; las 7 imágenes siguen en 0 en deuda.
targets.toml declara 7 perfiles; drenaje.json listaba 5. escritorio-cosmic (cola
incoming-cosmic) y escritorio-sway (cola incoming-wlr) declaraban una cola que
ningún grafo de GRAFOS contenía, así que cargar() devolvía None y --todos hacía
`continue` pelado. Dos imágenes enteras fuera del artefacto sin dejar rastro, y
los dos números —5 medidos, 7 declarados— no se cruzaban en ningún lado.
Mismo olvido que ya costó 17 días de build-state-wlr.json congelado: la lista de
grafos crece a mano y se queda atrás cuando se abre una cola.
Tres cambios:
- GRAFOS suma los grafos de cosmic y wlr.
- Un perfil sin medir se anota en el artefacto (`sin_medir`), se grita por stdout
y drenar.py sale 1. Regla 3 del repo: un ausente falla ruidosamente.
- cosecha-cron deja de tragarse la salida; filtra las líneas ⚠ al log, que si no
llegaban como un "falló" mudo que no dice cuál imagen falta.
Medido: las 2 imágenes que nadie miraba estaban limpias, 0 en deuda. Ahora son
7/7 verificadas en vez de 5 verificadas y 2 supuestas.
dolphin filelight kate kinfocenter konsole kscreen plasma-integration
plasma-desktop. Ninguna era fallo de receta: las 8 murieron el 2026-09-03 con
«No space left on device» y el bucle las anotó ✗ igual que a una que no compila.
Reintentadas tal cual, sin tocar una sola receta, sellaron las 8 a la primera.
escritorio-kde pasa a 263/263 y drenaje.json queda en 0 en deuda en los cinco
perfiles: base, cli, escritorio-{gnome,kde,mirada}.
`vigia-imagen.py` daba ✗ en cursores en DOS de los cuatro escritorios. No es cosmético: con el
cursor por software —obligatorio en virtio-gpu y en todo render por CPU— el compositor dibuja la
imagen que le da el TEMA, y sin tema el ratón se mueve invisible. cosmic llegó a 43/43 y sway a
173/173 así, porque un tema de cursor no es dep de build de nadie: sólo entra si se DECLARA.
`adwaita-cursors` (corpus, 48.1, data-only): del mismo tarball que `adwaita-icon-theme` pero SÓLO
`Adwaita/cursors/` — 39 ficheros y 14 MB, sin un icono. Promover el tema entero habría regalado a
sway y a cosmic los iconos de GNOME, que está anotado como decisión pendiente y no como olvido.
Las dos cosas que el tarball no trae y la receta fabrica:
· los nombres X11 heredados (`left_ptr`, `xterm`, `watch`, `hand2`…) son enlaces que genera el
`meson.build` de upstream. El mapa se PARSEA de ahí, no se copia: copiado envejece en silencio.
Si el origen de un enlace no existe, la fase falla — upstream pone un `files()` como aserción.
· `/usr/share/icons/default/index.theme` con `Inherits=Adwaita`. Sin `XCURSOR_THEME` en el
entorno, libXcursor y wlroots buscan el tema llamado literalmente `default`; sin él no hay
puntero AUNQUE Adwaita esté instalado. Es el eslabón que hace que ande sin configuración.
⚠ no declarar esta receta junto a `adwaita-icon-theme`: chocan en `Adwaita/cursors/*`.
Y el vigía estaba midiendo el invariante de al lado: exigía `index.theme` en el directorio para
contar un tema, que es correcto para ICONOS —la búsqueda XDG recorre `Directories=`— y falso para
CURSORES, porque libXcursor abre `<tema>/cursors/<nombre>` directo y el índice sólo hace falta para
seguir un `Inherits=`. Con la receta instalada seguía diciendo «NINGÚN tema de cursor».
De paso queda anotado en `targets.toml` que el comentario de cosmic decía «sin ellos arranca sin
puntero» sobre `cosmic-icons`, que no trae cursores: describía una protección que no existía.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CGyBj4QyeCZiwLMkP9GJp6
`-DKCOREADDONS_USE_QML=OFF` estaba desde que se escribió la receta, con el argumento razonable de
que un framework tier-1 no debería arrastrar QML. El precio no se vio hasta hacer CLIC en el
lanzador dentro de QEMU: `kickoff` importa `org.kde.coreaddons` y ese módulo lo instala esta receta
y ninguna otra ⇒ **el menú de aplicaciones no abría**. La librería C++ salía completa, sus 70
consumidores enlazaban bien y el perfil reportaba 100%.
Es la forma más pura del «sellado ≠ arranca»: no falta una librería, falta una porción OPCIONAL de
una librería que sí está. Ninguna métrica de clausura puede verlo — mide recetas, no features.
`qtdeclarative` ya estaba en `[deps].build`, así que prenderlo no agrega una dep: deja de tirar lo
que ya se podía construir.
VERIFICADO CON UN SOLO BUILD (56 s), a propósito, en vez de pagar la cascada para averiguarlo:
· panel → menú abre (usuario, buscador, Favoritos/Todas, Aplicaciones/Lugares/Sesión)
· buscar «konsole» + Enter → la terminal arranca y corre:
uname -a → Linux (none) 6.16.12 #1 SMP PREEMPT_DYNAMIC … x86_64
konsole --version → konsole 25.04.3
Es la cadena completa del escritorio por primera vez: panel → menú → búsqueda → app → shell.
COSTO, medido antes de tocar y confirmado después: `yupana radio kcoreaddons` predijo 71, y el grafo
regenerado da exactamente **71 en deuda** (`escritorio-kde 192/263`). Queda como deuda DECLARADA
para una campaña de granja; la imagen de hoy corre con un kcoreaddons más nuevo que aquel contra el
que enlazaron sus consumidores, lo que es legítimo porque cruza un SONAME (misma ABI, sólo se suma
un módulo QML) — la misma regla que decidió la promoción de pipewire.
De yapa: `export SHELL=/bin/sh` en plasma-start-qemu.sh. El aviso rojo de konsole («Could not find
'', starting '/bin/sh' instead») era real y no venía de /etc/passwd —que dice /bin/sh— sino de que
konsole lee $SHELL y este getty no es un login shell.
Y el barrido que encuentra esto sin hacer clic queda escrito en el runbook: cruzar los `import` de
los `.qml` instalados contra los módulos con `qmldir`. Además de éste destapó `org.kde.kscreenlocker`
y `org.kde.newstuff.core`, sin diagnosticar.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGXe6mShYYw6V8ea1dQ13u
Medido sobre los artefactos del cierre de cada imagen, contando qué `usr/share/icons/*/`
trae un `index.theme` (que es lo que convierte un directorio en un tema):
escritorio-kde sólo Breeze_Light y breeze_cursors — que son CURSORES
escritorio-gnome CERO, ni siquiera hicolor
escritorio-cosmic Cosmic + hicolor <- el único que estaba bien
escritorio-sway CERO
Las dos capturas de QEMU de hoy ya lo mostraban y se leyeron como «arranca»:
- `plasma6-qemu-2026-09-03-kactivitymanagerd.png`: panel con el reloj y nada más. Los `.so`
de los applets estaban TODOS instalados; lo que faltaba era qué pintar. `kickoff`,
`systemtray`, `showdesktop` y `trash` SON un icono, así que sin tema quedan de ancho cero
— el reloj se ve porque dibuja TEXTO. El log lo decía en una línea:
`kf.iconthemes: Icon theme "breeze" not found.`
- `gnome-shell-qemu-2026-09-03-libs-compartidas.png`: barra superior con la fecha y el pill
de espacios, y la DERECHA vacía — red, volumen y batería son iconos.
`breeze` (ya declarado) es el tema de WIDGETS y CURSORES; los ~14.000 iconos viven en
`breeze-icons`, receta aparte, sellada desde siempre y declarada por NADIE. Igual
`adwaita-icon-theme` en GNOME, que además trae los XCursor (su cabecera dice por qué:
sin tema de cursor no hay puntero visible con el cursor por software de virtio-gpu).
Es la figura de las fuentes y de `foot` otra vez: data de RUNTIME, ninguna arista de BUILD
la alcanza, y la métrica de clausura no la echa de menos porque mide lo declarado.
`hicolor-icon-theme` —el fallback obligatorio de freedesktop— se promueve al corpus para que
lo alcancen las cuatro imágenes: hash IDÉNTICO desde la cola y desde el corpus
(b3:98ad44a5), y sus 4 consumidores (adwaita-icon-theme, cosmic-icons, cosmic-app-library,
cosmic-launcher) miden el mismo hash antes y después ⇒ un solo artefacto, CERO rebuilds.
Cierre tras declararlos, todo sellado y sin deuda:
kde 263/263 (+2) · gnome 158/158 (+2) · sway 173/173 (+1) · cosmic 133/133 (igual)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGXe6mShYYw6V8ea1dQ13u
Arrancando la imagen KDE en QEMU: kwin toma el DRM, expone wayland-0, plasmashell
arranca… y la pantalla se queda EN NEGRO con los dos procesos vivos. El serial
repetía 'STATUS: kwin=1 plasmashell=1' durante minutos, que se lee como salud.
La causa estaba en el log de Qt, no en el estado de procesos:
kde.plasmashell: Aborting shell load: The activity manager daemon
(kactivitymanagerd) is not running.
No sale de la clausura de las 7 raíces porque NO es dep de build de nada: plasmashell
lo pide por D-Bus al arrancar. scripts/kde/plasma-start-qemu.sh ya lo lanzaba (l.188);
lo que faltaba era que el paquete entrara al rootfs. Ya estaba sellado — declararlo no
cuesta un build.
Misma figura que las raíces de runtime de GNOME (imports.gi.*): lo que se invoca por
bus es invisible al grafo de deps.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0164nrZWZc78Mr2srrsnoM8U
Handoff de vuelta desde tawasuyu (SDD 25 §8): las seis tareas del otro lado
estan cerradas, y eso dejo este contrato mintiendo de dos formas.
- Alta de `proceso-por-descriptor` (pidfd_open / pidfd_send_signal). Se usa
desde W1 y no estaba declarada. `symbols` vacio a proposito: no depende de
ningun CONFIG_*, es interfaz del core desde Linux 5.3. Al no estar en ningun
perfil no se comprueba contra un .config; entra porque el contrato es la
lista de lo que se USA, y si manana el minimo de kernel baja de 5.3, esta
linea es la que lo dice.
- Los cinco consumidores de cgroup llevaban numero de linea y quedaron viejos
con W1-W4. Van por nombre de funcion, y la regla de escritura queda arriba.
- Los `silent` de esos cinco describian el bug que W4 arreglo ("solo emite un
warn!", "silencio total"). Un guardian que dice que hay un punto ciego donde
ya no lo hay es peor que no tenerlo.
- `contabilidad-por-tarea` decia que sandokan sondea /proc para medir una
unidad. Desde W2 eso sale del cgroup en O(1); el que sigue sondeando /proc es
el monitor de procesos del SISTEMA, que es otro consumidor.
Y en SDD 25 §8, el estado real: las seis cerradas, mas W4.bis, donde el hallazgo
no fue el que este documento suponia. En arje el limite no se descartaba: NO SE
PEDIA. El camino `plain` -el de casi todas las Cards- no creaba cgroup, y
`apply_rlimits_to_cgroup` la llamaba solo shuma.
Verificado con el binario, no de memoria: `hammer kernel contract --list` carga
las 14 capacidades, y `hammer kernel contract --profile anfitrion-cards` sigue
en verde (11 exigidas presentes, 13 miradas).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GiYsdSwF1nxjBTTsa1empe
Cierra el ⚠ que quedaba en la tabla de D8. Tres cosas, y la del medio es la que
más duele.
1. **Sniper pineado, y por la versión correcta.** No se pinea «la última» sino
la que `latest-container-runtime-depot.txt` dice que despliega el cliente de
Steam — 3.0.20260805.254768. Pinear otra sería pinear algo que nadie corre.
Se pinean DOS artefactos: la imagen (rootfs, 302 MB, 11196 ficheros) y el
depot `SteamLinuxRuntime_sniper.tar.xz` con pressure-vessel adentro. El
segundo es el que destraba el paso 6: ese runtime sólo se baja al instalar un
juego (credenciales), y pineado se coloca a mano ⇒ pressure-vessel se puede
ejercitar sin cuenta, sin juego y sin pantalla.
2. **Los digests estaban en prosa y ABREVIADOS, y eso no es un pin.** Cuando la
poda se llevó las imágenes, `895661bd…` no alcanzó para volver a traerlas:
hubo que ir a buscar los sha256 otra vez a upstream. Ahora enteros y
verificados en `docs/state/qorpa-imagenes.toml`, con de qué lista salieron y
**si esa lista está firmada** — que no todas: Ubuntu firma su SHA256SUMS,
Arch firma el tarball pero no la lista, y Valve no firma nada.
3. **`--retry` de curl no cubría el fallo que de verdad pasa.** Los 302 MB de
sniper murieron al 73% con `HTTP/2 INTERNAL_ERROR` y curl NO reintentó: sin
`--retry-all-errors` sólo considera transitorios los timeouts y los 5xx. Y
aun reintentando, sin `-C -` cada intento vuelve a empezar de cero. Con las
dos banderas el mismo pull sobrevivió dos cortes más y llegó. El parcial ya
no se borra al fallar (es lo que permite reanudar); es seguro porque quien
decide es el sha256 de después, y `prune` ya lo barre.
De paso, dos comprobaciones en vez de suposiciones: el rootfs de sniper viene en
`files/` con un hermano `metadata` y el anclaje por estructura lo elevó solo
(tercera forma real de empaquetado), y traer el depot como rootfs FALLA en vez
de adivinar («no encuentro un rootfs en el archivo»).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QZjGRqvjWij9dew7NVFu4Q