gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

el reconciliador ARRANCA solo: montar sysfs, y un diagnóstico que no mentía a medias

Cierra el §2 del ADR 0018, verificado con dos arranques de la imagen
completa en OVMF:

  1º (por la fallback) → "ESP detectada en /dev/vda p1",
     "⚠ EL ARRANQUE ESTABA CAMBIADO — takana lo repuso",
     "faltaba la entrada «takana» ⇒ escrita en Boot0004",
     "BootOrder: 0000,0001,0002,0003 → 0004,0000,0001,0002,0003"
  2º → BdsDxe: starting Boot0004 "takana" from HD(1,GPT,923A070F-…)
       /\EFI\takana\takanax64.efi
       "✓ arranque en orden: Boot0004 «takana» ya es la primera"

Un sistema recién instalado se da de alta en el firmware en su PRIMER
arranque y desde el segundo arranca por su propia entrada, sin que nadie
corra un comando. Y el segundo no escribe nada.

Lo caro no fue el reconciliador sino un diagnóstico FALSO: el primer
arranque con el hook dijo "sin firmware EFI — esta máquina no arrancó
por UEFI" en una VM que SÍ arrancó por UEFI. La causa no tenía nada que
ver con UEFI: busybox switch_root no arrastra /sys —igual que no
arrastra /dev, cosa que el script ya contemplaba— así que el directorio
de efivars no existía. El mensaje mandaba a investigar el firmware, que
estaba perfecto.

Dos arreglos:
- el wrapper monta sysfs y después efivarfs. CONFIG_EFIVAR_FS=y ya
  estaba en el .config SELLADO (verificado, no supuesto) ⇒ no se
  re-hashea ningún kernel.
- el mensaje distingue TRES estados que se parecen: no existe (BIOS o
  /sys sin montar), existe y está VACÍO (falta el mount, y lo dice con
  el comando exacto), o tiene variables. Decir "no hay UEFI" cuando
  falta un mount manda a diagnosticar al lugar equivocado.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HHAKWoBqof9XvsYCvDicEj

66eaf8738fe9e35c8077921c758fd1ce0b7741cb · por Sergio · (hace 1 mes) · padre 236abe48f · ver el árbol en este commit

Delta semántico · 1

crates/takana-cli/src/main.rs

  • cambió por dentro fn main

4 archivos · +69 −2

diff --git a/crates/takana-cli/src/main.rs b/crates/takana-cli/src/main.rs
index 6697884b..d6f6378e 100644
--- a/crates/takana-cli/src/main.rs
+++ b/crates/takana-cli/src/main.rs
@@ -1574,9 +1574,18 @@ fn main() -> anyhow::Result<()> {
                     EntryCmd::Reconcile { loader, label, efivars, sys_block, disk, partition, dry_run } => {
                         // 1) ¿Hay firmware EFI? Sin NVRAM no hay nada que reconciliar, y eso NO es
                         //    un error: puede ser una máquina que arranca por BIOS. Salir limpio.
+                        // Tres estados que se parecen y NO son lo mismo. Decir «no arrancó por UEFI»
+                        // cuando lo que falta es un `mount` manda a diagnosticar al lugar equivocado
+                        // — y eso pasó de verdad en el primer arranque de este hook.
                         if !efi_boot::hay_firmware_efi(&efivars) {
-                            println!("boot entry reconcile: sin firmware EFI en {} — nada que hacer", efivars.display());
-                            println!("  (esta máquina no arrancó por UEFI; el arranque sigue normal)");
+                            if !efivars.exists() {
+                                println!("boot entry reconcile: no existe {} — nada que hacer", efivars.display());
+                                println!("  (o esta máquina arrancó por BIOS, o /sys no está montado)");
+                            } else {
+                                println!("boot entry reconcile: {} existe pero está VACÍO", efivars.display());
+                                println!("  ⇒ falta montarlo: mount -t efivarfs efivarfs {}", efivars.display());
+                                println!("  (NO es que no haya UEFI: el directorio existe porque el kernel trae CONFIG_EFI)");
+                            }
                             return Ok(());
                         }
 
diff --git a/docs/adr/0018-soberania-del-arranque.md b/docs/adr/0018-soberania-del-arranque.md
index cbb30c9b..380ee683 100644
--- a/docs/adr/0018-soberania-del-arranque.md
+++ b/docs/adr/0018-soberania-del-arranque.md
@@ -69,6 +69,45 @@ Y —esto no es opcional— **el reconciliador reporta que tuvo que actuar**. Si
 usuario vive con una rareza intermitente que nunca entiende. Un ausente falla ruidosamente; un
 arreglo mudo se parece demasiado a que no pasó nada (regla 3 de `CLAUDE.md`).
 
+> **ENMIENDA 2026-09-11 (3ª) — el §2 está implementado, y lo caro no fue el reconciliador.**
+>
+> `takana boot entry reconcile` descubre su propia ESP por **tipo de partición** (GUID de ESP en GPT,
+> `0xEF` en MBR), que es el único dato fiable sin montar nada. Si hay **varias** ESP no adivina: las
+> lista y pide `--disk`. Elegir mal significa escribir una entrada que apunta a un disco que puede no
+> estar, y eso es peor que no escribir nada. Corre desde el wrapper de PID1 de las dos imágenes, y
+> cuando actúa **grita a `/dev/tty0` además del serial** — un reconciliador que repara en silencio
+> deja al usuario conviviendo con una rareza que no entiende.
+>
+> **Lo que costó el tiempo fue un diagnóstico falso, y vale más que el código:** el primer arranque
+> con el hook puesto imprimió
+>
+> > `boot entry reconcile: sin firmware EFI en /sys/firmware/efi/efivars — nada que hacer`
+> > `(esta máquina no arrancó por UEFI)`
+>
+> **en una VM que había arrancado por UEFI.** La causa no tenía nada que ver con UEFI:
+> `busybox switch_root` **no arrastra `/sys`** —igual que no arrastra `/dev`, cosa que el script ya
+> contemplaba con su `mount -t devtmpfs`— así que `/sys/firmware/efi/efivars` sencillamente no
+> existía. El mensaje mandaba a investigar el firmware, que estaba perfecto.
+>
+> **Verificado después en la máquina real, dos arranques seguidos de la imagen completa:**
+>
+> | arranque | qué hizo | salida |
+> |---|---|---|
+> | 1º (por la ruta fallback) | detectó su ESP **solo** y vio que faltaba la entrada | `ESP detectada en /dev/vda p1` · `⚠ EL ARRANQUE ESTABA CAMBIADO — takana lo repuso` · `faltaba la entrada «takana» ⇒ escrita en Boot0004` · `BootOrder: 0000,0001,0002,0003 → 0004,0000,…` |
+> | 2º (sin tocar nada) | **el firmware arrancó por la entrada que se escribió sola** | `BdsDxe: starting Boot0004 "takana" from HD(1,GPT,923A070F-…)/\EFI\takana\takanax64.efi` · `✓ arranque en orden: Boot0004 «takana» ya es la primera` |
+>
+> O sea: un sistema recién instalado **se da de alta en el firmware en su primer arranque** y a
+> partir del segundo arranca por su propia entrada, sin que nadie corra un comando. Y el segundo
+> arranque no escribe nada.
+>
+> Dos arreglos, y el segundo importa tanto como el primero:
+> 1. El wrapper monta `sysfs` y después `efivarfs`. El kernel ya traía `CONFIG_EFIVAR_FS=y`
+>    —verificado en el `.config` **sellado**, no supuesto—, así que no se re-hashea nada.
+> 2. El mensaje distingue ahora **tres** estados que se parecen: el directorio no existe (BIOS, o
+>    `/sys` sin montar), existe y está **vacío** (falta el `mount`, y lo dice con el comando exacto),
+>    o tiene variables. Decir «no hay UEFI» cuando lo que falta es un `mount` manda a diagnosticar al
+>    lugar equivocado — y el que se equivocó primero fue este ADR.
+
 ### 3. La segunda pata, porque el reconciliador tiene huevo y gallina
 
 Si Windows deja a takana de último, **takana no arranca, y entonces el reconciliador nunca corre**.
diff --git a/scripts/install-image-efi.sh b/scripts/install-image-efi.sh
index 7d8a0ec1..6d0cdb64 100755
--- a/scripts/install-image-efi.sh
+++ b/scripts/install-image-efi.sh
@@ -194,6 +194,19 @@ if [ -x /usr/bin/hammer ]; then
     /bin/busybox timeout 15 /usr/bin/hammer boot menu > /dev/ttyS0 2>&1 || true
 fi
 
+# efivarfs: la NVRAM del firmware NO es visible hasta que se monta, y el kernel `linux-metal` ya trae
+# CONFIG_EFIVAR_FS=y (verificado en el .config sellado, no supuesto) — sólo faltaba montarlo. El
+# directorio sólo existe si la máquina arrancó por UEFI, así que el `[ -d ]` es la prueba de firmware
+# y no una precaución: en BIOS no está y no hay nada que montar.
+# ⚠ `busybox switch_root` NO arrastra /sys, igual que no arrastra /dev (por eso existe la línea del
+# devtmpfs de arriba). Sin sysfs, `/sys/firmware/efi/efivars` NO EXISTE y el reconciliador concluye
+# «esta máquina no arrancó por UEFI» — en una máquina que arrancó por UEFI. Medido: el primer intento
+# de este hook dio exactamente ese diagnóstico falso.
+/bin/busybox mount -t sysfs sys /sys 2>/dev/null || true
+if [ -d /sys/firmware/efi/efivars ]; then
+    /bin/busybox mount -t efivarfs efivarfs /sys/firmware/efi/efivars 2>/dev/null || true
+fi
+
 # Reconciliador del arranque (ADR 0018 §2). La NVRAM del firmware es estado compartido: otro sistema
 # operativo instalado al lado la reescribe sin coordinarse —Windows Update poniéndose primero en
 # BootOrder es el caso típico—. Contra eso no sirve confiar, sirve CONVERGER en cada arranque.
diff --git a/scripts/takana-live-install.sh b/scripts/takana-live-install.sh
index 2be0b90a..8acbf929 100755
--- a/scripts/takana-live-install.sh
+++ b/scripts/takana-live-install.sh
@@ -452,6 +452,12 @@ echo "HAMMER-EFI-INIT-OK: arje-zero PID1" > /dev/ttyS0 2>/dev/null || true
 # Menú de arranque por grafo (ADR 0010): emite /run/hammer/boot-graph.json y, si hay compositor (mirada),
 # lo pinta sobre KMS. Graceful (sin compositor sigue) y al serial (no pinta tty0 ⇒ cero-parpadeo).
 [ -x /usr/bin/hammer ] && /usr/bin/hammer boot menu > /dev/ttyS0 2>&1 || true
+# efivarfs: sin montarlo la NVRAM del firmware no se ve. El directorio sólo existe si arrancamos por
+# UEFI, así que el `[ -d ]` distingue UEFI de BIOS sin preguntarle a nadie.
+# switch_root no arrastra /sys (ni /dev): sin esto el directorio de efivars no existe y el
+# reconciliador diagnostica «no arrancó por UEFI» en una máquina que sí lo hizo.
+/bin/busybox mount -t sysfs sys /sys 2>/dev/null || true
+[ -d /sys/firmware/efi/efivars ] && /bin/busybox mount -t efivarfs efivarfs /sys/firmware/efi/efivars 2>/dev/null || true
 # Reconciliador del arranque (ADR 0018 §2): la NVRAM es estado compartido y el vecino la reescribe
 # sin avisar. Converger en cada arranque, y DECIRLO en pantalla cuando hubo que actuar — si repara
 # en silencio, el usuario nunca se entera de que algo le está pisando el arranque.