Audio
├─ Devices: 48. HDA Intel [alsa]
├─ Sinks: * 52. HDA Intel Analog Stereo [vol: 0.40]
├─ Sources: * 53. HDA Intel Analog Stereo [vol: 1.00]
Y gvc con perfiles reales (`output:analog-stereo+input:analog-stereo`). Se fue el auto_null.
LA CAUSA: SPA pide el device `card` (alsa-udev.c:178-183), que no tiene major:minor, y
libudev-zero recorría SÓLO /sys/dev/{block,char} — sólo devices CON nodo. El device que
SPA necesita nunca entraba en la enumeración: no faltaba una propiedad, faltaba la mitad
del espacio de búsqueda.
**Y LA PRIMERA VERSIÓN DEL PARCHE ARREGLÓ EL AUDIO Y ROMPIÓ EL VÍDEO.** Recorría
/sys/class entero, y /sys/class/drm no trae sólo tarjetas: trae los CONECTORES
(card0-Virtual-1) y un fichero `version`, ninguno con nodo. Mutter los tomaba como
candidatos ⇒ `No available CRTC for monitor` + `Page flip failed: drmModeAtomicCommit:
Invalid argument` en bucle. Pantalla negra con el compositor vivo: el mismo síntoma de
antes por una causa nueva. El udev real también los enumera, pero les adjunta las
propiedades por las que mutter los descarta, y ésas libudev-zero no las sintetiza.
La lección, que vale para cualquier reimplementación parcial de una API: **ensanchar la
enumeración expone los huecos de PROPIEDADES a más consumidores. Los dos lados del
contrato tienen que crecer juntos.** El parche final lleva una LISTA ACOTADA de
subsistemas (`sound` hoy); agregar otro es una línea *y* una prueba de que el consumidor
lo necesita y no se rompe.
POR QUÉ NO eudev — y corrijo mi propia sugerencia de antes, que era la peor opción: el
repo ya lo había probado en otro frente y ROMPIÓ EL INPUT. Su libudev.so.1 pisa el de
libudev-zero y, sin udevd, no expone ID_INPUT ⇒ libinput ignora todos los dispositivos en
silencio. Verificación A/B en QEMU de aquel episodio: eudev = 0 «New device»,
libudev-zero = 5. eudev sin udevd es PEOR, y correr udevd contradice la arquitectura
(arje-zero es PID1). El arreglo va donde está el hueco.
Radio pagado: 51 sellados a deuda, 9 en el cierre GNOME (reconstruidos: libinput,
libgudev, colord, mutter, gnome-shell, libgdm, upower, pipewire, wireplumber). El resto
—base, cli, KDE— queda para el latido.
Captura actualizada: escritorio pintando (628 colores) Y audio, cero page-flip fallidos.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
24 KiB
Runbook — GNOME en QEMU: el escritorio PINTA
Estado al 2026-07-29: cerrado. gnome-shell arranca desde fuente sobre el kernel de hammer, toma
el DRM master y los tres dispositivos de input por logind, expone wayland-0, y dibuja el Overview
de GNOME. Cinco muros caídos, cada uno por medición y no por conjetura:
| muro | causa real | cómo se midió |
|---|---|---|
SIGSEGV en get_seat_proxy |
object path de la Session mal escapado (_1 en vez de _31) |
el cliente calcula el path solo y no pregunta |
| cuelgue de la hebra de input | el fd de TakeDevice sin O_NONBLOCK |
wchan=evdev_read en /proc, no el core |
Requiring <X> en bucle |
7 typelibs de runtime + 2 capas más abajo | js/misc/dependencies.js + cierre de <include> |
| pantalla negra | Main.start() abortaba por un gschema de g-s-d |
el stack trace, que estaba en el log desde el principio |
| (descartado) KMS legacy | NO era la causa | atomic tomó efecto y la pantalla siguió con 2 colores |
Hermano de kde-qemu-desktop.md, del que reusa el andamiaje: la base
work/metal-rootfs, la inyección de mesa-llvmpipe/LLVM/musl, el truco del console-getty y el propio
scripts/kde/run-qemu-desktop.sh.
Ciclo completo
cd ~/hammer
bash scripts/gnome/hydrate-gnome.sh # cierre de gnome-shell + las raíces de RUNTIME → work/gnome-rootfs
bash scripts/gnome/qemu-desktop-image.sh # funde base+gnome, parchea, → work/hammer-gnome-qemu.img
IMG=work/hammer-gnome-qemu.img SERIAL=work/gnome-qemu-serial.log MON=work/gnome-monitor.sock \
TIMEOUT=150 DISP=none bash scripts/kde/run-qemu-desktop.sh
grep -a "gnome-qemu ::" work/gnome-qemu-serial.log | awk '!seen[$0]++'
DISP=gtk para ver la ventana (necesita DISPLAY=:0 GDK_BACKEND=x11). Regla heredada de KDE:
validar escritorios con PANTALLA, nunca sólo por serial — y sin humano delante se cumple con el
screendump del monitor de QEMU, ver abajo. Aplicarla es lo que destapó el muro de hoy: el serial
decía «sesión viva» y la pantalla estaba negra.
Sacar el core y el backtrace
El gnome-start deja el core en la raíz ext4 y hace sync, así que sobrevive al SIGKILL de QEMU.
sfdisk -J work/hammer-gnome-qemu.img # localizar hammer-root (part 2)
dd if=work/hammer-gnome-qemu.img of=/tmp/root.img bs=1M skip=129 count=5113 status=none
debugfs -R "dump /core.gnome-shell.<pid> /tmp/core.gnome-shell" /tmp/root.img
gdb -batch -q -ex "set sysroot $PWD/work/gnome-qemu-rootfs" \
-ex "core-file /tmp/core.gnome-shell" -ex "bt 25" work/gnome-qemu-rootfs/usr/bin/gnome-shell
🏔 GNOME PINTA (2026-07-29)
El Overview de GNOME Shell, construido entero desde fuente sobre el kernel de hammer, arje-zero como PID1 y musl: el conmutador de espacios de trabajo arriba a la izquierda, el reloj en el panel, la miniatura del escritorio, el dash abajo, y la notificación estándar de GNOME por sesión de root («Logged in as a privileged user»).
Cómo se validó, y es la parte reusable: screendump por el monitor de QEMU, sin humano delante.
printf 'screendump /tmp/gnome.ppm\n' | socat - UNIX-CONNECT:work/gnome-monitor.sock
python3 -c "from PIL import Image; Image.open('/tmp/gnome.ppm').save('/tmp/gnome.png')"
Métrica barata para saber si pinta antes de mirar: contar colores distintos. Con la pantalla
negra eran 2 (negro + el gris de la consola del kernel); pintando son 582, con el azul GNOME
(2,60,136) y los grises del shell (34,34,38) al frente.
El muro que parecía de KMS y era de GSettings
El diagnóstico anterior de este runbook culpaba al KMS: «el plano primario de virtio-gpu no publica
formatos, sólo hay Queue mode set y ningún page flip». Era una correlación, no la causa. Se
probó quitando MUTTER_DEBUG_FORCE_KMS_MODE=simple —el log pasó a decir using atomic mode setting,
o sea que el cambio SÍ tomó efecto— y la pantalla siguió con exactamente 2 colores. Refutada.
La causa estaba en el stack trace, en el log, desde el principio:
GNOME Shell-CRITICAL: Failed to setup quick settings:
Error: GSettings schema org.gnome.settings-daemon.peripherals.touchscreen not found
Stack trace: systemActions.js:156 → status/system.js:236 → quickSettings.js:29
Esa excepción ocurre dentro de Main.start(), construyendo los quick settings: el panel nunca se
termina de armar, así que no hay nada que pintar. El proceso queda vivo y el compositor con DRM
master — de ahí la pantalla negra con gnome-shell=2. Mutter no tenía un frame que presentar; no
es que no supiera presentarlo.
Lo resolvió la receta gsd-schemas: los gschemas de gnome-settings-daemon sin g-s-d (que sigue
aparcada por GTK3/X11). Tercera vez que aparece la misma lección — un gschema no es un fichero de
datos del demonio, es una interfaz publicada que consume otro programa.
Dos trampas del camino, las dos de diagnóstico
glib-compile-schemassale con 0 aunque RECHACE un esquema. Instalé los once XML, el log dijoesquemas OK, y el shell seguía diciendoschema ... not found. Lo que faltaba eraorg.gnome.settings-daemon.enums.xml—que meson genera conglib-mkenumsy no es uno de los.in—: sin los<enum>, glib descarta el esquema entero, avisa por stderr y sigue.gnome-startahora vuelca ese stderr siempre, no sólo cuando el comando falla.- El log serial persiste entre arranques. Dos veces leí un
STATUS +30sque era del arranque anterior y saqué conclusiones de una VM muerta. Truncar (: > serial.log) antes de arrancar, y esperar a que la imagen esté hecha Y no haya otro QEMU con el disco tomado (Failed to get "write" lockes el aviso de que hay uno vivo).
Iconos y cursor: adwaita-icon-theme (cerrado)
No cursor theme available no era cosmético: con el cursor por software —obligatorio en
virtio-gpu con render software— mutter dibuja la imagen que le da el tema, y sin tema el puntero se
movía invisible. Con adwaita-icon-theme (+ hicolor-icon-theme, que su index.theme hereda) el
cursor aparece y la notificación del shell tiene su icono. Colores distintos: 582 → 629.
Dos gotchas de esas dos recetas: hicolor 0.18 pasó de autotools a meson (su tarball ya no trae
configure, y un ./configure heredado sale con 127), y adwaita declara gtk-update-icon-cache
como required: true para un add_install_script que su propio autor marcó
skip_if_destdir: true — exige un binario que en un build empaquetado no puede ejecutar. Se borran
los dos bloques; required: false no alcanza porque meson no propaga el disabler ahí dentro.
El setuid del launch-helper: una causa, dos síntomas (cerrado)
dbus-daemon-launch-helper es el que dbus-daemon ejecuta para activar un servicio del bus de
SISTEMA bajo demanda, y comprueba sus propios permisos antes de hacer nada: si no es setuid root
se niega, y el cliente recibe The permission of the setuid helper is not correct — que es lo que
reportaba colord. Sin eso ninguna activación por bus de sistema funciona. La imagen ahora lo deja
root:messagebus 4750, y el síntoma de colord cambió de «permiso incorrecto» a «timed out»: la
activación ya se intenta de verdad, y lo que queda es del demonio, no del bus.
El bus de sistema, completo (cerrado): faltaba polkit
== gnome-qemu :: bus: org.freedesktop.login1 OK
== gnome-qemu :: bus: org.freedesktop.PolicyKit1 OK
== gnome-qemu :: bus: org.freedesktop.Accounts OK
== gnome-qemu :: bus: org.freedesktop.UPower OK
accounts-daemon y upowerd arrancaban, seguían vivos, y nunca adquirían su nombre: los dos se
bloquean en polkit_authority_get_sync() al iniciar, y org.freedesktop.PolicyKit1 no lo servía
nadie —nuestra receta polkit es libs-only a propósito, porque el demonio lo pone arje—. gnome-shell
esperaba después 25 s por cada uno.
El dato que lo resolvió no salió del log de los daemons sino de la LISTA DE NOMBRES DEL BUS. Ahí
estaban como conexiones anónimas :1.0, :1.1 — sin nombre bien conocido. Eso distingue tres cosas
que en el log del cliente se ven igual: «no arrancó», «arrancó y no llegó a pedir el nombre» y «lo
pidió y se lo negaron». Era la segunda. gnome-start ahora espera cada nombre con
NameHasOwner y, si no aparece, vuelca el log del daemon y la lista de nombres.
Lo sirve recipes/arje-polkit-compat.toml (b3:03e0a86f), el tercer shim de este tipo tras
arje-logind-compat y arje-sdlogin-compat. ⚠ Autoriza TODO — es la postura de sistema confiado que
arje ya tenía tomada, no algo que la receta introduzca; está escrito en su comentario.
Dos gotchas del empaquetado, los dos medidos:
- La política de polkit ya existe y NO alcanza: permite
ownsólo al usuariopolkitd, y el shim corre como root. Se agrega unzz-arje-polkit-compat.confen vez de reescribir la de upstream — dbus leesystem.den orden alfabético y las reglas posteriores ganan. - Los ficheros del rootfs fundido son hardlinks de SÓLO LECTURA del store (0444). Un
cat >encima falla conPermission deniedy rompió un build. Regla de este script: nunca sobrescribir un fichero que venga de un artefacto; agregar al lado, orm -fprimero — y entonces se está pisando algo sellado, que es una decisión, no un descuido.
Audio: PipeWire (cerrado — decisión del usuario, 2026-07-29)
El servidor de audio de la distro es PipeWire, no PulseAudio. Cierra una pregunta que estaba
explícitamente abierta en varias recetas, y por eso pulseaudio se había construido -Ddaemon=false:
sólo el cliente, para que gvc hablara el protocolo sin cerrar la decisión de prestado.
Los dos conviven, y eso es lo que hace que la decisión no rompa nada: pipewire va con
-Dlibpulse=enabled, que produce pipewire-pulse — un servidor que habla el protocolo de
PulseAudio. gnome-shell usa libpulse sin enterarse de qué hay del otro lado. No hubo que tocar una
línea del cliente.
== gnome-qemu :: socket pipewire-0 OK
== gnome-qemu :: socket pulse/native OK — gvc va a poder conectar
Gvc-DEBUG: get server info / update server
Gvc-DEBUG: Updating client: index=32 name='pipewire'
Gvc-DEBUG: Updating sink: index=33 name='auto_null' description='Dummy Output'
El Failed to connect context: Connection refused desapareció y gvc ve el servidor. El sink es
auto_null («Dummy Output»), que es la respuesta honesta: la VM no tiene tarjeta de sonido.
🔊 AUDIO FUNCIONANDO (cerrado): el muro era libudev-zero
Audio
├─ Devices: 48. HDA Intel [alsa]
├─ Sinks: * 52. HDA Intel Analog Stereo [vol: 0.40]
├─ Sources: * 53. HDA Intel Analog Stereo [vol: 1.00]
Y gvc lo ve con perfiles reales: output:analog-stereo+input:analog-stereo (Current). Ya no hay
auto_null.
Hicieron falta TRES cosas, en este orden, y cada una parecía la última:
- ALSA en el kernel (
linux-metalb3:613bca15). Estaba-d SOUND -d SND. wireplumber+lua— el gestor de sesión, sin el cual PipeWire acepta clientes y no enumera.- Parchear
libudev-zeropara enumerar devices de CLASE. Esto era el muro real: SPA pide el devicecard(alsa-udev.c:178-183), que no tienemajor:minor, y libudev-zero recorría sólo/sys/dev/{block,char}— o sea sólo devices CON nodo. El device que SPA necesita nunca entraba en la enumeración: no faltaba una propiedad, faltaba la mitad del espacio de búsqueda.
⚠ Y la primera versión del parche, que recorría /sys/class ENTERO, arregló el audio y ROMPIÓ EL
VÍDEO. /sys/class/drm no trae sólo tarjetas: trae los conectores (card0-Virtual-1) y un fichero
version, ninguno con nodo. Al entrar en la enumeración, mutter los toma como candidatos:
Failed to use linear monitor configuration: No available CRTC for monitor 'RHT QEMU Monitor'
Page flip failed: drmModeAtomicCommit: Invalid argument (en bucle)
Pantalla negra con el compositor vivo — el mismo cuadro de antes, por una causa nueva. El udev real también enumera esos conectores, pero les adjunta las propiedades por las que mutter los descarta, y ésas libudev-zero no las sintetiza (su tabla es fija y está orientada a input).
La lección, y vale para cualquier reimplementación parcial de una API: ensanchar la enumeración
expone los huecos de PROPIEDADES a más consumidores. Los dos lados del contrato tienen que crecer
juntos. El parche final va con una lista acotada de subsistemas (sound hoy); agregar otro es
una línea y una prueba de que el consumidor lo necesita y no se rompe.
Por qué no eudev, que era el camino que parecía obvio: el repo ya lo había probado en otro frente y
rompió el input — su libudev.so.1 pisa el de libudev-zero y, sin udevd corriendo, no expone
ID_INPUT, así que libinput ignora todos los dispositivos en silencio. Verificación A/B en QEMU: eudev
= 0 «New device», libudev-zero = 5. eudev sin udevd es PEOR, y correr udevd contradice la arquitectura.
Costo del parche: yupana radio libudev-zero = 51 sellados a deuda (9 en el cierre GNOME, que se
reconstruyeron acá; el resto —base, cli, KDE— quedan para el latido).
wireplumber cerrado (b3:39a9a06c), y con él lua (b3:e6c35f98), que hubo que autorar: el
Makefile de Lua no produce .so ni .pc —los agrega cada distro—, así que la receta enlaza la
compartida a mano desde la .a con --whole-archive y escribe el pkg-config. -fPIC es obligatorio:
libwplua es un objeto compartido y una .a no-PIC no entra (la regla del corpus que ya obligó a las
variantes -shared de zlib, sqlite, libxml2, libuuid y dbus).
Los TRES procesos y su orden, porque cada uno es cliente del anterior: pipewire → pipewire-pulse
→ wireplumber. gnome-start verifica cada paso y termina volcando wpctl status, que es el dato que
importa: no el pid, sino qué ve la política.
PipeWire 'pipewire-0' [1.2.7]
└─ Clients: 32. pipewire · 34. WirePlumber · 47. WirePlumber [export] · 48. wpctl
Audio
├─ Devices: ← vacío
├─ Sinks: * 33. Dummy Output
Y ese Devices: vacío NO es un fallo de wireplumber: el kernel de esta imagen no tiene ALSA.
recipes/linux-metal.toml:111 lo apaga explícitamente — -d SOUND -d SND. No hay /dev/snd ni
/sys/class/sound que enumerar. Se verificó agregando una ich9-intel-hda emulada a QEMU
(AUDIO=1, ahora el default de run-qemu-desktop.sh): con tarjeta y sin ALSA en el kernel, el
resultado no cambia. Encender el sonido en la distro es una decisión con costo —re-sellar el
kernel y rehacer la imagen metal— y queda para quien la tome, no escondida en un default.
Un bug propio que esto destapó: el bloque de wireplumber quedó DUPLICADO en gnome-start por un
merge descuidado, y el resultado eran dos wireplumber vivos peleándose el grafo. El síntoma no era
un error sino una lista de clientes que se lee normal si no se cuenta: dos «WirePlumber» con pids
distintos en wpctl status.
Gotcha de empaquetado, medido: ya existía incoming-kde/pipewire.toml sellada y no se puede reusar
hidratándola acá — los dos cierres traen glib y no son la misma glib: incoming-kde/glib-shared y
incoming-gnome/glib producen libglib-2.0.so.0.8800.1 con bytes distintos (cmp) y comparten 370
rutas. Proyectar las dos deja que una gane por orden ⇒ dos registros de GType en un proceso, el cuadro
de colord. Hay copia en la cola GNOME. Lo que SÍ fue gratis: alsa-lib, cuya única dep resuelve al
catálogo padre ⇒ hash idéntico y cache hit.
Lo que queda, y ninguno impide el escritorio
- colord sigue sin arrancar (gestión de color de pantalla). Su activación por bus ya está permitida; falta ver por qué el demonio no sube.
Missing required core component Settings— es gnome-control-center, que no está en el corpus.
Dos lecciones de método que costaron una iteración cada una
- Un pid no es un servicio. La primera versión del lanzamiento de upowerd decía «lanzado» y el shell seguía esperando. Reportar el arranque de un daemon sin comprobar que adquirió su NOMBRE es reportar una intención, no un hecho.
- El log serial persiste, y la imagen tarda más que el polling. Tres veces leí un marcador del arranque anterior y saqué conclusiones de una VM muerta. El orden correcto: esperar a que la imagen esté hecha, después esperar el marcador. Truncar no alcanza si la truncada ocurre a mitad de la cadena.
CÓMO SE CERRÓ LA CAPA JS (2026-07-29)
Era el muro anterior, y quedó cerrado. Vale la pena dejar cómo, porque el método es reusable.
El síntoma era: el compositor sube, expone wayland-0, y el shell sale con código 1 porque a
imports.gi.* le falta un typelib. Cada vez que se cerraba uno, aparecía el siguiente.
Y ESA ITERACIÓN ERA INNECESARIA — la lista está declarada en el propio shell.
js/misc/dependencies.js enumera EXACTAMENTE lo que el shell exige al arrancar. Cruzada contra el
rootfs hidratado, la frontera completa es de siete typelibs, de cinco recetas nuevas y una a
rehacer (medido, no estimado):
| typelib | lo provee | estado |
|---|---|---|
GnomeDesktop-4.0, GnomeBG-4.0 |
gnome-desktop |
ya sellada, pero con -Dintrospection=false y estática ⇒ hace falta la variante de isla dinámica |
Geoclue-2.0 |
geoclue | sin receta |
GWeather-4.0 |
libgweather | sin receta |
IBus-1.0 |
ibus | sin receta |
Rsvg-2.0 |
librsvg | sin receta (es Rust) |
UPowerGlib-1.0 |
upower | sin receta |
Lo demás de esa lista ya está: AccountsService, Atk, Atspi, Gcr, Gdk, Gdm, Gio, GioUnix,
GDesktopEnums, GdkPixbuf, Graphene, Pango, Polkit, PolkitAgent, Soup, y los cinco de mutter/shell
(Meta, Clutter, Cogl, Shell, St). GnomeBluetooth, NM/NMA4 y Malcontent son condicionales de
compilación o de runtime y no bloquean.
La regla que sale de acá, y es el precio de no haberla aplicado antes: cuando el muro es
Requiring X, no cierres X y vuelvas a arrancar — leé el fichero donde el programa DECLARA sus
dependencias de runtime y cerralas todas de una. Cada ronda de este bucle cuesta un rebuild de
imagen y un arranque completo.
Cerrados por este camino hasta hoy, en orden: AccountsService → DBus-1.0 (que incluye Atspi) →
cairo-1.0 (que incluyen Gdk y Pango) → Gdm-1.0.
CÓMO CAYÓ EL MURO ANTERIOR — la hebra de input (cerrado 2026-07-29)
Vale la pena dejarlo escrito porque el diagnóstico que había acá era falso y la forma de refutarlo es reusable.
Decía: «el hilo principal espera en un condvar a que la Mutter Input Thread avise que terminó de
inicializarse; nunca avisa» —eso era correcto— «hipótesis principal: libudev-zero, que
libinput_udev_assign_seat() enumera por udev y el rootfs no trae udev de verdad». Eso era la
conjetura, apoyada en un episodio parecido de otro frente (mirada-usb-nvidia).
La sonda que la refutó: libinput list-devices, que hace exactamente lo que hace
init_libinput() de mutter —udev_new + libinput_udev_create_context +
libinput_udev_assign_seat("seat0")—. Volvió con rc=0 y los tres dispositivos listados. La
enumeración por /sys con libudev-zero funciona perfecto. Está horneada en gnome-start y corre en
cada arranque, antes del shell.
El dato que dio la causa: tid 201 [Mutter Input Th] wchan=evdev_read syscall=0. El hilo estaba
dormido en un read() de evdev DENTRO DEL KERNEL. Ese volcado por hilo ya estaba en el script pero
corría después del kill -ABRT, sobre un /proc/<pid>/task que ya no existía: salía vacío y no
decía nada. El core tampoco servía — gdb no desenrolla a través de musl y devuelve ?? () para los
11 hilos que no son el principal. Acá /proc le gana al core.
La causa: arje-logind-compat abría el device de TakeDevice sin O_NONBLOCK. El compositor
no elige los flags —recibe el fd ya abierto por el bus—, y libinput asume no-bloqueante para poder
leer en bucle hasta EAGAIN; lo dice donde abre (libinput/src/evdev.c:2401) y le pasa
O_RDWR|O_NONBLOCK|O_CLOEXEC a open_restricted(), pero mutter, cuando hay logind, ignora esos
flags y delega la apertura. systemd-logind abre con O_NONBLOCK, así que la dependencia no se nota
hasta que la implementa otro. Arreglado en tawasuyu 3dd88f582, con test.
Y por qué la sonda no lo veía: libinput list-devices abre el devnode él mismo, con
O_NONBLOCK. Sólo el camino por logind pasaba por el fd malo. Esa asimetría es justamente lo que la
convirtió en un experimento y no en una repetición.
Tres perillas de diagnóstico que quedaron y valen para el próximo muro:
MUTTER_DEBUG es una lista de tópicos (g_parse_debug_string sobre meta_debug_keys,
src/core/util.c:42), no un booleano — con 1 no encendía nada; con backend imprime
«Opening and taking control of device file ''» por cada device y dice en cuál se para. El ping
D-Bus a login1 separa «daemon tildado» de «daemon vivo que ya contestó». Y los logs de /tmp (tmpfs)
se copian a la raíz ext4 antes de abortar, para sacarlos con debugfs junto al core.
LO QUE YA SE ARREGLÓ ANTES (dos bugs reales en arje-logind-compat)
Ambos encontrados arrancando esta imagen, ambos con test, ambos ya en tawasuyu y sellados:
- La sesión se creaba PEREZOSAMENTE.
ensure_usersólo corría dentro de un método del Manager, ywrite_login_statevive adentro. Pero mutter no empieza por D-Bus: lo primero que hace essd_pid_get_session(), que arje-sdlogin-compat resuelve LEYENDO/run/systemd/sessions. Huevo y gallina — el estado en disco sólo se escribía después de un pedido que sólo ocurre si el estado ya existe. Ahora la sesión se crea al arrancar (eager_session, apagable conARJE_LOGIN_EAGER=0, uid porARJE_LOGIN_UID). - El object path de la Session estaba mal escapado. Era
/session/_1; la convención de systemd (bus_label_escape) codifica como_<hex>todo lo que no sea[A-Za-z0-9]y también el primer carácter si es dígito, así que el id"1"da_31. Importa porque el cliente calcula el path por su cuenta y no pregunta: mutter reimplementa la misma regla enmeta-dbus-utils.c:escape_dbus_component. Con_1no había nadie sirviendo ahí, la propiedadSeatvolvía NULL y mutter —que no chequea— moría de SIGSEGV enget_seat_proxy. Los objetosUserNO usan este escapado (systemd hardcodea_<uid>), así queuser_path()queda igual.
De paso, un arreglo de portabilidad musl preexistente: libc::ioctl toma c_ulong en glibc y
c_int en musl, así que DRM_IOCTL_SET_MASTER se guarda pelado y se convierte en el sitio de uso.
Y ARJE_LOGIN_STATE=1 ya existía: el comentario del daemon dice literalmente «en arje (sin
systemd) el launcher de sesión lo prende. Default off» — y el launcher es gnome-start. El puente
que escribía /run/systemd/ a mano fue reinventar esa perilla; queda como fallback inerte.
El muro gráfico que este runbook listaba como «el que viene después» nunca apareció: los fixes
que KDE dejó pagos y precargados en gnome-start-qemu.sh (GBM_ALWAYS_SOFTWARE, kms_swrast,
LP_NUM_THREADS=1, MUTTER_DEBUG_SEND_KMS_MODIFIERS=0) alcanzaron: mutter crea el renderer gbm y
elige /dev/dri/card0 como primaria sin quejarse. Es el rédito directo de la campaña anterior.
Lo que falta, en orden
- Los seis proveedores de typelib de la tabla de arriba, en una sola tanda.
gnome-desktopdinámica+introspectada primero (ya está sellada, sólo cambia el modo), después geoclue, libgweather, upower, librsvg e ibus. Ojo al costo delibelogind: re-sellarla re-hashea todo lo que la declara (mutter, gnome-shell…) ⇒ pasaryupana radio libelogindANTES de tocarla — ya pasó dos veces en esta campaña. - Empaquetar la política D-Bus de login1 dentro del artefacto de arje-logind-compat (hoy la escribe el script de imagen).
- Arreglar el
identity mismatchdelAnnounceal bus del fractal (hoy sólo un WARN). - Con la capa JS viva: validar CON PANTALLA (
DISP=gtk), nunca sólo por serial — regla heredada de KDE (metal-dual-desktop-en-curso).
Recetas nuevas de esta etapa
accountsservice (b3:0328b0d0, + parche fgetspent_r para musl) · gi-foreign-typelibs
(b3:c8a4d2f8 — un .gir NO es un typelib: gjs resuelve contra el compilado) · libgdm
(b3:46fac484 — sólo la librería cliente; el demonio sigue aparcado por linux-pam).
libelogind pasó de 14 a 25 símbolos en tres tandas.
