perfiles: metal-tigerlake es una CAPA DE HARDWARE componible, no otra lista por escritorio

El SDD 27 §2 dice que el repo mezcla tres capas —piso, escritorio, extras— en una sola
lista por escritorio, y que esa es la causa de que la composición no esté definida. El
firmware es un cuarto caso que el SDD no nombra y que sigue la misma lógica: no es un
escritorio ni un toolbox, es lo que hace falta para que un METAL CONCRETO arranque con todo
su hardware vivo.

Por eso va como perfil propio y se compone, en vez de duplicarse en los cuatro escritorios:

    scripts/targets.py cli metal-tigerlake escritorio-kde

Otro metal = otro perfil de estos con su propia receta firmware-<plataforma> derivada del
mismo linux-firmware. Ese es el punto de haber partido el firmware en base + derivada.

La máquina, medida con lspci/cpuinfo sobre el metal real:

    CPU    i7-11370H · family 6 · model 140 (0x8c) · stepping 1   ⇒ intel-ucode/06-8c-01
    GPU    TigerLake-LP GT2 [Iris Xe] [8086:9a49]                 ⇒ i915 / xe
    WiFi   Intel Wi-Fi 6 AX201 [8086:a0f0]                        ⇒ iwlwifi
    Audio  500 Series HD Audio [8086:a0c8]                        ⇒ snd_sof_pci_intel_tgl

Y zsh entra en `cli`, no en `base`: base define el shell del SISTEMA (bash) y esto es el
del usuario. Dos hechos distintos, como `paquetes` y `servicios` un piso más abajo.

El runbook deja el encargo para el worker, y su parte útil son los dos muros que aparecieron
al cruzar ficheros que nadie había leído juntos:

  1. takana-live-install.sh:275 bifurca «UEFI ⇒ rama EFI-stub soberana», y metal-usb-sdboot.sh
     dice que el EFI-stub «en el firmware del usuario se cuelga tras Measured initrd PCR 9».
     ES EL MISMO FIRMWARE. El lazo de instalación EFI está validado en OVMF, que no tiene ese
     quirk ⇒ el instalador va a pasar la prueba y colgarse en el metal de destino. La salida
     es llevar el instalador a systemd-boot, que es el camino ya probado en esta máquina.
  2. El instalador reparticiona en MBR el disco entero, y ese disco tiene /home con 893 G
     usados. Si la instalación conserva /home o se lleva el disco con respaldo previo es
     decisión del usuario, no del runbook — y hasta que se decida, no correrlo sobre el NVMe.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-16 15:12:29 -04:00
co-authored by Claude Opus 5
parent 38c2874e48
commit 11a9ead671
2 changed files with 196 additions and 0 deletions
@@ -0,0 +1,143 @@
# Runbook — el instalador para la laptop del usuario (TigerLake), y los dos muros que tiene delante
> **Estado: ENCARGO, no cerrado.** Las recetas de este runbook se escribieron el 2026-09-16 desde el
> propio laptop —que no tiene lab ni store— así que **ninguna está sellada**. Lo que sigue es el
> trabajo para el worker, en orden, con lo que ya está medido separado de lo que hay que averiguar.
> Hermano de [`kde-qemu-desktop.md`](kde-qemu-desktop.md) y [`cosmic-desktop.md`](cosmic-desktop.md),
> de los que reusa todo el andamiaje.
## 0. Qué se quiere
Un medio que arranque en la laptop del usuario e **instale takana reemplazando la Artix** que hay
hoy. No un USB de pruebas —eso ya existe con `mirada-usb.sh`— sino una instalación a disco.
## 1. La máquina, medida
`lspci -nn`, `/proc/cpuinfo` y `lsblk` sobre el metal real, 2026-09-16:
| pieza | qué es | driver | firmware |
|---|---|---|---|
| CPU | i7-11370H · family 6 · model 140 (0x8c) · stepping 1 | — | `intel-ucode/06-8c-01` |
| GPU | TigerLake-LP GT2 [Iris Xe] `[8086:9a49]` | `i915` / `xe` | `i915/tgl_{dmc,guc,huc}*` |
| WiFi | Intel Wi-Fi 6 AX201 `[8086:a0f0]` | `iwlwifi` | `iwlwifi-{QuZ-a0-hr-b0,cc-a0}-*.ucode` |
| Audio | 500 Series HD Audio `[8086:a0c8]` | `snd_sof_pci_intel_tgl` | `intel/sof/sof-tgl.ri` |
| Disco | NVMe 1,8 T | `nvme` | — |
| Firmware del equipo | **UEFI** (`/sys/firmware/efi` presente) | — | — |
## 2. Lo que se escribió para esto (sin sellar)
Cinco recetas nuevas y un perfil. Todas parsean y `takana hash` las acepta; el grafo de deps cierra.
| receta | qué es | nota |
|---|---|---|
| `linux-firmware` | tarball 20260910 pineado (648 MB) | sha256 contrastado contra el `sha256sums.asc` de kernel.org |
| `sof-firmware` | sof-bin v2025.12.2 | **no está en linux-firmware** — medido, 0 coincidencias |
| `intel-ucode` | microcode-20260812 | tampoco: Intel lo publica aparte |
| `firmware-tigerlake` | derivada: recorta ~25 MB de las tres familias de este metal | la única que viaja en la imagen |
| `zsh` | el shell de login del usuario | seis parches de musl de Alpine |
| `[perfil.metal-tigerlake]` | la capa de hardware, componible con cualquier escritorio | `firmware-tigerlake` + `intel-ucode` |
Esto cierra el `TODO(soberanía)` que `scripts/metal-firmware.sh` llevaba desde que se escribió: hasta
hoy el firmware se **copiaba de `/lib/firmware` del host**, o sea de la Artix que veníamos a
reemplazar. Un instalador que sólo se puede construir desde la distro que viene a sustituir no es un
instalador.
## 3. La tanda — qué construir, en orden
El orden importa: `firmware-tigerlake` depende de las dos de firmware y falla ruidosa si no las
encuentra materializadas.
```sh
cd /opt/takana
flock -o work/.farm-build.lock bash -c '
for r in linux-firmware sof-firmware intel-ucode firmware-tigerlake zsh; do
./target/release/takana --store ./store build "$r" || { echo "FALLÓ: $r"; break; }
done'
```
`flock -o`, no `flock` a secas — CLAUDE.md §1, y está medido: el lock lo sostiene la descripción de
fichero abierta y los nietos la heredan.
### Lo que puede salir mal, y cómo se ve
- **`zsh` sale dinámico.** Es lo que le pasó a `bash`: si el `configure` mete `-rdynamic`, el wrapper
de cc del lab tira el `-static` y el binario queda contra `libncursesw.so.6`, que ningún artefacto
del corpus provee. Síntoma: `Error relocating ... symbol not found`. Arreglo conocido:
`make LOCAL_LDFLAGS=`. **Comprobar con `file`: debe decir `statically linked`.**
- **`linux-firmware` tarda y pesa.** 648 MB de fetch, ~2 GB extraídos. El worker tiene 71 G libres.
- **`firmware-tigerlake` aborta con `0 blobs de SOF`.** Significa que `sof-firmware` no se materializó
como dep. No ablandar la aserción: ese contador es la única defensa contra un `/lib/firmware` a
medias, que no falla al construir y falla meses después en el metal como «no hay WiFi».
## 4. ⚠ Muro 1 — la rama EFI del instalador es justo la que se cuelga en este firmware
Éste es el hallazgo que ordena el trabajo, y sale de cruzar dos ficheros que nadie había leído juntos.
`scripts/takana-live-install.sh:275-281` detecta el firmware y bifurca:
> `--- Detección de firmware: UEFI ⇒ rama EFI-stub SOBERANA (ADR 0010 paso 5); BIOS ⇒ MBR+GRUB ---`
O sea: en esta laptop, que es UEFI, el instalador tomaría **la rama EFI-stub**. Y
`scripts/metal-usb-sdboot.sh` dice, en su tercera línea:
> *Alternativa de BRINGUP al boot por EFI-stub directo (que **en el firmware del usuario se cuelga
> tras 'Measured initrd PCR 9'**, por el quirk de LoadOptions del firmware).*
**Es el mismo firmware.** El lazo completo de instalación EFI está validado en OVMF
(`scripts/efi-install-test.sh`), y OVMF no tiene ese quirk. Así que el instalador probablemente
funcione perfecto en la prueba y se cuelgue en el metal de destino.
Las tres salidas, en orden de coste:
1. **Llevar el instalador a systemd-boot**, que es el camino ya probado en este metal: pasa una
cmdline limpia y entrega el initrd por `LoadFile2`, esquivando el quirk. El precio está escrito y
aceptado como deuda: `systemd-bootx64.efi` es un binario ajeno del host — crutch de bringup.
2. **Arrancar el medio por systemd-boot y dejar que instale la rama EFI-stub.** No sirve: el disco
instalado arrancaría por EFI-stub y se colgaría igual, sólo que después de borrar Artix.
3. **Loader soberano propio.** Es el `TODO` que ya está anotado y no es trabajo de una sesión.
**Recomendado: (1).** Y el test de aceptación no es OVMF: es el USB arrancando en el metal.
## 5. ⚠ Muro 2 — el particionado, y una pregunta que es del usuario
`takana-live-install.sh` particiona en **MBR**, incluida su rama EFI (una ESP tipo `0xEF` en tabla
MBR, que UEFI acepta igual). Sobre el disco de esta laptop eso tiene dos consecuencias:
- El NVMe es de **1,8 T**. MBR direcciona hasta 2 T: entra por poco, pero es el borde exacto del
formato y no hay razón para quedarse ahí cuando el disco ya es GPT.
- El instalador **reparticiona el disco entero**. Hoy ese disco tiene `/home` con **893 G usados de
1,1 T** — el trabajo del usuario, incluido `~/tawasuyu` (497 G).
> **Pregunta abierta, y es decisión del usuario, no del runbook:** ¿la instalación conserva `/home`
> —instalando sólo sobre la raíz de 164 G— o se lleva el disco entero con respaldo previo? El
> instalador hoy no sabe hacer lo primero: no tiene modo «usar esta partición y no tocar las otras».
Mientras eso no se decida, **no correr el instalador sobre `/dev/nvme0n1`.** El camino sin riesgo es
el USB: `metal-usb-sdboot.sh` produce una imagen para `dd` a un pendrive y no toca el disco interno.
## 6. Orden de trabajo propuesto
1. Construir la tanda del §3 y verificar que `zsh` sale estático y que `firmware-tigerlake` reporta
los tres contadores distintos de cero.
2. Armar un USB de prueba con el perfil compuesto y **arrancarlo en el metal**:
```sh
scripts/targets.py cli metal-tigerlake escritorio-kde # la lista de la imagen
scripts/metal-usb-sdboot.sh # → work/hammer-metal-usb.img
```
Lo que se valida acá no es el escritorio: es **el firmware**. Que asocie el WiFi, que el display
tome el DMC y que el DSP de audio levante. Son las tres cosas que hoy sólo funcionan porque las
presta la Artix instalada.
3. Recién entonces, el instalador: la rama systemd-boot del §4 y la decisión de particionado del §5.
4. Y sólo después, KDE/GNOME/COSMIC en metal con GPU real — hoy los tres corren por llvmpipe, que en
QEMU es correcto y en una Iris Xe es tirar la GPU a la basura.
## 7. Lo que este runbook NO resuelve
- **La laptop sigue sin poder hidratar.** Su `.dev-fs/alpine` tiene 104 paquetes contra los 110 de
`lab-toolchain.lock`, así que calcula `ArtifactHash` distintos y no encuentra nada del store
compartido. Hasta que `farm-lab-sync.sh` corra hacia acá, todo lo de este runbook pasa por el
worker.
- **`kitty`, el terminal del usuario, no tiene receta.** `foot` sí está sellada y es el terminal
Wayland del proyecto; sirve de puente, pero no es lo que él usa.
- **Los escritorios en metal con aceleración.** Distinto problema del firmware: es mesa con el driver
Iris real en vez de llvmpipe.
+53
View File
@@ -169,6 +169,15 @@ paquetes = [
"pigz", # gzip en paralelo
"miller", # `jq` para CSV/TSV — el hueco de datos tabulares
"dwarves", # `pahole`: inspeccionar el BTF/DWARF del kernel. Esta distro compila el suyo
# ── BARRIDO DE LA MÁQUINA DEL USUARIO (2026-09-16) ──────────────────────────────────────────
# `zsh` es EL SHELL DE LOGIN del usuario, medido en su historial (1611 `cd`, 1054 `cargo`, 134
# `zellij`), y no tenía receta ni en el corpus ni en ninguna de las cuatro colas. Una imagen de
# takana instalada en su laptop lo dejaba en `bash`: funciona, pero no es su máquina. Entra en
# `cli` y no en `base` porque `base` define el shell del SISTEMA (bash) y esto es el del usuario
# — dos hechos distintos, como `paquetes` y `servicios` un piso más abajo.
# Es el mismo hueco de RUNTIME que `bash-completion`: nadie lo alcanza por deps de build, así que
# ninguna métrica de deuda podía verlo. Sólo se ve mirando la máquina de quien la usa.
"zsh",
]
[perfil.escritorio-mirada]
@@ -1439,3 +1448,47 @@ paquetes = [
# `shell = /bin/sh` —no `/bin/false`—, porque este demonio existe para abrir PTYs: con la shell
# inerte el servicio arranca, se supervisa, y cada pestaña muere al instante.
servicios = ["sshd", "gitea", "caddy", "minga", "squid", "crond", "chronyd", "shuma-daemon", "shuma-gateway"]
# ════════════════════════════════════════════════════════════════════════════════════════════════
[perfil.metal-tigerlake]
descripcion = "capa de HARDWARE de la laptop del usuario: firmware y microcódigo del metal real"
cola = "corpus"
# ── POR QUÉ ES UN PERFIL Y NO PAQUETES SUELTOS EN CADA ESCRITORIO ───────────────────────────────
# Esto no es un escritorio ni un toolbox: es **lo que hace falta para que ESTE metal arranque con
# todo su hardware vivo**. Se compone con cualquiera de los cuatro escritorios en vez de duplicarse
# en los cuatro — que es exactamente el error que el SDD 27 §2 describe («hoy el repo mezcla las
# tres capas en una sola lista por escritorio»).
#
# ── LA MÁQUINA, MEDIDA ─────────────────────────────────────────────────────────────────────────
# `lspci -nn` + `/proc/cpuinfo` sobre el metal real, 2026-09-16:
#
# CPU 11th Gen Intel Core i7-11370H · family 6 · model 140 (0x8c) · stepping 1
# GPU Intel TigerLake-LP GT2 [Iris Xe] [8086:9a49] ⇒ i915 / xe
# WiFi Intel Wi-Fi 6 AX201 [8086:a0f0] ⇒ iwlwifi
# Audio Intel 500 Series HD Audio [8086:a0c8] ⇒ snd_sof_pci_intel_tgl
# Disco NVMe ⇒ nvme (sin firmware)
#
# ── POR QUÉ HASTA HOY NO EXISTÍA ───────────────────────────────────────────────────────────────
# Porque el firmware se COPIABA DEL HOST: `scripts/metal-firmware.sh` lee `/lib/firmware` de la
# Artix que ya está instalada. Eso alcanza para un USB de pruebas y NO alcanza para un instalador —
# un instalador que sólo se puede construir desde la distro a la que viene a reemplazar no es un
# instalador. El `TODO(soberanía)` de ese script es justamente esto.
#
# ── NO ENTRA EN NINGÚN ESCRITORIO POR DEFECTO ──────────────────────────────────────────────────
# Es específico de un modelo de laptop. Se pide explícitamente al armar la imagen:
#
# scripts/targets.py cli metal-tigerlake escritorio-kde
#
# Otro metal = otro perfil de estos, con su propia receta `firmware-<plataforma>` derivada del mismo
# `linux-firmware`. Ese es el punto de haberlo partido en dos recetas.
paquetes = [
# Los blobs de las tres familias de este hardware, recortados del linux-firmware pineado.
# Arrastra por deps a `linux-firmware` (648 MB de tarball) y a `sof-firmware`, que NO van en la
# imagen: sólo viaja el recorte de ~25 MB. Es la misma economía que `atuq` sobre `firefox`.
"firmware-tigerlake",
# Microcódigo de la CPU. Va aparte del firmware porque se carga por otro camino: el árbol plano
# sirve para la carga tardía, y el `GenuineIntel.bin` que la receta deja en
# `/usr/share/intel-ucode/` es el que el armador de la imagen debe prepender al initramfs como
# cpio SIN comprimir para la carga TEMPRANA — la que llega a tiempo para las mitigaciones.
"intel-ucode",
]