Fija la política (capa GUI adopta linking DINÁMICO: Qt carga plugins .so en runtime, incompatible con el static-musl del userland CLI), el orden topológico en 5 capas (sustrato→Qt6→KF6→Plasma→apps), 6 hitos verificables (gate = H-Qt: qtbase + una ventana Qt bajo el régimen dinámico) y la estrategia de granja (cola aislada incoming-kde/, cadencia por capa, qtwebengine diferido). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
11 KiB
0011 — Etapa Escritorio: campaña KDE Plasma 6
Estado: propuesto (roadmap de campaña, no implementación) Fecha: 2026-07-11 Relacionado: etapa-g-importar-nix, etapa-g-gui-chain-boundary, granja-efimera-hcloud, 0003-zig-cc-builder, 0008-bootstrap-stages, 0010-arranque-grafo-mirada
Contexto
El catálogo firmado tiene ~748 paquetes y ~760 recetas canónicas. En la práctica es userland
CLI: cadenas Rust/Go self-contained que la granja muele fácil, más un cimiento gráfico GTK
(gtk4/libadwaita/cairo/pango/harfbuzz/freetype/fontconfig/mesa/wayland) capaz de
correr apps GTK sueltas — no un escritorio.
El objetivo de esta etapa es un escritorio completo, booteable y usable: KDE Plasma 6. Se eligió KDE primero (sobre GNOME/XFCE) a pesar de ser el más caro (~600–800 recetas nuevas, C++ pesado) porque define el techo de dificultad: si la máquina de build sobrevive a Qt+Plasma, GNOME y XFCE son cuesta abajo y comparten casi todo el sustrato de bajo nivel.
Este ADR no importa ni construye nada. Fija la política, el orden topológico, los hitos y la estrategia de granja. La primera tanda real es un paso posterior.
El eje del problema: static-musl/zig-cc vs. el mundo Qt/KDE
Todo el lab se construyó sobre una disciplina (ADR 0003): link estático, musl, zig-cc, cierre de
deps explícito. Eso hizo reproducibles 748 paquetes. Pero KDE es exactamente el terreno donde esa
disciplina deja de aplicar sin traducción:
- Qt carga plugins
.soen runtime. La plataforma (QPA:libqwayland*.so,libqxcb.so), los formatos de imagen, los estilos, los backends de multimedia — todos son bibliotecas compartidas cargadas pordlopen. Un Qt "todo estático" no arranca un escritorio: sin el plugin QPA no hay ventana. Esto no es una opción a desactivar como engtk4(-Dx11-backend=false); es la arquitectura. - Plasma es una constelación de procesos + QML.
kwin,plasmashell,krunner,systemsettings, servicios D-Bus. Comparten bibliotecas KF6/Qt6 a nivel de.so; estatizarlas multiplicaría el binario por N procesos y rompería los plugins igual. - C++ a escala Qt es territorio no ejercitado. El corpus es C/Rust/Go.
zig-cccompila C++, pero Qt6 + KF6 es el stress-test más grande que va a ver; el zig-skew ya rompiócairo(ctime_r) en el laptop (etapa-g-gui-chain-boundary).
Decisión de política
La capa gráfica de KDE adopta linking DINÁMICO. Concretamente:
- Bibliotecas compartidas (
.so) para Qt6, KF6 y Plasma, conSONAMEyrpath/ld.so.confsoberanos. Se abandona el-staticpara esta capa; se conserva para el userland CLI ya sellado (no se re-hashea nada existente). - musl dinámico como objetivo por defecto. Si un componente pelea con musl de forma irreducible (glibc-ismos duros), se aísla y se documenta como deuda, igual que la "deuda GL de Alpine" que ya arrastramos (mirada-usb-nvidia). No se introduce glibc a la ligera.
compilerpor componente.zig-ccdonde funcione; caída agcc-de-gueto (el patrón ya usado para kernel/cmake) donde el C++ de Qt lo exija. Se prueba zig primero, se documenta cada caída.- CMake es el sistema de build dominante (ECM lo es todo en KDE). Ya existe
recipes/cmake.toml.
Esta es la decisión arquitectónica que este ADR registra: la etapa escritorio parte el mundo en dos regímenes de linking, y eso es deliberado, no un accidente.
Lo que SÍ reusa el cimiento actual
El preview del planeamiento dijo "reusa casi nada"; es pesimista. Qt≠GTK a nivel toolkit, pero todo el sustrato de bajo nivel es compartido y ya está sellado:
freetype, fontconfig, harfbuzz, fribidi, pixman, libpng, libjpeg-turbo, libtiff,
expat, zlib, libffi, pcre2, libxml2, libxkbcommon, wayland, wayland-protocols,
libdrm, mesa, dbus, glib (Qt puede integrarse con glib main loop).
Es decir: la capa 0 (abajo) ya existe en buena parte. Lo nuevo empieza en Xorg/servicios y sube.
Orden topológico (capas de la campaña)
De abajo hacia arriba; cada capa es puerta de la siguiente. Números = recetas nuevas estimadas.
Capa 0 — Sustrato gráfico y de sistema (~60–120)
Lo que falta bajo Qt, mayormente C/Meson-CMake, dentro de la disciplina actual (dinámico ahora):
- Mesa completo (no
mesa-swrast): DRI, Gallium, Vulkan (KWin quiere Vulkan). Hoy tenemos base. - Pila X11 para XWayland/xcb:
libxcb,xcb-util*,libX11,libXext,libXi,libXcursor,libXrandr,libXfixes,xkeyboard-config,xcb-util-cursor. (Qt xcb + apps legacy vía XWayland.) - XWayland + Xorg server (para XWayland embebido).
- Seat/sesión:
seatd(ya en cola del otro agente) o elogind (logind sin systemd, clave en musl),pam/linux-pamopam_rundir,polkit. - Audio:
pipewire+wireplumber(Plasma 6 asume PipeWire). - Media (Qt Multimedia / phonon):
ffmpegogstreamer. - Cripto/red base para servicios:
openssl(tenemos),NetworkManageroconnman,BlueZ. - Imagen/color:
libepoxy(tenemos),lcm2/little-cms,libglvnd.
Capa 1 — Qt 6 (~15–25 recetas, pero enormes)
El corazón. Módulos, en orden:
qtbase(el mastodonte: gui, widgets, network, dbus, sql, el plugin QPA wayland+xcb).qtshadertools,qtdeclarative(QML — Plasma es QML),qtwayland,qtsvg,qt5compat,qttools,qtmultimedia,qtsensors,qtvirtualkeyboard,qtimageformats,qtquick3d(opc),qtwebengine(diferible — Chromium embebido, la receta más cara de todo el proyecto).- Extras KDE:
qtkeychain.
Capa 2 — KDE Frameworks 6 (~80 recetas, por tiers ECM)
extra-cmake-modules (ECM) primero — es el build-system de todo KDE. Luego por tiers de dependencia:
- Tier 1 (sin deps entre frameworks):
kcoreaddons,kconfig,kguiaddons,ki18n,kwidgetsaddons,kwindowsystem,kdbusaddons,karchive,kcodecs,kitemviews,solid,sonnet,threadweaver,kholidays,prison,syntax-highlighting,breeze-icons,kirigami… - Tier 2:
kauth,kcompletion,kcrash,kdoctools,kjobwidgets,knotifications,kpackage,kunitconversion,kservice… - Tier 3:
kconfigwidgets,kiconthemes,kio,kglobalaccel,ktextwidgets,kxmlgui,kbookmarks,kwallet,knewstuff,kparts,kdeclarative,kcmutils,kdesu,krunner,plasma-framework/libplasma,frameworkintegration… - Integración:
kwayland,kdnssd,kpeople,modemmanager-qt,networkmanager-qt,bluez-qt,kactivities,baloo(búsqueda),purpose.
Capa 3 — Plasma 6 workspace (~40–60)
- Base:
libkscreen,libksysguard,kscreenlocker,kglobalacceld,kdecoration,layer-shell-qt,plasma-activities,kpipewire. - Compositor:
kwin(Wayland; requiere Vulkan/GL, XWayland). - Shell:
plasma-workspace(plasmashell,krunner,ksmserver),plasma-desktop,plasma-pa(audio),plasma-nm(red),powerdevil,systemsettings,kmenuedit,plasma-systemmonitor,kactivitymanagerd,milou,kscreen,sddm(display manager) o integración con el arranque-grafo-mirada (ver ADR 0010),breeze(tema/estilo Qt).
Capa 4 — Apps núcleo (opcional para "booteable", ~20–60)
dolphin (archivos), konsole (terminal), kate/kwrite, ark, gwenview, okular,
spectacle, kcalc, kwalletmanager… Se prioriza el mínimo para un escritorio usable, el resto
por demanda.
Hitos (definición de "hecho" por etapa, verificable)
- H-Qt:
qtbaseconstruye + un binario Qt trivial (QApplication+QLabel) abre una ventana sobre el compositor de referencia (mirada/QEMU). Prueba que el régimen dinámico + QPA wayland funciona end-to-end. Sin esto, nada de KDE tiene sentido — es el gate real. - H-QML: una app
qtdeclarative(QML) renderiza. Plasma es QML; este hito de-riskea la capa 3. - H-KF6: ECM + tier 1 +
kioconstruyen; una app KDE de ejemplo corre. - H-kwin:
kwin_waylandlevanta como compositor y pinta un fondo. - H-shell:
plasmashellarranca sobrekwin, con panel y lanzador. ← "escritorio prende". - H-sesión: login (SDD/mirada) → sesión Plasma completa, con audio (PipeWire), red (plasma-nm),
konsole+dolphincorriendo. ← distro gráfica booteable-usable.
Estrategia de granja
- La granja efímera (granja-efimera-hcloud) es la herramienta de volumen:
farm-run N. - PERO: el escritorio no es "importar 700 y
farm-run". El build-yield de C++/CMake/Qt es bajo; cada receta pide de-Alpinización manual, patches y orden estricto. La granja muele lo que ya está bien importado; el cuello es producir recetas de calidad, denso y asistido. - Aislamiento de cola: el otro agente comparte
recipes/incoming/(stack tawasuyu). Esta campaña usa cola propiarecipes/incoming-kde/y commits con rutas explícitas (nuncagit add -A), mismo patrón queincoming-go(etapa-g-frente-go). - No rebuildear en el laptop el stack que el worker selle (zig-skew, etapa-g-gui-chain-boundary).
- Cadencia por capa: importar+pinnear una capa →
farm-run→ cosechar+firmar → subir a la siguiente. No fan-out ciego entre capas (violaría el orden topológico). qtwebengine(Chromium) se difiere: es la receta más cara del proyecto y no es necesaria para H-shell. Se ataca sólo si una app núcleo lo exige.
Riesgos y deudas conocidas
- musl vs. Qt/KDE: partes pueden exigir glibc-ismos. Mitigación: aislar + documentar deuda, no glibc global.
- zig-cc en C++ a escala: puede haber caídas masivas a gcc-gueto. Aceptado; se documenta por comp.
- Vulkan/GL soberano: KWin quiere aceleración; hoy arrastramos "deuda GL de Alpine". Puede forzar atacar Mesa/driver a fondo antes de H-kwin.
- Tamaño: install de escritorio KDE ronda miles de paquetes contando cierre transitivo; esta es una campaña larga, no una tanda. Los ~700 son las recetas nombradas; el árbol es mayor.
- Reproducibilidad: el régimen dinámico + plugins dlopen complica el hashing determinista que dio
748 reproducibles. Hay que extender la disciplina de sellado a
.socon SONAME estable.
Alternativas consideradas
- XFCE/GNOME primero (más baratos): descartado por decisión de producto — KDE fija el techo.
- Mantener todo estático: inviable, Qt/Plasma requiere dlopen de plugins.
- Adoptar binarios Qt/KDE de Alpine sin rebuild: viola soberanía del bootstrap; se acepta sólo como deuda puntual (ej. GL), no como base del escritorio.
Próximo paso concreto
Importar+pinnear la Capa 0 faltante a recipes/incoming-kde/ (empezando por Mesa-completo +
pila xcb/X11 + elogind/seatd + PipeWire), y correr la primera farm-run de la campaña. El gate
temprano a perseguir es H-Qt: si qtbase + una ventana Qt no funciona bajo el régimen dinámico,
todo lo demás se replantea antes de gastar granja en 700 recetas.