ADR 0015 (propuesto): imágenes ajenas — el mundo glibc entra enjaulado y no entra al store

Decide la frontera antes de escribir código. Sale de una medición incómoda: el
corpus tiene cuatro escritorios que cierran y CERO navegador, ofimática,
reproductor o editor de imagen. Al partir el «qué falta» por causa, la
intersección de «sólo X11» con «compilable desde fuente en musl» es casi vacía:
casi todo lo que se pierde por Wayland ya estaba perdido por la libc. El montón
que duele son binarios ajenos que nadie va a recompilar.

Las siete decisiones:

D1 — Una imagen ajena NO es un artefacto y no vive en el store. El store promete
     reconstrucción bit a bit desde fuente; un rootfs de Fedora no. Meterlo ahí
     sería la misma clase de error que el artefacto vacío: algo que se lee como
     garantía y no lo es. Namespace paralelo, por digest, fuera de hash_inputs.
D2 — Se cruza el borde con protocolos y nodos de dispositivo, NUNCA con
     librerías. Wayland/PipeWire son protocolos; /dev/dri y /dev/ntsync son ABI
     de kernel. Mesa va adentro de la imagen. Corolario: la jaula no sabe qué
     libc hay adentro, y por eso resuelve el montón entero de una vez.
D3 — El manifiesto es la verdad; el `upper` del overlay es CACHÉ. Misma relación
     que receta↔artefacto. De ahí se caen solas la actualización de base (se
     recrea, no se rebasea), el respaldo (KB, no GB) y la poda.
D4 — Cuatro granularidades, no una. El runtime curado inmutable (tipo 2) sigue
     siendo el preferido cuando alcanza: se sella. El rootfs con dnf existe
     porque es justo lo que el tipo 2 no permite.
D5 — Transparencia por shims GENERADOS, no por un FUSE global. Es el poder de
     Bedrock sin sus formas: cero costo en runtime, inspeccionable, revocable, y
     se exporta lo declarado (Bedrock arbitra en tiempo de exec, con heurísticas).
     Los nodos exportados entran al grafo con clase `ajeno` ⇒ no se pueden contar
     como corpus. Bedrock no puede decirte qué tenés.
D6 — Steam ya ES un contenedor: se anida pressure-vessel adentro, que es la
     configuración que Valve prueba. El bwrap anidado hay que VERIFICARLO.
D7 — Es el único lugar del sistema donde la política se escribe en vez de
     derivarse. harkaq deriva `política = clausura(deps)`; una imagen ajena no
     tiene clausura declarada. Excepción nombrada y acotada, por defecto vacía.

Y lo que el ADR admite que NO resuelve, escrito para no descubrirlo en producción:
el socket de Wayland es un borde de privilegio y lo pasamos crudo (screencopy y
virtual-keyboard incluidos — Flatpak pasa un proxy filtrante, nosotros no lo
tenemos); el UID mapping va a fallar primero y las piezas ya están en el corpus
(shadow instala newuidmap/newgidmap y crea /etc/subuid vacío, falta
provisionarlo); es una segunda cadena de suministro sin garantías; y hay que
acotar por escrito el claim de bit-repro o la cultura de números honestos se
erosiona sola.

Se cae gratis: `xwayland` deja de ser deuda del corpus (va DENTRO de la imagen,
que ya lo trae, y se cuelga de kwin por el socket) ⇒ el wanted de KDE se
disolvería sin escribir la receta y sin tocar Wayland-only. GIMP e Inkscape dejan
de reabrir la deuda GTK3. Y del plan de juegos: F2 (glibc+multilib desde fuente,
«una campaña entera») queda CANCELADA y F0 (flatpak+ostree al catálogo)
innecesaria.

Lo nativo no se afloja: el montón A se sigue construyendo, en orden mpv → OBS →
Firefox.

Toca sólo documentación: el ADR nuevo, la nota de generalización en
plan-jaula-juegos.md §Capa 3, y el comentario en targets.toml que evita que
alguien escriba la receta de xwayland sin ver la decisión pendiente. Cero recetas
tocadas, cero re-hasheo: --kde sigue en 978 sealed / 1 wanted / 171-171, CIERRA.
This commit is contained in:
Sergio
2026-09-03 02:49:40 +00:00
parent 3b275f482e
commit 776692d01a
3 changed files with 336 additions and 0 deletions
+322
View File
@@ -0,0 +1,322 @@
# ADR 0015 — Imágenes ajenas: el mundo glibc entra enjaulado, y no entra al store
- **Estado:** PROPUESTO — sin implementar. Este documento decide la frontera; el código viene después.
- **Fecha:** 2026-09-03
- **Frontera (a crear):** `hammer ajenas {traer,crear,correr,exportar,listar,podar}`,
`/var/lib/hammer/ajenas/<sha256>/`, `/var/lib/hammer/instancias/<id>/`,
`instancia.toml` (manifiesto), clase de nodo `ajeno` en `build-state.py`.
- **Continúa:** [SDD 04](../04-overlay.md) (overlay), [SDD 16](../16-harkaq-jaula.md) (harkaq),
[ADR 0004](0004-no-custom-nix.md) (hammer no usa nix), [SDD 20](../20-catalogo-publicable-y-completa.md)
(catálogo publicable).
- **Absorbe:** [`plan-jaula-juegos.md`](../plan-jaula-juegos.md) §Capa 3. Su **F1** pasa a ser un
caso particular de este ADR (imagen de tipo 2); su **F0** (flatpak al catálogo) queda innecesaria;
su **F2** (glibc + multilib 32-bit desde fuente, «una campaña entera») queda **cancelada**.
---
## Contexto
### El problema, medido
El corpus tiene hoy 788 recetas selladas y cuatro escritorios que cierran. De apps de usuario final
tiene esto:
```
kate konsole dolphin okular gwenview ark spectacle kcalc filelight kfind · foot · vim
```
Ni navegador, ni suite ofimática, ni reproductor, ni editor de imagen. La pregunta natural es qué
lo impide, y la respuesta se parte en tres montones **con causas distintas**:
| montón | qué hay adentro | qué lo bloquea |
|---|---|---|
| **A** | Firefox, Chromium, LibreOffice, mpv, GIMP, Inkscape, Blender, OBS | **nada estructural**: son Wayland-nativos y compilables. Falta escribirlas. |
| **B** | Steam/Proton, IDEs de JetBrains, Zoom/Slack/Discord/Spotify, binarios comerciales | **la libc**. Son prebuilts glibc. Mueren en el loader, antes de tocar el servidor gráfico. |
| **C** | herramental X11: `xdotool`, `xbindkeys`, `x11vnc`, Barrier | **Wayland**, y Xwayland tampoco los salva (sólo ve clientes X). |
La medición que ordena el debate: **la intersección de «sólo X11» con «compilable desde fuente en
musl» es casi vacía**. Casi todo lo que se pierde por Wayland ya estaba perdido por musl. El montón
que duele es **B**, y ninguna cantidad de trabajo en el corpus lo mueve: son binarios que nadie va a
recompilar.
### Por qué no alcanza con lo que ya decidimos
Tres salidas parecen razonables y las tres son peores:
1. **Construir glibc + multilib 32-bit en el corpus.** Es la F2 del plan de juegos, descrita ahí
mismo como «una campaña entera»: toolchain dual, loader, locales. Y aun así no corrés Steam: el
cliente espera un userland glibc completo, no una libc suelta.
2. **Flatpak al catálogo** (F0 del mismo plan). Funciona, pero mete ostree + flatpak + su modelo de
runtimes y portales, y la cadena de custodia pasa a ser de flathub, no nuestra. Era la validación
barata mientras no hubiera jaula propia.
3. **Aflojar Wayland-only.** No resuelve B —el problema es la libc— y sí revierte una decisión
tomada con fundamento.
### Lo que ya está construido
Este ADR compone piezas existentes. No inventa infraestructura:
| pieza | dónde | estado |
|---|---|---|
| aislamiento de namespaces | `recipes/bwrap.toml` | sellada; ya es dep del lab de build |
| capa mutable sobre base inmutable | [SDD 04](../04-overlay.md) + `crates/hammer-overlay` | overlayfs, `hammer try` |
| política de grano fino en el kernel | [SDD 16](../16-harkaq-jaula.md) | Landlock + seccomp; fase 1 ✅, barrido con 0 irreducibles |
| rootfs ajeno pineado por sha256 | `scripts/lab-image.sh` | en producción desde 2026-08-10 |
| `newuidmap` / `newgidmap` / `/etc/subuid` | `recipes/shadow.toml` | **instalados**; falta provisionarlos |
| kernel con lo necesario | `recipes/linux-metal.toml:111-114` | `OVERLAY_FS` (+redirect_dir/index/xino/metacopy), `USER_NS`, `NAMESPACES`, `SECURITY_LANDLOCK`, `SECCOMP` |
Nada de esto hay que re-sellar. El kernel propio ya arranca con todo encendido.
---
## Decisión
**Se adopta un subsistema de imágenes ajenas: rootfs de otras distribuciones, traídos enteros y
pineados por digest, que corren enjaulados sobre el mismo kernel y comparten con el escritorio
únicamente protocolos y nodos de dispositivo. Sus artefactos NO entran al store.**
### D1 — La invariante del store
> **Una imagen ajena no es un artefacto y no vive en el store.**
No es prolijidad. El store promete que **cada entrada se reconstruye desde fuente bit a bit**. Un
rootfs de Fedora no. Meterlo ahí haría que el store mienta, y sería la misma clase de error que el
artefacto vacío que ya nos costó caro: *algo que se lee como garantía y no lo es*
(`CLAUDE.md` regla 3 — «un ausente falla ruidosamente; un vacío llega hasta el final diciendo que
todo fue bien»).
Espacio de nombres paralelo, direccionado por digest, **fuera de `hash_inputs` de todo**:
```
/var/lib/hammer/ajenas/<sha256>/ imagen — INMUTABLE, verificada por digest
/var/lib/hammer/instancias/<id>/
├── instancia.toml manifiesto — LA VERDAD
├── upper/ capa mutable — CACHÉ
└── work/ overlayfs
```
El precedente exacto ya existe y funciona: `scripts/lab-image.sh` trae el rootfs del lab pineado por
sha256 porque `apk add` contra Alpine edge es irrepetible por diseño. Misma figura, otro consumidor.
### D2 — La regla del borde
> **Se cruza el borde con protocolos y nodos de dispositivo, nunca con librerías compartidas.**
| qué | cómo cruza | por qué |
|---|---|---|
| pantalla | socket `wayland-0` | protocolo, no ABI. La imagen trae su `libwayland`. |
| audio | socket de PipeWire | ídem |
| IPC | socket de D-Bus (opcional, por sesión) | ídem |
| GPU | `/dev/dri/*` | ABI de kernel (DRM), estable |
| juegos | `/dev/ntsync` | ABI de kernel |
| input | `/dev/input/*` (sólo si se concede) | ABI de kernel |
| **Mesa / libc / cualquier `.so`** | **no cruza** | nuestro Mesa es musl; un proceso glibc no lo carga. La imagen trae el suyo, que habla DRM con nuestro kernel sin conocerlo. |
El corolario práctico: **la jaula no sabe ni le importa qué libc hay adentro.** Glibc, musl ajeno,
uclibc, bionic. Lo único que cruza es la ABI del kernel, que es estable por contrato. Por eso este
mecanismo resuelve el montón B completo de una sola vez.
El error a evitar —y es el que convierte esto en un pantano— es intentar compartir librerías del
host «para ahorrar espacio».
### D3 — El manifiesto es la verdad; el `upper` es caché
> **Una instancia se declara, no se acumula.**
Si el `upper` con 200 paquetes instalados a mano fuese el activo, tendríamos un blob irreemplazable:
justo lo que hammer existe para no tener. La relación correcta es la misma que receta↔artefacto:
```toml
# /var/lib/hammer/instancias/juegos/instancia.toml
base = "sha256:…" # digest de la imagen, inmutable
distro = "fedora-43" # informativo
paquetes = ["steam", "mesa-dri-drivers", "mesa-vulkan-drivers"]
[concesiones] # POR DEFECTO NADA
sockets = ["wayland", "pipewire"]
devices = ["/dev/dri", "/dev/ntsync"]
directorios = [{ host = "~/Juegos", dentro = "/home/usuario/Juegos", modo = "rw" }]
red = true # lo necesita dnf y lo necesita Steam
[exporta] # capa de transparencia; ver D5
binarios = ["steam"]
apps = ["steam.desktop"]
```
Consecuencias que se caen solas:
- **`hammer ajenas recrear <id>`** reconstruye la instancia desde el manifiesto. El `upper` es
descartable.
- **Actualizar la base** (Fedora 43 → 44) no es un rebase riesgoso: se cambia el digest y se recrea.
- **El respaldo** es el manifiesto (KB), no el `upper` (GB). `respaldo-storagebox.sh` no toca
`/var/lib/hammer/instancias/*/upper` y eso es correcto, no un olvido.
- La poda tiene una regla trivial: **un `upper` siempre se puede borrar.**
### D4 — Granularidad: cuatro tipos, no uno
| tipo | qué es | mutable | ¿sellable? | para qué |
|---|---|---|---|---|
| **1** | rootfs completo con gestor (Fedora+`dnf`, Arch+`pacman`) | sí | no | «literalmente lo que sea» |
| **2** | runtime curado congelado (Steam Linux Runtime *sniper*, runtime freedesktop) | **no** | **sí**, `file_drop` por sha256 | cadena de custodia nuestra |
| **3** | bundle por app (AppImage) | no | sí | una app suelta |
| **4** | glibc en un prefijo, sin jaula | — | — | **rechazado**: frágil y ensucia justo lo que se protege |
El tipo 2 es la F1 del plan de juegos y **sigue siendo el preferido cuando alcanza**: es inmutable,
se sella y su digest entra en el índice firmado. El tipo 1 existe porque `dnf install` es
precisamente lo que el tipo 2 no permite.
### D5 — Transparencia: shims generados, no un sistema de ficheros
El objetivo es el poder de Bedrock Linux —un espacio de nombres unificado, apps de cualquier
«stratum» disponibles en todos lados— **sin sus formas**: un FUSE global en el camino de cada
`exec`, integración a nivel de PID 1, y arbitraje por heurística de qué binario gana.
Acá no hace falta nada de eso, porque **el FHS de esta distro ya es una proyección, no la verdad**:
`hammer hydrate` proyecta artefactos del store a un árbol. Extender la proyección a instancias es
idiomático. Tres capas:
**Capa 1 — shims.** Al crear o actualizar una instancia se **generan** lanzadores finos en el
espacio del host: un script que hace `exec` hacia adentro, más el `.desktop` con su icono. Firefox
de Fedora aparece en el menú de Plasma al lado de kate; `steam` está en el `PATH`.
Gana en tres cosas concretas contra el FUSE:
- **cero costo en runtime** — no hay proceso en el camino crítico de cada `exec`;
- **inspeccionable** — `cat` al shim y ves exactamente qué hace;
- **revocable** — se borran los shims y la instancia desaparece del sistema sin desmontar nada.
**Se generan, no se copian.** El `Exec=` de un `.desktop` ajeno es texto ajeno; copiarlo pondría
una línea de comando que no escribimos en el menú del usuario.
**Capa 2 — se exporta lo declarado.** Si se exporta todo, el `ls` y el `systemctl` de Fedora compiten
con los nuestros. Ésa es la falla de Bedrock: **arbitra en tiempo de `exec`**, con heurísticas. Acá
la lista `[exporta]` del manifiesto resuelve la ambigüedad **al declarar**. Tiene precedente directo:
la hidratación del escritorio ya va por lista explícita (`TARGETS="…"`), nunca por glob.
**Capa 3 — el grafo lo sabe.** Los nodos exportados entran en `build-state.json` con **clase
`ajeno`**, y el reporte pasa a decir:
```
escritorio-kde 171 nativas + 6 ajenas (ajenas: sin procedencia de fuente, sin repro)
```
Bedrock no puede decirte qué tenés. Nosotros sí, y esto cierra el riesgo real de todo el ADR: que en
seis meses alguien cuente esas apps como parte del corpus. **En otra clase no se pueden contar mal.**
### D6 — El caso Steam, que es el que ordena el diseño
Steam **ya es un contenedor**: el cliente corre en el sistema y los juegos corren dentro de
*pressure-vessel*, el contenedor bwrap de Valve con el runtime *sniper*. La forma correcta no es
meter Steam en nuestra jaula sino anidarlas:
```
arje-zero → kwin (wayland)
└─ instancia glibc (tipo 1: drivers, libs de 32 bits, dnf)
└─ cliente Steam
└─ pressure-vessel (tipo 2, de Valve) ← anidado
└─ el juego + Proton
```
Corre mejor así porque **es la configuración exacta que Valve prueba**. Nosotros ponemos el nivel de
afuera y la política; adentro no tocamos nada.
**Verificar, no asumir:** pressure-vessel necesita crear user namespaces *desde dentro* de uno ya
creado. El kernel los tiene encendidos, pero el anidamiento hay que probarlo con un juego real. Es
la clase de cosa que sella verde y falla en la mano del usuario.
### D7 — La política se escribe, y es la única vez
harkaq deriva la política en vez de escribirla: `política = clausura(deps declaradas)`, y de ahí sale
la evidencia negativa que hace valioso al subproducto ([SDD 16](../16-harkaq-jaula.md) §3).
**Una imagen ajena no tiene clausura declarada.** Es el primer y único lugar del sistema donde la
política hay que **autorarla**. No es un defecto: es una excepción que conviene nombrar y acotar en
vez de descubrir. El bloque `[concesiones]` del manifiesto es esa política, **por defecto vacío**, y
se compila al mismo `PolicySpec` que ya consume `harkaq-exec`.
Un `dnf` que no alcanza `~/.ssh` es un argumento que ninguna distro ofrece.
---
## Lo que este ADR admite que NO resuelve
Se escriben acá para que no se descubran en producción.
1. **El socket de Wayland es un borde de privilegio, no un caño.** Pasarlo crudo le da a la imagen
ajena todos los protocolos privilegiados que exponga el compositor: `screencopy`,
`virtual-keyboard`, `input-method`. Flatpak no pasa el socket: pasa un **proxy que filtra
globals**. No lo tenemos. Mientras no exista, **una instancia con socket de Wayland puede
capturar la pantalla y sintetizar teclas**, y el manifiesto debe decirlo en la cara del usuario.
Cerrarlo es tarea propia y probablemente el ticket más valioso que sale de este ADR.
2. **UID mapping.** Sin userns privilegiados, `root` adentro es tu UID afuera — que es la propiedad
de seguridad que queremos, pero rompe operaciones que hacen `chown` a UIDs distintos (rpm crea
usuarios de servicio). La salida son rangos subuid, y **las piezas ya están en el corpus**:
`recipes/shadow.toml` instala `newuidmap`/`newgidmap` y crea `/etc/subuid` vacío. Falta
provisionarlo (capacidad de fichero o setuid + rango en `/etc/subuid`) y probarlo con un `dnf
install` real. Es la primera cosa que va a fallar.
3. **Segunda cadena de suministro, sin ninguna garantía de hammer.** Sin repro, sin cierre firmado,
sin escaneo de licencias. El riesgo no es técnico: es que se normalice. Mitigación = D5 capa 3
(clase `ajeno` en el grafo) + un renglón explícito en [SDD 20](../20-catalogo-publicable-y-completa.md):
**las imágenes ajenas no entran en el catálogo publicable ni en el reporte de licencias, porque
no podemos enumerarlas.**
4. **El alcance del claim.** Desde el día que exista una instancia, la frase «hammer reproduce bit a
bit» hay que acotarla por escrito: *el sistema base reproduce; las instancias ajenas no, y se
declaran como tales*. Sin eso, la cultura de números honestos se erosiona sola — que es
exactamente la falla que ya nos pasó con el store-gc y con la deuda fantasma.
5. **Disco.** Un rootfs de Fedora son 1-2 G y no lo alcanzan `store-gc` ni `.dmerge`. Necesita poda
propia. Este repo ya tuvo tres emergencias de disco; que la poda nazca con el subsistema, no
después.
6. **Red adentro.** `dnf` la necesita. Es la concesión más peligrosa del manifiesto y por eso es la
única que se escribe sola en una línea aparte. También hace falta `/etc/resolv.conf`: es el
segundo fallo clásico de la primera corrida.
7. **X entre instancias.** Un Xwayland dentro de una instancia levanta *su* servidor X. Portapapeles
con el escritorio funciona (pasa por el compositor); entre dos instancias, no. Aceptado.
---
## Lo que se cae, y lo que se resuelve gratis
- **`xwayland` deja de ser deuda del corpus.** Si las apps X sólo corren dentro de instancias, el
Xwayland va **adentro de la imagen** —Fedora y Arch ya lo traen— y se cuelga de nuestro kwin por
el socket. El nodo `wanted` de `escritorio-kde` se disuelve sin escribir la receta y sin tocar la
postura Wayland-only. `targets.toml` debe sacarlo de las raíces con una nota que apunte acá.
- **GIMP e Inkscape dejan de reabrir GTK3.** Son GTK3 y GTK3 está aparcado a propósito
(ver la memoria del frente GNOME). Con instancias, corren sin traer el árbol GTK3 al corpus.
- **F2 del plan de juegos, cancelada.** Las libs de 32 bits las trae la imagen.
- **F0 del plan de juegos, innecesaria.** No hace falta meter flatpak+ostree al catálogo para tener
juegos.
## Lo que este ADR NO cambia
- **El montón A se sigue construyendo nativo.** La jaula es para binarios ajenos, no una excusa para
no empaquetar. Orden acordado: **mpv → OBS → Firefox**.
- **Wayland-only sigue en pie**, y este ADR es lo que lo hace barato.
- **arje-zero sigue siendo PID 1.** Nada de integración a nivel de init, que es una de las formas de
Bedrock que se rechazan explícitamente.
- **Cada instancia se gestiona con su propio gestor**, entrando explícitamente. Nada de multiplexar
`dnf`/`pacman` detrás de un comando único (el `pmm` de Bedrock): es menos mágico y no miente.
---
## Orden de trabajo propuesto
1. **Provisionar subuid** y probar `dnf install` en una instancia mínima. Es lo primero que falla
(§NO-resuelve 2) y define si el resto es fácil o difícil.
2. `hammer ajenas traer <url> --sha256` + verificación de digest. Reusa el patrón de `lab-image.sh`.
3. Instancia = overlay sobre la imagen + `instancia.toml`; `crear` / `recrear` / `correr`.
4. Concesiones → `PolicySpec` de harkaq. Empezar por **nada** y abrir sólo lo declarado.
5. Shims + `.desktop` generados (`exportar`), y clase `ajeno` en `build-state.py`.
6. **Steam de punta a punta**, con verificación explícita del bwrap anidado.
7. Poda (`hammer ajenas podar`) y renglón en SDD 20 sobre licencias.
8. Proxy filtrante de Wayland — ticket propio, el más valioso de la lista.
## Nombre
El subsistema pide un nombre de la familia del repo (harkaq, yupana, arje, wawafs, kikin, churay,
mirada, minga, khipu). Propuesta: **`qorpa`** — *huésped alojado*: alguien que entra a la casa, se
le dan habitaciones concretas y no las demás. Encaja con lo que hace y con cómo se comporta. Queda a
criterio del autor del repo; el resto del ADR no depende del nombre.
+9
View File
@@ -55,6 +55,15 @@ verificación existente, como el 2b7c701.
## Capa 3 — la jaula glibc (el elefante, por fases)
> **⚠ GENERALIZADO por [ADR 0015 — Imágenes ajenas](adr/0015-imagenes-ajenas.md) (2026-09-03,
> PROPUESTO).** Esta capa razonaba sobre un runtime concreto de Valve; el ADR razona sobre
> cualquier rootfs ajeno y decide la frontera con el store. Si el ADR se acepta: **F1** queda como
> caso particular (imagen «de tipo 2»: curada, inmutable, sellable por `file_drop`), **F0**
> (flatpak+ostree al catálogo) queda innecesaria, y **F2** (glibc + multilib 32-bit desde fuente)
> queda **cancelada** — las libs de 32 bits las trae la imagen ajena. El resto de este plan
> (capas 1 y 2, todo lo nativo) no cambia.
Steam, Proton y el catálogo de juegos son binarios glibc, parte 32-bit. musl no los va a
correr y perseguir eso es un pozo. La respuesta con ADN hammer: **el runtime ajeno se trae
entero, pineado por hash, y corre enjaulado** — verificar, no confiar, aplicado a un rootfs
+5
View File
@@ -63,6 +63,11 @@ paquetes = [
# roto: sin tipos de fichero, sin apps X11, sin diálogos de autorización y con los controles QML
# en un estilo genérico. Ver docs/state/frontera-triaje.toml para el porqué de cada uno.
"shared-mime-info", "xwayland", "polkit-qt-1", "qqc2-breeze-style",
# ⚠ `xwayland` sigue acá pero su receta NO se escribe todavía: [ADR 0015 — Imágenes ajenas]
# (../adr/0015-imagenes-ajenas.md, PROPUESTO 2026-09-03) propone que el Xwayland viva DENTRO de
# la imagen ajena —Fedora y Arch ya lo traen y se cuelga de kwin por el socket— con lo cual este
# hueco se disuelve sin receta y sin tocar la postura Wayland-only. Si el ADR se acepta, sale de
# esta lista. Los otros tres ya están sellados (2026-09-02/03).
]
[perfil.escritorio-gnome]