El usuario pidió respaldar en «el volumen, aunque sea montándolo aquí». No se
puede: un HC Volume es un dispositivo de bloque por RED, sólo se adjunta a
servidores de Hetzner del mismo DC, y sólo a uno a la vez. harkaq-cosecha es el
disco del worker efímero y vvv está al 78%.
El producto correcto es un Storage Box: se monta desde el laptop (SSHFS/CIFS) y
habla rsync/borg/restic por SSH. BX11 = 1 TiB, €3,20/mes, sin alta. Creado en
hel1 con protección de borrado y la clave github5.
rsync plano y no borg: el store es CAS, los ficheros son inmutables y se nombran
por hash, así que incremental es exactamente lo correcto y no hay repo ni claves
que mantener. borg comprimiría 4x (79% del store es .debug_) pero 126 G en 1 TiB
no aprieta.
El store va SIN --delete a propósito: un respaldo que replica los borrados no
protege del borrado por error, y store-gc.sh acaba de demostrar que puede
equivocarse en silencio.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
El script informó «364 artefactos borrados · libres: 24G → 48G» y no había
borrado ninguno: los 364 de su propio manifiesto seguían enteros en el store.
`xargs rm -rf` salió con 0 y el echo se lo creyó. Se reprodujo: corriéndolo en
SEGUNDO PLANO el borrado no se materializa; en primer plano sí.
Da igual la causa: un rm que devuelve 0 no es prueba de que el fichero se fue.
La válvula de escape del disco estaba rota EN SILENCIO y encima reportaba
éxito, que es peor que fallar — el disco llegó al 98% mientras yo creía haber
liberado 24G.
Ahora recuenta sobre el filesystem y sale distinto de cero si sobrevivió algo.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
La paridad cosmic no se demuestra con un cliente nuestro (eso probaria que nos
entendemos con nosotros mismos), se demuestra con la herramienta que usa el
resto del mundo. wlr-randr habla wlr-output-management-unstable-v1, que mirada
sirve. Entra a base-system-1 con ese rol acotado.
C sobre meson, 28 KB, trae el XML del protocolo adentro: solo wayland-client.
Tarball de release y no el -/archive/ autogenerado de GitLab, que no es estable
byte a byte y rompe el sha256 pinneado con el tiempo.
Queda anotado en la receta lo que hoy NO puede hacer, para no acusar al paquete:
en mirada apply/test de zwlr_output_configuration_v1 contestan failed, asi que
wlr-randr lista bien y no cambia nada. Cuando mirada implemente el apply, esta
misma receta pasa a probar tambien el apply.
Por lo mismo no entran kanshi ni way-displays: no son herramientas sino una
funcion —perfiles de salida por hotplug— y su lugar es adentro de mirada, que ya
tiene el estado. Instalarlos hoy seria ademas inutil.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Cae el último muro real de la cola GNOME. Cuatro piezas, ninguna en la receta
que fallaba:
1. SOMBRA de libadwaita en incoming-gnome/. El «relocation ... libfontconfig.a»
no lo ponía xdp-gnome sino el cierre de la libadwaita del CORPUS, receta de
la era estática. La del corpus no se toca (3 dependientes ahí).
2. libyaml-shared: la única no-PIC del cierre de libadwaita sin variante.
3. xdg-desktop-portal 1.19.4 en esta cola (COSMIC sigue en 1.18.4). xdp-gnome 48
exige >=1.19.1, y el corte de la dep dura de gstreamer es 1.19.1 EXACTO
—1.19.0 no la pide—, así que no hay versión que cumpla ambas. Se saca con dos
sed: gstreamer alimenta un solo binario auxiliar (validate-sound) que el
daemon invoca por exec, no linkea. Precio: notificaciones con sonido propio
quedan rechazadas. Barato vs traer gstreamer+gst-plugins-base al corpus.
4. gettext-tiny + los cierres .pc de libadwaita-1 y gnome-desktop-4.
Y se corrige una regla que estaba MAL escrita en la receta: medir PIC con
`readelf -r x.a | grep R_X86_64_32` cuenta las reubicaciones de .rela.debug_*,
inocuas y presentes en todo objeto. Así medido libepoxy da 39.630 «no-PIC» y
sin embargo está embebida dentro de la libgtk-4.so de la isla, con 3.446
símbolos epoxy_ definidos. Excluyendo debug el control sale limpio (libepoxy=0,
fontconfig=1122), y el barrido dio 7 no-PIC en vez de 13: ahorró cinco builds,
dos de ellos openssl y curl.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Deps canónicas -> variantes -shared, y link=static -> dynamic: la receta era
de la era estática y el link moría con «relocation R_X86_64_64 ... recompile
with -fPIC» sobre libfontconfig.a.
No sella todavía, y el muro queda MEDIDO en la receta para que nadie itere en
falso: el cierre tiene un único camino a la fontconfig estática,
xdp-gnome -> libadwaita -> fontconfig, y esa libadwaita es la del CORPUS, una
receta entera de la era estática (gtk4/glib/cairo/pango canónicas). No le falta
una variante: no pertenece a la isla dinámica.
El paso siguiente es una sombra de libadwaita en incoming-gnome, como se hizo
con glib. `yupana radio libadwaita` = 4 dependientes, 0 sellados cayendo.
El frontend generico xdg-desktop-portal SI sello (b3:db5e5cf8).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
El default era fósil de cuando `incoming-gnome-onda1` era el frente entero:
listaba esa cola (6 recetas) pero NO `incoming-gnome` (86, donde viven gtk4,
mutter y gnome-shell) ni `incoming-gnome-onda2` (la isla dinámica, 22). El
worker reportaba moler GNOME y molía 6 de 114.
Se agregan las dos y se mueven las tres ANTES de incoming-kde: con 205 recetas
KDE por delante, un ciclo se consumía sin darles turno aunque estuvieran
listadas.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
xdg-desktop-portal-gnome documentaba en prosa que le faltaba el frontend
genérico («la dep dura que falta»). La campaña COSMIC ya lo autoró y selló,
así que se copia a incoming-gnome/ junto con su dep fuse3 y se declara.
NO es cache-hit, y conviene dejarlo escrito: desde incoming-gnome el cierre
resuelve contra la glib de la isla dinámica en vez de la de COSMIC, así que
el ArtifactHash se mueve (f4adb8c9 -> db5e5cf8) y hay que construirlo. Es lo
correcto —backend y frontend tienen que compartir glib— y es el mismo patrón
ya medido con pipewire.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sube el pin de portal-probe a a5c959b (persist_mode + --wait + flush línea a línea).
MEDIDO en la OptiPlex 3060 (UHD 630, iris por hardware), handshake completo de 4 pasos:
[3/4] Start → streams: node id 75, position (0,0), size (1920,1080), source_type 1
restore_token "d2b5b24f-2f2c-44e2-9a41-014f965b389b"
[4/4] OpenPipeWireRemote → fd = 5 → socket:[84493]
== portal-probe screencast: OK ==
Y PipeWire tiene el nodo `cosmic-screencast` como Video/Source con puertos capture_0/1.
El muro no era la GPU. La hipótesis del EGL por software queda falsificada: en metal, con
iris real, el síntoma era idéntico hasta que se mandó `persist_mode`. Era un strlen(NULL)
en xdg-desktop-portal 1.18.4 (ver el commit anterior), que mataba al portal justo antes de
emitir el Response.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Causa raíz de que ScreenCast se quedara colgado en Start, medida en metal (OptiPlex 3060).
No era el EGL por software de QEMU: en metal, con iris por hardware, pasaba exactamente
lo mismo. Esa hipótesis queda falsificada.
Lo que pasa de verdad, con cuatro segfaults reproducibles (uno por intento, todos `at 0`
y todos en el MISMO offset de libc, 0x34f64 = `strlen`):
1. el cliente no manda `persist_mode` ⇒ el portal asume PERSIST_MODE_NONE
2. el backend de COSMIC devuelve `restore_data` de todos modos
3. xdg-desktop-portal 1.18.4 entra por la rama NONE de
xdp_session_persistence_generate_and_save_restore_token, que hace
`g_clear_pointer(in_out_restore_token, g_free)` — token = NULL
4. a la vuelta, el llamador hace `g_variant_new_string(*in_out_restore_token)` SIN
comprobar nada ⇒ glib llama strlen(NULL) ⇒ SIGSEGV
El portal muere JUSTO ANTES de emitir el Response. Desde el cliente eso se ve como «Start
aceptado y nunca contesta», que es indistinguible de un backend que se cuelga — y nos
mandó a buscar el problema en la GPU durante meses.
Con persist_mode >= 1 el token se genera (uuid) y no hay nulo. Es un fallo de aguas
arriba; esto lo esquiva desde el cliente sin tocar el portal. Por defecto 1 (transitorio),
que es lo que quiere cualquiera que sólo va a capturar una vez.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Redirigida a fichero, stdout se bufferiza por bloques: mientras la sonda espera un
Response el log muestra sólo la línea de la llamada. Eso se lee como «se colgó al
llamar» cuando en realidad estaba esperando como debe. Nos pasó depurando ScreenCast en
metal — dos minutos mirando un fichero que no avanzaba, con la sonda perfectamente viva.
setvbuf(_IOLBF) incondicional, no sólo cuando la salida es una terminal: el caso que
importa es justamente el redirigido.
Una sonda que no se puede leer MIENTRAS mide es media sonda.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`Start` de ScreenCast y el `Screenshot` interactivo ABREN UN SELECTOR: no terminan hasta
que alguien elige una pantalla. Tenían 60s clavados, y en metal eso alcanza para que la
sonda se rinda antes de que nadie llegue a hacer clic. El informe entonces dice «el
portal aceptó la llamada y no contestó», que se lee como un fallo del portal cuando la
cadena está simplemente esperando.
Es el mismo error de método que ya nos costó tres diagnósticos falsos en esta campaña
(initramfs 5s, cosmic-diag 50s, wifi-up 6s): medir contra el reloj en vez de contra el
hecho. Acá el hecho depende de un humano, así que el reloj tiene que ser AJUSTABLE, no
adivinado.
Los plazos de CreateSession/SelectSources siguen en 15s a propósito: esos pasos no le
piden nada a nadie, y si tardan es que algo anda mal de verdad.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Cierra el segfault mudo de iris. El intento anterior (`-Wl,--build-id=sha1`) NO prendió:
meson lo registra pero `zig cc` 0.13 lo ignora en silencio — el configure lo dice
(«supports link arguments -Wl,--build-id=sha1: NO») y la .so sale sin ninguna nota.
zig 0.16 sí la emite (verificado a mano), pero `zig_version` está pineada a 0.13.0 como
escotilla contra la regresión de zig 0.14: subirlo cambia un muro por otro.
Tampoco había escape por entorno, y esta vez medido sobre el fuente en vez de deducido:
el retorno temprano es `if (INTEL_DEBUG(DEBUG_DISK_CACHE_DISABLE_MASK))` y en 24.0.9 esa
máscara está definida como 0 ⇒ el `if` no dispara nunca. Por eso el desensamblado no
tenía ni un salto condicional: el compilador lo dobló.
`-Dshader-cache=disabled` lo garantiza el preprocesador — el cuerpo entero de
`iris_disk_cache_init` vive en un `#ifdef ENABLE_SHADER_CACHE`. Verificado en el
artefacto: la función es ahora un único `ret`.
MEDIDO EN METAL (OptiPlex 3060 / UHD 630), bibliotecas desplegadas por SSH sobre la
máquina viva, sin re-quemar el USB: sesión COSMIC completa arriba — cosmic-comp, panel
con applets, bg, launcher, term, toplevel, workspaces — y CERO segfaults nuevos.
Confirmado en pantalla por el usuario.
Costo aceptado: sin caché en disco los shaders se recompilan en cada arranque.
Re-sella mesa: b3:6d443d9f… → b3:f43c41d1…
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Depurando la OptiPlex por SSH sobre un hotspot, la máquina desaparecía de la red cada
pocos minutos. No es «la WiFi anda mal»: son dos causas que se suman y ninguna deja
rastro en dmesg.
- `udhcpc -q` (el que usa wifi-up) pide la dirección UNA vez y termina. Nadie renueva
el lease.
- el AP olvida a los clientes ociosos y deja de contestar ARP. Desde fuera se ve «No
route to host» mientras la máquina se cree perfectamente conectada.
El síntoma engaña justo en la dirección peor: la máquina no reporta nada, así que parece
que se colgó lo que estabas depurando.
`wifi-keep` hace ping al gateway cada 10s, que resuelve las dos a la vez — detecta la
caída para reasociar Y mantiene viva la entrada del cliente en la tabla del AP.
Sin esto cada sesión remota se interrumpe sola y hay que volver físicamente al teclado,
que es exactamente lo que la red venía a evitar.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Causa raíz del escritorio COSMIC que no arrancaba en metal, medida en el OptiPlex 3060
(UHD 630). cosmic-comp moría sin panic y con RUST_BACKTRACE=full; el dmesg tenía la
respuesta que ningún log de usuario podía dar:
cosmic-comp[1266]: segfault at 10 ip ... error 4 in iris_dri.so[9626c0,...]
El offset resuelve a `_mesa_sha1_format` (bytes del desensamblado idénticos al `Code:`
del kernel), y su llamador `iris_disk_cache_init` es tres llamadas seguidas sin un solo
salto condicional entre medio:
build_id_find_nhdr_for_addr → NULL (ninguna .so de mesa traía nota)
build_id_data → NULL+0x10 (offsetof del campo)
_mesa_sha1_format → lee 0x10 ⇒ SIGSEGV
El `assert(note && ...)` que cazaba esto lo borra -Db_ndebug=true.
Tres decisiones razonables por separado que juntas dan un cuelgue mudo: meson no pide
build-id, lld no lo pone solo (37 de 40 .so del corpus SÍ lo traen — era exclusivo de
mesa) y el assert no existe en release. No lo salva MESA_SHADER_CACHE_DISABLE: la
desreferencia va antes de consultar si la caché está habilitada. Y no se ve en QEMU,
donde el userland es swrast/llvmpipe y esta ruta es de iris.
Fix: -Dc_link_args/-Dcpp_link_args con -Wl,--build-id=sha1.
Re-sella mesa: b3:6d443d9f… → b3:c3c18cde…
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
El /tmp/wpa.conf que generaba sólo traía el bloque `network`. Sin
`ctrl_interface=/run/wpa_supplicant`, wpa_supplicant no abre socket de control y
`wpa_cli` no conecta — síntoma que parece un fallo de red y es una puerta que no
existe. Peor: deja ciego el único dato que distingue «clave mal» de «DHCP mudo»,
que es wpa_state. Y la espera de asociación que acabo de añadir dependía de wpa_cli,
o sea que habría fallado siempre.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
En el OptiPlex la interfaz wlan SÍ aparece (ath10k cargó y el re-probe PCI funcionó),
pero `udhcpc` salía a preguntar 6s después de lanzar wpa_supplicant — antes de que
hubiera asociación. Sin lease, y el mensaje decía «¿clave correcta?», que manda a
buscar exactamente donde NO está el problema.
Ahora espera al HECHO: wpa_state=COMPLETED (techo 40s), informa el estado real
mientras espera, y distingue los casos en el mensaje de fallo — 4WAY_HANDSHAKE es
clave, SCANNING es que no ve la red. Y DHCP reintenta 3 veces, porque el AP a veces
ignora el primer DISCOVER justo tras asociar.
Tercera vez hoy que un `sleep` fijo produce un diagnóstico falso (initramfs 5s,
cosmic-diag 50s, wifi-up 6s). El patrón: esperar al reloj en vez de al hecho no falla
donde se prueba, falla en la máquina lenta — y miente sobre la causa.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
WIFI. El OptiPlex 3060 SÍ tiene WiFi: `pci 0000:02:00.0: [168c:0042]` = Qualcomm
Atheros QCA9377. No aparecía interfaz porque el kernel sólo llevaba IWLWIFI. Añadido
ATH10K/ATH10K_PCI a linux-metal-dual + el firmware QCA9377 a la imagen + `wifi-up`.
El detalle que hace falta: con MODULES desactivado el driver va BUILTIN y prueba el
dispositivo a los ~5s pidiendo firmware, pero el rootfs se monta a los ~13s ⇒
`Direct firmware load failed -2` y la tarjeta queda muda, sin módulo que cargar
después. `wifi-up` fuerza un re-probe PCI (remove+rescan) con /lib/firmware ya
montado. Es la MISMA carrera que la del initramfs con el USB, un piso más abajo.
COSMIC-DIAG. La 1ª versión esperaba `sleep 50` y en esa máquina la sesión tarda ~105s
en llegar al compositor ⇒ el dmesg «después» se capturó ANTES de que cosmic-comp
arrancara y salió byte a byte idéntico al de antes. El viaje se gastó sin dato, y yo
leí ese dmesg vacío como «no hubo segfault», que era una conclusión sin respaldo.
Ahora espera al HECHO: que cosmic-comp aparezca y luego desaparezca (techo de 6 min).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`grep -i "Code: "` matchea `microcode: Current revision: 0x...`, o sea que reportaba
como hallazgo una línea de arranque normal. Anclado a lo que el kernel imprime de
verdad ante una señal: segfault, general protection fault, traps:, Killed process.
Dato real de la corrida en el OptiPlex: NO hubo segfault ⇒ cosmic-comp no muere por
señal, sale por su cuenta sin escribir nada. Cambia la búsqueda.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
En metal cada iteración cuesta un viaje físico, así que la captura no puede depender
de que alguien recuerde los pasos. `cosmic-diag` corre la sesión y deja en
/var/log/cosmic: dmesg ANTES, run.txt de la sesión, y dmesg DESPUÉS.
El dmesg de después es lo que faltaba. Medido en el OptiPlex 3060: cosmic-comp toma
seat0 (seatd lo confirma: "Opened client 1"), vive 4,9s y se DESCONECTA, pero su log
se corta a los 0,4s sin panic y con RUST_BACKTRACE=1 activo. Eso no es un error
manejado, es una señal — y si es SIGSEGV el kernel imprime
`cosmic-comp[PID]: segfault at ... in <BIBLIOTECA>`, que ES el diagnóstico.
Descartado antes de pedir otro viaje: la clausura está completa (iris_dri.so, libEGL
y cosmic-comp resuelven todos sus NEEDED en el rootfs), y los errores de tema no son
la causa — cosmic-panel sobrevive al mismo GetKey(list_button) y muere después, de
NoCompositor. Los tres clientes que "no encuentran compositor" son consecuencia.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diagnosticado por el usuario en el OptiPlex 3060 quitando los pipes de say().
Abrir un puerto serie sin portadora BLOQUEA en open() esperando DCD, salvo que el
termios tenga CLOCAL. El kernel pone CLOCAL cuando registra el puerto COMO CONSOLA,
y eso pasa en QEMU porque el cmdline lleva `console=ttyS0,115200`. En ese metal la
firmware NO aplica el CONFIG_CMDLINE horneado —el kernel arranca con `Command line:`
VACÍO— así que ttyS0 es un puerto común, sin cable: el PRIMER say() se colgaba ahí.
Explica los tres síntomas que no cerraban:
- /var/log/cosmic se creaba (el mkdir va antes) pero el .log nunca aparecía;
- `cosmic-start > /salida.txt` daba VACÍO ⇒ parecía que el script no se ejecutaba,
cuando estaba bloqueado en su primera línea de salida;
- la corrida terminaba siempre en «log del compositor (primer tramo)»: no era el
último paso, era el dump() bloqueándose en el mismo sitio.
El serial no se pierde: cuando ES la consola, /dev/console YA ES ttyS0. Cuando no lo
es, no había nadie del otro lado. En metal lo que sirve es el fichero de log.
Con say() destrabado, la detección de GL quedó CONFIRMADA en metal por primera vez:
== cosmic :: GL por HARDWARE — kernel drm=i915 + iris_dri.so (sin overrides)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dos defectos que juntos hicieron ilegible el 3er viaje.
1. LOG CONTAMINADO. Los logs de sesión van a disco para sobrevivir al apagón en
metal — bien— pero validar la imagen en QEMU ESCRIBE DENTRO DEL FICHERO DE
IMAGEN, y después se quema. El usuario grepeó /var/log/cosmic en su máquina y
leyó `drm=virtio-pci`: mi corrida en QEMU, no la suya. Un log viejo que parece
nuevo es peor que no tener log.
Fix: la imagen crea /var/log/cosmic VACÍO como último paso. Y la regla —validar
sobre una COPIA, o regenerar antes de quemar— queda escrita donde se comete.
2. SALIDA DOBLE. `say` tee'aba a /dev/console siempre. Lanzado a mano desde el
getty, stdout YA es la pantalla, y /dev/console es tty0 = la MISMA pantalla
cuando el cmdline llega vacío (la firmware del OptiPlex no aplica el
CONFIG_CMDLINE horneado). Cada línea salía dos veces, entreverada con lo que
arje-zero escribe a consola. Eso es lo que se leía como «basura de init»: no era
ruido ajeno, era el propio script. Ahora /dev/console sólo si `[ -t 1 ]` es falso.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Documenta el diagnóstico del OptiPlex 3060: la GPU estaba perfecta (i915 inicializó,
fbcon en el framebuffer) y lo que fallaba era el hardcodeo de software GL, más la
preparación de sesión que la imagen de metal nunca tuvo.
Deja las dos reglas: un artefacto compartido entre QEMU y metal no puede llevar el
entorno hardcodeado (se detecta), y «llega al prompt» no valida NADA del escritorio
— hay que correr cosmic-start en la imagen que se va a quemar.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diagnóstico del 1er viaje al OptiPlex 3060 (Coffee Lake, UHD 630). El dmesg del
propio USB muestra que la GPU estaba PERFECTA:
[drm] Found coffeelake (device ID 3e92) ... Initialized i915 1.6.0 on minor 0
fbcon: i915drmfb (fb0) is primary device
Lo que fallaba era el script de arranque. `cosmic-start-qemu.sh` exportaba
LIBGL_ALWAYS_SOFTWARE=1 y MESA_LOADER_DRIVER_OVERRIDE=kms_swrast INCONDICIONAL —
correcto sobre virtio-gpu, letal sobre Intel real: la mesa del corpus va con
-Dgallium-drivers=iris -Dllvm=disabled y NO EXISTE ningún kms_swrast_dri.so ⇒ EGL
falla. Y en el mejor caso habría sido peor: si arrancaba, componía por software y
ScreenCast fallaba igual que en QEMU ⇒ el viaje NO PODÍA contestar su pregunta.
El origen es un comentario que yo escribí en metal-desktop-image.sh afirmando que
el script no tenía supuestos del emulador. Los tenía, y el nombre del fichero lo
decía. Ahora:
- `cosmic-start-qemu.sh` → `cosmic-start.sh` (se llama por lo que hace).
- El modo de GL se DETECTA con dos patas: driver DRM del kernel Y .so de mesa
presente. Si no hay ninguna, lo DICE en vez de morir dentro de EGL.
- La imagen VERIFICA que el script instalado no fuerce kms_swrast (falla el build
si vuelve a pasar).
Y correr cosmic-start sobre la imagen de metal POR PRIMERA VEZ (antes sólo se
validaba que llegara al prompt) destapó que le faltaba entera la preparación de
sesión que sólo tenía qemu-desktop-image.sh: sin grupo `video` no arranca seatd,
sin usuario `messagebus` no arranca el bus de SISTEMA — y sin bus de sistema NO HAY
PORTAL, o sea que portal-probe screencast no habría tenido con quién hablar aunque
el GL fuese perfecto. Copiada: arje-logind-compat + política, video, messagebus,
setuid del launch-helper, /var/run→/run, COSMIC_MODE, libc.musl-x86_64.so.1.
Además, para que el próximo fallo en metal no cueste otro viaje a ciegas:
- Los logs van a /var/log/cosmic (ext4) y no a /tmp (RAM, se evapora al apagar).
`dump()` también, que iba SÓLO al serial — donde se perdió la explicación de los
tres fallos de arriba.
- authorized_keys horneada: sshd escuchaba en :22 pero era INALCANZABLE
(PasswordAuthentication no, sin clave) ⇒ ahora se depura por red.
- netup-wait: el r8169 levanta el enlace a los 20,2s y el ente sshd pedía DHCP a
los 13,7s, sin reintento. En QEMU no se ve: virtio-net tiene carrier desde el
instante cero.
- firmware i915 de otras generaciones (la base sólo traía tgl_*; el Coffee Lake
pedía kbl_dmc_ver1_04.bin).
Validado arrancando como usb-storage: seatd OK, bus de sistema OK, login1 OK,
pipewire+wireplumber OK, compositor OK. La línea de GL dice la verdad en QEMU.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Documenta el diagnóstico completo: la AUSENCIA del `EXT4-fs mounted` como prueba de
que el root nunca se montó, la carrera contra la enumeración USB (invisible en QEMU
porque virtio está desde el instante cero), y la ceguera del /dev/console = serial.
La lección que generaliza: CADA capa del arranque tiene que escribir a /dev/tty0. Se
arregló la capa post-switch_root en el viaje de KDE y el initramfs quedó ciego; tapar
una sola capa garantiza que la siguiente vuelva a caer.
Incluye el comando para reproducir metal desde el laptop (qemu-xhci + usb-storage +
-serial null) y la evidencia en pantalla.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Síntoma en metal ajeno: la pantalla se congela justo tras `sdc: sdc1 sdc2 sdc3 sdc4`
/ `Attached SCSI removable disk`. No estaba colgado.
Prueba de que el root nunca se montó: con `ignore_loglevel` un montaje ext4 imprime
`EXT4-fs (...): mounted filesystem` en pantalla sí o sí, y no aparecía.
Dos causas encadenadas:
1. CARRERA. El rdinit arranca en cuanto se desempaqueta el initramfs, pero el bus USB
enumera asíncrono y tarda segundos (reset de hub, settling de 1s por dispositivo,
scan SCSI). Los 5 reintentos de 1s no alcanzaban. En QEMU el disco es virtio y está
desde el instante cero ⇒ la carrera NUNCA se veía en validación. Es el `rootwait`
que no podemos usar porque no hay root= en el cmdline. Ahora espera 60s.
2. CEGUERA. El cmdline horneado es `console=tty0 console=ttyS0,115200` y /dev/console
= la ÚLTIMA `console=` ⇒ el serial. El `exec sh` de rescate nacía invisible. Es el
MISMO bug que costó el 1er viaje físico de KDE, una capa más temprano: allá se
arregló para después del switch_root (getty en tty1) y el initramfs quedó ciego.
Ahora el log del pivote va a /dev/tty0, el marcador INIT-OK también, y el rescate
abre shell en tty1 listando los bloques visibles.
+ `timeout 15` a `hammer boot menu`: corre ANTES del exec de arje-zero ⇒ colgarse ahí
deja un arranque sin PID1 ni pantalla, indistinguible de un kernel muerto. El
`|| true` protegía del fallo, no del bloqueo.
Validado arrancando la imagen COMO USB (qemu-xhci + usb-storage, -serial null, con
pantalla): marcadores del pivote visibles, motd y prompt `/ #`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Qué correr con el USB en la mano, en orden, y —lo que importa— CUÁL ES EL VEREDICTO:
el `[4/4] OpenPipeWireRemote` con su fd, no que el diálogo aparezca (eso ya pasaba en
QEMU). Y el contrafáctico que hace falsable el diagnóstico de hoy: si vuelve a
colgarse en `Start` pero YA NO aparece `Erroneous EGL call` en el log del compositor,
entonces la causa era otra y lo de hoy estaba incompleto.
`ls /dev/dri` con renderD128 es la señal barata de que hay HW: con swrast no existe.
Gotchas del quemado, todos medidos y todos con su porqué:
· NUNCA a un NVMe y NUNCA POR NOMBRE — hoy mismo, tras el reboot, nvme0n1 y nvme1n1
se intercambiaron respecto de lo anotado en julio. Identificar por TRAN=usb.
· el progreso NO se mide con kill -0 (sudo dd corre como root ⇒ EPERM desde el
usuario y parece que terminó): se mide por /sys/block/sda/stat campo 7.
· no correr os-prober sobre el device que estás dd-eando.
· `pkill -f <patrón>` mata su propio shell si el patrón está en su cmdline. Volvió a
pasar hoy (exit 144), con el gotcha ya escrito. Usar pgrep -x.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Hermano de kde/metal-desktop-image-dual.sh, pero con la decisión INVERTIDA y ése es
el motivo de existir. La de KDE va por mesa-llvmpipe a propósito (tenía que aguantar
también una NVIDIA Pascal, cuya mesa HW sólo existe como binario Alpine ⇒ rompería
soberanía).
Acá el objetivo es cerrar ScreenCast, y el diagnóstico de hoy midió que lo que falla
es el COMPOSITOR en una llamada EGL —8 ms antes del `Paused`— porque en QEMU mesa es
kms_swrast: software, SIN exportación dmabuf. El `mesa` del corpus se construye con
-Dgallium-drivers=iris y YA está en el rootfs de COSMIC; en QEMU nunca se usaba, en
un TigerLake es el driver correcto y trae dmabuf de verdad. O sea que este viaje no
es "lo mismo pero en metal": es la única forma de saber si ScreenCast está bien.
⚠ Por eso NO se inyecta llvmpipe: mezclarlos no es aditivo — llvmpipe trae su propio
libgbm/libEGL/libgallium y sobrescribirlos DESACTIVA iris. Si la máquina no tuviera
Intel, la imagen correcta sería la de KDE, no ésta con un parche.
Y lo que NO hace falta inyectar, medido: la de KDE mete libLLVM.so.18 + libgcc_s +
libstdc++ porque el JIT de llvmpipe los NEEDea. Acá NO — iris_dri.so pide sólo
libglapi/libdrm/libz/libzstd/libc (mesa va con -Dllvm=disabled) y cosmic-comp ocho
NEEDED sin C++. CERO binarios ajenos de Alpine. Verificado con clausura ELF completa
del rootfs: 472 objetos escaneados, 42 raíces de runtime, 0 con NEEDED sin proveedor
(los 3 huecos son llvm-*/perl, herramientas de build que el escritorio no arranca).
Se instala EL MISMO cosmic-start validado en QEMU, no una variante: nada de lo que
hace es específico del emulador, y que corra el mismo fichero es lo que hace que
"validado en QEMU" signifique algo para el metal.
VALIDADO EN OVMF CON PANTALLA, que es la regla de oro que costó un USB en el 1er
viaje de KDE (-serial null para simular metal sin puerto serie): arje-zero PID 1, las
4 particiones montadas, el motd VISIBLE y el prompt `/ #` en la pantalla — o sea que
el getty de tty1 hace su trabajo. El shell responde: iris_dri.so presente,
/dev/dri/card0, y cosmic-start/portal-probe/wireplumber en PATH.
Falta quemar el USB, que es destructivo y necesita que el usuario confirme el device.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Con RUST_LOG=trace el log del backend tiene CINCO LÍNEAS en total y la última es la
de siempre ('Connecting' -> 'Paused'). Después no escribe nada más: ni error, ni
panic, ni progreso. O sea que el trace no aportó — screencast_thread no tiene más
instrumentación y buscar ahí estaba agotado.
La pieza que faltaba mirar era EL COMPOSITOR, que es quien entrega los frames:
15:19:02.301568Z WARN smithay::backend::egl::error: Erroneous EGL call didn't set EGLError
15:19:02.310127Z INFO …screencast_thread: state-changed 'Connecting' -> 'Paused'
↑ OCHO MILISEGUNDOS
Y la correlación no es casual: el contador de "Erroneous EGL" sube DE A DOS por cada
intento de screencast (uno al abrir el diálogo con su miniatura en vivo, otro al
pulsar Share) y no se mueve en ningún otro momento.
`ls /usr/lib/dri/` → iris_dri.so, kms_swrast_dri.so, swrast_dri.so. En QEMU con
virtio-gpu-pci sin virgl carga kms_swrast: mesa por software, SIN exportación dmabuf
real. Que es justo lo que un stream continuo necesita y una captura de una sola toma
no — por eso cosmic-screenshot SÍ funciona (va por shm) y ScreenCast no.
EL FRENTE NO ESTÁ BLOQUEADO POR UNA RECETA SINO POR EL ENTORNO. Esto reencuadra el
día entero: pipewire no era, wireplumber no era, el backend no era. Las tres piezas
están construidas, corriendo y haciendo su trabajo —el nodo `cosmic-screencast` existe
en el grafo— y el que no puede cumplir es el compositor sobre una GPU de software. Es
el MISMO muro que documenta el frente KDE (GBM/EGL de software), llegando por otro
camino.
Y no se puede verificar acá: `qemu-system-x86_64 -display help` da sólo none/gtk/sdl
y no existe virtio-gpu-gl-pci — este binario no se compiló con virgl, aunque
libvirglrenderer.so.1 esté en el host. Las salidas son metal (donde iris_dri.so YA
está en la imagen) o un QEMU con virgl.
Lo honesto: ScreenCast está verificado HASTA DONDE EL ENTORNO PERMITE — la cadena
D-Bus completa funciona, el stream se crea y se negocia, y el último tramo (los
píxeles) depende de una GPU que esta VM no tiene.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
b3:b8f3baf0, selló a la primera. Arranca desde cosmic-start ("wireplumber OK (pid
192) — hay gestor de sesión"), se conecta al grafo (dos clientes en wpctl status) y
wpctl pasa a mostrar una sección Video que antes no existía.
Y el Start de ScreenCast SIGUE sin Response a los 60s. Mismo resultado exacto.
LA HIPÓTESIS QUEDA MATADA POR MEDICIÓN. "Falta el gestor de sesión que mueva el nodo
de Paused a Streaming" era mía y era razonable; no era cierta. Queda escrita junto a
su refutación porque una hipótesis descartada CON EVIDENCIA vale más que una lista de
sospechosos: acota el próximo paso a lo que queda, que es el backend mismo.
El dato nuevo, que es por dónde seguir: con wireplumber corriendo, `wpctl status`
lista `Video → Streams` VACÍO durante el handshake. O sea que el nodo
`cosmic-screencast` que SÍ existe en `pw-cli ls Node` no llega a wireplumber como
stream gestionado. Próximo movimiento: RUST_LOG=trace sobre screencast_thread, no
otra dep.
── por qué receta propia y no la de GNOME ──────────────────────────────────────
La de incoming-gnome funciona pero NEEDea libglib/libgobject/libpipewire de la ISLA
DINÁMICA de GNOME: traerla metería una segunda glib y una segunda pipewire en la
imagen. De 19 deps, 14 dan hash idéntico; las que divergen divergen a propósito —
sobre todo `pipewire`, que acá apunta a la de COSMIC (338d1d8c), la que el escritorio
realmente ARRANCA. Un gestor de sesión contra otra pipewire que la que corre no
gestiona nada.
El cambio de fondo es glib → glib-shared. COSMIC usa la glib ESTÁTICA del corpus, que
le alcanza al portal porque es un ejecutable. Acá no: wireplumber produce un .so y 17
módulos, y libglib-2.0.a tiene 44.275 reubicaciones R_X86_64_32/32S ⇒ no es PIC. La
regla del frente GNOME (readelf -r ANTES de gastar el build) ahorró uno.
Y la salida no fue una campaña nueva sino una MEDICIÓN: incoming-kde/glib-shared
copiada a esta cola resuelve al MISMO hash (0584ce1f) y ya estaba sellada ⇒ cero
rebuild. Idem pcre2-shared, lua y libelogind. Las dos glib coexisten sin pisarse (.a
y .so son ficheros distintos) y el portal conserva sus 3 NEEDED.
escritorio-cosmic: 84 → 89 recetas, 0 faltantes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>