SDD 27: perfiles instalables — y la medición de que los escritorios no traen base

PROPUESTA, nada implementado. Escrito a pedido del usuario mientras se tapaba el hueco de upower.

⚠ EL HALLAZGO QUE LO MOTIVA, y es peor de lo que parecía: `targets.toml` ya avisaba que
«kde/gnome/cosmic NO heredan base», pero la consecuencia no estaba escrita en ningún lado. Medida:
**de los 27 paquetes del perfil `base`, la clausura de escritorio-kde alcanza 2**. Y comprobado
contra el rootfs real de la imagen: NO hay `bash`, ni `sudo`/`doas`, ni `git`, ni `useradd`, ni
`gpg`, **ni `dhcpcd`** — o sea que la imagen no sabe pedir una IP. Lo que sí hay (`ip`, `mount`,
`fsck`) son APPLETS DE BUSYBOX: `/sbin/ip → ../bin/busybox`.

O sea que la respuesta a «¿abrir un escritorio es como si base no existiera?» es **sí**. Y la causa
es que hay DOS cosas llamadas base que nadie había distinguido por escrito:
  · base de ARRANQUE (`metal-rootfs`): arje-zero + busybox. La imagen la funde. Existe.
  · base de USERLAND (`[perfil.base]`): las 27. No la funde nadie.

El documento separa las cuatro capas (piso / escritorio / extras / toolbox CLI), explica que un
«metapaquete» YA EXISTE y se llama perfil, y nombra las tres cosas que le faltan para ser
instalable: herencia entre perfiles, publicación al repo firmado, y un verbo que resuelva una LISTA
y no un paquete.

Y plantea la única decisión que no es de implementación: instalar un escritorio REPRODUCIENDO
(coherente con que el canal no distribuya binarios, pero son horas en la máquina del usuario) o
HIDRATANDO artefactos firmados (segundos, pero es entregar binarios y activa entera la obligación
de licencias que se cerró hoy). La salida propuesta es la del ADR 0014: que existan las dos y que
reproducir sea lo que hace verificable a hidratar.

Nota de nomenclatura, porque el usuario preguntó: `.swm` NO es residuo del renombre — significa
«Software Mutación» y describe lo que el fichero ES. El verbo ya es el correcto, `takana install`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LCt3ettR4Z7b6wPCBmbvEV
This commit is contained in:
Sergio
2026-09-09 22:10:59 +00:00
co-authored by Claude Opus 5
parent c4ebb9f5c7
commit 755dcc5c39
@@ -0,0 +1,129 @@
# SDD 27 — Perfiles instalables: del rootfs hidratado al `takana install escritorio-kde`
> **Estado: PROPUESTA.** Nada de lo de acá está implementado. Lo que sí está medido es el punto de
> partida, y las mediciones llevan fecha 2026-09-09. Escrito a pedido del usuario mientras se
> cerraban los huecos de la imagen KDE.
## 0. La pregunta
Hoy sabemos construir. Sabemos hidratar un rootfs y meterlo en una imagen que arranca. Lo que no
existe es **instalar un escritorio como una unidad**: hoy «KDE» es una lista dentro de un fichero
del repo, no algo que un usuario pueda pedir.
Y hay una pregunta previa que el usuario formuló mejor de lo que estaba escrito en ningún lado:
> *el toolbox CLI es general, que sea piso userland del sistema siempre. los extras son igual
> instalaciones, depende de quién instale qué.*
Eso son **tres capas distintas**, y hoy el repo las mezcla en una sola lista por escritorio.
## 1. Lo medido: hoy los escritorios NO heredan la base
`docs/state/targets.toml` declara un perfil `base` de **27 paquetes**: `bash`, `git`, `sudo`, `doas`,
`util-linux`, `shadow`, `kbd`, `procps-ng`, `iproute2`, `iputils`, `dhcpcd`, `e2fsprogs`,
`dosfstools`, `gnupg`, `ca-certificates`… El fichero ya avisa que «kde/gnome/cosmic **NO** heredan
base», pero la consecuencia no estaba escrita. Medida:
> **De los 27 paquetes de `base`, la clausura de `escritorio-kde` alcanza 2.**
Y comprobado contra el rootfs real de la imagen KDE (`kde-qemu-rootfs`):
| se busca | está |
|---|---|
| `bash`, `git`, `sudo`, `doas`, `dhcpcd`, `useradd`, `gpg` | **NO** |
| `ip`, `mount`, `fsck` | sí, pero **son applets de busybox** (`/sbin/ip → ../bin/busybox`) |
| `ssh`, `curl` | sí, de rebote: entran por la clausura de KDE, no por `base` |
**Sí: abrís el escritorio y es como si `base` no existiera.** No hay shell de verdad (busybox `sh`,
no bash), no hay `sudo` ni `doas`, no hay `git`, y **no hay `dhcpcd`** — o sea que la imagen no sabe
pedir una IP salvo lo que haga busybox. Lo que sí hay es el **otro** base: `arje-zero` como PID1 más
busybox, que es lo mínimo para arrancar. Son dos cosas distintas con el mismo nombre coloquial:
- **base de arranque** (`metal-rootfs`): arje-zero + busybox + kernel. La imagen la funde por
hardlinks. Existe.
- **base de userland** (`[perfil.base]`): las 27. **No la funde nadie.**
Esto no es un bug de una imagen: es que la composición entre perfiles **no está definida**.
## 2. Las tres capas que hay que separar
| capa | qué es | quién decide | hoy |
|---|---|---|---|
| **piso** | userland siempre presente: shell, red, usuarios, paquetes, `git` | la distro | existe como `[perfil.base]`, no lo hereda nadie |
| **escritorio** | KDE / GNOME / COSMIC / sway y lo que los hace ser ellos | la distro | existe como perfil, es lo único que se materializa |
| **extras** | lo que cada quien instala encima | el usuario | no existe como operación |
Y hay una cuarta que el usuario nombró y conviene no perder: **el toolbox CLI**. Hoy hay
**652 recetas selladas que ninguna imagen alcanza** — 361 Go, 214 Rust, 67 C — y son casi todas
herramientas de línea de comandos. Ya construidas, ya reproducibles: **coste de build cero, sólo
declararlas**. Si el toolbox es piso, va en la capa 1 y no en cada escritorio.
## 3. Un «metapaquete» ya existe, y se llama perfil
`[perfil.escritorio-kde]` con sus 49 raíces **es** el metapaquete: una lista de nombres cuya
clausura define qué entra. Lo que le falta para ser instalable son tres cosas concretas:
1. **Herencia.** Un perfil tiene que poder decir `hereda = ["base"]` en vez de repetir la lista. Hoy
los cuatro escritorios repiten `dejavu-fonts`, `desktop-file-utils` y las `*-shared` de runtime,
y ya se vio lo que pasa: se añade a uno y se olvida en los otros.
2. **Publicación.** `targets.toml` vive en el repo y es de tiempo de build. Para que el instalador
lo use tiene que salir al repositorio firmado como un objeto más, igual que un `.swm`.
3. **Un verbo.** `takana install escritorio-kde` no existe: `install` resuelve **un paquete** por
nombre en el índice. Instalar un perfil es resolver una LISTA y aplicar su clausura.
## 4. La decisión de fondo del instalador: reproducir o hidratar
Ésta es la única pregunta que no es de implementación, y conviene decidirla antes de escribir código.
**Hoy el canal de paquetes NO distribuye binarios.** `pack` produce un `.swm` —una receta de
transformación sobre fuente pública— e `install` **reproduce construyendo**, con cache-hit del
corpus. Es coherente con todo el diseño: lo que viaja es la receta, no el binario.
- **Reproducir** un escritorio entero en la máquina del usuario son **horas** de compilación (KDE son
301 nodos; Qt y Firefox solos ya son la mayor parte de una tarde). Coherente y honesto, pero
inaceptable como experiencia de instalación.
- **Hidratar desde artefactos firmados** es lo que ya hace `hydrate-profile.py`: segundos, porque
son hardlinks contra el store. Pero eso **es entregar binarios**, y activa entera la obligación de
licencias que se cerró el 2026-09-09 (`scripts/licencias-rootfs.sh`, que veta si un paquete no
declara licencia). También activa la pregunta de confianza: el ADR 0014 ya dice que el cuerpo es
inmutable y direccionado por contenido, así que **el origen no necesita confianza** — lo que se
firma es la raíz, no el servidor.
**La salida no es elegir una: es que las dos existan y el usuario elija**, igual que el ADR 0014 hizo
con los orígenes. Instalar por hidratación es el camino normal; reproducir es el camino auditable, y
que exista es lo que hace verificable al primero. Lo que hay que definir es el **default** — y ahí la
respuesta razonable es hidratar, porque el que quiere auditar puede reproducir cuando quiera y
comparar hashes, que es exactamente lo que `selfhost-verify` ya hace.
## 5. La imagen y el instalador son el mismo problema con dos salidas
Hoy hay dos caminos que hacen casi lo mismo y no se hablan:
- **Imagen**: perfil → `hydrate-profile.py` → rootfs → `install-image-efi.sh``.img` que arranca.
- **Instalador**: TUI + `base-system`, que instala sobre un disco.
Si un perfil es publicable e instalable, los dos son **el mismo verbo con distinto destino**: uno
escribe a una imagen, el otro a una partición. Vale la pena unificarlos antes de que diverjan más:
hoy ya divergieron una vez —los `hydrate-*.sh` por escritorio contra `targets.toml`, con 21 paquetes
declarados que no llegaban a la imagen de GNOME y 17 a la de COSMIC— y costó encontrarlo.
## 6. Sobre el nombre del paquete (`.swm` vs `.tkn`)
`.swm` **no es residuo del renombre**: significa «Software Mutación» y describe lo que el fichero
es —una mutación reproducible sobre una fuente—, no la marca. Renombrarlo a `.tkn` sería alinear
marca y formato, y es defendible, pero **no lo pide ninguna inconsistencia técnica**. Si se hace,
es una decisión de ADR y con la misma disciplina que el renombre de hoy: hay que mirar si la
extensión entra en algún hash o en el índice del repo antes de tocarla.
El verbo, en cambio, ya es el correcto: **`takana install`**.
## 7. Orden propuesto
1. **Herencia entre perfiles** (`hereda = [...]`) y hacer que los cuatro escritorios hereden `base`.
Es lo más barato y arregla un fallo real: hoy los escritorios no traen shell ni red.
2. **Decidir el piso**: qué del toolbox CLI de 652 entra en `base`. Coste de build cero.
3. **Publicar perfiles** al repositorio firmado.
4. **`takana install <perfil>`**, hidratando por defecto y con `--reproduce` como camino auditable.
5. **Unificar imagen e instalador** sobre ese verbo.
Los pasos 1 y 2 se pueden hacer ya y no dependen de ninguna decisión de arquitectura.