# Runbook — relanzar el escritorio KDE Plasma 6 en QEMU Plasma 6 renderizado 100% por software (QPainter + llvmpipe) sobre `virtio-gpu`, en la cadena soberana de takana (LLVM 18 + mesa desde fuente). Sin GPU real. Cerrado 2026-07-20 tras resolver 5 bugs estructurales + 2 de cursor (ver [[kde-metal-qemu-desktop]] en memoria y `git log` del frente `kde/qemu:`). Este runbook es sólo para **relanzar y verificar**, no para rediagnosticar. ## Relanzar (caso normal — la imagen ya existe) ```sh cd ~/hammer # la ventana gtk necesita el X del laptop (Xwayland de mirada): DISPLAY=:0 GDK_BACKEND=x11 TIMEOUT=1800 DISP=gtk bash scripts/kde/run-qemu-desktop.sh ``` - Abre una ventana gtk con el virtio-gpu. Bootea UEFI → kernel → arje-zero → Plasma pinta solo (~30-45s). - `TIMEOUT=1800` = auto-kill a los 30 min (omitir para dejarlo indefinido; matarlo a mano con el kill de abajo). - `DISP=none` = headless (sólo serial, para diagnóstico sin ventana ni interferir con mirada). - Toda la config que lo hace funcionar (los 7 fixes) vive en `scripts/kde/plasma-start-qemu.sh`, que se hornea en la imagen. No hace falta setear nada a mano. ## Verificar sin mirar la ventana (oráculo screendump) La ventana gtk **se congela si mirada reinicia su Xwayland** (QEMU sigue vivo por dentro). Para ver el scanout REAL del guest, independiente de la ventana: ```sh cd ~/hammer printf 'screendump %s/shot.ppm\n' "$PWD" | socat - unix-connect:work/qemu-monitor.sock magick shot.ppm /tmp/shot.png # y abrir /tmp/shot.png ; luego: rm shot.ppm ``` Salud por el serial (no necesita la ventana): ```sh grep -a 'STATUS +' work/qemu-desktop-serial.log | tail -3 # kwin=1 plasmashell=1 = vivo grep -ac 'código 139' work/qemu-desktop-serial.log # crashes de kwin (÷3: cada línea sale x3) ``` ## Matar / cerrar ```sh pkill -KILL -f 'qemu-sys[t]em-x86_64 -machine q35' # el [t] evita auto-matar el propio comando ``` ## Reconstruir la imagen (si se tocó una receta KDE, mesa/llvm, o plasma-start) ```sh cd ~/hammer bash scripts/kde/qemu-desktop-image.sh # funde base+kde-rootfs, inyecta llvmpipe/musl, hornea plasma-start # necesita en store/: *-mesa-llvmpipe, *-llvm18, y los rootfs work/{metal-rootfs,kde-metal-rootfs} ``` Rebuild ~40s (host-side, hardlinks + artefactos ya sellados; **no** compila nada). Luego relanzar. ## Los 7 fixes que lo hacen andar (por si algo regresa) Todos en `plasma-start-qemu.sh` salvo `-vga none` (en `run-qemu-desktop.sh`): | Fix | Sin él | |---|---| | `GBM_ALWAYS_SOFTWARE=1` | segfault al init (virtio sin 3D tratado como HW → vtable NULL) | | `KWIN_DRM_USE_MODIFIERS=0` | negro total (virtio rechaza `AddFB2WithModifiers` con EINVAL) | | `KWIN_DRM_DEVICES=` | doble output (efifb+virtio) rompe buffers (redundante con `-vga none`) | | `KWIN_COMPOSE=Q` (QPainter) | kwin segfaltea en el rasterizador llvmpipe (`lp_rast_clear_color`) | | `-vga none` | **pantalla clavada en TianoCore** (VGA-std por defecto + simpledrm roban el scanout) | | `XCURSOR_THEME=breeze_cursors` + `kcminputrc` | `Failed to load cursor theme "default"` (cursor invisible) | | `KWIN_FORCE_SW_CURSOR=1` | cursor aparece/desaparece (plano HW de virtio no se presenta) | ## Gotchas de operación - **Lectura STALE del serial:** no se trunca hasta que el run-script arranca QEMU (tras el rebuild ~40s). Un `until grep 'escritorio arriba'` matchea el run ANTERIOR. Esperá un marcador único del run nuevo: `rm -f work/qemu-monitor.sock` antes de lanzar y `until [ -S work/qemu-monitor.sock ]; do sleep 2; done`. - **`pkill -f qemu...` se auto-mata** (el patrón matchea el propio comando) → usar siempre `qemu-sys[t]em`. - **"Se queda en TianoCore" tras varios relanzamientos:** el `work/qemu-desktop-OVMF_VARS.fd` persistente acumula boot entries stale → `rm -f work/qemu-desktop-OVMF_VARS.fd` (el run-script lo recrea limpio). - **Serial triplicado:** cada línea sale ×3 (`say` tee a console+ttyS0). "139: 3" = 1 crash real. - El escritorio queda sólo con wallpaper+panel; sin discos/energía reales (no hay udisksd/upowerd en el rootfs) ni efectos GL pesados (llvmpipe no los soporta). Es esperado, no un fallo. ## Prerrequisitos - `work/hammer-kde-qemu.img` (la imagen; si falta, reconstruir arriba). - OVMF: `/usr/share/edk2/x64/OVMF_CODE.4m.fd` + `OVMF_VARS.4m.fd`. - Herramientas host: `qemu-system-x86_64`, `socat`, `magick` (ImageMagick) para el screendump. - Para la ventana gtk: sesión gráfica del laptop viva (`DISPLAY=:0`). Headless (`DISP=none`) no la necesita. Relacionado: memoria [[kde-metal-qemu-desktop]], [[frente-escritorio-kde]], [[arranque-grafo-mirada]]. ## 2026-09-03 — verificar el escritorio SIN humano delante (gioser, TCG, sin socat) Este runbook asumía el laptop: `DISP=gtk` para ver la ventana y `socat` para el monitor. En **gioser no hay ninguna de las dos cosas** —es un vServer sin `/dev/kvm` y sin `socat`— y aun así se puede verificar todo, incluido **hacer clic**. Las tres piezas: ```sh # 1. la imagen y el rootfs viven en el VOLUMEN (/mnt/vvv está al 98%), y el STAGE también: # sin STAGE= el install-image-efi hardlinkea de /mnt/cosecha a work/ y muere con EXDEV. E=/mnt/cosecha/escritorios BASE=$E/base-rootfs KDE=$E/kde-rootfs MERGED=$E/kde-qemu-rootfs \ IMG=$E/hammer-kde-qemu.img STAGE=$E/.stage-kde bash scripts/kde/qemu-desktop-image.sh # 2. arrancar headless (cae solo a TCG: gioser no tiene KVM; Plasma pinta en ~2 min) IMG=$E/hammer-kde-qemu.img SERIAL=work/kde-qemu-serial.log MON=work/kde-monitor.sock \ VARS=work/kde-OVMF_VARS.fd TIMEOUT=1200 DISP=none bash scripts/kde/run-qemu-desktop.sh & ``` 3. el monitor de QEMU **por socket unix desde python**, que reemplaza a `socat`: ```python import socket, time s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM); s.connect('work/kde-monitor.sock') time.sleep(.5); s.recv(65536) def cmd(c, p=.6): s.sendall((c+'\n').encode()); time.sleep(p) try: s.recv(200000) except: pass cmd('screendump /mnt/cosecha/escritorios/shot.ppm', 4) # el scanout REAL del guest ``` ### Hacer CLIC sin ventana — y por qué el ratón es relativo `info mice` dice `QEMU PS/2 Mouse`: **movimiento RELATIVO**, así que no hay «ir a (x,y)». La maniobra que sí funciona es **fijar contra una esquina** y moverse desde ahí: ```python cmd('mouse_move -3000 3000', 2) # clava el puntero en la esquina INFERIOR IZQUIERDA cmd('mouse_move 10 -8', 1) # y desde la esquina, al lanzador del panel cmd('mouse_button 1', .5); cmd('mouse_button 0', 8) ``` `sendkey` también anda (`sendkey alt-f2`, `sendkey k`, …) y **la combinación arranca krunner** —se ve en el log de kwin— pero **la ventana de krunner no llegó a pintar** en dos intentos. Queda anotado como pendiente propio, separado del bug de abajo. ### Lo que estas dos herramientas destaparon el 2026-09-03 1. **El panel salía con el reloj y nada más, y no era el panel: eran los ICONOS.** Los `.so` de todos los applets estaban instalados; lo que faltaba era `breeze-icons`. Ver el commit «escritorios: KDE y GNOME corrían SIN tema de iconos». Evidencia: `../evidencia/plasma6-qemu-2026-09-03-panel-con-iconos.png` — kickoff, gestor de tareas, bandeja (notificaciones, volumen, teclado, red), reloj y «mostrar escritorio», todos pintando. 2. **El lanzador de aplicaciones NO ABRE**, y el diálogo de error lo dice entero: ``` qrc:/qt/qml/plasma/applet/org/kde/plasma/kickoff/main.qml:191:25: Type FullRepresentation unavailable .../Header.qml:18:1: module "org.kde.coreaddons" is not installed ``` `recipes/incoming-kde/kcoreaddons.toml` pasa `-DKCOREADDONS_USE_QML=OFF` (la cabecera lo dice: «QML bindings / python / docs apagados»), así que el módulo QML `org.kde.coreaddons` no se construye. Evidencia: `../evidencia/plasma6-qemu-2026-09-03-kickoff-sin-coreaddons.png`. **`yupana radio kcoreaddons` = 71**, o sea que prenderlo es una campaña de granja, no un ticket. **Regla que sale de las dos:** una captura donde el escritorio «pinta» NO prueba que el escritorio funcione. El barrido barato que sí lo prueba es cruzar los `import` de los `.qml` instalados contra los módulos QML con `qmldir` que hay en el rootfs; así salió `org.kde.coreaddons` y, de yapa, `org.kde.kscreenlocker` y `org.kde.newstuff.core`, que también faltan. ### El arreglo, verificado con UN build (2026-09-03) `-DKCOREADDONS_USE_QML=ON` + **un solo** `takana build kcoreaddons` (56 s) instala `usr/lib/qt6/qml/org/kde/coreaddons/{libkcoreaddonsplugin.so,qmldir,…}`. Hidratado ESE artefacto en el rootfs y rehecha la imagen, el menú **abre**: usuario, buscador, Favoritos / Todas las aplicaciones, y las pestañas Aplicaciones / Lugares / Sesión (`../evidencia/plasma6-qemu-2026-09-03-menu-abre.png`). Escribiendo `konsole` en el buscador y Enter, la terminal arranca y corre — `uname -a` da el kernel 6.16.12 de takana y `konsole --version` da 25.04.3 (`../evidencia/plasma6-qemu-2026-09-03-konsole-uname.png`). Es la cadena completa del escritorio por primera vez: **panel → menú → búsqueda → app → shell**. Se probó con UN build a propósito: la cascada de 71 es de granja y no hacía falta pagarla para saber si el arreglo era el correcto. Las 71 quedan como **deuda declarada** —`escritorio-kde 192/263`— y la imagen de hoy corre con un `kcoreaddons` más nuevo que aquel contra el que enlazaron sus consumidores. Eso es legítimo porque lo que cruza es un **SONAME** (misma versión, misma ABI, sólo se suma un módulo QML); es la misma regla que decidió la promoción de pipewire. Lo que NO se puede es hidratar dos artefactos distintos en la misma ruta. ⚠ El aviso rojo `Could not find '', starting '/bin/sh' instead` de konsole era real y NO venía de `/etc/passwd` (que dice `/bin/sh`): konsole lee **`$SHELL`**, y este getty no es un login shell. Arreglado exportándolo en `plasma-start-qemu.sh`.