Files
takana/docs/adr/0011-escritorio-kde-plasma.md
T
Sergio 97ceb72411 takana etapa 5b: los 59 docs de diseño, runbooks y ADR
645 líneas. Los ADR entran porque en este repo SON documentos vivos, no
registros inmutables: el 0013 tiene 5 commits, el 0009 dos. Eso se comprobó
antes de decidir, no se asumió por convención general.

EXCLUIDOS por ser REGISTRO o generado: docs/evidencia/ (6), el HANDOFF de la
noche de KDE (1) y docs/state/ (24, se regenera solo). Reescribir un comando
dentro de una evidencia la falsifica.

Y el ADR 0016 se excluye de todo barrido, con un aviso adentro para el próximo
que barra: habla SOBRE el renombre, así que necesita seguir diciendo 'hammer'.
El barrido se lo llevó puesto y lo dejó titulado 'Renombre del sistema: takana
→ takana'; revertido.

Congelados, verificados uno por uno con controles: /opt/hammer, /var/lib/hammer,
/usr/bin/hammer, /mnt/vvv/hammer, la URL de gitea, hammer-farm.service,
hammer-live-install.sh, BRIEFING-hammer.md, hammerd, hammer-recover y
HAMMER_LIVE.
2026-09-09 19:25:51 +00:00

278 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 0011 — Etapa Escritorio: campaña KDE Plasma 6
Estado: aceptado · **gate H-Qt PASADO (2026-07-11)** · **hito H-QML PASADO (2026-07-14)**
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 (~600800 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:
1. **Qt carga plugins `.so` en runtime.** La plataforma (QPA: `libqwayland*.so`, `libqxcb.so`),
los formatos de imagen, los estilos, los backends de multimedia — todos son bibliotecas
compartidas cargadas por `dlopen`. 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 en `gtk4` (`-Dx11-backend=false`);
es la arquitectura.
2. **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.
3. **C++ a escala Qt es territorio no ejercitado.** El corpus es C/Rust/Go. `zig-cc` compila 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**, con `SONAME` y `rpath`/`ld.so.conf`
soberanos. Se abandona el `-static` para 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.
- **`compiler` por componente.** `zig-cc` donde funcione; caída a `gcc`-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 (~60120)
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-pam` o `pam_rundir`, `polkit`.
- **Audio**: `pipewire` + `wireplumber` (Plasma 6 asume PipeWire).
- **Media** (Qt Multimedia / phonon): `ffmpeg` o `gstreamer`.
- **Cripto/red base para servicios**: `openssl` (tenemos), `NetworkManager` o `connman`, `BlueZ`.
- **Imagen/color**: `libepoxy` (tenemos), `lcm2`/`little-cms`, `libglvnd`.
### Capa 1 — Qt 6 (~1525 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 (~4060)
- 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", ~2060)
`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)
1. **H-Qt**: `qtbase` construye + 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.*
2. **H-QML**: una app `qtdeclarative` (QML) renderiza. Plasma es QML; este hito de-riskea la capa 3.
3. **H-KF6**: ECM + tier 1 + `kio` construyen; una app KDE de ejemplo corre.
4. **H-kwin**: `kwin_wayland` levanta como compositor y pinta un fondo.
5. **H-shell**: `plasmashell` arranca sobre `kwin`, con panel y lanzador. **← "escritorio prende".**
6. **H-sesión**: login (SDD/mirada) → sesión Plasma completa, con audio (PipeWire), red (plasma-nm),
`konsole` + `dolphin` corriendo. **← 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 propia **`recipes/incoming-kde/`** y commits con rutas explícitas (nunca `git add -A`),
mismo patrón que `incoming-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 `.so` con 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.
## Resultado H-Qt (2026-07-11) — GATE PASADO ✅
`qtbase 6.11.1` **construye y sella** en la granja (`b3:7c7c747d4d4b609f0d9eddbab5b4bc73e7816ce71c03e0fc53cfebf7ba35cebd`),
receta `recipes/incoming-kde/qtbase.toml` (de-Alpinizada del APKBUILD, conserva sus parches de musl).
Produce `libQt6Core/Gui/Widgets/OpenGL.so` **dinámicos** + el plugin QPA `libqwayland.so`. La app de
prueba `scripts/kde/h-qt-test.cpp` (QApplication+QLabel) compila y linkea contra él, y **corre a rc=0**
con `QT_QPA_PLATFORM=offscreen` en el rootfs musl del worker: crea la ventana y el event loop sale
limpio. **El régimen dinámico + zig-cc + musl del ADR queda probado end-to-end en el componente más
difícil de KDE** — el riesgo #1 (¿sobrevive el toolchain a Qt?) está respondido: sí.
**Snapshot `takana-kde-qtbase-2026-07-11` (img 407438750)**: worker con qtbase + su cierre de deps ya
sellados. Arrancar futuras `farm-up` de la campaña KDE desde ESTA imagen (no la golden limpia) evita
re-pagar ~45 min de build. El worker efímero se destruyó (baseline €0).
### Lecciones durables (patrón de-Alpinización Qt/KDE)
1. **zig-cc + CMake**: CMake canonicaliza el symlink `cc``/opt/zig/zig`, perdiendo el despacho por
`argv[0]`; ASM y custom-commands invocan `zig -std=…` (subcomando inválido). Fix: scripts wrapper
reales (`$PWD/.zwrap/{cc,cxx}` = `exec zig cc/c++ -mcpu=baseline`), en el ÁRBOL DE FUENTE (no /tmp,
que se vacía entre fases), y `-DCMAKE_{C,CXX,ASM}_COMPILER` apuntándolos. Un script no se canonicaliza.
2. **Tensión estático↔dinámico (la deuda central de Capa 0)**: la capa GUI arma `.so`, pero muchas
libs C canónicas están selladas como **archive estático sin -fPIC** (openssl `libcrypto.a`, sqlite)
o **incompletas bajo `-Wl,--no-undefined`** (glib) o **sin arrastrar deps transitivas** (fontconfig
→expat). `libQt6Core.so` SÍ linkea con glib/pcre2 (PIC-compat) y `zlib` entra como `libz.so`. Para
el gate se apagó/bundleó lo problemático (dbus/sql/openssl/glib/fontconfig OFF; freetype/harfbuzz/
libpng/libjpeg bundled). **DEUDA para KDE real: reconstruir el closure C shared-PIC + `.pc` con
`Requires.private` completo** (SSL/SQL/glib/fontconfig los va a exigir Plasma).
3. **Hidratación runtime**: correr un binario musl del store exige el rootfs musl (`.dev-fs/alpine`, el
host del worker es glibc) + el cierre de `.so` en `LD_LIBRARY_PATH` (mesa/libdrm/…). Varios libs son
static-only en el store: se puede fabricar la `.so` desde el `.a` si es PIC
(`zig cc -shared -Wl,--whole-archive lib.a`). Falta una hidratación FHS que capture el cierre runtime.
## Próximo paso concreto
Con H-Qt cerrado, la **Capa 1 (Qt6)** sigue con **qtdeclarative (QML)** — Plasma es QML, es el
siguiente de-risk (hito H-QML) — más `qtwayland` como módulo completo (ya tenemos su QPA en qtbase,
pero KDE usa `qtwayland` extendido). En paralelo, **saldar la deuda de Capa 0**: sqlite+openssl
shared-PIC y glib `.a` completo, para reactivar SSL/SQL/glib en un qtbase "real" (hoy es el qtbase del
gate, reducido; se rebuildea con features plenas antes de promover a canónico/firmado). Arrancar las
`farm-up` desde el snapshot `takana-kde-qtbase-2026-07-11`.
## Resultado H-QML (2026-07-14) — HITO PASADO ✅
`qtdeclarative` (QML/QtQuick) cosechado en el repo firmado del escritorio (`work/repo-kde`, 161 pkgs
KDE). El test `scripts/kde/h-qml-test.cpp` (`QQmlApplicationEngine` que carga QML inline `Window` +
`Text` vía `import QtQuick`) **compila** con zig-cc/musl contra el FHS hidratado y **corre a rc=0** con
`QT_QPA_PLATFORM=offscreen`: el engine instancia el árbol de objetos QtQuick y el event loop sale
limpio. **El motor QML — el corazón de Plasma — carga e instancia una escena bajo el régimen
dinámico/musl/zig-cc.** Reproducible con `scripts/kde/h-qml-run.sh` en el worker.
### La HIDRATACIÓN FHS (salda la deuda de la lección 3 del gate H-Qt)
El gate dejó pendiente "una hidratación FHS que capture el cierre runtime". Ahora existe y está
probada, en tres piezas nuevas:
1. **`scripts/kde/repo-selfcontain.py`** — vuelve `work/repo-kde` AUTO-CONTENIDO para `install`:
`install` lee los `depends` del recipe embebido en cada `.swm` y resuelve cada nombre como CLAVE
del índice. El repo cosechado no cerraba por dos causas: (a) deps a nombres de receta-archivo
qt-cortos (`qtbase`) cuando el paquete es `qt6-qtbase` (fuga de de-Alpinización, 79 recetas), y
(b) faltaban libs base del cierre. El script trae de `dist/repo` (repo base firmado, cierre
completo) todo paquete ausente (colisión → gana la versión KDE) y agrega entradas ALIAS
qt-corto→qt6-* (mismo `.swm`, otra clave). Índice resultante 884 entradas, re-firmado con
`takana repo sign``repo verify` trusted.
2. **`scripts/kde/hydrate-fhs.sh`** — hidrata el cierre runtime instalando **cada** paquete del
cierre en el MISMO prefix (clave: `install <pkg> --prefix P` sólo baja los ficheros de `<pkg>`, NO
de su cierre, igual que `product-userland-from-repo.sh`). Con el store del worker caliente los
32 pkgs del cierre de `qt6-qtdeclarative` cache-hitean; produce `work/kde-rootfs` con 455 `.so`
(libQt6Core/Gui/Qml/Quick + el QPA `libqoffscreen.so` + mesa/EGL/xcb/wayland/openssl/...).
3. **`scripts/kde/h-qml-run.sh`** — compila+corre el reproducer H-QML contra ese FHS.
### Deudas/lecciones nuevas (para KDE real)
- **`target_bin` espurio en recetas de LIBS**: las recetas KDE declaran `target_bin=/usr/bin/<pkg>`
que no existe (son libs). `install` hidrata los ficheros y LUEGO falla la aserción con exit 1;
`hydrate-fhs.sh` lo tolera (cuenta éxito si dejó ficheros). **Fix pendiente**: quitar/corregir
`target_bin` en las recetas de librería (requiere re-pack del `.swm`).
- **Cache-miss al re-resolver deps**: agregar libpng/openssl/etc. al cierre cambió el input-hash de
qtbase → `install` rebuildeó un qtbase MÁS COMPLETO (con módulo Network/SSL, antes apagado en el
gate). Es avance hacia el "qtbase real", pero rompe la reutilización del sellado `7c7c747d`. Para
reproducibilidad estricta hay que fijar el cierre de build-deps exacto del sellado.
- **Fuentes**: Qt ya no trae fuentes (`QFontDatabase: Cannot find font directory`). Cosmético para
H-QML (no bloquea la instanciación), pero desplegar dejavu/fontconfig antes de apps reales.
### Hidratación del ESCRITORIO COMPLETO — store-directa, rebuild-free (2026-07-14)
`install`-reproduce NO escala al escritorio completo: el hashing determinista es frágil bajo el régimen
dinámico — cada consumidor qt (qtwayland/kwin) recomputa el cierre de build y puede obtener un hash de
qtbase distinto del sellado → **rebuild** (se observó qtbase rebuildeándose al instalar qtwayland). La
vía correcta es **`takana hydrate <hash> --into` = proyectar el artefacto YA SELLADO del store al FHS,
sin reproduce**. `scripts/kde/hydrate-from-store.sh`:
- computa el cierre (nombres reales qt6-*) y, por paquete, elige el artefacto `store/<hash>-<name>` MÁS
RECIENTE con mtime **anterior al inicio de hoy** (CUTOFF) = la cosecha FINAL de la granja (set
coherente, todo contra el mismo qtbase del cascade; evita los rebuilds ad-hoc de la sesión).
- **Resultado: 137/137 proyectados, 0 faltantes, 1257 `.so`, 241 binarios, 5.0G** en `work/kde-store-
rootfs`. Los hashes elegidos coinciden EXACTO con los sellados de la campaña (kwin `3a674cb6`,
plasma-workspace `284c862f`, libplasma `963403fe`, kscreenlocker `55120487`, breeze `df1d1e68`,
kio `44376420`). Binarios presentes: `plasmashell kwin_wayland startplasma-wayland krunner
plasma_session kscreenlocker_greet` (ksmserver no existe en Plasma 6 Wayland → plasma_session).
- **CIERRE RUNTIME VERIFICADO COMPLETO**: todos los `NEEDED` de plasmashell (30), kwin_wayland (24),
startplasma-wayland (11), krunner (19) y libs core (libPlasma/libPlasmaQuick/libKF6XmlGui/libQt6Quick)
resuelven dentro del rootfs+sysroot musl. **Cero dependencias colgantes** — el objetivo "capturar el
cierre runtime" queda cumplido para el escritorio entero.
`hydrate-fhs.sh` (install-reproduce) queda para validar UN closure chico con verificación de firma
end-to-end (como H-QML); `hydrate-from-store.sh` es la vía para el rootfs de PRODUCTO completo.
### Próximo paso concreto
Con H-QML cerrado y el escritorio hidratado con cierre runtime completo, lo que falta para "escritorio
VIVO" es: (1) **arrancar `startplasma-wayland` sobre `kwin_wayland` en metal/VM con GPU** (el worker es
headless glibc — necesita KMS/DRM real; coordinar con [[arranque-grafo-mirada]] / QEMU-GPU); (2)
desplegar fuentes (dejavu/fontconfig, hoy warning); (3) empaquetar `work/kde-store-rootfs` como imagen
de disco (reusar `scripts/disk-image.sh`/`install-image-efi.sh`). En paralelo, **Capa 2 (KDE Frameworks
6)**: `extra-cmake-modules` ya está; atacar tier 1
(`kcoreaddons`, `kconfig`, `ki18n`, `kirigami`…) hacia el hito **H-KF6** (una app KDE de ejemplo
corre). En paralelo saldar la deuda Capa 0 (sqlite/openssl/glib shared-PIC) para promover un qtbase
"real" a canónico/firmado. Mantener la hidratación FHS como el patrón de validación por capa.