Commit Graph
1263 Commits
Author SHA1 Message Date
sergioandClaude Opus 5 1355fc1650 cosmic: dav1d 1.5.4 sellado (b3:aab7a874) — la feature de cargo la prende OTRO, no el paquete
cosmic-bg declara `image` con default-features=false y sin AVIF, y aun así se
compila dav1d-sys: las features de cargo se UNIFICAN en el grafo, así que alcanza
con que otro crate del árbol la prenda para que la decisión del que la apagó no
mande. Mismo modo de falla que un '.pc Requires' arrastrando una dep que nadie
declaró.

Se podría parchear el Cargo.toml de upstream para cortarlo; no se hizo, porque
eso es mentirle al paquete sobre lo que hace. Si el grafo dice que sabe
decodificar AVIF, que lo sepa de verdad — y cualquier cosa del corpus que decodifique
AV1 va a querer dav1d igual.

Dos decisiones del build, las dos leídas del meson.build y no supuestas: nasm es
dep REAL (find_program en :536, exige >= 2.14; copiado de la cola GNOME con hash
verificado b3:33383070), y default_library=both porque quien consuma dav1d con
enlace estático necesita la .a — publicar sólo la .so convierte cualquier
link=static río abajo en una etiqueta falsa.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 10:58:39 -04:00
sergioandClaude Opus 5 b1bbdefc85 cosmic: sctk ENLAZA libxkbcommon — «habla Wayland en Rust» no quiere decir «no toca C»
cosmic-bg se escribió sin [deps] con ese argumento y reventó en el build.rs de
smithay-client-toolkit pidiendo xkbcommon.pc. El que dlopea xkbcommon es winit,
que es otra capa. Hablar el protocolo en Rust dice cómo viaja el byte, no con
qué se interpreta un teclado. El link=static sigue siendo verdad: el artefacto de
libxkbcommon trae .a además de .so.

Corolario anotado en el runbook: todo cliente de la suite va a necesitar al menos
libxkbcommon + pkgconf.

Entran además cosmic-idle (cliente Wayland puro, SIN deps a propósito: no usa
sctk y no necesita interpretar teclas) y cosmic-osd, que es el primer cliente de
iced/libcosmic y por eso vale como sonda: panel, launcher, app-library,
workspaces y notifications comparten su mismo sustrato exacto.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 10:50:46 -04:00
sergio 2d604d5641 estado: cosecha granja 2026-08-03T14:47:35Z — avance del árbol KDE 2026-08-03 10:47:35 -04:00
sergioandClaude Opus 5 ebe63cbf92 runbook cosmic: el cuarto escritorio, escrito mientras se hace
Deja asentado por qué COSMIC no se parece a KDE ni a GNOME (no hay torre de C
debajo: la primera receta salió estática y con cero NEEDED), la tabla de lo que
se hereda gratis de mirada/GNOME, el pin en lockstep epoch-1.5.0, y los seis
gotchas medidos — entre ellos que start-cosmic es bash de verdad (mapfile, [[ ]],
${!var}) y que bash no lo pide ningún [deps], así que a la imagen no lo trae
nadie por accidente.

Y el porqué del orden de ataque, que NO es el orden de arranque: cosmic-bg antes
del panel para que «pinta el fondo pero no el panel» separe la capa de UI del
transporte.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 10:45:39 -04:00
sergioandClaude Opus 5 bc6f664650 cosmic: recetas del compositor, del fondo y del tema de iconos (cola incoming-cosmic)
cosmic-comp es LA pieza y la receta salió casi gratis: mirada-compositor ya
probó que smithay construye en este lab, y las deps en C de smithay dependen de
las features del backend, no del compositor. La lista es la misma menos
linux-pam y más libdisplay-info.

libdisplay-info y hwdata entran COPIADAS byte a byte de la cola GNOME (idénticas
a las de KDE): las deps resuelven hermano→padre, así que desde incoming-cosmic
no se ven las de otra cola. Verificado que el hash NO se mueve (b3:260f0519 y
b3:bdc36cf9) ⇒ los artefactos ya sellados sirven y la copia no cuesta un build.

cosmic-bg va antes que el resto de los clientes porque separa dos preguntas:
habla Wayland por smithay-client-toolkit y NO toca libcosmic/iced, así que si el
fondo pinta y el panel no, el problema es de la capa de UI y no del transporte.

Toda la suite está tagueada epoch-1.5.0, confirmado repo por repo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 10:43:23 -04:00
sergioandClaude Opus 5 e1564614e1 cosmic: primera receta del cuarto escritorio — cosmic-session SELLADO (b3:81f02351)
Sonda barata antes del compositor: Rust puro, sin una dep en C, y prueba las
tres cosas nuevas que la cola COSMIC necesita — edition 2024 sobre el rustc 1.96
del sandbox, deps de git en el Cargo.lock (launch-pad, cosmic-dbus-a11y), y el
patrón de instalación de la suite (binario + start-cosmic + cosmic.desktop).
Salió a la primera: ELF estático, cero NEEDED.

Toda la cola incoming-cosmic va pinneada al tag epoch-1.5.0: COSMIC versiona sus
repos en lockstep y mezclar epochs no da error de compilación sino un escritorio
que no se entiende consigo mismo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 10:22:40 -04:00
sergioandClaude Opus 5 557ffefa23 runbook gnome: el ítem 1 estaba hecho hace rato — los seis typelibs sellados, con sus hashes
El plan seguía sin tilde aunque el shell arranca justamente porque están: se
verificó uno por uno con `hammer hash` contra el store en vez de fiarse del
recuerdo. Se deja el texto original del plan por la advertencia de libelogind,
que sigue vigente.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 10:06:23 -04:00
sergioandClaude Opus 5 c0055331c7 gnome: esperar el NOMBRE de PolicyKit1 antes de lanzar a sus clientes
accounts-daemon y upowerd morían al arrancar: el shim de polkit se lanza en
background y tarda ~2s en adquirir org.freedesktop.PolicyKit1, ellos llamaban a
polkit_authority_get_sync() en ese hueco, D-Bus intentaba ACTIVAR el servicio y
fallaba con 'Failed to execute program ... Permission denied'.

Lo peor era el informe: los tres esperar_nombre estaban al final, así que para
cuando corrían el shim ya tenía el nombre y el resumen daba 'PolicyKit1 OK'
sobre dos clientes ya muertos. Un chequeo posterior a la carrera no la mide.

esperar_nombre pasa a definirse antes del primer daemon y el bloque de polkit
espera su propio nombre antes de que arranque ningún cliente suyo. Lanzar en
orden no es estar listo en orden.

De paso queda cerrado el ítem 4 del runbook: validación CON PANTALLA (DISP=gtk)
del Overview con el PID1 sellado nuevo — 689 colores distintos, con evidencia.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 10:05:29 -04:00
sergioandClaude Opus 5 84e088fd13 imágenes: PID1 sale del artefacto sellado, no del directorio base congelado
Las 4 imágenes de escritorio (GNOME + los 3 de KDE: qemu, metal, dual) fundían `work/metal-rootfs`
por hardlinks y se llevaban SU arje-zero, que era del 2026-06-19: ese directorio se armó a mano en
la campaña de metal y nadie lo regeneraba al re-sellar la receta. Resultado: todas arrancaban con un
PID1 de hace mes y medio, en silencio.

No es hipotético — se comió un fix real. El `identity mismatch` del bus del fractal estaba arreglado
río arriba y la VM seguía imprimiendo el mensaje viejo porque el binario de la imagen no venía de la
receta (ver el comentario de recipes/arje-zero.toml).

El síntoma engaña porque el directorio base es LEGÍTIMO para todo lo demás —busybox, firmware, el
kernel EFI-stub, la estructura de /etc—: sólo la pieza que TAMBIÉN es receta se queda atrás, y justo
esa es PID1. La regla que queda escrita en el helper: si algo del rootfs tiene receta, la imagen lo
toma del artefacto sellado, no de la copia congelada.

El helper va en scripts/lib/ y no inline ×4 a propósito: el porqué es largo y vale una sola copia.
Elige el artefacto por `hammer hash` (el de la receta de HOY, no el más nuevo por fecha, que miente
en cuanto conviven dos) y ABORTA si falta, porque seguir con el PID1 congelado es exactamente el
modo de falla que cierra.

Probado: las 4 pasan `bash -n` y la imagen GNOME lo ejecuta bien sourceado (`✓ e570c1482432 (el de
work/metal-rootfs era de 2026-06-19)`), con la VM ya validada booteando ese PID1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 19:52:00 -04:00
sergio e4b6c0f127 estado: cosecha granja 2026-07-30T23:51:17Z — avance del árbol KDE 2026-07-30 19:51:18 -04:00
sergio 7190cc48a3 estado: cosecha granja 2026-07-30T23:20:59Z — avance del árbol KDE 2026-07-30 19:20:59 -04:00
sergioandClaude Opus 5 2430528c16 dbus: las políticas de login1 y PolicyKit1 viajan en su ARTEFACTO, no en el script de imagen
Cierra un TODO que el propio script tenía escrito («esto pertenece al artefacto de
arje-logind-compat, no a la imagen») y que estaba bien puesto: **un servicio que no puede
adueñarse de su nombre no es un servicio**, así que su política D-Bus es parte de lo que el
paquete promete, igual que el binario. Con la política en el script de UNA imagen,
cualquier otra —metal, KDE, mirada— se llevaba el daemon y no podía usarlo.

arje-logind-compat b3:b4795829 · arje-polkit-compat b3:6c82f44b. Radio de las dos: 0.

**Y la comprobación que reemplaza a escribirlas atrapó un bug de verdad en el primer
intento.** Mover algo a un artefacto sólo es una mejora si se NOTA cuando falta, así que el
script pasó de ESCRIBIR los .conf a EXIGIRLOS. Falló al toque: `✗ falta
org.freedesktop.login1.conf`. Causa — el script inyectaba **sólo el binario** del artefacto
(`install -Dm755 .../usr/bin/...`), así que el .conf existía en el store y nunca llegaba a
la imagen. Sin esa comprobación habría sido el fallo tardío de siempre: daemon que arranca,
no adquiere el nombre, y 25s de espera por servicio sin decir por qué.

Verificado de punta a punta con las políticas viniendo del artefacto: los cuatro nombres
del bus arriba (login1, PolicyKit1, Accounts, UPower) y el audio intacto.

El `zz-` de la de polkit no es decorativo y queda explicado en su receta: a diferencia de
login1, ese nombre YA tiene política —la trae el artefacto de polkit— y permite `own` sólo
al usuario polkitd; dbus lee system.d en orden alfabético y las reglas posteriores ganan, así
que un fichero que ordene después AÑADE el permiso sin descartar el resto de upstream.

ColorManager sigue sin aparecer: es lo de colord, ya diagnosticado hasta dónde llega y
fuera del alcance de este cambio.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 17:18:42 -04:00
sergio 845e842579 estado: cosecha granja 2026-07-30T21:04:12Z — avance del árbol KDE 2026-07-30 17:04:12 -04:00
sergio 4fe0f0f9ea estado: cosecha granja 2026-07-30T20:33:59Z — avance del árbol KDE 2026-07-30 16:33:59 -04:00
sergioandClaude Opus 5 ef2668ad97 wireplumber: el -I$PWD/lib/wp NO hacía falta — era la carrera del ADR 0012
La receta llevaba una bandera de include que su propio comentario marcaba EN DUDA: se
había puesto porque el build cortaba con `../lib/wp/wp.h:13: fatal error: 'client.h' file
not found`, un header que SÍ existe justo al lado del que lo incluye. La explicación real
era que **otro agente construía en el mismo repo y borraba árboles de work/sources/ en
pleno build** — la carrera del ADR 0012, que produce exactamente esa firma: ficheros que
existen cuando los mirás después y no existían al compilar.

Re-probado CON EL REPO QUIETO —comprobando primero que no hubiera ningún `hammer build`
vivo— y sella igual sin la bandera. Confirmado, no supuesto. Verificado además de punta a
punta: audio sigue dando `48. HDA Intel [alsa]` con sink y source reales, 0 page-flips
fallidos.

La lección queda en la receta: antes de agregar una bandera que no se explica, mirar si hay
otro build vivo. Es barato y evita inventar arreglos para síntomas que no son del código.

**GOTCHA DEL LAB, aprendido a la mala en el mismo movimiento: los BYTES del fichero .patch
entran al ArtifactHash.** Corregir la PROSA obsoleta de `pipewire-sound-initialized.patch`
—decía que la decisión libudev-zero-vs-eudev seguía pendiente cuando ya está resuelta—
re-hasheó pipewire y arrastró wireplumber. La distinción que conviene tener presente:
**comentar una RECETA es gratis** (hash_inputs toma source/compiler/target/link/flags/fases/
deps, no los comentarios del TOML) **y comentar un PARCHE cuesta un rebuild**. Anotado en
pipewire.toml, que es donde se va a leer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 13:04:50 -04:00
sergio 1e5313a412 estado: cosecha granja 2026-07-30T17:02:59Z — avance del árbol KDE 2026-07-30 13:03:00 -04:00
sergio 05ad4f5540 estado: cosecha granja 2026-07-30T11:30:56Z — avance del árbol KDE 2026-07-30 07:30:56 -04:00
sergioandClaude Opus 5 17b86cf85e estado: deuda del corpus CERRADA — base, cli y mirada al 100%
sealed  765 → 768        debt  3 → 0        never  2 (los dos con bloqueo documentado)
  base    50/51 → 51/51    cli   73/74 → 74/74    escritorio-mirada  29/31 → 31/31

Cierre de la deuda que yo mismo abrí al parchear libudev-zero (una hoja del cierre de las
CINCO imágenes): reconstruidas `usbutils` (b3:245c718b — depende de libudev por pkg-config),
`mirada-compositor` (b3:c906e244) y `mirada-greeter` (b3:c7dfcf09).

Ojo con la aritmética, que casi me confunde: `yupana radio libudev-zero` dice 58 dependientes
transitivos y build-state sólo veía 3 en deuda. No es contradicción — **build-state cubre el
catálogo canónico `recipes/`, no las colas `incoming-*`**, y 47 de esos 58 están en
incoming-kde. Los 8 de incoming-gnome ya se habían reconstruido ayer.

Los dos `never` NO son trabajo pendiente disfrazado; los dos tienen bloqueo real y ya escrito:

- **dwarves**: su cmake no halla libdw. La receta ya lo documentaba y el build lo confirmó
  palabra por palabra («Could NOT find libdw include dir / library»): `elfutils.toml`
  empaqueta sólo LIBELF —lo que kbuild necesita— y es INTOCABLE porque es build-dep de los
  kernels sellados. La salida es una receta hermana `elfutils-libdw`, que en musl arrastra
  shims de argp/fts/obstack. Campaña propia, no un arreglo.
- **llimphi-counter**: es una PLANTILLA, no un paquete. Su commit es `000…0`, un placeholder
  que nunca se llenó. Gasté un build en descubrirlo, así que ahora la receta lo dice en la
  primera línea: ` ESTO ES UNA PLANTILLA, NO UN PAQUETE. NO INTENTES CONSTRUIRLA.` El estado
  `never` del grafo era técnicamente cierto y semánticamente engañoso.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 07:10:36 -04:00
sergio ccb13a075a estado: cosecha granja 2026-07-30T10:29:46Z — avance del árbol KDE 2026-07-30 06:29:46 -04:00
sergioandClaude Opus 5 beb2851d99 colord: el demonio ya se construye (b3:8100fa39) — arranca, abre sus DB y NO adquiere el nombre
La receta iba con `-Ddaemon=false` y el razonamiento era «mutter enlaza libcolord, no
necesita el demonio». Cierto para COMPILAR mutter y falso para el escritorio andando: el
artefacto INSTALA el `.service` de activación (`Exec=/usr/libexec/colord`) y ese binario no
existía, así que cada arranque se comía 25s de timeout. **No era «colord apagado» sino
colord roto de forma lenta** — el peor de los dos, porque no falla, tarda.

Su propio comentario marcaba la condición de vuelta: «si alguna vez hace falta el demonio
de verdad, vuelve con polkit encima». Polkit ya está (arje-polkit-compat). Y medido: prender
el demonio **no agrega una sola dep nueva** salvo polkit-gobject-1, ya sellada — el bloque
de dependency() de colord 1.4.7 es de nivel superior y pedía gusb/gudev/libudev igual con
daemon=false. El coste estaba pagado desde el 2026-07-27 sin que nadie lo cobrara.

**PERO EL TIMEOUT SIGUE**, y lo que aprendí es dónde NO está:
- El binario existe y arranca: `/usr/libexec/colord` crea sus tres bases en
  /var/lib/colord (mapping.db, storage.db) y lo dice en el log.
- Con `--verbose` NO hay una línea más después de abrir la tercera base.
- La política D-Bus SÍ permite `own` a root, y el `.service` corre como root: no es el caso
  de polkit (donde `own` estaba restringido al usuario `polkitd`).
- Los cuatro `cd_main_load_introspection` que van entre las DB y `g_bus_own_name`
  (cd-main.c:2434-2460) leen de un **GResource compilado en el binario**, no de disco, así
  que no pueden faltar. Los XML instalados en /usr/share/dbus-1/interfaces son para otros.

⇒ Queda entre `cd_main_load_introspection` y `g_main_loop_run`, y el siguiente dato es si el
proceso sigue vivo en ese momento. **Esa comprobación me faltaba en el script** — reportaba
«colord lanzado (pid N)» sin verificar nada, que es exactamente el error que yo mismo había
señalado para upowerd («un pid no es un servicio») y no apliqué acá. Ya está puesta: sin
ella, «no apareció el nombre» no distingue MURIÓ de SE COLGÓ, y son dos investigaciones
distintas.

Verificado que no hay regresión en lo que sí funciona: audio (48. HDA Intel, sink y source
reales) y vídeo (0 page-flips fallidos) siguen bien con el demonio en la imagen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 04:13:40 -04:00
sergio 04569d9972 estado: cosecha granja 2026-07-30T07:58:56Z — avance del árbol KDE 2026-07-30 03:58:56 -04:00
sergioandClaude Opus 5 888fdc31c7 firmware: SOF para TigerLake — el DSP de audio, pineado como el de i915
El kernel ya traía el driver (SND_SOC_SOF_TIGERLAKE); faltaban los blobs, y sin ellos SOF
carga y falla: en el laptop no hay sonido aunque ALSA esté. Mismo patrón que i915 con su
DMC/GuC — driver desde fuente, firmware pineado por contenido, porque Intel no libera el
código y la soberanía build-from-source no aplica a datos fijos.

Tres piezas, cada una por un motivo distinto:
- `sof-tgl.ri` + `sof-tgl-h.ri`: el firmware del DSP. Se copian LOS DOS porque el driver
  elige según el SKU y no quiero hornear la suposición. **`cp -L` es obligatorio**: en
  linux-firmware son SYMLINKS a `intel-signed/`, y un symlink relativo copiado a otro
  árbol apunta a la nada. Verificado: los tres quedan ficheros reales (525K/447K/95K).
- `sof-tgl.ldc`: el diccionario de logs del DSP. No es opcional en la práctica — el
  driver lo pide al inicializar y sin él el firmware arranca SIN TRAZA, o sea que el día
  que algo falle no hay por dónde mirar.
- 47 topologías (`sof-hda-generic-*`, `sof-tgl-*`): describen el grafo de audio. El driver
  pide UNA por nombre derivado de la máquina, y no se puede saber cuál sin el hardware
  delante. Copiar de más cuesta megas; copiar de menos cuesta un viaje físico al laptop
  para descubrir qué nombre pidió.

~3 MB en total. Si no hay SOF en el origen, AVISA y NO falla: el audio del laptop se
pierde pero la imagen sigue booteando y en QEMU suena por HDA legacy — fallar bloquearía
builds que no necesitan SOF.

Verificado que no hay regresión: con los blobs en la imagen, el audio de la VM sigue
funcionando por la ruta HDA (48. HDA Intel [alsa], sink y source reales) y cero page-flips
fallidos. **El camino SOF en sí queda SIN VALIDAR hasta el próximo viaje al metal** — en
QEMU no se ejerce, y eso está escrito en la receta del kernel en vez de dado por bueno.

De paso, la cabecera del script deja de mentir: se llama «firmware» y no «wifi» porque
copia las TRES familias de blobs que el metal necesita (iwlwifi, i915, SOF).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 03:04:03 -04:00
sergio 03ad0f0581 estado: cosecha granja 2026-07-30T02:56:59Z — avance del árbol KDE 2026-07-29 22:56:59 -04:00
sergioandClaude Opus 5 7f2fdd5a41 🔊 audio FUNCIONANDO — el muro era libudev-zero, y ensancharlo de más rompía el vídeo
Audio
   ├─ Devices:   48. HDA Intel                [alsa]
   ├─ Sinks:   * 52. HDA Intel Analog Stereo  [vol: 0.40]
   ├─ Sources: * 53. HDA Intel Analog Stereo  [vol: 1.00]

Y gvc con perfiles reales (`output:analog-stereo+input:analog-stereo`). Se fue el auto_null.

LA CAUSA: SPA pide el device `card` (alsa-udev.c:178-183), que no tiene major:minor, y
libudev-zero recorría SÓLO /sys/dev/{block,char} — sólo devices CON nodo. El device que
SPA necesita nunca entraba en la enumeración: no faltaba una propiedad, faltaba la mitad
del espacio de búsqueda.

**Y LA PRIMERA VERSIÓN DEL PARCHE ARREGLÓ EL AUDIO Y ROMPIÓ EL VÍDEO.** Recorría
/sys/class entero, y /sys/class/drm no trae sólo tarjetas: trae los CONECTORES
(card0-Virtual-1) y un fichero `version`, ninguno con nodo. Mutter los tomaba como
candidatos ⇒ `No available CRTC for monitor` + `Page flip failed: drmModeAtomicCommit:
Invalid argument` en bucle. Pantalla negra con el compositor vivo: el mismo síntoma de
antes por una causa nueva. El udev real también los enumera, pero les adjunta las
propiedades por las que mutter los descarta, y ésas libudev-zero no las sintetiza.

La lección, que vale para cualquier reimplementación parcial de una API: **ensanchar la
enumeración expone los huecos de PROPIEDADES a más consumidores. Los dos lados del
contrato tienen que crecer juntos.** El parche final lleva una LISTA ACOTADA de
subsistemas (`sound` hoy); agregar otro es una línea *y* una prueba de que el consumidor
lo necesita y no se rompe.

POR QUÉ NO eudev — y corrijo mi propia sugerencia de antes, que era la peor opción: el
repo ya lo había probado en otro frente y ROMPIÓ EL INPUT. Su libudev.so.1 pisa el de
libudev-zero y, sin udevd, no expone ID_INPUT ⇒ libinput ignora todos los dispositivos en
silencio. Verificación A/B en QEMU de aquel episodio: eudev = 0 «New device»,
libudev-zero = 5. eudev sin udevd es PEOR, y correr udevd contradice la arquitectura
(arje-zero es PID1). El arreglo va donde está el hueco.

Radio pagado: 51 sellados a deuda, 9 en el cierre GNOME (reconstruidos: libinput,
libgudev, colord, mutter, gnome-shell, libgdm, upower, pipewire, wireplumber). El resto
—base, cli, KDE— queda para el latido.

Captura actualizada: escritorio pintando (628 colores) Y audio, cero page-flip fallidos.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 22:36:43 -04:00
sergio 5ca11de820 estado: cosecha granja 2026-07-30T02:26:40Z — avance del árbol KDE 2026-07-29 22:26:40 -04:00
sergioandClaude Opus 5 8c3bd323d5 audio: ALSA encendido en el kernel — y el muro real es libudev-zero, no el stack de audio
ALSA =y en linux-metal (b3:613bca15): HDA legacy + codecs (lo que emula QEMU y usan las
máquinas pre-SOF), SOF para TigerLake (el laptop del target NO suena por la ruta legacy:
Intel movió el audio al DSP) y SND_USB_AUDIO. Todo =y porque el producto es monolítico.
⚠ Falta inyectar el FIRMWARE de SOF en la imagen (intel/sof/*.ri, sof-tplg/*.tplg), igual
que metal-firmware.sh hace con los tgl_* de i915: sin blobs el driver carga y falla.

FUNCIONÓ LA MITAD: en la VM `/dev/snd` ya trae controlC0 + pcmC0D0p/c y /sys/class/sound
lista card0. El kernel detecta la tarjeta. Pero wpctl sigue con `Devices:` vacío.

**Y LA CAUSA ES ESTRUCTURAL, no una propiedad que falte.** `get_card_nr` de SPA
(alsa-udev.c:178-183) sólo acepta el device CARD —`/sys/.../sound/card0`—, que es un
device de CLASE: sin major:minor, sin nodo en /dev. Y `udev_enumerate_scan_devices` de
libudev-zero recorre EXCLUSIVAMENTE /sys/dev/block y /sys/dev/char (udev_enumerate.c:281),
o sea sólo devices CON nodo; el udev real enumera /sys/class entero. **El device que SPA
necesita nunca entra en la enumeración**: no hay guarda que sacar, falta la mitad del
espacio de búsqueda. Salidas: (a) enseñarle a libudev-zero a recorrer /sys/class —radio 51
sellados— o (b) empaquetar eudev. Es decisión de arquitectura, no parche.

CORRIJO ALGO QUE ESCRIBÍ ANTES: el parche `pipewire-sound-initialized.patch` se hizo
creyendo que SOUND_INITIALIZED era el bloqueo, y NO lo era — con el parche aplicado el
resultado no cambió. Se conserva porque la incompatibilidad que describe es real (sin
udevd nadie pone esa propiedad y SPA descartaría toda tarjeta en cuanto la enumeración
funcione), pero su prosa ahora empieza avisando que no es la solución. Sacarlo del camino
importa: dejarlo presentado como el arreglo mandaría al próximo a buscar en el lugar
equivocado.

Dos arreglos de andamiaje que costaron un ciclo cada uno:
- **`-nic none` por defecto.** Agregar la tarjeta de sonido CORRIÓ LAS RUTAS PCI, la entrada
  de disco cacheada en las VARS de OVMF dejó de coincidir, y la firmware se fue al orden por
  defecto: PXE v4, PXE v6, HTTP… minutos de timeouts. Con un TIMEOUT corto eso se lee como
  «la VM no arrancó» y el serial sólo dice `PXE-E16: No valid offer received`.
- El filtro del log de wireplumber era `alsa|udev|sound|card|monitor` con `tail -40`, y se
  llenó de bluez/v4l2/libcamera —tres monitores que avisan que su plugin no está— dejando
  fuera justo las líneas de ALSA. **Un filtro ancho con cola corta es peor que ninguno.**
  Ahora filtra `alsa` y además copia el log entero a la raíz ext4 (tmpfs muere con la VM).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 21:59:18 -04:00
sergio c8bb73bae6 estado: cosecha granja 2026-07-30T01:56:27Z — avance del árbol KDE 2026-07-29 21:56:27 -04:00
sergio db58125b5f estado: cosecha granja 2026-07-30T01:26:10Z — avance del árbol KDE 2026-07-29 21:26:10 -04:00
sergio ce0c44217e estado: cosecha granja 2026-07-30T00:55:55Z — avance del árbol KDE 2026-07-29 20:55:55 -04:00
sergioandClaude Opus 5 51c6830f58 audio: wireplumber (b3:39a9a06c) + lua (b3:e6c35f98) — y el Devices vacío es del KERNEL
Cierra el gestor de sesión de PipeWire, que es lo que separa «PipeWire acepta clientes»
de «PipeWire tiene dispositivos». Su política está escrita en Lua, así que arrastró una
receta de Lua que hubo que autorar entera.

LO QUE LA RECETA DE LUA TIENE QUE INVENTAR: el Makefile de upstream sólo produce
liblua.a y los binarios — **no hay regla de .so ni fichero pkg-config**, los agrega cada
distro. Acá la compartida se enlaza a mano desde la .a con --whole-archive (una estática
sólo aporta lo referenciado y hay que llevarse todo) y el .pc se escribe con los TRES
nombres que se usan por ahí, porque wireplumber prueba lua-5.4, lua5.4 y lua54 en orden.
`-fPIC` no es opcional: libwplua es un objeto compartido.

Dos símbolos más en libelogind (tawasuyu 087230054 → re-pineado 749edfe41):
sd_uid_get_seats y sd_uid_get_state, que module-logind.c de wireplumber usa para saber si
el usuario está en un asiento antes de tomar los dispositivos. Van 28 símbolos sd-*.

**EL `Devices:` VACÍO DE wpctl NO ES UN FALLO DE wireplumber: el kernel no tiene ALSA.**
recipes/linux-metal.toml:111 lo apaga explícito (`-d SOUND -d SND`), así que no hay
/dev/snd que enumerar. Y esto NO se dio por supuesto: se agregó una ich9-intel-hda
emulada a QEMU (AUDIO=1, ahora el default de run-qemu-desktop.sh) justo porque un
«Devices: vacío» se lee IGUAL si wireplumber funciona sobre una VM sin hardware que si no
funciona. Con tarjeta y sin ALSA en el kernel, el resultado no cambia — la ambigüedad
queda resuelta. Encender el sonido en la distro es una decisión con costo (re-sellar el
kernel, rehacer la imagen metal) y queda a la vista en vez de escondida en un default.

Bug propio destapado en el camino: el bloque de wireplumber quedó DUPLICADO en
gnome-start y había DOS wireplumber peleándose el grafo. El síntoma no era un error sino
una lista de clientes que se lee normal si no se cuenta: dos «WirePlumber» con pids
distintos en wpctl status.

Y una nota de ADR 0012 que costó un rato: la cascada de libelogind cortó a mitad y dejó
el `output/` de mutter a medio hacer; el reintento moría con «error opening
'...c.o.d': No such file or directory». Un `rm -rf output` en el configure NO alcanzó
—el árbol tenía estado viejo más allá del build dir—; lo que lo arregló fue BORRAR
work/sources/mutter-* para que el fetch lo re-extraiga limpio.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 20:40:12 -04:00
sergio d57fb8c5c7 estado: cosecha granja 2026-07-30T00:25:06Z — avance del árbol KDE 2026-07-29 20:25:06 -04:00
sergioandClaude Opus 5 5faa259603 audio: PipeWire es el servidor de la distro (decisión del usuario) — gvc conecta
Cierra una pregunta que estaba explícitamente abierta en varias recetas, y que es la
razón por la que `pulseaudio` se había construido con `-Ddaemon=false`: sólo el cliente,
para que gvc hablara el protocolo sin cerrar la decisión de prestado.

**Los dos conviven y por eso la decisión no rompe nada**: pipewire va con
`-Dlibpulse=enabled` ⇒ `pipewire-pulse`, un servidor que habla el protocolo de
PulseAudio. gnome-shell usa libpulse sin enterarse de qué hay del otro lado. No hubo que
tocar una línea del cliente.

  == gnome-qemu :: socket pipewire-0 OK
  == gnome-qemu :: socket pulse/native OK — gvc va a poder conectar
  Gvc-DEBUG: Updating client: index=32 name='pipewire'
  Gvc-DEBUG: Updating sink: index=33 name='auto_null' description='Dummy Output'

El `Failed to connect context: Connection refused` desapareció. El sink es auto_null, que
es la respuesta honesta: la VM no tiene tarjeta de sonido.

**⚠ Falta wireplumber** (gestor de sesión, Lua + su cierre). Sin él PipeWire acepta
clientes pero NO enumera ni enruta dispositivos. «El shell conecta» ≠ «hay sonido», y el
log de arriba es justo el caso donde confundirlos sería fácil. Queda escrito en la receta
y en el runbook.

GOTCHA MEDIDO: ya existía incoming-kde/pipewire.toml sellada y NO se puede reusar
hidratándola acá — los dos cierres traen glib y **no son la misma glib**:
incoming-kde/glib-shared y incoming-gnome/glib producen libglib-2.0.so.0.8800.1 con bytes
distintos (verificado con cmp) y comparten 370 rutas. Proyectar las dos deja que una gane
por orden de proyección ⇒ dos registros de GType en un proceso, el cuadro que costó el
episodio de colord. De ahí la copia en la cola GNOME (glib-shared→glib, dbus→dbus-shared,
pcre2-shared→pcre2), que sí re-construye. Lo que FUE gratis: alsa-lib, cuya única dep es
pkgconf y resuelve al catálogo PADRE ⇒ hash idéntico y cache hit (b3:93cae411).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 19:59:30 -04:00
sergio d250d57c2b estado: cosecha granja 2026-07-29T23:54:54Z — avance del árbol KDE 2026-07-29 19:54:54 -04:00
sergio 579107b6db estado: cosecha granja 2026-07-29T23:24:42Z — avance del árbol KDE 2026-07-29 19:24:42 -04:00
sergioandClaude Opus 5 3d01d5cb04 gnome: el bus de sistema COMPLETO — faltaba polkit, y lo dijo la lista de nombres
bus: org.freedesktop.login1      OK
  bus: org.freedesktop.PolicyKit1  OK
  bus: org.freedesktop.Accounts    OK
  bus: org.freedesktop.UPower      OK

accounts-daemon y upowerd arrancaban, seguían vivos, y NUNCA adquirían su nombre: los
dos se bloquean en `polkit_authority_get_sync()` al iniciar, y `org.freedesktop.PolicyKit1`
no lo servía nadie —nuestra receta polkit es libs-only a propósito, porque el demonio lo
pone arje—. gnome-shell esperaba después 25s por cada uno.

**El dato que lo resolvió no salió del log de los daemons sino de la LISTA DE NOMBRES DEL
BUS**: ahí estaban como conexiones anónimas `:1.0`, `:1.1`, sin nombre bien conocido. Eso
distingue tres cosas que en el log del cliente se ven igual — «no arrancó», «arrancó y no
llegó a pedir el nombre» y «lo pidió y se lo negaron». Era la segunda. `gnome-start` ahora
espera cada nombre con NameHasOwner y, si no aparece, vuelca el log del daemon y la lista.

Receta nueva `arje-polkit-compat` (b3:03e0a86f), tercer shim de este tipo tras
arje-logind-compat y arje-sdlogin-compat. Su propio autor ya había escrito el diagnóstico
en el crate: «apps que usan polkit bloquean en CheckAuthorization si no responde nadie».
⚠ AUTORIZA TODO — es la postura de sistema confiado que arje ya tenía tomada, no algo que
esta receta introduzca; queda explícito en su comentario.

Dos gotchas del empaquetado:
- **La política de polkit ya existe y NO alcanza**: permite `own` sólo al usuario polkitd
  y el shim corre como root. Se agrega un `zz-arje-polkit-compat.conf` en vez de reescribir
  la de upstream — dbus lee system.d en orden alfabético y las posteriores ganan.
- **Los ficheros del rootfs fundido son hardlinks de SÓLO LECTURA del store** (0444). Un
  `cat >` encima falla con Permission denied y rompió un build. Regla: nunca sobrescribir
  un fichero que venga de un artefacto; agregar al lado.

Queda escrito en el runbook lo que sigue faltando (colord, y que el shell no tiene servidor
de sonido porque pulseaudio se construyó sólo-cliente: el demonio de audio de la distro
sigue sin decidirse) y las dos lecciones de método que costaron una iteración cada una.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 19:19:23 -04:00
sergioandClaude Opus 5 32926dc6df gnome: runbook — iconos/cursor cerrados, y el setuid del launch-helper era una causa con dos síntomas
Captura actualizada: ahora se ve el puntero (Adwaita) y el icono de la notificación.
Colores distintos 582 → 629.

El setuid del dbus-daemon-launch-helper explicaba DOS cosas, no una: el «permission of
the setuid helper is not correct» de colord y, por la misma vía, que ninguna activación
por bus de sistema funcionara. Con el arreglo, colord pasó de «permiso incorrecto» a
«timed out» — la activación ya se intenta y lo que queda es del demonio.

Queda UPower: upowerd arranca y sigue vivo, pero no adquiere su nombre en el bus (su
política D-Bus está verificada y permite own a root), así que el shell espera sus 25s.
Es el indicador de batería en una VM sin batería.

Y queda escrita la lección que costó una iteración: **un pid no es un servicio**.
Reportar «lanzado» sin comprobar que el daemon adquirió su nombre es reportar una
intención, no un hecho.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 19:02:45 -04:00
sergioandClaude Opus 5 3999b421da gnome: cursor visible, iconos y el setuid del launch-helper de D-Bus
adwaita-icon-theme b3:429aef43 + hicolor-icon-theme. No es cosmética: con el cursor por
SOFTWARE —obligatorio en virtio-gpu— mutter dibuja la imagen que le da el tema, y sin
tema el puntero se movía INVISIBLE. Ahora se ve en la captura, y la notificación del
shell tiene su icono. Colores distintos 582 → 618.

hicolor arrastrada por `Inherits=hicolor` del index.theme de Adwaita: la cadena de
fallback tiene que terminar en algo que sea un TEMA (con su index.theme), no sólo un
directorio. No trae un solo icono propio — es el contrato, no el contenido.

Dos gotchas medidos:
- **hicolor 0.18 pasó de autotools a meson**: su tarball ya no trae `configure` (127).
- adwaita declara `gtk-update-icon-cache` como `required: true` para un
  `add_install_script` que **su propio autor marcó `skip_if_destdir: true`** — exige un
  binario que en un build empaquetado no puede ejecutar. Se borran los dos bloques.
  `required: false` NO alcanza: meson no propaga el disabler dentro de
  add_install_script y revienta con «Unhandled python exception». Se descartó declarar
  gtk4 como dep: acoplaría el hash de un paquete de DATOS al del toolkit.

**El setuid del launch-helper es la causa raíz de dos síntomas, no de uno.** El
`dbus-daemon-launch-helper` comprueba sus propios permisos antes de activar nada y se
niega si no es setuid root — de ahí el «The permission of the setuid helper is not
correct» de colord. Sin eso NINGUNA activación por bus de sistema funciona, que es
también por qué UPower timeouteaba a los 25s. La imagen ahora lo deja root:messagebus 4750.

Y `gnome-start` lanza upowerd, pero **verificando**: la primera versión decía «lanzado»
y el shell seguía esperando 25s. Un pid no es un servicio. Ahora comprueba que siga vivo
y, si murió, vuelca su log. Además crea los directorios de estado que upower deriva de
--prefix y sin los cuales se muere en silencio.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 18:59:46 -04:00
sergio df43352786 estado: cosecha granja 2026-07-29T22:54:32Z — avance del árbol KDE 2026-07-29 18:54:32 -04:00
sergio 330850182b estado: cosecha granja 2026-07-29T22:24:15Z — avance del árbol KDE 2026-07-29 18:24:15 -04:00
sergioandClaude Opus 5 723f3ead33 gnome: 🏔🏔 EL ESCRITORIO PINTA — Overview de GNOME desde fuente, con captura
docs/evidencia/gnome-shell-qemu-2026-07-29.png: el conmutador de espacios de trabajo,
el reloj en el panel, la miniatura del escritorio, el dash, y la notificación estándar
de GNOME por sesión de root. Todo construido desde fuente sobre el kernel de hammer,
arje-zero como PID1 y musl.

**EL MURO NO ERA DE KMS.** El diagnóstico anterior culpaba al plano primario de
virtio-gpu («no advertised formats», sólo `Queue mode set`, ningún page flip). Era
correlación. Se probó quitando MUTTER_DEBUG_FORCE_KMS_MODE=simple —el log pasó a decir
`using atomic mode setting`, o sea que el cambio SÍ tomó efecto— y la pantalla siguió
con exactamente 2 colores. Refutada. Mutter no tenía un frame que presentar; no es que
no supiera presentarlo.

La causa estaba en el stack trace, en el log, desde el principio: la excepción por el
gschema `org.gnome.settings-daemon.peripherals.touchscreen` ocurre DENTRO de
`Main.start()`, construyendo los quick settings ⇒ el panel nunca se arma. Proceso vivo,
compositor con DRM master, nada que pintar.

Receta `gsd-schemas`: los gschemas de gnome-settings-daemon SIN g-s-d, que sigue
aparcada por GTK3/X11. **Tercera vez que aparece la misma lección** (tras la política
D-Bus de login1 y el `org.gnome.login-screen` de libgdm): un gschema no es un fichero de
datos del demonio, es una interfaz publicada que consume otro programa.

Dos trampas de diagnóstico, las dos ahora blindadas:
- **`glib-compile-schemas` sale con 0 aunque RECHACE un esquema.** Instalé los once XML,
  el log dijo `esquemas OK` y el shell seguía diciendo `not found`: faltaba
  `org.gnome.settings-daemon.enums.xml`, que meson genera con glib-mkenums y no es uno
  de los `.in`. Sin los `<enum>`, glib descarta el esquema entero, avisa por stderr y
  sigue. `gnome-start` ahora vuelca ese stderr SIEMPRE, no sólo al fallar.
- El log serial persiste entre arranques y me hizo leer dos veces un `STATUS +30s` de una
  VM ya muerta. Truncarlo antes de arrancar; `Failed to get "write" lock` avisa de que
  hay otro QEMU con el disco tomado.

Y queda escrito cómo validar CON PANTALLA sin humano delante: screendump por el monitor
de QEMU, con una métrica barata previa a mirar — contar colores distintos. Negro = 2;
pintando = 582, con el azul GNOME (2,60,136) al frente.

Lo que falta son detalles, ninguno impide el escritorio: lanzar upowerd desde gnome-start,
un tema de cursor, el setuid de colord y gnome-control-center.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 18:05:20 -04:00
sergio 517c1bb4ff estado: cosecha granja 2026-07-29T19:32:09Z — avance del árbol KDE 2026-07-29 15:32:09 -04:00
sergioandClaude Opus 5 a3b49c24dc gnome: runbook al día — la capa JS cerrada, el muro nuevo es que no PINTA
Estado: gnome-shell corre 5 minutos sobre DRM real sin una sola JS ERROR, y la
captura del framebuffer muestra la consola del kernel en negro. Mutter nunca
presentó un frame.

La pista del log de KMS es concreta: el plano primario 33 de virtio-gpu 'has no
advertised formats' y sólo hay 'Queue mode set' — ningún page flip. Tres hipótesis
de una variable cada una, la primera es quitar MUTTER_DEBUG_FORCE_KMS_MODE=simple,
que se heredó de la campaña KDE (donde el que fallaba con atomic era kwin).

Queda además escrito CÓMO validar con pantalla sin humano delante: screendump por
el monitor de QEMU + PPM→PNG. Aplicar esa regla es lo que destapó este muro — el
serial decía 'sesión viva'.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 15:19:22 -04:00
sergioandClaude Opus 5 417ba2a502 gnome: 🏔 LA SESIÓN ARRANCA Y SE QUEDA VIVA — cae el último muro de la capa JS
== gnome-qemu :: compositor OK (wayland-0) — el shell ES el display server
  == gnome-qemu :: STATUS +15s … +315s: gnome-shell=2

Sin una sola `JS ERROR`. gnome-shell corre 5 minutos seguidos sobre DRM real.

Dos cierres, los dos por auditar en vez de adivinar:

1. GL-1.0 y libxml2-2.0 sumados a gi-foreign-typelibs. La primera auditoría de
   `<include>` la hice sólo sobre los girs de /usr/share/gir-1.0 y me faltaron los que
   entran por los girs PRIVADOS de mutter (Clutter-16, Cogl-16 → GL-1.0, o sea que sin
   él no carga `Meta`: el compositor entero) y por los de eds (Camel, EBook,
   EDataServer → libxml2-2.0). Un ciclo de imagen+arranque perdido por auditar de menos.
   La forma correcta —y ahora escrita en la receta— es cruzar los `<include>` de TODOS
   los .gir del rootfs hidratado contra los typelibs presentes. Queda un solo huérfano,
   `xlib-2.0`, que sólo incluye `xft-2.0`, a quien no incluye nadie: no es una falta.

2. libgdm vuelve a construir su `data/`. La había borrado entera por parecer «cosas del
   greeter», y ahí vive el gschema **org.gnome.login-screen**, que gnome-shell lee al
   arrancar: sin él muere con `Gio.IOErrorEnum: GSettings schema ... not found`. Un
   esquema de GSettings no es un fichero de datos del demonio — es una interfaz publicada
   que consume otro programa. Se borra sólo `subdir('dconf')`, la única pieza que necesita
   el binario `dconf`.

Lo que queda son avisos, no muros: falta un tema de cursor, colord no arranca por el
setuid del helper, y `org.gnome.settings-daemon.peripherals.touchscreen` no existe
porque g-s-d está aparcada (rompe quick-settings, no la sesión).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 15:16:03 -04:00
sergio f70c4a2339 estado: cosecha granja 2026-07-29T19:02:00Z — avance del árbol KDE 2026-07-29 15:02:00 -04:00
sergioandClaude Opus 5 8d1efca26e gnome: GIRepository-2.0 — el typelib que no pide el shell sino gjs
Con los siete de `dependencies.js` cerrados, el arranque avanzó y murió en uno que NO
está en esa lista:

  JS ERROR: Requiring GIRepository, version 2.0: Typelib file ... not found

El que lo pide es **gjs**, desde su propio JavaScript embebido: su GResource trae
literalmente `imports.gi.versions.GIRepository = '2.0';` (verificado con strings sobre
libgjs.so.0). Dep de runtime del INTÉRPRETE — invisible al grafo de build Y a la lista
del shell. O sea que `dependencies.js` es necesario pero no suficiente: hay una capa
más abajo.

HAY DOS GIRepository Y NO SON LO MISMO, y los números confunden a propósito:
  · GIRepository-3.0 = la API NUEVA, la que GLib absorbió (libgirepository-2.0). La
    produce glib-introspected y ya estaba.
  · GIRepository-2.0 = la API VIEJA, la de libgirepository-1.0.so.1, contra la que gjs
    está enlazado. La produce gobject-introspection, pero sólo con
    -Dbuild_introspection_data=true, y el nuestro va con false.
La 2.0 es la vieja porque nombra la librería 1.0; la 3.0 es la nueva porque nombra la 2.0.

Receta aparte en vez de prenderle la opción a g-i: su radio alcanza toda la cadena GNOME
(catorce recetas la declaran para escanear) y además traería de vuelta los typelibs de
X11/cairo que motivaron apagarla. Acá el radio es cero.

Replica el custom_target('gir-girepository') de upstream (gir/meson.build:494) pero
escaneando contra la libgirepository-1.0 ya instalada. **La lista de fuentes va enumerada
a mano y no como glob**, y no es prolijidad: `girepository/*.h` barre también
`gitypelib-internal.h`, que declara G_TYPELIB_ERROR; el scanner emite entonces el stanza
del error-quark y su binario temporal no linkea, porque `g_typelib_error_quark` es LOCAL
en la .so instalada. Upstream nunca lo escanea — el glob era el error.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 14:54:34 -04:00
sergio 7642b4fbbc estado: cosecha granja 2026-07-29T18:31:51Z — avance del árbol KDE 2026-07-29 14:31:51 -04:00
sergioandClaude Opus 5 bc4d0c8aea gnome: los 7 typelibs CERRADOS — librsvg y ibus, y dos deudas viejas pagadas de paso
Rsvg-2.0   librsvg b3:351f4658
  IBus-1.0   ibus    b3:d4d3750a

**1. PERILLA NUEVA DEL LAB: `[source] cargo_vendor`.** `detect_build_system` asume UN
sistema de build por árbol, y librsvg genuinamente tiene dos: `configure.ac` gana por
precedencia pero su Makefile llama a `cargo build`, que dentro del sandbox hermético
no tiene red. La perilla fuerza el vendoreo (que ocurre en el fetch, donde sí hay red)
sin tocar la detección. **No entra al ArtifactHash** —decide de dónde salen las deps,
no cuáles: eso lo fija el Cargo.lock, ya bajo el sha256 de la fuente— así que se puede
prender en una receta ya sellada sin re-hashear nada. Con test, y verificado en vivo:
libelogind no movió su hash tras el cambio.

**2. LA DEUDA DEL UNWINDER, PAGADA.** librsvg moría en
`undefined reference: _Unwind_DeleteException`. No es de librsvg: es de la `std` de
rustc, que trae landing pads y espera el runtime que en glibc vive en libgcc_s. Es la
deuda que el corpus arrastra desde matar-gcc —«las 12 recetas Rust son UN problema, no
12»— y el remedio estaba a mano: **zig empaqueta la libunwind de LLVM** y exporta los
`_Unwind_*` (verificado con nm). Alcanza `LIBS=-lunwind`. Va por LIBS y no por LDFLAGS
porque autotools pone LIBS al FINAL de la línea de enlace, que es donde tiene que ir
una librería que resuelve símbolos indefinidos.

librsvg va en 2.58.5 y no 2.59+: en 2.59 cambió a meson + cargo-c, y cargo-cbuild
enlaza el crate `cargo` entero (libgit2, libssh2, libcurl, openssl) — una campaña
propia por un binario que sólo corre en el constructor. 2.58.5 produce el mismo
Rsvg-2.0. Mismo criterio que gnome-desktop 44.5.

**3. `x11-compose-data`, y es una tensión que vale la pena tener escrita.** ibus COMPILA
la tabla de teclas muertas de X11 dentro de libibus (Makefile.am:310, incondicional, sin
`--disable-`). Sin datos no construye. Los datos viven en el tarball de libX11 por
historia, no por necesidad técnica: son 5192 líneas de reglas. La receta extrae SÓLO los
ficheros de locale reproduciendo la regla de upstream (`cpprules.in`: cpp crudo +
CPP_SED_MAGIC literal) y no compila una línea de X11. Un escritorio Wayland-only sigue
necesitando la tabla de composición del mundo Unix.

Gotchas de ibus, los tres medidos: su ayuda MIENTE (`--enable-gtk4`/`--enable-wayland`
sugieren default apagado; el default es `yes`); `--disable-emoji-dict` NO apaga
`--disable-unicode-dict`; y con `--disable-wayland` el build muere igual porque
`tools/main.c` llama wl_display_* sin `#ifdef` mientras WAYLAND_LIBS sólo se agrega si
la opción está prendida — bug de upstream en su propia configuración sin Wayland.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 14:28:50 -04:00
sergio 0a76ead129 estado: cosecha granja 2026-07-29T18:01:41Z — avance del árbol KDE 2026-07-29 14:01:41 -04:00
sergioandClaude Opus 5 4d48edac0d gnome: 5 de los 7 typelibs de runtime — gnome-desktop a la isla dinámica + 5 recetas nuevas
De los siete que faltaban quedan dos (Rsvg, IBus). Cerrados acá:

  GnomeDesktop-4.0 + GnomeBG-4.0  gnome-desktop b3:b3aed0d6
  UPowerGlib-1.0                  upower        b3:95d1081a
  Geoclue-2.0                     geoclue       b3:50e9de94
  GWeather-4.0                    libgweather   b3:d289ac66

gnome-desktop NO se duplicó en una variante `-introspected`, y la razón es la regla de
los dos registros de GType: mutter y gnome-shell ENLAZAN libgnome-desktop y gjs además
dlopearía la .so del typelib ⇒ convivirían la .a enlazada y la .so cargada, cada una
con su tabla. Es el cuadro que costó el episodio de colord. `yupana radio` = 2 sellados
a deuda (mutter, gnome-shell), el mismo par de siempre. Con introspección encendida los
dos seds que borraban `libgnome_rr_gir`/`libgnome_bg_gir` dejan de hacer falta.

Su cierre tuvo que pasar a las variantes `-shared`, y no por prolijidad: con `libpng`
estática no hay libpng16.so, `libgdk_pixbuf-2.0.so.0` no relocaliza y el `ldd` con que
g-ir-scanner resuelve las shlibs sale con 127. **Si una receta introspecta, su cierre
entero tiene que ser CARGABLE** — el scanner compila y ejecuta un binario de verdad.

Dos recetas entraron por transitividad, no por la lista del shell:
- geocode-glib (b3:f24e4147), que pide libgweather. Su `-Dsoup2=false` es LA opción:
  con el default se construye `geocode-glib-1.0` contra libsoup2 —que esta distro no
  tiene— y libgweather no la encuentra aunque esté instalada.
- py3-gobject/pygobject (b3:492930f2), y ésta ni siquiera va a la imagen: va al
  CONSTRUCTOR. `gen_locations_variant.py` de libgweather importa gi.repository.GLib
  para serializar la base de ciudades a un GVariant binario. El formato lo define GLib.

Decisiones de alcance escritas en cada receta: geoclue va SIN demonio
(-Denable-backend=false evita ModemManager, Avahi y libsoup; la librería cliente habla
por D-Bus), upower sin libimobiledevice, y libgweather sin `po-locations` ⇒ las ciudades
salen en inglés, la base de datos se genera igual.

De upower, tres perillas que hay que fijar porque su `auto` significa "preguntale a un
pkg-config de systemd": udevrulesdir/udevhwdbdir (nuestro udev-pc declara `udevdir`, no
`udev_dir`) y systemdsystemunitdir=no.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 13:43:06 -04:00
sergioandClaude Opus 5 cde77a8c91 gnome: la frontera de runtime MEDIDA — 7 typelibs, 6 proveedores, y la regla que la destapó
Venía cerrando typelibs de a uno: AccountsService → DBus-1.0 → cairo-1.0 → Gdm-1.0,
un rebuild de imagen y un arranque completo por cada uno. Cuatro rondas para
descubrir que la lista estaba escrita todo el tiempo.

`js/misc/dependencies.js` de gnome-shell ENUMERA lo que el shell exige al arrancar.
Cruzada contra el rootfs hidratado, la frontera completa es exacta:

  GnomeDesktop-4.0 + GnomeBG-4.0  → gnome-desktop (YA sellada, pero -Dintrospection=false
                                     y estática ⇒ falta la variante de isla dinámica)
  Geoclue-2.0                     → geoclue      (sin receta)
  GWeather-4.0                    → libgweather  (sin receta)
  IBus-1.0                        → ibus         (sin receta)
  Rsvg-2.0                        → librsvg      (sin receta; es Rust)
  UPowerGlib-1.0                  → upower       (sin receta)

Los otros veinte de la lista ya están. GnomeBluetooth, NM/NMA4 y Malcontent son
condicionales y no bloquean.

REGLA, y es el precio de no haberla aplicado antes: cuando el muro es `Requiring X`,
no cierres X y vuelvas a arrancar — leé el fichero donde el programa DECLARA sus deps
de runtime y cerralas todas de una.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 13:02:51 -04:00