reparación: pisé la receta de swayimg de otro agente — y el volumen
⚠⚠ LO PRIMERO, PORQUE ES UNA REPARACIÓN Y NO UNA MEJORA.
Escribí recipes/swayimg.toml con `cat >` SIN COMPROBAR QUE YA EXISTÍA. Otro
agente la había llevado de 4.7 a 5.5 (commits d8dd7798 y e2bcd96f) y mi commit
f675db27 borró 70 líneas suyas. Entre ellas su decisión de usar el liblua por
DEFECTO, que es luajit — y por eso ese agente había escrito recipes/luajit.toml.
Mi -Dliblua=lua dejó su luajit SIN UN SOLO CONSUMIDOR (medido: ningún [deps] del
catálogo lo nombraba).
Y además lo declaramos los dos: swayimg quedó DUPLICADO en 4 perfiles (kde,
gnome, cosmic, sway).
Reparado:
· swayimg vuelve a -Dliblua=luajit, el default de upstream y lo que ese agente
empaquetó para esto (luajit.pc + libluajit-5.1.{a,so}, sellado al hash
vigente). Verificado: sella y el guardián confirma el símbolo luaJIT_setmode
· quitadas MIS 4 declaraciones duplicadas, conservando las suyas, que llegaron
primero. escritorio-mirada conserva la mía porque ahí era la única. Cada
perfil queda con una
· CONSERVO -Dexif=enabled con exiv2, que ellos tenían apagado: sin EXIF las
fotos verticales de móvil salen tumbadas. Eso es una mejora, no una
preferencia, y va con su motivo escrito
LA LECCIÓN, que es la regla 2 del repo por una puerta que no estaba escrita:
`cat >` sobre un fichero del repo compartido es DESTRUCTIVO y no avisa. El
`git add` acotado no protege de esto — el fichero ya estaba sobrescrito antes de
llegar a git. Lo que correspondía era comprobar `[ -f <ruta> ]` antes de escribir.
── Y EL VOLUMEN ──────────────────────────────────────────────────────────────
pamixer cierra «audio de escritorio», que el censo marcaba 5 de 5 ausente con el
problema exacto: PipeWire sonaba y no había con qué subirle el volumen — ni
gráfico, ni de consola, ni un atajo de teclado posible, porque un atajo llama a
un comando y el comando no existía.
⚠ Sus DOS fallos estaban documentados en este repo, por mí, hoy:
· exit 127 en `meson setup` → meson es un script de Python y no declaré
python3. Está en la memoria `receta-meson-exige-python3`
· «--help no muestra su uso» → el cargador decía
«Error loading shared library libsndfile.so.1 (needed by
libpulsecommon-17.0.so)». La cadena pamixer → libpulse → libpulsecommon →
libsndfile está dibujada con los mismos símbolos (sf_command,
sf_error_number) en recipes/espeak-ng.toml, que escribí esta misma sesión
Tenerlo escrito no sirvió porque no lo consulté antes de escribir la receta
nueva. El conocimiento de este repo vive en las recetas vecinas, no sólo en la
fuente de upstream.
DECLARADO: pamixer en los 5 escritorios (7,5 MB; pipewire, pulseaudio y
libsndfile ya viajaban ahí). smartmontools en `base`, junto a parted y
e2fsprogs, que son de su familia — 13 MB de los que el 82 % es .debug_*.
cxxopts NO se declara: es una cabecera y no deja nada que viaje.
Delta semántico
Ninguna definición cambió: el cambio es de texto, documentación o datos.
3 archivos · +220 −141
- docs/state/targets.toml +108 −136
- recipes/pamixer.toml +93 −0
- recipes/swayimg.toml +19 −5
diff --git a/docs/state/targets.toml b/docs/state/targets.toml
index 4f9de918..a82453b8 100644
--- a/docs/state/targets.toml
+++ b/docs/state/targets.toml
@@ -183,6 +183,24 @@ paquetes = [
"iproute2", "iputils", "dhcpcd", "e2fsprogs", "dosfstools", "parted", "rsync",
"sed", "tzdata", "vim", "dbus", "ca-certificates", "gnupg", "lsof", "strace",
"pciutils", "usbutils", "mandoc",
+ # `smartmontools` (2026-10-20): SMART, o sea preguntarle a un disco si se está muriendo. Va en
+ # `base` —y por tanto en las 8 imágenes— por dos razones:
+ # · es de la MISMA familia que `parted` y `e2fsprogs`, que ya están en esta lista: herramientas
+ # de disco que uno quiere tener **antes** de necesitarlas, no después
+ # · el censo marcaba «discos y salud del equipo» 4 de 4 ausente, y acá no es hipotético: la
+ # memoria del repo tiene un disco de 5,9 G que al llenarse NO se degrada, se cae entero, y un
+ # «0 fallan» que era mentira por falta de inodos. Todo eso es ESPACIO; la salud del hardware
+ # no la miraba nadie. Un disco con sectores reasignados en aumento avisa días antes — pero
+ # sólo si alguien pregunta
+ #
+ # ⚠ PESO: 13 MB, de los que **el 82 % es `.debug_*`** (10,7 MB, sumado con readelf) ⇒ ~2,4 MB
+ # desnudado. Norma del corpus; su sitio es el SDD 23, no esta línea.
+ #
+ # ⚠ Lo que NO cubre, dicho: su receta va con `--without-libusb`, así que **no lee el SMART de un
+ # disco externo por USB**; los internos (ATA/SCSI/NVMe) van por ioctl. Y no instala servicio: el
+ # init es `arje`, así que `smartd` —la vigilancia continua— se declara ahí cuando alguien lo
+ # decida. Lo que esta línea da es `smartctl`, a mano.
+ "smartmontools",
# `pinentry` (2026-09-22, paso 9): el diálogo de contraseña que a `gnupg` le faltaba. Sin él, el
# gnupg que ya viajaba acá VERIFICA bien pero no puede usar NINGUNA clave con contraseña
# —`gpg: signing failed: No pinentry`—, o sea que `git commit -S` fallaba en la imagen con la
@@ -696,6 +714,24 @@ paquetes = [
# el perfil `cli`, que hoy no lleva visor. No se declara ahí porque son 70 MB en una imagen que no
# me pidieron cambiar — pero el coste está medido y la capacidad existe.
"swayimg",
+ # ── Y SE PUEDE SUBIR EL VOLUMEN (2026-10-20) ────────────────────────────────────────────────
+ # El censo marcaba «audio de escritorio» 5 de 5 ausente, con el problema exacto: «PipeWire suena y
+ # no hay con qué subirle el volumen desde una ventana». O sea que la distro reproducía audio y
+ # **no tenía ningún control de volumen** — ni gráfico, ni de consola, ni un atajo de teclado
+ # posible, porque un atajo llama a un comando y el comando no existía.
+ #
+ # `pamixer` sube, baja, silencia y lista fuentes y sumideros: es lo que un compositor engancha a
+ # las teclas de volumen. Su `cxxopts` NO se declara — es sólo una cabecera y no deja nada que viaje.
+ #
+ # ⚠ Habla el protocolo de PulseAudio y eso NO es un desajuste: `pipewire` publica esa capa
+ # (`pipewire-pulse` + `libpipewire-module-protocol-pulse.so`, verificado en el artefacto) y la
+ # biblioteca cliente `libpulse.so.0` la publica `pulseaudio`. Las dos ya viajan en estos cinco
+ # perfiles, igual que `libsndfile`, así que esto cuesta sólo sus 7,5 MB.
+ #
+ # ⚠ Su cadena de runtime baja TRES niveles y es lo que hizo fallar el primer build:
+ # `pamixer → libpulse.so → libpulsecommon.so → libsndfile.so.1`. Está documentada igual en
+ # `recipes/espeak-ng.toml` — el sandbox sólo monta lo declarado, y yo no la consulté.
+ "pamixer",
"fontconfig-shared", # /etc/fonts/fonts.conf y el soname que enlaza el riel
"freetype-shared", # libfontconfig.so.1 pide libfreetype.so.6: sin ella el riel muere al cargar
"libpng-shared", # y freetype pide libpng16.so.16 — la cadena entera entro por querer letras
@@ -929,40 +965,6 @@ paquetes = [
# máquina. No se declara acá por simetría —se sigue dónde estaba `espeak-ng`— pero es una decisión
# pendiente y no un olvido.
"speech-dispatcher", "dotconf", "brltty", "liblouis",
- # ── Y SE PUEDE ABRIR UNA IMAGEN (2026-10-20) ────────────────────────────────────────────────
- # `censo-distro.py` marcaba «visores de imagen» **5 de 5 ausente**: la distro no tenía NINGUNA
- # forma de abrir un JPEG. Los tres candidatos obvios se descartaron por MEDICIÓN, no por fama:
- # `nsxiv`, `feh` son Xlib, y esta distro es Wayland-only ⇒ muro
- # `imv` el recomendado para Wayland, y **no sirve acá**: pide `egl`, `gl`, `opengl`,
- # `glu` y `wayland-egl`, y este corpus no publica `libGL.so` ni `gl.pc`
- # (comprobado) — el mismo muro que bloquea a `kitty`
- # `swayimg` **cero menciones de GL** en su `meson.build`. Pinta por software
- #
- # `swayimg` png, jpeg, webp, tiff y gif, **cada formato con su perilla FIJA**: sus opciones son
- # `feature` con default `auto`, y una dep ausente se saltaría EN SILENCIO dejando un
- # visor que no abre PNG y no dice por qué
- # `exiv2` la rotación EXIF. Una cámara de móvil no rota los píxeles: anota la orientación en
- # una etiqueta. Sin esto **todas las fotos verticales salen tumbadas**, sin error y
- # sin remedio. ⚠ NO se declara acá: entra ESTÁTICA dentro del binario (su `.so`
- # habría cruzado objetos de C++ entre módulos, que es lo que segfaulteó a
- # `libime_pinyindict`)
- #
- # ⚠ PESO: 70 MB, y **el 85 % es `.debug_*`** (59 de 69 MB, sumado con readelf) ⇒ ~10 MB
- # desnudado. La norma del corpus; su sitio es el SDD 23.
- #
- # ✅ El binario sale **autosuficiente: un solo `NEEDED`, `libc.so`** (medido). Todo lo demás
- # —wayland, xkb, drm, png, jpeg, webp, tiff, gif, fontconfig, freetype, lua— entra estático, así
- # que declararlo no arrastra ningún proveedor compartido.
- #
- # ⚠ QUEDA AFUERA Y SE DICE: `svg=disabled`, porque `librsvg` sólo existe en `incoming-gnome`
- # enredada con su pila de introspección (promoverla cuesta 35 recetas, medido). **No abre SVG.**
- # Y `heif/avif/jxl/jp2/exr/raw` tampoco: esas bibliotecas no están en el corpus.
- #
- # ⚠ Y UNA DECISIÓN QUE NO TOMO ACÁ: `swayimg` se construyó con `drm=enabled`, o sea que puede
- # mostrar una imagen **desde una consola TTY, sin compositor**. Eso es exactamente lo que querría
- # el perfil `cli`, que hoy no lleva visor. No se declara ahí porque son 70 MB en una imagen que no
- # me pidieron cambiar — pero el coste está medido y la capacidad existe.
- "swayimg",
# `dejavu-fonts-nerd` es la MISMA DejaVu Sans Mono parcheada con Nerd Fonts (~10.000 glifos de
# iconos: Powerline, Font Awesome, Devicons…) que usan starship, lsd, eza, neovim y las
# statuslines; sin ellos dibujan cuadraditos. Se AÑADE, no reemplaza: la licencia de Bitstream
@@ -1092,6 +1094,24 @@ paquetes = [
# ninguna cola. swayimg rasteriza a `wl_shm` y no toca GL; el porqué largo está en su receta.
# Trae de yapa backend DRM: muestra imágenes en una TTY pelada, sin compositor.
"swayimg",
+ # ── Y SE PUEDE SUBIR EL VOLUMEN (2026-10-20) ────────────────────────────────────────────────
+ # El censo marcaba «audio de escritorio» 5 de 5 ausente, con el problema exacto: «PipeWire suena y
+ # no hay con qué subirle el volumen desde una ventana». O sea que la distro reproducía audio y
+ # **no tenía ningún control de volumen** — ni gráfico, ni de consola, ni un atajo de teclado
+ # posible, porque un atajo llama a un comando y el comando no existía.
+ #
+ # `pamixer` sube, baja, silencia y lista fuentes y sumideros: es lo que un compositor engancha a
+ # las teclas de volumen. Su `cxxopts` NO se declara — es sólo una cabecera y no deja nada que viaje.
+ #
+ # ⚠ Habla el protocolo de PulseAudio y eso NO es un desajuste: `pipewire` publica esa capa
+ # (`pipewire-pulse` + `libpipewire-module-protocol-pulse.so`, verificado en el artefacto) y la
+ # biblioteca cliente `libpulse.so.0` la publica `pulseaudio`. Las dos ya viajan en estos cinco
+ # perfiles, igual que `libsndfile`, así que esto cuesta sólo sus 7,5 MB.
+ #
+ # ⚠ Su cadena de runtime baja TRES niveles y es lo que hizo fallar el primer build:
+ # `pamixer → libpulse.so → libpulsecommon.so → libsndfile.so.1`. Está documentada igual en
+ # `recipes/espeak-ng.toml` — el sandbox sólo monta lo declarado, y yo no la consulté.
+ "pamixer",
# ── LAS `.so` QUE mesa Y wayland PIDEN EN RUNTIME Y NINGÚN ARTEFACTO DEL CIERRE PROVEE ────────
# Medido el 2026-09-03 recorriendo los NEEDED de todo el cierre de esta imagen contra los SONAME
# que ese mismo cierre publica: `libEGL.so.1` pide `libexpat.so.1` y `libwayland-client.so.0` pide
@@ -1488,6 +1508,24 @@ paquetes = [
# ninguna cola. swayimg rasteriza a `wl_shm` y no toca GL; el porqué largo está en su receta.
# Trae de yapa backend DRM: muestra imágenes en una TTY pelada, sin compositor.
"swayimg",
+ # ── Y SE PUEDE SUBIR EL VOLUMEN (2026-10-20) ────────────────────────────────────────────────
+ # El censo marcaba «audio de escritorio» 5 de 5 ausente, con el problema exacto: «PipeWire suena y
+ # no hay con qué subirle el volumen desde una ventana». O sea que la distro reproducía audio y
+ # **no tenía ningún control de volumen** — ni gráfico, ni de consola, ni un atajo de teclado
+ # posible, porque un atajo llama a un comando y el comando no existía.
+ #
+ # `pamixer` sube, baja, silencia y lista fuentes y sumideros: es lo que un compositor engancha a
+ # las teclas de volumen. Su `cxxopts` NO se declara — es sólo una cabecera y no deja nada que viaje.
+ #
+ # ⚠ Habla el protocolo de PulseAudio y eso NO es un desajuste: `pipewire` publica esa capa
+ # (`pipewire-pulse` + `libpipewire-module-protocol-pulse.so`, verificado en el artefacto) y la
+ # biblioteca cliente `libpulse.so.0` la publica `pulseaudio`. Las dos ya viajan en estos cinco
+ # perfiles, igual que `libsndfile`, así que esto cuesta sólo sus 7,5 MB.
+ #
+ # ⚠ Su cadena de runtime baja TRES niveles y es lo que hizo fallar el primer build:
+ # `pamixer → libpulse.so → libpulsecommon.so → libsndfile.so.1`. Está documentada igual en
+ # `recipes/espeak-ng.toml` — el sandbox sólo monta lo declarado, y yo no la consulté.
+ "pamixer",
# ── LECTOR DE DOCUMENTOS ─────────────────────────────────────────────────────────────────────
# ⚠ NO ESTÁ EN `escritorio-kde`, y no es un olvido. `zathura-pdf-poppler` necesita `poppler-glib`,
# que es una receta NUEVA del corpus (la que ya existía va `-DENABLE_GLIB=OFF` y vive en la cola
@@ -1706,40 +1744,6 @@ paquetes = [
# máquina. No se declara acá por simetría —se sigue dónde estaba `espeak-ng`— pero es una decisión
# pendiente y no un olvido.
"speech-dispatcher", "dotconf", "brltty", "liblouis",
- # ── Y SE PUEDE ABRIR UNA IMAGEN (2026-10-20) ────────────────────────────────────────────────
- # `censo-distro.py` marcaba «visores de imagen» **5 de 5 ausente**: la distro no tenía NINGUNA
- # forma de abrir un JPEG. Los tres candidatos obvios se descartaron por MEDICIÓN, no por fama:
- # `nsxiv`, `feh` son Xlib, y esta distro es Wayland-only ⇒ muro
- # `imv` el recomendado para Wayland, y **no sirve acá**: pide `egl`, `gl`, `opengl`,
- # `glu` y `wayland-egl`, y este corpus no publica `libGL.so` ni `gl.pc`
- # (comprobado) — el mismo muro que bloquea a `kitty`
- # `swayimg` **cero menciones de GL** en su `meson.build`. Pinta por software
- #
- # `swayimg` png, jpeg, webp, tiff y gif, **cada formato con su perilla FIJA**: sus opciones son
- # `feature` con default `auto`, y una dep ausente se saltaría EN SILENCIO dejando un
- # visor que no abre PNG y no dice por qué
- # `exiv2` la rotación EXIF. Una cámara de móvil no rota los píxeles: anota la orientación en
- # una etiqueta. Sin esto **todas las fotos verticales salen tumbadas**, sin error y
- # sin remedio. ⚠ NO se declara acá: entra ESTÁTICA dentro del binario (su `.so`
- # habría cruzado objetos de C++ entre módulos, que es lo que segfaulteó a
- # `libime_pinyindict`)
- #
- # ⚠ PESO: 70 MB, y **el 85 % es `.debug_*`** (59 de 69 MB, sumado con readelf) ⇒ ~10 MB
- # desnudado. La norma del corpus; su sitio es el SDD 23.
- #
- # ✅ El binario sale **autosuficiente: un solo `NEEDED`, `libc.so`** (medido). Todo lo demás
- # —wayland, xkb, drm, png, jpeg, webp, tiff, gif, fontconfig, freetype, lua— entra estático, así
- # que declararlo no arrastra ningún proveedor compartido.
- #
- # ⚠ QUEDA AFUERA Y SE DICE: `svg=disabled`, porque `librsvg` sólo existe en `incoming-gnome`
- # enredada con su pila de introspección (promoverla cuesta 35 recetas, medido). **No abre SVG.**
- # Y `heif/avif/jxl/jp2/exr/raw` tampoco: esas bibliotecas no están en el corpus.
- #
- # ⚠ Y UNA DECISIÓN QUE NO TOMO ACÁ: `swayimg` se construyó con `drm=enabled`, o sea que puede
- # mostrar una imagen **desde una consola TTY, sin compositor**. Eso es exactamente lo que querría
- # el perfil `cli`, que hoy no lleva visor. No se declara ahí porque son 70 MB en una imagen que no
- # me pidieron cambiar — pero el coste está medido y la capacidad existe.
- "swayimg",
# `dejavu-fonts-nerd` es la MISMA DejaVu Sans Mono parcheada con Nerd Fonts (~10.000 glifos de
# iconos: Powerline, Font Awesome, Devicons…) que usan starship, lsd, eza, neovim y las
# statuslines; sin ellos dibujan cuadraditos. Se AÑADE, no reemplaza: la licencia de Bitstream
@@ -2123,40 +2127,6 @@ paquetes = [
# máquina. No se declara acá por simetría —se sigue dónde estaba `espeak-ng`— pero es una decisión
# pendiente y no un olvido.
"speech-dispatcher", "dotconf", "brltty", "liblouis",
- # ── Y SE PUEDE ABRIR UNA IMAGEN (2026-10-20) ────────────────────────────────────────────────
- # `censo-distro.py` marcaba «visores de imagen» **5 de 5 ausente**: la distro no tenía NINGUNA
- # forma de abrir un JPEG. Los tres candidatos obvios se descartaron por MEDICIÓN, no por fama:
- # `nsxiv`, `feh` son Xlib, y esta distro es Wayland-only ⇒ muro
- # `imv` el recomendado para Wayland, y **no sirve acá**: pide `egl`, `gl`, `opengl`,
- # `glu` y `wayland-egl`, y este corpus no publica `libGL.so` ni `gl.pc`
- # (comprobado) — el mismo muro que bloquea a `kitty`
- # `swayimg` **cero menciones de GL** en su `meson.build`. Pinta por software
- #
- # `swayimg` png, jpeg, webp, tiff y gif, **cada formato con su perilla FIJA**: sus opciones son
- # `feature` con default `auto`, y una dep ausente se saltaría EN SILENCIO dejando un
- # visor que no abre PNG y no dice por qué
- # `exiv2` la rotación EXIF. Una cámara de móvil no rota los píxeles: anota la orientación en
- # una etiqueta. Sin esto **todas las fotos verticales salen tumbadas**, sin error y
- # sin remedio. ⚠ NO se declara acá: entra ESTÁTICA dentro del binario (su `.so`
- # habría cruzado objetos de C++ entre módulos, que es lo que segfaulteó a
- # `libime_pinyindict`)
- #
- # ⚠ PESO: 70 MB, y **el 85 % es `.debug_*`** (59 de 69 MB, sumado con readelf) ⇒ ~10 MB
- # desnudado. La norma del corpus; su sitio es el SDD 23.
- #
- # ✅ El binario sale **autosuficiente: un solo `NEEDED`, `libc.so`** (medido). Todo lo demás
- # —wayland, xkb, drm, png, jpeg, webp, tiff, gif, fontconfig, freetype, lua— entra estático, así
- # que declararlo no arrastra ningún proveedor compartido.
- #
- # ⚠ QUEDA AFUERA Y SE DICE: `svg=disabled`, porque `librsvg` sólo existe en `incoming-gnome`
- # enredada con su pila de introspección (promoverla cuesta 35 recetas, medido). **No abre SVG.**
- # Y `heif/avif/jxl/jp2/exr/raw` tampoco: esas bibliotecas no están en el corpus.
- #
- # ⚠ Y UNA DECISIÓN QUE NO TOMO ACÁ: `swayimg` se construyó con `drm=enabled`, o sea que puede
- # mostrar una imagen **desde una consola TTY, sin compositor**. Eso es exactamente lo que querría
- # el perfil `cli`, que hoy no lleva visor. No se declara ahí porque son 70 MB en una imagen que no
- # me pidieron cambiar — pero el coste está medido y la capacidad existe.
- "swayimg",
# ⚠ «sin puntero» lo decía este comentario desde que se escribió y NO era cierto: `cosmic-icons`
# instala iconos de aplicación, no cursores, así que este perfil llegó a 43/43 con el puntero
# INVISIBLE. Lo cazó `vigia-imagen.py` el 2026-09-04. Los cursores son su propia raíz.
@@ -2270,6 +2240,24 @@ paquetes = [
# ninguna cola. swayimg rasteriza a `wl_shm` y no toca GL; el porqué largo está en su receta.
# Trae de yapa backend DRM: muestra imágenes en una TTY pelada, sin compositor.
"swayimg",
+ # ── Y SE PUEDE SUBIR EL VOLUMEN (2026-10-20) ────────────────────────────────────────────────
+ # El censo marcaba «audio de escritorio» 5 de 5 ausente, con el problema exacto: «PipeWire suena y
+ # no hay con qué subirle el volumen desde una ventana». O sea que la distro reproducía audio y
+ # **no tenía ningún control de volumen** — ni gráfico, ni de consola, ni un atajo de teclado
+ # posible, porque un atajo llama a un comando y el comando no existía.
+ #
+ # `pamixer` sube, baja, silencia y lista fuentes y sumideros: es lo que un compositor engancha a
+ # las teclas de volumen. Su `cxxopts` NO se declara — es sólo una cabecera y no deja nada que viaje.
+ #
+ # ⚠ Habla el protocolo de PulseAudio y eso NO es un desajuste: `pipewire` publica esa capa
+ # (`pipewire-pulse` + `libpipewire-module-protocol-pulse.so`, verificado en el artefacto) y la
+ # biblioteca cliente `libpulse.so.0` la publica `pulseaudio`. Las dos ya viajan en estos cinco
+ # perfiles, igual que `libsndfile`, así que esto cuesta sólo sus 7,5 MB.
+ #
+ # ⚠ Su cadena de runtime baja TRES niveles y es lo que hizo fallar el primer build:
+ # `pamixer → libpulse.so → libpulsecommon.so → libsndfile.so.1`. Está documentada igual en
+ # `recipes/espeak-ng.toml` — el sandbox sólo monta lo declarado, y yo no la consulté.
+ "pamixer",
# ── LECTOR DE DOCUMENTOS ─────────────────────────────────────────────────────────────────────
# ⚠ NO ESTÁ EN `escritorio-kde`, y no es un olvido. `zathura-pdf-poppler` necesita `poppler-glib`,
# que es una receta NUEVA del corpus (la que ya existía va `-DENABLE_GLIB=OFF` y vive en la cola
@@ -2559,40 +2547,6 @@ paquetes = [
# máquina. No se declara acá por simetría —se sigue dónde estaba `espeak-ng`— pero es una decisión
# pendiente y no un olvido.
"speech-dispatcher", "dotconf", "brltty", "liblouis",
- # ── Y SE PUEDE ABRIR UNA IMAGEN (2026-10-20) ────────────────────────────────────────────────
- # `censo-distro.py` marcaba «visores de imagen» **5 de 5 ausente**: la distro no tenía NINGUNA
- # forma de abrir un JPEG. Los tres candidatos obvios se descartaron por MEDICIÓN, no por fama:
- # `nsxiv`, `feh` son Xlib, y esta distro es Wayland-only ⇒ muro
- # `imv` el recomendado para Wayland, y **no sirve acá**: pide `egl`, `gl`, `opengl`,
- # `glu` y `wayland-egl`, y este corpus no publica `libGL.so` ni `gl.pc`
- # (comprobado) — el mismo muro que bloquea a `kitty`
- # `swayimg` **cero menciones de GL** en su `meson.build`. Pinta por software
- #
- # `swayimg` png, jpeg, webp, tiff y gif, **cada formato con su perilla FIJA**: sus opciones son
- # `feature` con default `auto`, y una dep ausente se saltaría EN SILENCIO dejando un
- # visor que no abre PNG y no dice por qué
- # `exiv2` la rotación EXIF. Una cámara de móvil no rota los píxeles: anota la orientación en
- # una etiqueta. Sin esto **todas las fotos verticales salen tumbadas**, sin error y
- # sin remedio. ⚠ NO se declara acá: entra ESTÁTICA dentro del binario (su `.so`
- # habría cruzado objetos de C++ entre módulos, que es lo que segfaulteó a
- # `libime_pinyindict`)
- #
- # ⚠ PESO: 70 MB, y **el 85 % es `.debug_*`** (59 de 69 MB, sumado con readelf) ⇒ ~10 MB
- # desnudado. La norma del corpus; su sitio es el SDD 23.
- #
- # ✅ El binario sale **autosuficiente: un solo `NEEDED`, `libc.so`** (medido). Todo lo demás
- # —wayland, xkb, drm, png, jpeg, webp, tiff, gif, fontconfig, freetype, lua— entra estático, así
- # que declararlo no arrastra ningún proveedor compartido.
- #
- # ⚠ QUEDA AFUERA Y SE DICE: `svg=disabled`, porque `librsvg` sólo existe en `incoming-gnome`
- # enredada con su pila de introspección (promoverla cuesta 35 recetas, medido). **No abre SVG.**
- # Y `heif/avif/jxl/jp2/exr/raw` tampoco: esas bibliotecas no están en el corpus.
- #
- # ⚠ Y UNA DECISIÓN QUE NO TOMO ACÁ: `swayimg` se construyó con `drm=enabled`, o sea que puede
- # mostrar una imagen **desde una consola TTY, sin compositor**. Eso es exactamente lo que querría
- # el perfil `cli`, que hoy no lleva visor. No se declara ahí porque son 70 MB en una imagen que no
- # me pidieron cambiar — pero el coste está medido y la capacidad existe.
- "swayimg",
# `dejavu-fonts-nerd` es la MISMA DejaVu Sans Mono parcheada con Nerd Fonts (~10.000 glifos de
# iconos: Powerline, Font Awesome, Devicons…) que usan starship, lsd, eza, neovim y las
# statuslines; sin ellos dibujan cuadraditos. Se AÑADE, no reemplaza: la licencia de Bitstream
@@ -2756,6 +2710,24 @@ paquetes = [
# ninguna cola. swayimg rasteriza a `wl_shm` y no toca GL; el porqué largo está en su receta.
# Trae de yapa backend DRM: muestra imágenes en una TTY pelada, sin compositor.
"swayimg",
+ # ── Y SE PUEDE SUBIR EL VOLUMEN (2026-10-20) ────────────────────────────────────────────────
+ # El censo marcaba «audio de escritorio» 5 de 5 ausente, con el problema exacto: «PipeWire suena y
+ # no hay con qué subirle el volumen desde una ventana». O sea que la distro reproducía audio y
+ # **no tenía ningún control de volumen** — ni gráfico, ni de consola, ni un atajo de teclado
+ # posible, porque un atajo llama a un comando y el comando no existía.
+ #
+ # `pamixer` sube, baja, silencia y lista fuentes y sumideros: es lo que un compositor engancha a
+ # las teclas de volumen. Su `cxxopts` NO se declara — es sólo una cabecera y no deja nada que viaje.
+ #
+ # ⚠ Habla el protocolo de PulseAudio y eso NO es un desajuste: `pipewire` publica esa capa
+ # (`pipewire-pulse` + `libpipewire-module-protocol-pulse.so`, verificado en el artefacto) y la
+ # biblioteca cliente `libpulse.so.0` la publica `pulseaudio`. Las dos ya viajan en estos cinco
+ # perfiles, igual que `libsndfile`, así que esto cuesta sólo sus 7,5 MB.
+ #
+ # ⚠ Su cadena de runtime baja TRES niveles y es lo que hizo fallar el primer build:
+ # `pamixer → libpulse.so → libpulsecommon.so → libsndfile.so.1`. Está documentada igual en
+ # `recipes/espeak-ng.toml` — el sandbox sólo monta lo declarado, y yo no la consulté.
+ "pamixer",
# ── LECTOR DE DOCUMENTOS ─────────────────────────────────────────────────────────────────────
# ⚠ NO ESTÁ EN `escritorio-kde`, y no es un olvido. `zathura-pdf-poppler` necesita `poppler-glib`,
# que es una receta NUEVA del corpus (la que ya existía va `-DENABLE_GLIB=OFF` y vive en la cola
diff --git a/recipes/pamixer.toml b/recipes/pamixer.toml
new file mode 100644
index 00000000..e321d9bd
--- /dev/null
+++ b/recipes/pamixer.toml
@@ -0,0 +1,93 @@
+# pamixer 1.6 — subirle y bajarle el volumen desde la línea de comandos.
+#
+# ══ POR QUÉ ENTRA ══════════════════════════════════════════════════════════════════════════════
+# `censo-distro.py` marca «audio de escritorio» **5 de 5 ausente**, con el comentario exacto del
+# problema: «PipeWire suena y no hay con qué subirle el volumen desde una ventana». O sea que la
+# distro reproduce audio y **no tiene ningún control de volumen**: ni gráfico, ni de consola, ni
+# atajo de teclado posible — porque un atajo de teclado llama a un comando, y el comando no existía.
+#
+# `pamixer` es el más pequeño que cierra eso: un binario que sube, baja, silencia y lista fuentes y
+# sumideros. Es lo que un compositor engancha a las teclas de volumen.
+#
+# ══ ⚠ HABLA EL PROTOCOLO DE PULSEAUDIO, Y ACÁ EL SERVIDOR ES PIPEWIRE ══════════════════════════
+# Eso NO es un desajuste: la decisión del repo es PipeWire, y PipeWire expone la capa de
+# compatibilidad de PulseAudio (`pipewire-pulse`). `pamixer` se conecta por ahí, igual que lo hacen
+# `mpv` y el resto del corpus que enlaza `libpulse`.
+#
+# ⇒ **Pero la dependencia de RUNTIME es esa capa, no sólo la biblioteca**: `pamixer` enlazado y sin
+# `pipewire-pulse` corriendo arranca y falla al conectar. Es la figura de «el motor sin su driver»;
+# queda dicho acá porque el síntoma («no se conecta») no nombra la causa.
+#
+# Sus únicas deps son `libpulse` —que ya está— y `cxxopts`, su parser de argumentos, que es una
+# cabecera y entró como `recipes/cxxopts.toml`.
+name = "pamixer"
+version = "1.6"
+license = "GPL-3.0-or-later"
+
+[source]
+tarball = "https://github.com/cdemoulins/pamixer/archive/refs/tags/1.6/pamixer-1.6.tar.gz"
+sha256 = "8b7199e495dc19b190f8f02ace8782f533266a4bd7c7d3cf6f4cf09b2de13e71"
+
+[build]
+compiler = "zig-cc"
+target = "x86_64-linux-musl"
+link = "dynamic"
+flags = []
+
+[build.phases]
+# `--prefer-static` para que pkg-config entregue los `Requires.private`: el corpus es
+# estático-primero y sin eso el enlace puede no cerrar (lección de `swayimg`, donde
+# `libfontconfig.a` dejaba 11 símbolos de expat sin resolver).
+configure = 'PKG_CONFIG_PATH=/usr/lib/pkgconfig meson setup output --prefix=/usr --buildtype=release --prefer-static'
+compile = 'meson compile -C output'
+# El guardián comprueba por SÍMBOLO DEFINIDO y no por `NEEDED`: con `--prefer-static` casi nada
+# queda en NEEDED, y pedirlo ahí rechazaría un build correcto — es el error que cometí cinco veces
+# el 20-oct, incluido en esta misma campaña con `swayimg`.
+install = '''
+set -e
+DESTDIR=/out meson install -C output
+[ -x /out/usr/bin/pamixer ] || { echo "pamixer: no quedó el binario — NO sello" >&2; exit 1; }
+definido() {
+ readelf -sW "$1" 2>/dev/null | awk -v s="$2" '$8==s && $7!="UND" {f=1} END{exit !f}'
+}
+# `pa_context_connect` es lo que hace que esto sirva de algo: sin la biblioteca de PulseAudio
+# dentro, el binario existe y no puede hablar con el servidor.
+definido /out/usr/bin/pamixer pa_context_connect || readelf -d /out/usr/bin/pamixer 2>/dev/null | grep -q 'libpulse' || {
+ echo "pamixer: ni símbolo pa_context_connect definido ni NEEDED a libpulse — no podría conectarse al servidor de audio" >&2
+ readelf -d /out/usr/bin/pamixer 2>/dev/null | grep NEEDED >&2
+ exit 1
+}
+# Y que ARRANQUE. Ejecución y truncado separados: el estado de una tubería es el del último comando.
+sal=$(/out/usr/bin/pamixer --help 2>&1) || true
+printf '%s\n' "$sal" | grep -qiE 'usage|--get-volume|--increase' || {
+ echo "pamixer: --help no muestra su uso; el binario no arranca bien" >&2
+ printf '%s\n' "$sal" | head -5 >&2
+ exit 1
+}
+echo "pamixer: binario + libpulse · controla volumen, mute y fuentes"
+'''
+
+[deps]
+# ⚠ `python3` NO es opcional aunque pamixer no lo use: **meson es un script de Python**, y sin él
+# `meson setup` muere con `exit 127` — «comando no encontrado» — que no menciona a python. Está
+# documentado en la memoria del repo (`receta-meson-exige-python3`) y aun así me lo salté acá.
+build = ["meson", "samurai", "pkgconf", "pulseaudio", "cxxopts", "binutils", "python3",
+ # ⚠ **LA CADENA DE PULSEAUDIO BAJA TRES NIVELES, Y YA ESTABA DOCUMENTADA EN ESTE REPO.**
+ # `pamixer` no nombra ninguna de estas, pero el cargador sí:
+ #
+ # Error loading shared library libsndfile.so.1: No such file or directory
+ # (needed by /usr/lib/pulseaudio/libpulsecommon-17.0.so)
+ # Error relocating libpulsecommon-17.0.so: sf_command: symbol not found
+ #
+ # O sea: pamixer → libpulse.so → libpulsecommon.so → **libsndfile.so.1**. Tres saltos, y el
+ # sandbox sólo monta lo DECLARADO, así que hay que nombrarlas aunque pamixer no las
+ # mencione nunca. `glib`, `libffi` y `pcre2` son las deps de runtime de pulseaudio por el
+ # mismo motivo.
+ #
+ # ⚠ Esto es **literalmente** lo que escribí hoy en `recipes/espeak-ng.toml`, con los mismos
+ # símbolos (`sf_command`, `sf_error_number`) y la cadena dibujada — y no lo apliqué acá. La
+ # nota estaba en mi propio repo y la volví a pagar.
+ "libsndfile", "glib", "libffi", "pcre2"]
+# ⚠ Lo que de verdad necesita en EJECUCIÓN es la capa de compatibilidad de PulseAudio que publica
+# PipeWire: sin ella arranca y no se conecta. Ver la nota de arriba.
+runtime = ["pipewire", "pulseaudio", "libsndfile", "glib", "libffi", "pcre2"]
diff --git a/recipes/swayimg.toml b/recipes/swayimg.toml
index c91dc2e3..96a93d13 100644
--- a/recipes/swayimg.toml
+++ b/recipes/swayimg.toml
@@ -20,8 +20,22 @@
# incluida `librsvg-2.0` — o sea que el bloqueo de GNOME no toca acá.
#
# ⚠ Con una excepción que casi no vi: `lua = dependency(get_option('liblua'))` **no es
-# condicional** — es obligatoria, y el nombre del módulo pkg-config sale de la opción. Su default es
-# `luajit`, que no tenemos; nuestra `lua` 5.4.8 publica `lua.pc`, así que se pasa el nombre a mano.
+# condicional** — es obligatoria, y el nombre del módulo pkg-config sale de la opción.
+#
+# ⚠⚠ **Y ACÁ ME CORRIJO, PORQUE PISÉ TRABAJO AJENO.** Escribí esta receta con `cat >` **sin mirar
+# que ya existía**: otro agente la había llevado de 4.7 a 5.5, y mi versión borró 70 líneas suyas.
+# Entre ellas, la decisión de usar el default `luajit` — por eso ese agente había escrito
+# `recipes/luajit.toml`. Mi `-Dliblua=lua` dejó **su luajit sin un solo consumidor** (medido:
+# ningún `[deps]` del catálogo lo nombraba).
+#
+# ⇒ Vuelve a `luajit`, que es el default de upstream y lo que ese agente empaquetó para esto
+# (`luajit.pc`, `libluajit-5.1.{a,so}`, sellado al hash vigente). Lo que SÍ conservo de mi pasada es
+# `-Dexif=enabled` con `exiv2`: ellos lo tenían apagado, y sin EXIF las fotos verticales de móvil
+# salen tumbadas. Eso es una mejora, no una preferencia.
+#
+# La lección, que es la regla 2 del repo por otra puerta: **`cat >` sobre un fichero del repo
+# compartido es destructivo y no avisa.** El `git add` acotado no protege de esto — el fichero ya
+# estaba sobrescrito antes de llegar a git.
#
# ══ ⚠ TODAS LAS PERILLAS EXPLÍCITAS, Y ESO ES EL PUNTO DE ESTA RECETA ══════════════════════════
# Sus opciones de formato son `feature` con default **`auto`**: una dep ausente se **salta en
@@ -81,7 +95,7 @@ set -e
PKG_CONFIG_PATH=/usr/lib/pkgconfig meson setup output --prefix=/usr --buildtype=release \
--prefer-static \
-Dversion=5.6 \
- -Dliblua=lua \
+ -Dliblua=luajit \
-Dpng=enabled -Djpeg=enabled -Dwebp=enabled -Dtiff=enabled -Dgif=enabled \
-Dexif=enabled \
-Dwayland=enabled -Dcompositor=enabled -Ddrm=enabled \
@@ -120,7 +134,7 @@ falta=""
for par in "wl_display_connect:wayland" "xkb_context_new:xkbcommon" "drmModeGetResources:drm (modo consola)" \
"png_create_read_struct:png" "jpeg_read_header:jpeg" "WebPGetInfo:webp" \
"TIFFOpen:tiff" "DGifOpen:gif" "FcInit:fontconfig" "FT_Init_FreeType:freetype" \
- "lua_newstate:lua"; do
+ "luaJIT_setmode:luajit"; do
sim=${par%%:*}; que=${par##*:}
definido /out/usr/bin/swayimg "$sim" || falta="$falta $que($sim)"
done
@@ -140,4 +154,4 @@ echo "swayimg: binario autosuficiente ($n NEEDED) · wayland + drm + png jpeg we
[deps]
build = ["meson", "samurai", "pkgconf", "wayland", "wayland-protocols", "libxkbcommon",
"fontconfig", "freetype", "libpng", "libjpeg-turbo", "libwebp", "libtiff",
- "giflib", "exiv2", "libdrm", "lua", "expat", "zlib", "brotli", "binutils", "python3"]
+ "giflib", "exiv2", "libdrm", "luajit", "expat", "zlib", "brotli", "binutils", "python3"]