Commit Graph
100 Commits
Author SHA1 Message Date
Sergio 5cb6e568d6 catálogo: wl-clipboard sube al corpus — cerraba el único orphan_dep de cuatro grafos
Estaba sólo en `recipes/incoming-wlr/`, o sea inalcanzable desde las otras
cuatro colas. `cliphist` vive en el CORPUS y la pide en `[deps] run`, así que
corpus, gnome, kde y cosmic la reportaban como `orphan_deps: ["wl-clipboard"]`.

No era cosmético: `escritorio-cosmic` declara `cliphist` de raíz, y la imagen
se habría armado con el demonio de historial y SIN `wl-copy`/`wl-paste` — el
modo de fallo silencioso que la propia receta de cliphist advierte (el binario
corre y no hace nada). La clausura no lo podía ver: decía `falta=0` en los
cinco perfiles, porque una dep que no resuelve no se cuenta, desaparece.

Solución = la que el catálogo ya usó con `mpv` y `atuq`: subirla al corpus, de
donde las colas la alcanzan (sibling-first y después el catálogo padre).

Medido antes de mover: ninguna de sus 9 deps tenía variante hermana en
`incoming-wlr`, así que el ArtifactHash no podía cambiar — y no cambió
(`b3:fc2ab7b7…` a los dos lados, comprobado con `takana hash`). Cero re-sellos.

Tras regenerar los cinco grafos: `orphan_deps: []` en los cinco, y la clausura
de `escritorio-cosmic` pasa de 273 a 274, sellada.
2026-09-14 13:54:28 +00:00
Sergio d2187fda11 estado: 11 recetas KDE más verificadas reproducibles (SDD 23) 2026-09-14 13:48:34 +00:00
Sergio 98df75a8cb estado: cosecha granja 2026-09-14T13:32:34Z — avance del árbol KDE 2026-09-14 13:32:34 +00:00
Sergio 5614d8c855 estado: cosecha granja 2026-09-14T13:02:49Z — avance del árbol KDE 2026-09-14 13:02:49 +00:00
Sergio edfdda2d4d estado: cosecha granja 2026-09-14T12:32:23Z — avance del árbol KDE 2026-09-14 12:32:23 +00:00
Sergio a26780cbd8 estado: cosecha granja 2026-09-14T12:03:00Z — avance del árbol KDE 2026-09-14 12:03:00 +00:00
Sergio 658eecb9cd estado: cosecha granja 2026-09-14T11:32:56Z — avance del árbol KDE 2026-09-14 11:32:56 +00:00
Sergio 0eee35a041 estado: cosecha granja 2026-09-14T11:03:49Z — avance del árbol KDE 2026-09-14 11:03:49 +00:00
Sergio 6c45f438b0 estado: cosecha granja 2026-09-14T10:32:23Z — avance del árbol KDE 2026-09-14 10:32:23 +00:00
Sergio af2469107f estado: cosecha granja 2026-09-14T10:02:17Z — avance del árbol KDE 2026-09-14 10:02:17 +00:00
Sergio d21d69ff8f estado: cosecha granja 2026-09-14T09:32:17Z — avance del árbol KDE 2026-09-14 09:32:17 +00:00
Sergio d16018bab7 estado: cosecha granja 2026-09-14T09:01:54Z — avance del árbol KDE 2026-09-14 09:01:54 +00:00
Sergio 97a04a145b estado: cosecha granja 2026-09-14T08:31:57Z — avance del árbol KDE 2026-09-14 08:31:57 +00:00
Sergio 192b9ab652 estado: cosecha granja 2026-09-14T08:02:17Z — avance del árbol KDE 2026-09-14 08:02:17 +00:00
Sergio 804b2a4953 estado: cosecha granja 2026-09-14T07:32:15Z — avance del árbol KDE 2026-09-14 07:32:15 +00:00
Sergio 230a95e06e estado: cosecha granja 2026-09-14T07:02:26Z — avance del árbol KDE 2026-09-14 07:02:26 +00:00
Sergio 34d673ae54 estado: cosecha granja 2026-09-14T06:32:02Z — avance del árbol KDE 2026-09-14 06:32:02 +00:00
Sergio c8f0c92728 estado: cosecha granja 2026-09-14T06:02:12Z — avance del árbol KDE 2026-09-14 06:02:12 +00:00
Sergio f2cd2d70c9 estado: cosecha granja 2026-09-14T05:31:57Z — avance del árbol KDE 2026-09-14 05:31:57 +00:00
Sergio 7ef4494e33 estado: cosecha granja 2026-09-14T05:02:07Z — avance del árbol KDE 2026-09-14 05:02:07 +00:00
Sergio 6833515475 estado: cosecha granja 2026-09-14T04:31:58Z — avance del árbol KDE 2026-09-14 04:31:58 +00:00
Sergio 20b268b229 estado: cosecha granja 2026-09-14T04:02:15Z — avance del árbol KDE 2026-09-14 04:02:15 +00:00
Sergio a5c4a86ff7 estado: cosecha granja 2026-09-14T03:31:53Z — avance del árbol KDE 2026-09-14 03:31:53 +00:00
Sergio 3df51ced38 estado: cosecha granja 2026-09-14T03:02:13Z — avance del árbol KDE 2026-09-14 03:02:13 +00:00
Sergio e2e5fd2dd7 estado: cosecha granja 2026-09-14T02:31:54Z — avance del árbol KDE 2026-09-14 02:31:54 +00:00
Sergio 11cc2fd3ff estado: cosecha granja 2026-09-14T02:02:19Z — avance del árbol KDE 2026-09-14 02:02:19 +00:00
Sergio 3d79cdf98b SDD 30 4c: GNOME con los demonios supervisados por arje — y el control arregló colord
Los demonios de sistema pasan de lanzarse con `&` desde un script de 500 líneas
a ser Cards del `genesis`. El bloqueo que este frente daba por corpus se levantó
solo: otro agente selló evolution-data-server y gnome-shell mientras esto se
escribía, y escritorio-gnome quedó 309/309.

SE CORRIÓ UN CONTROL PRIMERO, y es lo único que hace interpretable el resultado:

  colord              control: `MURIÓ al arrancar`   cards: `ya vive (pid 175)`
  ColorManager        control: `NO apareció en 40s`  cards: `OK`
  login1/Accounts/UPower  OK en los dos
  compositor          wayland-0 y shell vivo en los dos

El fallo del control DESAPARECIÓ, y no lo buscaba: colord moría arrancado por el
script y vive arrancado por arje, con el bus ya listo porque la espera está
dentro de su argv. Sin el control, «ColorManager OK» sería un dato suelto en vez
de una diferencia. Los PIDs lo confirman: polkit=119, colord=175, upowerd=178,
accounts=180 — de antes de que el lanzador de sesión existiera.

QUÉ NO SE COMPROBÓ: no hay screendump; QEMU salió por timeout y el control
tampoco lo tuvo. La comparación es serial contra serial y lo que se afirma es
sobre los DEMONIOS, no sobre el pintado.

Las piezas donde corresponde: `takana service-cards` (UNA sola implementación de
receta→Card; el formato es contrato con card_core::Card), `targets.py
--service-paths` (une qué-es con si-arranca), y un inyector en FICHERO APARTE
porque anidar dos heredocs de python falló en vivo — el terminador del interno
cerró el externo y media cosa corrió como shell.

La espera del bus va DENTRO del argv de las 5 recetas de sistema: sin ella un
daemon arranca antes de que dbus escuche y queda en modo idle sin registrar su
nombre — un fallo que no se ve, porque el proceso vive y el bus no lo tiene. Los
5 hashes intactos. Y el guardia de gnome-start es por «¿está corriendo?», no por
una perilla: así es correcto venga de donde venga el proceso y la misma copia
sirve donde no se inyectaron cards.
2026-09-14 01:51:19 +00:00
Sergio 2a1cb93be5 estado: cosecha granja 2026-09-14T01:33:42Z — avance del árbol KDE 2026-09-14 01:33:42 +00:00
Sergio 73b288171c libical y evolution-data-server: dos rotas más del censo — y una cae enlazando una .so, no un binario
Segunda tanda del censo con `verificar-repro.sh`, esta vez sobre `poppler-glib` y las dos recetas
CMake de la cola de GNOME: **2 de 3 no construyen**. Con esto el censo va en **7 rotas de 18
barridas**, todas por el mismo crash del `lld` de zig con el `--dependency-file` de CMake ≥3.27.

⚠ **`libical` cae enlazando `libical.so` — una librería COMPARTIDA, no un ejecutable.** Eso termina
de enterrar el predictor barato que intenté ayer («falla la que instala binarios», 12 aciertos de
14): el crash puede estar en CUALQUIER link del build. Ni ejecutables instalados, ni sólo
ejecutables: cualquier link.

`evolution-data-server` muere en `camel-lock-helper` y `camel-gpg-photo-saver`, y necesita su propia
perilla además de la de su dep — arreglar `libical` no la arregla, porque el fallo está en SU link.

Las dos estaban selladas y rotas a la vez. El artefacto tapaba que la cola de GNOME ya no se puede
reconstruir entera.
2026-09-14 01:32:19 +00:00
Sergio d078e5285f SDD 30 §4b.2: la cadena entera probada en un arranque real — PRODUCT_SSH_OK
Los tests no eran el punto: el punto era que un servicio DECLARADO en una receta
termine supervisado por PID 1. `product-boot-test.sh` sobre el product-rootfs de
la ruta real da `ok card sshd en la seed` y `PRODUCT_SSH_OK uid=0`, sin ningún
eslabón escrito a mano:

  recipes/openssh.toml [[service]] → sidecar dentro del artefacto sellado →
  service_cards() → genesis de /ente/seed.card.json → arje-zero encarna sshd →
  la sesión SSH responde.

Y HABÍA QUE DESCARTAR QUE LO MOVIERA ESTE CAMBIO: el product-rootfs salió con
hash distinto (5011955a… → 8639894332…). No fue la seed — las dos son
BYTE-IDÉNTICAS (diff del JSON, cero diferencias). Cambiaron `netup`, que es otro
artefacto que cuando se selló el viejo, y por arrastre `ente/attest.json`, que
registra su BLAKE3. O sea: la constante y la receta producen la misma seed,
comprobado sobre el árbol real y no sólo en un test.

Y queda escrito por qué el ESCRITORIO no se puede arrancar supervisado todavía,
que es corpus y no diseño: gnome-shell en deuda (bloqueado sólo por
evolution-data-server, que tiene blocked_by vacío) y sway sin sellar. Sin
compositor no hay sesión. NO se cablearon los scripts de imagen a ciegas: inyectar
cards en un genesis que no se puede bootear es escribir código que nadie puede
contradecir, y este mismo doc ya tiene el ejemplo de qué pasa entonces (el SDD 06
afirmando meses un lector que no existía).
2026-09-14 01:24:11 +00:00
Sergio 8fd653c0d0 estado: cosecha granja 2026-09-14T01:02:27Z — avance del árbol KDE 2026-09-14 01:02:27 +00:00
Sergio 60202bf526 imagen: el navegador arranca en la imagen booteada y NO PINTA VENTANA — medido, con lo descartado
Primera prueba de `atuq` dentro de una imagen de disco arrancada, y el resultado no es el de la
jaula. La cadena previa funcionó, y eso también es medición: el perfil `escritorio-cosmic` hidratado
con el cierre de hoy (275 nodos, 8,4 G) trae `/usr/bin/atuq`, `/usr/bin/llama-server` y el modelo —
declarar en el perfil SÍ pone las cosas en la imagen—, la imagen EFI de 12 G arranca en QEMU y COSMIC
pinta panel y dock en ~2 min.

Y `atuq` arranca —sus extensiones inician, la del foco sondea cada minuto, WebRender inicializa— sin
que la ventana aparezca nunca. Descartado, para que nadie lo repita: no es el sandbox de Gecko
(relanzado con los cinco MOZ_DISABLE_* puestos, idéntico), no es que el proceso muera (sigue
ejecutando el JS de las extensiones), y no es la IA (pasa con about:blank).

La pista: bajo sway headless el MISMO artefacto pinta perfecto y hay capturas del panel contestando.
La diferencia son el compositor (cosmic-comp+llvmpipe contra sway+pixman) y el arranque real contra
bwrap. Es su propia unidad de trabajo, no un parche apurado.

⚠ La lección del método: quince guardianes en verde, `vigia-imagen.py` en ✓, y el navegador igual no
se puede usar en la imagen. «Sella», «hidrata» y «los tests pasan» son tres cosas distintas de
«arranca y se ve».

De paso, `metal-iso.sh` acepta ahora STORE y AUG por entorno, porque en esta máquina no funcionaba:
arma el rootfs con `cp -al` desde el store y el store es un BIND-MOUNT del volumen — `linkat` rechaza
cruzar mounts aunque sea el mismo disco, así que hay que nombrar los dos lados dentro del mismo
mount. Es la cuarta vez que aparece el mismo EXDEV hoy.
2026-09-14 00:54:47 +00:00
Sergio 28fcd77cf2 estado: cosecha granja 2026-09-14T00:32:31Z — avance del árbol KDE 2026-09-14 00:32:31 +00:00
Sergio 13872f38d5 estado: cosecha granja 2026-09-14T00:02:28Z — avance del árbol KDE 2026-09-14 00:02:29 +00:00
Sergio af26cbc43b estado: cosecha granja 2026-09-13T23:32:00Z — avance del árbol KDE 2026-09-13 23:32:00 +00:00
Sergio 4db3e76e60 estado: cosecha granja 2026-09-13T23:02:10Z — avance del árbol KDE 2026-09-13 23:02:10 +00:00
Sergio 402d557763 estado: cosecha granja 2026-09-13T22:32:10Z — avance del árbol KDE 2026-09-13 22:32:10 +00:00
Sergio 6fadab1814 estado: cosecha granja 2026-09-13T22:02:42Z — avance del árbol KDE 2026-09-13 22:02:42 +00:00
Sergio 2b884a86a2 estado: cosecha granja 2026-09-13T21:34:43Z — avance del árbol KDE 2026-09-13 21:34:43 +00:00
Sergio 5e056b6177 atuq: una CAPTURA de la barra lateral — y la barra ya no se abre sola
`scripts/atuq-captura-ia.py`: el arnés de sway headless de los guardianes + `grim` + un PNG. No es un
guardián (los veredictos siguen saliendo del `dump`); es la evidencia que ningún log puede dar: que
el panel se pinta y que la respuesta está ahí.

Encontró tres cosas, ninguna visible en un log:

1. **la barra lateral se abría SOLA** en el primer arranque, ocupando un tercio de la ventana. Gecko
   lo hace al instalar una extensión con `sidebar_action`, y para un navegador que la trae de fábrica
   eso es imponerle un panel a todo el mundo. `"open_at_install": false`, con captura del después;
2. el diálogo «Close Firefox» en la segunda corrida — el arnés mataba el navegador sin despedirse y
   quedaba el `.parentlock`. Arreglado en el arnés;
3. dos barras de notificación VACÍAS en el arranque. El atajo era reportarlas como fuga de marca, y
   era falso: instrumentando una copia del artefacto para volcar el DOM salieron
   `sandbox-content-disabled` (lo apaga el propio arnés) y `startup-restore-session-suggestion` (por
   el cierre abrupto anterior). El texto está en el DOM y no en los píxeles — comprobado además
   quitando nuestro CSS, con el mismo resultado ⇒ es el render por software de la jaula.

⇒ Una captura muestra síntomas; el DOM dice de quién son. Sin ese segundo paso, dos de los tres
habrían entrado al SDD como bugs nuestros.

El log del navegador viaja junto a la foto, siempre: una captura muestra que algo se ve raro y no por
qué. Y `test-atuq-ia.py` + `test-atuq-archivo-semantico.py` siguen verdes tras el cambio.
2026-09-13 21:29:29 +00:00
Sergio bdecd1c479 mesa-llvmpipe: la campaña de glvnd, probada donde no le cuesta a nadie — y SALE QUE SÍ
mesa-llvmpipe  b3:7662f5ec25c42cd679da1679c8c6ed7c53cd49d57fa781493ab7ff433d51b9b0

En vez de lanzar 153 rebuilds a ciegas, la campaña se prueba en la única de las tres mesa que tiene
**radio 0 y cero imágenes** (`yupana radio mesa-llvmpipe`: 0 dependientes, «(ninguna declarada)»).
Cambiarla no tira un solo sellado ajeno, así que es el laboratorio exacto.

LA PREGUNTA, que hasta hoy nadie tenía contestada: con `-Dglvnd=true`, ¿mesa produce de verdad el
VENDOR que al despacho le falta? RESPUESTA MEDIDA SOBRE EL ARTEFACTO:

  usr/lib/libEGL_mesa.so.0                     ← el vendor (hoy no existe en ningún lado)
  usr/share/glvnd/egl_vendor.d/50_mesa.json    ← su registro, que es lo que glvnd busca
  usr/lib/libgbm.so.1 · libglapi.so.0 · dri/{swrast,kms_swrast}_dri.so

…y **deja de instalar libEGL.so.1 y libGLESv2.so.2** (los dos `ls` fallan).

⇒ La colisión de sonames del rootfs de KDE —dos libEGL.so.1 distintos en la misma ruta— DESAPARECE
POR CONSTRUCCIÓN con la campaña: mesa ya no reclama esas rutas y el dueño pasa a ser glvnd, que es
exactamente lo que su partición quiere. La campaña deja de ser una apuesta: se sabe qué produce.
Lo que queda por decidir es CUÁNDO pagar, no SI funciona.

EL PRECIO, medido antes de empezar y sin cambiar: `yupana radio mesa` = 148 directos, 154
transitivos, **153 sellados que caen a deuda**, las CINCO imágenes, 123 de ellos en incoming-kde —
la cola que otro agente está moliendo ahora mismo. Por eso esto es una prueba, no la campaña.

⚠ Y cubre SÓLO la mitad de mesa. La otra es que `libglvnd` vuelva a instalar su libEGL.so.1 de
despacho (hoy va `-Degl=false` justamente para no colisionar). Las dos mitades van en la MISMA
campaña o el resultado es el de hoy con otro disfraz. Queda escrito en las dos recetas.
2026-09-13 21:20:05 +00:00
Sergio 0e35652fb1 un solo NetworkManager (y KDE recupera WiFi) + upower al corpus sin arrastrar polkit
── 1. Se RETIRA incoming-kde/networkmanager.toml ───────────────────────────────────────────────
  networkmanager-qt  b3:78bbdcda00d758fb3cc3a0be7da6a67395dfbe0e4d55c5d8e5cf8afaf728ff72
  plasma-nm          b3:496a9ff7794ae5d89ac2842bdfbca38c25c91df37465a049db7cf75ee0041b82

Ayer se promovió NetworkManager al corpus CON WiFi porque la variante de KDE iba con -Dwifi=false,
y quedaron dos. Esto cierra el arco: retirada la de la cola, `networkmanager-qt` resuelve al PADRE
y la distro tiene UNO solo. Consecuencia concreta: **KDE pasa a tener WiFi**, porque su applet
hablaba con un demonio construido sin soporte inalámbrico.

Medido con `yupana radio` antes de borrar: 2 rebuilds (networkmanager-qt, plasma-nm), los dos en
la cola KDE. Y comprobado sobre el ARTEFACTO del corpus que publica lo que nm-qt pide —`libnm.pc`
y `usr/include/libnm`— antes de quitarle el suelo. Los dos sellan.

── 2. upower al corpus: COSMIC dibujaba una batería sin nadie que se la contara ────────────────
  libgudev  b3:87ca5e73…  ·  udev-pc  b3:fa880b5c…   (hash IDÉNTICO desde las dos partes ⇒ cache-hit)
  upower    b3:c82e655ff7011150f21f9413433c518f12c827c52ecf6f9fc3484f75d85c155c

Ayer escribí que esta cadena eran «3 promociones, una de ellas polkit, decisión de arquitectura».
Fui a mirar y polkit SALE de la ecuación con una perilla: la variante de KDE va `-Dpolkit=enabled`
«porque polkit YA está sellada» —cierto EN ESA COLA y falso desde el corpus—, y apagarlo cuesta
poco medido en FUNCIÓN: polkit en upower sólo gobierna las acciones privilegiadas (suspender e
hibernar por org.freedesktop.UPower, además deprecadas: hoy eso lo hace logind). Reportar batería,
carga, tiempo restante y línea de corriente NO pasa por polkit, que es justo lo que COSMIC quiere.

Se corrigió además la frase del comentario heredado que decía `-Dpolkit=enabled` al lado de un flag
que ahora dice `disabled`: una nota que desmiente al código de al lado es peor que no tener nota.
Y se le añadió su [[service]] (el corpus no lo traía; el label/id son los mismos que en GNOME a
propósito: el ULID identifica al SERVICIO, no al artefacto). No mueve el hash.

Comprobadas las NEEDED de upowerd con provee.py: libupower-glib, libffi.so.8, libz.so.1,
libudev.so.1 — las cuatro las publica el corpus y ya estaban en [deps]. Sin NEEDED colgante.

── 3. targets.toml ─────────────────────────────────────────────────────────────────────────────
  escritorio-kde     servicios += NetworkManager  (llegaba por clausura de plasma-nm y NADIE lo
                                                   arrancaba: el applet sobre un demonio apagado)
  escritorio-cosmic  paquetes  += upower · servicios += upowerd

⚠ Y se CORRIGE la nota de ayer que decía «NO declarar networkmanager en escritorio-kde porque
plasma-nm ya arrastra la variante de la cola». Ya no hay variante de cola.
2026-09-13 21:15:14 +00:00
Sergio ddfcdc7ab2 estado: cosecha granja 2026-09-13T21:04:00Z — avance del árbol KDE 2026-09-13 21:04:00 +00:00
Sergio 68dc9cc2de SDD 30 §4b: la seed de producto ya sale de la RECETA — y openssh reproduce bit a bit
El emisor lee la receta que viaja DENTRO del artefacto sellado (el sidecar
.hammer/recipe.toml) y no de recipes/, porque seal_product_rootfs sirve a las
DOS vetas —product desde recetas locales y product_from_repo desde el repo
firmado— y sólo una tiene recipes/ a mano. El sidecar es la única fuente que
ambas comparten, que es lo que sostiene que converjan al mismo product-rootfs.

LA TRAMPA QUEDA ARMADA, NO CERRADA: el sidecar no entra al ArtifactHash, así que
un artefacto anterior al bloque [[service]] es un cache-hit válido que no se
reconstruye solo. Si el emisor devolviera lista vacía sin protestar, el producto
saldría booteando, verde y SIN SSHD. Falla ruidosamente, y hay un test que exige
que el mensaje siga explicando la causa Y dando el arreglo (regla 3 del
CLAUDE.md: un ausente falla ruidosamente, un vacío llega hasta el final diciendo
que todo fue bien).

LA MIGRACIÓN, CON CONTROL, y el hecho nuevo que dejó: openssh no estaba
certificado como reproducible ("el criterio es construye y corre", dice su
receta). Manifiesto de 33 sha256+modos ANTES de tocar nada, respaldo por
hardlink, borrado, rebuild bajo flock -o, comparación. Resultado: 33/33
ficheros, modos idénticos, y la ÚNICA diferencia en todo el árbol es
.hammer/recipe.toml. openssh REPRODUCE BIT A BIT.

Gotcha que costó el primer intento: store/ es bind-mount de /dev/sdb y work/
vive en /dev/sdc ⇒ `cp -al` cruza mounts y muere con EXDEV. El respaldo va
DENTRO del mount del store; un dot-dir ahí es invisible para store-gc.sh, que
sólo mira dirs ^[0-9a-f]{64}-.
2026-09-13 21:00:57 +00:00
Sergio 0295fd6dbe estado: cosecha granja 2026-09-13T20:33:28Z — avance del árbol KDE 2026-09-13 20:33:28 +00:00
Sergio 5e5369f775 libffi-shared en base: python3 volvía a ser INERTE en servidor, cli y base — y el vigía no miraba ahí
`vigia-sonames.py` corría por defecto SÓLO sobre los cinco perfiles de escritorio
(`p.startswith("escritorio")`). O sea que `base`, `cli` y `servidor` —el objetivo de la mudanza—
**nunca se miraron**. Apuntándolo a ellos a mano:

    == servidor  147 nodos · 183 sonames provistos · 1 sin proveedor
       FALTA libffi.so.8   ← lo piden: python3

`python3` no arrancaba en las tres imágenes, por el mecanismo EXACTO que `musl-shared` y
`zlib-shared` arreglaron dos días antes: la receta canónica de libffi es `--disable-shared`, ningún
artefacto del cierre publica ese soname, y dentro del lab el agujero lo tapa el rootfs de Alpine —
así que el build pasa y la imagen sale rota. `libffi-shared` ya existía en el corpus y ya estaba
declarada en otros dos perfiles; sólo faltaba en `base`.

    servidor 148 nodos · 186 sonames · **0 sin proveedor**    (base y cli, igual)

## Y el vigía pasa a mirar TODOS los perfiles

⚠ **Es la tercera vez en dos días que un guardián de este repo mide menos de lo que su resumen
afirma**: `static-audit.sh` sólo globeaba `recipes/` y no las 5 colas (3 mentiras ocultas); el bloque
de raíces sucias sólo corría al hidratar un perfil y no veía las 649 recetas fuera de toda imagen
(qdrant con 69 M de basura); y éste dejaba fuera medio sistema. **Un «0 huecos» sobre la mitad del
sistema se imprime igual que uno sobre todo él.**

⇒ Al leer un guardián, leer su SCOPE antes que su veredicto: el glob, el bucle, de dónde saca la
lista. Los ocho perfiles dan 0 sin proveedor, así que ampliar el alcance no mete ruido — sólo deja de
esconder.
2026-09-13 20:13:16 +00:00
Sergio 01649076da SDD 26: el paquete opcional entra al catálogo FIRMADO, y las tres cosas que sólo aparecieron al instalarlo 2026-09-13 20:11:10 +00:00
Sergio af548b8555 estado: cosecha granja 2026-09-13T20:03:48Z — avance del árbol KDE 2026-09-13 20:03:48 +00:00
SergioandClaude Opus 5 1fc9de6a01 espejar-repos: mostrar el error de gh y cortar ante el límite de la API
Corrida real contra gioser: los 21 repos fallaron al crearse y el guión dijo «no se pudo crear» A
SECAS, porque mandaba el stderr de `gh` a /dev/null. La causa era el LÍMITE DE LA API DE GITHUB
agotado —que se resuelve esperando— y sin el mensaje eso parecía un problema de permisos, de nombre o
del propio guión: hubo que reproducirlo a mano para enterarse de algo que la herramienta ya sabía.

Dos arreglos:

· El error de `gh` se muestra, recortado a su primera línea.
· Ante «rate limit» se CORTA en el primero: los 20 restantes van a fallar igual y cada intento gasta
  cuota. Dice a qué hora se repone (leído de `gh api rate_limit`) y recuerda que reintentar es
  seguro, porque el guión es idempotente.

No quedó estado parcial de la corrida fallida: el `pushurl` se agrega DESPUÉS de crear el repo, así
que los 21 clones siguen con su remoto original intacto. Verificado en tres de ellos.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RomoxEGZUhaT4pob1QSX5x
2026-09-13 20:03:17 +00:00
Sergio df1230d2a5 vigía de subcomandos: separar el hueco CONOCIDO del NUEVO — «44 inertes» todos los días no se lee
El vigía escribe `docs/state/subcomandos.txt` en cada ciclo del latido desde ayer, y decía
`TOTAL: 44 herramientas selladas que no se pueden invocar` a secas. Un número grande, constante y sin
explicación al lado entrena a saltearse el informe — y entonces el hueco NUEVO, que es el único que
pide acción, pasa desapercibido entre el ruido del viejo. Es la misma trampa que ya tienen resuelta
`static-audit.sh` (deuda decidida) y `--auditar-raices`.

Los 44 son todos del mismo hueco, y ahora el informe dice cuál y por qué:

    • falta el binario `cargo` (el toolchain de Rust)
      PENDIENTE DE DECISIÓN, no olvido. `cargo`/`rustc` viven hoy en el LAB y en la cadena de
      selfhost (mrustc→1.91.1), no como receta del catálogo. Empaquetarlos es una decisión de
      TOOLCHAIN —qué Rust publica la distro, y desde qué cadena— no trabajo de granja.

    TOTAL: 44 … (44 de hueco CONOCIDO, 0 NUEVAS)   ⇒ exit 0

⚠ **«PENDIENTE DE DECISIÓN» y no «deuda decidida»**, que es distinto: en el audit estático las tres
mentiras tienen un arreglo evaluado y descartado por su coste; acá nadie decidió nada todavía. La
etiqueta tiene que decir cuál de las dos cosas es, o dentro de tres meses se lee como cerrada.

El código de salida ahora refleja sólo los huecos NUEVOS. Probado con los dos controles: sacando
`cargo` de la tabla salen `44 NUEVAS` y exit 1; restaurándola, `0 NUEVAS` y exit 0.

⚠ Y el primer intento de ese control estaba MAL y daba verde: escribí `CONOCIDOS = {} or {…}` para
vaciar la tabla, y en Python `{}` es falsy ⇒ la expresión devuelve el segundo dict y la tabla seguía
llena. El control «pasaba» sin probar nada. Rehecho renombrando la clave.
2026-09-13 20:02:32 +00:00
SergioandClaude Opus 5 713128f26d mudanza: guión que le da copia FUERA a los 25 repos que sólo existen en gioser
Hace por un árbol entero lo que `scripts/espejo-setup.sh` hace por takana: `pushurl` doble sobre
`origin`, de modo que cualquier `git push origin` que ya exista empiece a espejar sin tocar ningún
script. Crea el repo en GitHub como PRIVADO.

Cuatro decisiones:

· **Por defecto NO hace nada**: imprime qué haría; hay que pedirlo con `--apply`. Crear repos y
  empujar código a un servicio externo no es algo que deba pasar por correr un script sin leerlo.
· **Varios clones del MISMO origen van a UN repo remoto.** En gioser hay cinco de
  `tawasuyu/tawasuyu`; cinco repos distintos multiplican la confusión y empujarlos todos al mismo
  `main` los haría chocar. El primario empuja normal; un secundario sólo se empuja —bajo
  `refs/heads/clon/<nombre>/*`— SI aporta historia propia, y eso se comprueba preguntándole al
  primario si ya tiene esos objetos (`cat-file -e`). Medido: los cinco tienen CERO commits que no
  estén en su remoto, así que los cuatro secundarios se saltan y se dice por qué.
· **Sólo agrega; nunca toca el `fetch` de `origin`**, que sigue siendo el canónico.
· **Lo sucio no viaja, y se dice.** Un espejo guarda historia commiteada, no el árbol de trabajo, y
  `tawasuyu` tiene 980 ficheros sin commitear. Creer que está a salvo cuando la mitad del trabajo no
  está commiteado es justo el fallo que este guión existe para evitar.

⚠ Y un criterio que escribí mal y corregí midiendo: el primario era «el clon con más commits
alcanzables», y contra los cinco de tawasuyu dio un EMPATE EXACTO en 9343 — `rev-list --all` cuenta
las refs de `origin`, que los cinco comparten, así que la métrica estaba dominada por lo común y no
medía nada. El desempate quedaba en el orden del `find` y elegía `tw-deploy` (HEAD del 6/9) sobre
`tawasuyu` (del 12/9), que es el que se está trabajando. Ahora manda la fecha del HEAD en ISO, que
distingue y ordena como texto.

Ensayo sobre gioser: 25 repos sin copia fuera ⇒ 21 a espejar, 4 saltados por redundantes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RomoxEGZUhaT4pob1QSX5x
2026-09-13 19:54:12 +00:00
Sergio 8600ba8888 qdrant: reproduce contra el protobuf de zig — 907/907 sellado, deuda 0
Tras devolver protobuf y abseil a `zig-cc`, qdrant cayó a deuda y se reconstruyó en el worker:
2 ficheros, sólo `usr/`, 70 M, `qdrant 1.19.1`. La limpieza del `/out/src` —el DESTDIR global que
heredaba el `make install` anidado de protobuf-src— aguanta el cambio de dep. REPRODUCE bit a bit.

El corpus queda en 907/907 sellado con deuda 0.
2026-09-13 19:51:43 +00:00
Sergio 057091381e estado: cosecha granja 2026-09-13T19:32:21Z — avance del árbol KDE 2026-09-13 19:32:21 +00:00
Sergio 261f1c2a61 estado: cosecha granja 2026-09-13T19:02:47Z — avance del árbol KDE 2026-09-13 19:02:47 +00:00
Sergio 2215716047 estado: cosecha granja 2026-09-13T18:32:19Z — avance del árbol KDE 2026-09-13 18:32:19 +00:00
Sergio 219594ece3 estado: cosecha granja 2026-09-13T18:02:41Z — avance del árbol KDE 2026-09-13 18:02:41 +00:00
Sergio 95a3152586 estado: cosecha granja 2026-09-13T17:32:17Z — avance del árbol KDE 2026-09-13 17:32:17 +00:00
Sergio 2cca6c3630 estado: cosecha granja 2026-09-13T17:02:08Z — avance del árbol KDE 2026-09-13 17:02:08 +00:00
Sergio 6ac8566719 estado: cosecha granja 2026-09-13T16:32:15Z — avance del árbol KDE 2026-09-13 16:32:15 +00:00
Sergio 8f507c4a67 estado: cosecha granja 2026-09-13T16:02:35Z — avance del árbol KDE 2026-09-13 16:02:35 +00:00
Sergio 7766c063ea estado: cosecha granja 2026-09-13T15:32:23Z — avance del árbol KDE 2026-09-13 15:32:23 +00:00
Sergio e56efe6c3b estado: cosecha granja 2026-09-13T15:02:37Z — avance del árbol KDE 2026-09-13 15:02:37 +00:00
Sergio 7547beb00a estado: cosecha granja 2026-09-13T14:32:15Z — avance del árbol KDE 2026-09-13 14:32:15 +00:00
Sergio 16ec87fe25 estado: cosecha granja 2026-09-13T14:02:34Z — avance del árbol KDE 2026-09-13 14:02:34 +00:00
Sergio 3851b2fd40 estado: cosecha granja 2026-09-13T13:32:16Z — avance del árbol KDE 2026-09-13 13:32:16 +00:00
Sergio f299f061b0 estado: cosecha granja 2026-09-13T13:02:35Z — avance del árbol KDE 2026-09-13 13:02:35 +00:00
Sergio 0687a4fdf6 estado: cosecha granja 2026-09-13T12:32:19Z — avance del árbol KDE 2026-09-13 12:32:19 +00:00
Sergio f35a30cf8b estado: cosecha granja 2026-09-13T12:02:59Z — avance del árbol KDE 2026-09-13 12:03:00 +00:00
Sergio 13bc744b94 estado: cosecha granja 2026-09-13T11:32:31Z — avance del árbol KDE 2026-09-13 11:32:31 +00:00
Sergio 2208e4fe09 estado: cosecha granja 2026-09-13T11:02:11Z — avance del árbol KDE 2026-09-13 11:02:11 +00:00
Sergio f54adf119b estado: cosecha granja 2026-09-13T10:32:24Z — avance del árbol KDE 2026-09-13 10:32:24 +00:00
Sergio 2074d359c5 estado: cosecha granja 2026-09-13T10:02:33Z — avance del árbol KDE 2026-09-13 10:02:33 +00:00
Sergio 184be3529e estado: cosecha granja 2026-09-13T09:32:01Z — avance del árbol KDE 2026-09-13 09:32:01 +00:00
Sergio ce875b141a estado: cosecha granja 2026-09-13T09:02:41Z — avance del árbol KDE 2026-09-13 09:02:41 +00:00
Sergio ff84f791f1 estado: cosecha granja 2026-09-13T08:31:55Z — avance del árbol KDE 2026-09-13 08:31:55 +00:00
Sergio 5832a0090a estado: cosecha granja 2026-09-13T08:02:39Z — avance del árbol KDE 2026-09-13 08:02:39 +00:00
Sergio b59edab197 estado: cosecha granja 2026-09-13T07:32:17Z — avance del árbol KDE 2026-09-13 07:32:17 +00:00
Sergio 6734d3eda5 estado: cosecha granja 2026-09-13T07:02:22Z — avance del árbol KDE 2026-09-13 07:02:22 +00:00
Sergio f1402036aa estado: cosecha granja 2026-09-13T06:31:56Z — avance del árbol KDE 2026-09-13 06:31:56 +00:00
Sergio df5976baad estado: cosecha granja 2026-09-13T06:02:02Z — avance del árbol KDE 2026-09-13 06:02:02 +00:00
Sergio 00c9d5afaf estado: cosecha granja 2026-09-13T05:31:54Z — avance del árbol KDE 2026-09-13 05:31:54 +00:00
Sergio 948fa6a284 estado: cosecha granja 2026-09-13T05:02:08Z — avance del árbol KDE 2026-09-13 05:02:08 +00:00
Sergio 460c68e100 estado: cosecha granja 2026-09-13T04:32:22Z — avance del árbol KDE 2026-09-13 04:32:22 +00:00
Sergio 2b86b8d0c3 estado: cosecha granja 2026-09-13T04:02:26Z — avance del árbol KDE 2026-09-13 04:02:27 +00:00
Sergio e28140c5b0 estado: cosecha granja 2026-09-13T03:32:09Z — avance del árbol KDE 2026-09-13 03:32:09 +00:00
Sergio eab169976e estado: cosecha granja 2026-09-13T03:02:27Z — avance del árbol KDE 2026-09-13 03:02:27 +00:00
Sergio 7ecf9d1d58 estado: cosecha granja 2026-09-13T02:31:54Z — avance del árbol KDE 2026-09-13 02:31:54 +00:00
Sergio f39a2eafc3 estado: cosecha granja 2026-09-13T02:02:41Z — avance del árbol KDE 2026-09-13 02:02:41 +00:00
Sergio 4b38af8f3f networkmanager al corpus CON WiFi y con nmcli — y los perfiles que no tenían gestor de red
networkmanager  b3:c36414ece23e322ef007d0acc7ce6f65b8b822ae55c38b38c9afa4b3eb340adb  (52 MB)

Arreglo del segundo hueco del barrido: `networkmanager` figuraba SÓLO en escritorio-kde, y desde
GNOME, COSMIC o sway no se alcanza (cola hermana). Pero promover la receta de KDE tal cual habría
sido peor que no hacerlo, y sólo se vio mirando el ARTEFACTO:

  · `-Dwifi=false`  ⇒ un gestor de red que no maneja interfaces inalámbricas. Allá es correcto
    (esa receta existe para dar libnm.so a plasma-nm y nada más); acá habría puesto en tres
    imágenes un demonio que arranca, dibuja el applet y no lista una sola red.
  · sin `nmcli`     ⇒ ni una herramienta con la que manejarlo. En sway eso es la diferencia entre
    tener red y no tenerla.

La variante del corpus cambia tres cosas, y la tercera hizo falta MEDIRLA:
  1. `-Dwifi=true`. Habla nl80211 por libnl (ya era dep) y delega el handshake WPA2 en
     `wpa_supplicant`, que desde hoy está en perfil.base ⇒ va también en [deps] runtime.
  2. `readline` en [deps] build.
  3. `-Dnmcli=true -Dreadline=libreadline`. Con sólo la dep, nmcli NO se construyó: `-Dnmcli` vale
     true de fábrica pero `-Dreadline` es un COMBO que por defecto va en `auto`, y sin decirle
     dónde mirar resolvió a «none» ⇒ meson apagó el CLI EN SILENCIO. Comprobado sobre el store.

Y `readline-shared` en runtime, cazado con provee.py sobre las NEEDED del binario: nmcli sale con
`NEEDED libreadline.so.8` y la readline canónica del corpus es sólo .a. La dep de BUILD y la de
RUNTIME son artefactos distintos — tercer caso del día tras cmus y bluez. No mueve el hash.

⚠ Se queda `-Dcrypto=null`, y es una limitación real escrita en la receta: sin cripto no valida
802.1X / WPA-Enterprise (el WiFi de una oficina). WPA2-PSK funciona porque ése lo hace el
supplicant. Encender nss o gnutls arrastra dos cadenas enormes: unidad de trabajo aparte.

── targets.toml ────────────────────────────────────────────────────────────────────────────────
  escritorio-gnome, escritorio-cosmic, escritorio-sway  += networkmanager  (+ servicio)
  escritorio-kde, escritorio-sway                       += wireplumber     (+ servicio)

⚠ networkmanager NO se declara en escritorio-kde: allá plasma-nm ya arrastra la variante de la
cola, y dos NetworkManager distintos en la misma ruta es la enfermedad de las dos glib. Que la de
KDE vaya sin WiFi es deuda del frente KDE, y queda escrita donde toca.
2026-09-13 01:38:50 +00:00
Sergio 72b9f54c19 recetas: libtool y libndp al corpus — promoción GRATIS, hash idéntico desde las dos partes
libtool  b3:5c09bff565b24c0a8edb306e0d4ca4e5e8e2a8c8e4a2b8ac047c8816b6883dcb
  libndp   b3:51be8f4336084b181e94a7f4a4178b87602cd39e975c2ddbd3125e7b782b9189

Entran como escalón para promover `networkmanager` al corpus (el barrido de perfiles midió que
GNOME, COSMIC y sway no alcanzaban ningún gestor de red: la receta vivía sólo en incoming-kde, que
desde ellos es una cola hermana).

La comprobación que decide una promoción NO es `diff` de las recetas sino `takana hash`, porque la
resolución de deps es hermano→padre y dos ficheros idénticos en colas distintas PUEDEN sellar
distinto. Acá sellan IGUAL desde las dos partes ⇒ misma dirección del store ⇒ las dos entraron por
CACHE-HIT, cero builds y cero rebuilds. (networkmanager, en cambio, sí difiere: resuelve varias
deps contra el corpus en vez de contra la cola de KDE.)

Las copias de `incoming-kde` se DEJAN donde están, a propósito: sellan en la misma dirección, así
que no hay dos artefactos ni colisión de nombre, y retirar ficheros de la cola que otro agente está
moliendo ahora mismo no es algo que este barrido tenga que hacer. Jubilarlas es trabajo del frente
KDE, el día que le convenga.
2026-09-13 01:37:26 +00:00
Sergio 0cd3e62822 libglvnd: sólo despacho de GL — muere la colisión de libEGL. Y obs-studio llevaba meses sin construir
libglvnd    b3:e27d3b2833a6aa6a6b4a4caad5ef2121e7be31a3c7ae59d0db22b01d696ffc99
  obs-studio  b3:29d95ddf50ef79692b48cae493758def564202ef81eba236b6cb279757621403

── libglvnd: se apagan egl, gles1, gles2 y headers ─────────────────────────────────────────────
La receta se escribió para la campaña completa —glvnd toma libEGL y mesa pasa a ser vendor detrás—
y la campaña NO SE HIZO: las tres mesa siguen con -Dglvnd=false. El resultado, medido en
/mnt/cosecha/escritorios/kde-rootfs ya hidratado, era el cuadro que la propia receta anunciaba:

  /usr/lib/libEGL.so.1 -> libEGL.so.1.0.0   1.440.624 B   (mesa: el driver)
  /usr/lib/libEGL.so.1.1.0                    323.144 B   (glvnd: despacho, HUÉRFANO)

Dos libEGL.so.1 distintos en la MISMA ruta, más libGLESv2.so.2 y los headers GL/, EGL/ y GLES2/
duplicados y con BYTES DISTINTOS (gl.h: 79.877 vs 80.393). Quién gana depende del orden de
hidratación y nada lo guarda.

Y no hacía falta: OBS, que es la razón de que la receta exista, NO usa glvnd en runtime.
libobs-opengl.so sale con NEEDED libEGL.so.1 y nada más, y sus indefinidos son todos egl* —ni un
gl[A-Z] sin resolver— o sea que su glad resuelve por eglGetProcAddress contra la EGL de mesa. Lo
único que glvnd le da es satisfacer el OpenGL::GL de CMake AL ENLAZAR.

Ahora sella libGLdispatch.so.0 + libOpenGL.so.0 + opengl.pc y nada más: CERO ficheros en común con
mesa. Radio medido: 1 dependiente.

⚠ Esto quita el DAÑO, no cierra el muro: libOpenGL.so.0 enlaza y en runtime sigue sin haber vendor
(no hay libEGL_mesa.so.0 ni egl_vendor.d). Cerrarlo es re-sellar las TRES mesa con -Dglvnd=true en
un movimiento, y el precio está medido: `yupana radio mesa` = 148 directos, 154 transitivos, 153
sellados que caen a deuda, las CINCO imágenes. Decisión de distro, no arreglo de paso.

── obs-studio: el cache-hit tapaba una regresión ───────────────────────────────────────────────
Al forzar su rebuild, el configure murió pidiendo `qrcodegencpp`, que no es receta de ninguna cola.
La causa NO era libglvnd. La receta dice «[source] de takana NO clona submódulos ⇒ sus directorios
llegan VACÍOS» y por eso hacía `touch plugins/obs-websocket/CMakeLists.txt`. Esa premisa dejó de
ser cierta: los submódulos YA se materializan, así que `touch` no vacía nada —sólo toca la mtime de
un fichero que existe— y el CMakeLists de verdad entra pidiendo su dependencia.

Corregido a `mkdir -p` + `: >` (truncar), que funciona con submódulos y sin ellos: la receta deja
de depender de una premisa que puede cambiarle bajo los pies. Construye y sella en el hub.
2026-09-13 01:36:36 +00:00
Sergio 424363fbdc receta: wireplumber al corpus — KDE y sway tenían pipewire y no encaminaban nada
wireplumber  b3:bd5471f00f5cbd229fcb252ceced41c35547725733708426bf7a42ea3e39a7bd

Arreglo del hueco que destapó el barrido de servicios. `pipewire` está en los cuatro escritorios y
arranca, pero se construyó con `-Dsession-managers=[]`: sin gestor de sesión no hay política de qué
es entrada, qué es salida ni qué se enlaza con qué, y el sink que ve la aplicación es `auto_null`
—el nodo de descarte—. Audio que parece vivo y no suena.

wireplumber existía en `incoming-gnome` y en `incoming-cosmic`, y desde KDE o sway NO SE ALCANZA:
una receta resuelve sibling-first y después el catálogo PADRE, nunca una cola hermana. Por eso la
copia va al corpus, que es el único sitio desde el que las cuatro imágenes la ven — el mismo
argumento por el que viven acá `mpv` y `atuq`.

Medido antes de copiar, no supuesto:
- `yupana radio wireplumber` = **0 dependientes** ⇒ esta copia no fuerza un solo rebuild ajeno.
- Las tres variantes sellan DISTINTO (gnome b3:71afcef4…, cosmic b3:7ad25184…, corpus b3:bd5471f0…).
  No es la enfermedad de las dos glib: ninguna imagen hidrata dos wireplumber, cada una toma la
  suya. Es la figura de las tres `pulseaudio`, que también se quedaron a propósito.
- Consolidar las tres en una es el trabajo siguiente y NO se hace de paso: el método está probado
  (es lo que se hizo con pipewire el 2026-09-03) pero GNOME y COSMIC están validados y cambiarles
  el artefacto de audio sin probarlos sería pagar con su imagen una limpieza que no urge.
2026-09-13 01:36:36 +00:00
Sergio 47ec0d9559 estado: cosecha granja 2026-09-13T01:33:30Z — avance del árbol KDE 2026-09-13 01:33:30 +00:00
Sergio 741a5d767c receta: bluez estático de verdad — el audit del cron vuelve a verde
bluez  b3:6036ab1585ce2af12e7596edd16709d1baa906f8c0ca816aed44957a038fbd66
  11/11 ejecutables `statically linked` · `bluetoothctl: 5.87` corre · 31 ficheros (no se perdió nada)

El sello de ayer decía `static` y salía con los ONCE ejecutables dinámicos; el audit del cron lo
marcó esa misma noche (docs/state/static-audit.txt, 2026-09-12T21:04Z) y dejó el veredicto global
en rojo: 715 honestas y las dos nuevas mintiendo. Acá se puede ser estático de verdad —el artefacto
NO trae ningún plugin .so, o sea que nadie hace dlopen (a diferencia de cmus)— así que el arreglo
es el arreglo, no una re-declaración.

Dos mitades, y la segunda no se ve venir:

1. `LDFLAGS=-all-static` en compile **Y** en install: bluez enlaza con libtool, que lee el `-static`
   del lab como «preferí los .a de libtool» y además RELINKEA al instalar.
2. `LIBS=-lncursesw`. Con -all-static el enlace de bluetoothctl corta con
   `undefined symbol: tgoto ... in archive /usr/lib/libreadline.a`: readline usa termcap y su
   readline.pc lo declara en `Requires.private: ncurses`, que **sólo se expande con
   `pkg-config --static`**. El configure de bluez busca readline con AC_CHECK_LIB, no con
   pkg-config ⇒ la transitiva nunca entra. En dinámico no se nota: la resuelve el loader.

Y se QUITA el `runtime = ["readline-shared"]` que se había añadido horas antes: hacía falta
mientras bluetoothctl era dinámico, y con el estático pasó a ser la mentira simétrica —declarar una
dep que no se usa—. No mueve el hash (las deps de runtime no entran en hash_inputs).
2026-09-13 01:15:40 +00:00
Sergio 35f83748f9 receta: cmus va link = "dynamic" — carga sus formatos por dlopen
cmus  b3:9a540d4270674ec74679dffbeed11d98796c51801663bde88e87affc041213ab

La primera versión decía `static` y era MENTIRA MEDIBLE: el audit del cron
(docs/state/static-audit.txt, medido 2026-09-12T21:04Z) la marcó — «dice static, es DINÁMICO →
libncursesw.so.6 libc.so» — y dejó el veredicto global en rojo. 715 honestas y las dos nuevas de
ayer mintiendo.

Pero el arreglo NO es hacerlo estático: **cmus no puede serlo**. El artefacto trae cinco plugins
—usr/lib/cmus/ip/{wav,cue,ffmpeg}.so y usr/lib/cmus/op/{alsa,oss}.so— y los abre por dlopen. Un
binario estático no puede abrirlos: quedaría un reproductor que no reproduce nada. Es la misma
razón por la que `sway` va dinámico (dlopea los drivers DRI de mesa).

⇒ `dynamic` es la declaración CORRECTA, no una concesión. Una declaración que el build ignora es
peor que no declarar, porque las herramientas río abajo la creen.

La prueba que decide, y cuesta dos segundos:
    find store/<hash>-<nombre> -name '*.so' | wc -l
  0 plugins → se puede y se debe ser estático.   N plugins → dynamic es lo honesto.

Comprobadas las NEEDED de los plugins contra el corpus con scripts/provee.py, que es la otra mitad:
libasound.so.2 (alsa-lib), libavformat/libavcodec/libswresample .so (ffmpeg) y libncursesw.so.6
(ncurses-shared) los publica el corpus ⇒ no hay NEEDED colgante. Las tres primeras llegan por
[deps] build; ncurses-shared va declarada en runtime desde el commit anterior.
2026-09-13 01:14:18 +00:00
Sergio 584cc128a8 docs: adenda al plan de apps — el censo, el muro de GL revisado y la respuesta a «¿Electron?»
Tres preguntas del usuario, contestadas midiendo, y dos de las mediciones CORRIGEN cosas que este
mismo fichero afirmaba.

1. CENSO: de ~50 apps muy usadas el catálogo tiene 9, y CINCO de las nueve son de KDE (o sea que
   llegan a una de las cuatro imágenes).

2. ⚠ CORRECCIÓN al «tercer defecto del método». Este documento dice, con fecha 2026-09-03, que
   ninguna cola publica libGL.so ni gl.pc. Dejó de ser cierto AL DÍA SIGUIENTE: recipes/libglvnd.toml
   es del 2026-09-04 y `provee.py --desde corpus opengl` da ✓ (libOpenGL.so.0 + opengl.pc). Y la
   corrección trae su propia corrección: la campaña quedó A MEDIAS. Las tres mesa siguen con
   -Dglvnd=false, no hay libEGL_mesa.so.0 ni egl_vendor.d, y en el rootfs KDE hidratado conviven DOS
   libEGL.so.1 distintos (mesa 1.440.624 B gana el symlink; el de glvnd, 323.144 B, queda huérfano).
   OBS —la razón de escribir libglvnd— NO la usa en runtime: libobs-opengl.so sale con NEEDED
   libEGL.so.1 y ni un gl[A-Z] indefinido, o sea que su glad resuelve por eglGetProcAddress.
   ⇒ el `opengl ✓` es verdad DE ENLACE. El muro pasó de «no enlaza» a «enlaza y no corre».

   Corolario: darktable estaba MAL clasificada como caso de GL. Su UI es GTK3+cairo; su muro es la
   cola de deps (lensfun, libgphoto2, openexr, imath, libraw, osm-gps-map, portmidi + cuatro que
   sólo viven en colas). Blender sí es el caso de GL.

3. ELECTRON: `grep -rni electron docs/ recipes/` da CERO. Nunca estuvo planeado. Y no existe un
   «Electron con base Firefox» porque Gecko no tiene API de embebido desde XULRunner (SDD 26 §1) —
   pero eso es exactamente lo que es atuq, y ya está: artefacto derivado + chrome propio +
   extensiones + host de native messaging en Rust. Falta un modo SSB, que es más barato que UN port.

   GenOffice concretamente: Apache-2.0 (salvo ee/), acepta endpoints OpenAI-compatible locales ⇒ la
   mitad de IA es una línea de config contra el llama-cpp que YA viaja en los cuatro escritorios. La
   mitad de runtime es qorpa. ⚠ Y el muro real es el MODELO: Qwen2.5-1.5B no sostiene IA agéntica
   sobre un .xlsx.

4. QUÉ REHACER, con criterio escrito: sólo cuando el bloqueo es estructural Y el valor vive en un
   protocolo o formato abierto. Pasan tres: el shell de apps sobre atuq, una bóveda de contraseñas
   (la mitad cara —la integración con el navegador— ya está construida), y un cliente Matrix si
   fractal no construye. Thunderbird es el más desaprovechado de la lista de EMPAQUETAR: es Gecko.
2026-09-13 01:10:00 +00:00
Sergio cbecd0ba12 docs: el barrido de perfiles y servicios, con su método y la política que faltaba escribir
Deja escrito lo que el barrido midió y, sobre todo, CÓMO se midió, para que el recuento se pueda
repetir en vez de re-derivar.

Lo que aporta que no estaba en ningún lado:

1. **La política «catálogo ≠ imagen».** El repo ya la aplicaba de hecho y no la había escrito, y sin
   ella «620 hojas sin perfil» se lee como deuda. No lo es: 529 son volcado crudo del importador y
   355 son herramientas Go de nube. Una receta sellada y no declarada es CATÁLOGO — se instala por
   nombre. Se vuelve deuda sólo cuando lo que falta es una CAPACIDAD.

2. **El método en tres preguntas encadenadas**, y por qué el orden importa: ¿está en algún perfil?
   → ¿podría llegar por clausura ajena (`dependientes_total>0`)? → ¿fue curada alguna vez (la
   cabecera «PUNTO DE PARTIDA» del importador)? Las hojas son el hueco; las librerías no.

3. **El triaje completo de las 91 hojas trabajadas a mano**, en seis clases que suman 91 exactas.
   Incluye las que NO se declaran de oficio y por qué: `openrc` compite con arje-zero, `uutils` y
   coreutils/grep/findutils compiten con los applets de busybox, `waterfox` es un segundo Gecko,
   y valkey/opensmtpd/step-ca/qdrant definen QUÉ CLASE de servidor es el perfil `servidor`.

4. **Dos hallazgos que no eran el objetivo del barrido:**
   - `networkmanager` existe SÓLO en incoming-kde ⇒ GNOME, COSMIC y sway no lo alcanzan. Con
     wpa_supplicant la WiFi se destraba, pero se configura a mano y el indicador de red del
     escritorio no tiene con qué hablar.
   - `ia-modelo-embeddings` no está en ningún perfil: hay motor (llama-cpp) y hay chat
     (ia-modelo-chat) en los cuatro escritorios, y NO hay búsqueda por significado. La mitad
     semántica del §6.3 de atuq no viaja.

5. **Una trampa del instrumento**, que casi hace escribir mal las listas de servicios:
   `scripts/targets.py <perfil>` imprime las RAÍCES, no la clausura. Cruzar los [[service]] contra
   esa salida dejaba fuera a pipewire y colord en GNOME, que sí están en la imagen. La clausura la
   da el campo `perfiles` de los build-state*.json.
2026-09-13 01:08:17 +00:00
Sergio 9ac4e1727f targets: barrido de perfiles y servicios — la WiFi faltaba, y tres escritorios no arrancaban nada
── BARRIDO 1: las hojas selladas sin perfil ────────────────────────────────────────────────────
Método, para que se pueda repetir: cruzar el campo `perfiles` de los cinco build-state*.json con
`dependientes_total`. De 905 nodos, 631 sin perfil; de ésos, **620 son HOJAS** (nadie depende de
ellas, o sea que ninguna clausura las puede alcanzar) y 11 llegan por la clausura de otra.

Las 620 se parten en dos por una marca objetiva, la cabecera del importador:
  · **529** dicen «PUNTO DE PARTIDA, no final» — volcado crudo de import-nix/import-alpine
    (328 Go + 195 Rust + 6 C). Nadie las curó nunca para una imagen.
  · **91** están trabajadas a mano. Ésas son las que se triaron una por una.

Lo que salió de ese triaje, y lo que se declara:

**`base` += `wpa_supplicant` — la imagen NO PODÍA ASOCIARSE A UN WiFi.** dhcpcd resuelve la IP de
un cable; el handshake WPA2 de 4 vías lo hace un supplicant en userspace y busybox no lo trae. La
receta existía desde el frente de metal —su cabecera dice «para asociar el WiFi del medio live al
AP»— y estaba en CERO perfiles. Es la figura de `foot` y esta vez el precio era quedarse sin red.

**`cli` += nano, tig, patch, socat, pigz, miller, dwarves.** El criterio va escrito en el fichero
porque meter las 620 habría sido peor que no mirar: entra lo que un usuario de esta capa ESPERA
encontrar y hoy no está. El resto queda en el catálogo, que NO es lo mismo que la imagen.

**`escritorio-sway` += wlr-randr**: no había con qué cambiar la resolución ni rotar una pantalla.

── BARRIDO 2: el «enable» ──────────────────────────────────────────────────────────────────────
De los cuatro escritorios **sólo GNOME tenía lista `servicios`**. Los otros tres salían con sus
demonios instalados y NINGUNO arrancado, y la métrica de clausura daba N/N igual — `paquetes` dice
qué se instala, `servicios` dice qué se levanta, y sin la segunda la imagen está a medias sin que
nada falle.

Escritas las tres que faltaban, computando la lista (no a ojo): se cruzaron los `[[service]]` de
las 11 recetas que los declaran contra el campo `perfiles` de los cinco grafos — la CLAUSURA, no
las raíces, porque la mitad de los demonios llegan como dep. Y GNOME sumó `cupsd`+`bluetoothd`,
que nacieron ayer.

⚠ El cruce destapó tres ausencias que NO se arreglan acá y quedan escritas en el fichero:
  · KDE y sway tienen `pipewire` y **no tienen `wireplumber`**: sin gestor de sesión los nodos
    existen y nadie los conecta.
  · COSMIC **no tiene `upowerd`** y dibuja un indicador de batería.
  · KDE y sway no tienen `logind-compat`.

Comprobado: tomllib parsea, y los ocho perfiles resuelven con scripts/targets.py.
2026-09-13 01:06:01 +00:00
Sergio a9991194bc estado: cosecha granja 2026-09-13T01:02:20Z — avance del árbol KDE 2026-09-13 01:02:20 +00:00
Sergio dadd231b03 estado: cosecha granja 2026-09-13T00:32:07Z — avance del árbol KDE 2026-09-13 00:32:07 +00:00