Commit Graph
2622 Commits
Author SHA1 Message Date
Sergio d38b1bbe41 estado: cosecha granja 2026-09-12T22:31:56Z — avance del árbol KDE 2026-09-12 22:31:56 +00:00
Sergio 10cb6ef140 estado: cosecha granja 2026-09-12T22:01:59Z — avance del árbol KDE 2026-09-12 22:01:59 +00:00
Sergio 5881260aee estado: cosecha granja 2026-09-12T21:32:04Z — avance del árbol KDE 2026-09-12 21:32:04 +00:00
Sergio 3043abd295 estado: cosecha granja 2026-09-12T21:04:26Z — avance del árbol KDE 2026-09-12 21:04:26 +00:00
Sergio 4e807444d1 targets: mold, sccache y cliphist — las tres que habrían repetido el error del commit anterior
El grafo regenerado por el cron delató lo que faltaba: `mold` y `cliphist` salían con
`perfiles: []`. O sea que en el mismo día en que se midió que 649 recetas selladas no están en
ninguna imagen, dos de las recetas nuevas se iban a sumar a la lista. La métrica lo vio porque
existe; la intención no alcanza.

- `cli` += `mold` y `sccache`. Las dos son herramientas de quien CONSTRUYE con la distro, no de
  quien la usa. `sccache` estaba sellada hace meses y sin perfil; `mold` es de hoy.
- `escritorio-sway` y `escritorio-cosmic` += `cliphist`. SÓLO ahí: habla `wlr-data-control`, que
  KWin y mutter no implementan — mismo muro que `wf-recorder`. Declararlo en KDE o GNOME daría un
  binario que arranca y no hace nada, que es peor que no tenerlo.

Comprobado con scripts/targets.py: cli resuelve mold+sccache, y sway/cosmic los tres.
2026-09-12 21:02:31 +00:00
Sergio f0614f679e recetas: mold y wireguard-tools — link = "static" era una etiqueta, no un hecho
mold             b3:9ce9fe3194982cc2b28d0fa547b037d7d36dae773fbd033ad252d7f11cb92dd2
  wireguard-tools  b3:086d0837e30e8a7a5e05c61c2df47987c2574645c03226e0020f35635ba8ba41

Los dos sellaban, reproducían y NO CORRÍAN. Se descubrió ejecutando el binario; ni el sellado, ni
`takana hash`, ni la reproducibilidad lo veían.

mold — dos causas independientes, las dos leídas en su CMakeLists.txt:
  1. `:149` — `if(ZLIB_FOUND AND NOT MOLD_MOSTLY_STATIC)` enlaza la zlib COMPARTIDA del sistema
     (ídem zstd `:179` y blake3 `:161`). El binario salía pidiendo `libz.so.1`/`libzstd.so.1`, que
     el corpus no publica (`zlib` canónica es `.a`), y al correrlo tomaba la del anfitrión:
     `Error relocating /lib/libz.so.1: __snprintf_chk: symbol not found` — símbolo de
     _FORTIFY_SOURCE de glibc que musl no tiene. `-DMOLD_MOSTLY_STATIC=ON` usa las que trae en tree.
  2. El `LDFLAGS=-static` que el lab exporta para `link = "static"` NO llegaba a la línea de enlace
     de CMake ⇒ hace falta `-DCMAKE_EXE_LINKER_FLAGS=-static` explícito.
  Ahora: `statically linked`, y `mold --version` contesta 2.42.1.

  Y antes de eso, otro defecto que tampoco fallaba: el primer sello pesaba 629 MB, de los cuales
  628 eran UN SOLO FICHERO — /usr/bin/mold con el DWARF adentro, que CMAKE_BUILD_TYPE=Release no
  quita. Con `strip_debug = true` (SDD 23) quedó en 41 MB. Un artefacto obeso no rompe nada: entra
  en el store, en la imagen y en el respaldo, y nadie mira el tamaño.

wireguard-tools — acá el error era del razonamiento, y el artefacto lo desmintió. La receta iba
`link = "dynamic"` con [deps] build=["libmnl"] argumentando «wg enlaza libmnl y no hay libmnl.a en
el store». `readelf -d wg` da UN solo NEEDED, `libc.so`, y los `mnl_*` están definidos adentro.
La razón está en la fuente, `src/netlink.h:1`:

    /* This is a minimized version of libmnl meant to be #include'd */

Upstream embebe el subconjunto que usa para no arrastrar la dependencia. Pasa a `link = "static"`
y pierde la dep: declarar una que no se usa ata esta receta al hash de otra y haría que un rebuild
de libmnl la re-selle para nada.

REGLA, escrita en las dos recetas: `link = "static"` es una DECLARACIÓN. Lo único que la comprueba
es `readelf -d` sobre el artefacto, o correrlo.
2026-09-12 21:00:32 +00:00
Sergio 4fe5886447 recetas: cmus y bluez piden un .so que la imagen no llevaba — declarado en runtime
Se descubrió CORRIENDO los binarios, no auditando las recetas, y el hash NO se mueve (las deps de
runtime no entran en hash_inputs): los artefactos sellados siguen valiendo.

  cmus/cmus            NEEDED libncursesw.so.6   ⇒ runtime = ["ncurses-shared"]
  bluez/bluetoothctl   NEEDED libreadline.so.8   ⇒ runtime = ["readline-shared"]

Las canónicas `ncurses` y `readline` del corpus son `--without-shared`/sólo `.a`, así que sin
declarar la variante `-shared` esos `.so` no viajan en la imagen y el binario muere en el loader.
Es la MISMA fuga que el perfil de sway ya pagó con zlib/expat/libffi, y no la ve ningún auditor de
recetas: sólo `readelf -d` sobre el artefacto, o ejecutarlo.

El reparto de bluez era el peor posible: `bluetoothd` sale con `libc.so` a secas y habría
arrancado, y la herramienta con la que se emparejan los dispositivos habría sido la que no.

Comprobado con scripts/provee.py: los dos sonames SÍ los publica el corpus
(corpus/ncurses-shared, corpus/readline-shared) ⇒ no hay NEEDED colgante, faltaba la declaración.
2026-09-12 20:45:58 +00:00
Sergio e1fb4b71a7 estado: cosecha granja 2026-09-12T20:33:54Z — avance del árbol KDE 2026-09-12 20:33:54 +00:00
Sergio 66db4e4054 targets: declarar lo que ya estaba sellado y en ninguna imagen — y las dos capacidades del punto 8
MEDIDO al ir a declarar las recetas nuevas, y es más grande que ellas: de las 892 recetas selladas
del corpus, **649 no están en NINGÚN perfil**. El 73% del catálogo está compilado y no viaja en
ninguna imagen. No es deuda de build (drenaje.json dice 0) y la métrica de perfil NO lo puede ver:
mide la clausura de lo DECLARADO. Es la lección de foot a escala de catálogo.

Concreto: yazi, atuin, zellij, jujutsu, just, direnv, watchexec, mise, xh, age, rclone, restic,
lazygit, difftastic, bottom y duf estaban selladas hace meses y en cero imágenes; y `helix` estaba
declarada sólo en escritorio-gnome, que es donde menos sentido tiene.

perfil.cli += esas 16 + las nuevas de hoy (btop, ncdu, nushell, aerc, cmus, syncthing).
Cero recetas nuevas y cero builds: sólo dejan de ser invisibles. Como los CUATRO escritorios y
`servidor` heredan `cli`, una sola edición los alcanza a todos.

perfil.servidor += wireguard-tools: el kernel ya trae WireGuard (SDD 22) y no había con qué
configurarlo — misma figura que el cortafuegos y el reloj que este perfil ya declaraba.

Los cuatro escritorios += cups, bluez (punto 8 de PUBLICABLE, docs/20). Viven en el CORPUS y no en
las colas por lo mismo que mpv y atuq: se alcanzan sibling-first→padre, una copia para los cuatro.

⚠ DEUDA DECLARADA, NO OLVIDO: las dos recetas traen su [[service]] y los perfiles NO los arrancan
— de los cuatro escritorios sólo escritorio-gnome tiene lista `servicios`. Los otros tres no
arrancan NADA, y eso es más grande que cups y bluez. Va escrito en el fichero para que se vea.

El barrido de las 649 queda pendiente y es su propia unidad de trabajo: 363 son recetas Go
importadas en tanda (herramientas de desarrollo) y NO todas deben entrar en una imagen.

Comprobado con scripts/targets.py: los ocho perfiles resuelven, sin nombres desconocidos.
2026-09-12 20:31:35 +00:00
Sergio 0d93435fd8 receta: bluez — la pila Bluetooth, sellada (el otro medio punto 8 de PUBLICABLE)
bluez  b3:21bee949122f770a319b806b83d23fa2bddc958252f6de7e27fffa5a75a3315a  (28 MB, 31 ficheros)

Con esto queda cerrado el punto 8 de PUBLICABLE (docs/20): «cups y bluez».

El fallo del primer intento vale más que la receta: con [deps] build=["glib", ...] el configure
corta con «Package 'libpcre2-8', required by 'glib-2.0', not found». No falta una dep de bluez:
faltan las TRANSITIVAS del .pc de glib. Un enlace estático resuelve la cadena entera en el punto de
enlace, así que pcre2/libffi/zlib hay que materializarlas aunque bluez no las nombre — es el mismo
juego de cuatro que ya declaran cairo, appstream y adwaita-hello, y que nadie había escrito por qué.

Perillas leídas del «configure --help» del tarball pineado:
- --disable-obex: obexd pide libical, y libical existe SÓLO en incoming-gnome. Una receta del
  corpus resuelve sibling-first y después el catálogo PADRE, nunca una cola hermana ⇒ desde acá no
  se alcanza. Encenderlo exige promover libical, que es otra unidad de trabajo.
- --disable-manpages: las genera rst2man (docutils); no es receta.
- --disable-cups: el backend de impresión por Bluetooth. cups YA es receta desde hoy, o sea que
  esto se puede encender — queda anotado como lo próximo, no como olvido.

Declara [[service]] bluetoothd; el exec VERIFICADO contra el artefacto: /usr/lib/bluetooth/bluetoothd.
Y va escrito que esto no enciende el bluetooth de nadie: falta dbus vivo y que el perfil lo habilite.
2026-09-12 20:28:31 +00:00
Sergio 3f2620f6b7 recetas: nushell y cmus — shell moderna y reproductor de música, sellados
nushell  b3:742c008b462930c6ee9c2af0646fe842e9e1bad7fe35277eddabdb15aa4fdae6  (41m17s de cargo)
  cmus     b3:cae8d90b5c1c7e5864c708371b2bdefbbccaa3ef1248f165a20f2dc2ce481b8b

- nushell entra como shell INTERACTIVA y va escrito en la receta que no es ni va a ser /bin/sh: su
  lenguaje no es POSIX y un script del sistema no corre ahí. El catálogo tenía tres shells (bash,
  busybox/ash, elvish) y ninguna era una alternativa moderna. compiler="gcc" por el patrón
  zellij/gitui/delta: hay crates *-sys con build-script en C y cc-rs invoca gcc; el linker sigue
  siendo zig-cc.

- cmus cierra el hueco de audio: el catálogo había cerrado el vídeo con mpv y no tenía con qué
  escuchar música. Su configure NO es autotools — toma asignaciones clave=valor, no --flags — y
  eso importa: pasarle --prefix=/usr no da error, lo IGNORA, y el paquete acabaría en /usr/local
  sin que nada falle. CONFIG_PULSE=n a propósito: la salida ALSA desemboca en PipeWire por
  -Dpipewire-alsa, igual que hace mpv, y la libpulse del corpus es la variante con la glib
  ESTÁTICA adentro, que no se quiere en un cliente.
2026-09-12 20:26:53 +00:00
Sergio b8738c6c3f estado: cosecha granja 2026-09-12T20:03:45Z — avance del árbol KDE 2026-09-12 20:03:45 +00:00
Sergio 7c4bd40c23 estado: cosecha granja 2026-09-12T19:34:20Z — avance del árbol KDE 2026-09-12 19:34:21 +00:00
Sergio 63eab86ef7 receta: cups — el servidor de impresión, sellado (punto 8 de PUBLICABLE)
cups  b3:528b38b20d3cecf7e06fbc51f271603e3c71fbec6ef8047c86ad421edb7a1a45

No es una app más: es uno de los NUEVE pendientes de PUBLICABLE (docs/20, punto 8). Una distro de
escritorio que no imprime no es una distro de escritorio, y ese hueco no se ve contando recetas
— es de CAPACIDAD, la familia de foot y las fuentes.

El muro real fue el PIE, y el diagnóstico vale más que el arreglo: el configure detecta que el
compilador acepta -fPIE y mete «-fPIE -pie» en ALL_LDFLAGS *y sólo ahí* — los objetos de
libcups.a se compilan sin PIC — así que lld corta con «relocation R_X86_64_64 cannot be used
against local symbol». No se puede apagar con una flag: @PIEFLAGS@ se sustituye DENTRO de
Makedefs, no es una variable de make que «make PIEFLAGS=» pueda pisar. Y un ejecutable PIE con
-static exigiría -static-pie, que no es lo que esta distro construye ⇒ el sed que lo quita es lo
correcto acá, no un atajo.

Todas las perillas salen del «configure --help» del TARBALL PINEADO, no de un APKBUILD ajeno.
--with-dnssd=no y --disable-acl se apagan POR DECLARACIÓN aunque no haya avahi ni acl en el
catálogo: si el configure los busca y los encuentra en el sysroot del lab, el lab NO entra en
hash_inputs y el artefacto deja de reproducir sin que nadie toque la receta.

⚠ Queda escrito en la receta un segundo tramo que ESTA receta no paga: gtk3 del corpus está
sellada con -Dprint_backends=file, así que una app GTK3 seguirá viendo un solo destino hasta que
gtk3 se re-selle. La pieza está, el sistema la ignora, y ninguna métrica lo dice.

Declara [[service]] cupsd (SDD 30). Declararlo NO lo enciende: falta que el perfil lo habilite.
2026-09-12 19:28:46 +00:00
Sergio fad71087d8 receta: btop — monitor de recursos en TUI, sellado
btop  b3:d1e3d3111d306e158f2269ba3ecb4852d7d095f688e707db54381dbb3b26e34f

Dos cosas que valían el viaje:

- `configure = 'true'` NO es relleno. btop 1.4.x trae CMakeLists.txt *y* Makefile; el autodetector
  del lab ve el primero y generaba `cmake -S . -B _build`, que muere con `cmake: not found`
  (cmake es una receta del corpus, no una herramienta del lab). Apagar la fase de configure es lo
  que elige la vía soportada por upstream.

- C++20 (<ranges>, <format>) compila y ENLAZA ESTÁTICO con la libc++ de zig, sin gueto gcc. Se
  puede porque btop no enlaza ninguna librería C++ del corpus: todo su C++ es suyo. El binario sale
  con -D_LIBCPP_HARDENING_MODE, o sea libc++ de verdad y no libstdc++.
2026-09-12 19:22:52 +00:00
Sergio a65910298a recetas: aerc y syncthing — correo en terminal y sincronización, sellados
aerc       b3:a33dbafdcc302154888095b7b5b14278461e60a69c4c8f310e388ba85f544d0a  (43 ficheros)
  syncthing  b3:544ebf125c682c720b8555faf4259cd48bee5b4a302c4a4cc29a7311691a6e34

Las dos necesitaron salirse del driver Go genérico, y por motivos distintos:

- aerc se construye con SU GNUmakefile. El driver hace `go install` y deja el binario en
  /out/usr/bin; eso habría dado un paquete que ARRANCA Y NO SIRVE — aerc busca plantillas,
  stylesets y filtros en /usr/share/aerc, y dos filtros (colorize, wrap) son fuente C que hay que
  compilar. Con el Makefile el artefacto trae los 43 ficheros. VERSION y GOFLAGS van fijados a
  mano: el Makefile los saca de `git describe` y de contrib/goflags.sh, y el árbol llega al
  sandbox SIN .git ⇒ el binario dependería de si hay un .git al lado.

- syncthing falla con `go install` a secas y el error no dice por qué:
  `lib/api/api_statics.go:45:25: undefined: auto.Assets`. La GUI web se sirve desde un fichero Go
  GENERADO que empaqueta gui/ y el repo no lo versiona: lo produce `go run build.go assets`. No es
  una dependencia que falte, es un CODEGEN. Todo local, sin red.

commit = el tag PELADO en los dos casos (ambos son tags anotados; la trampa de foot).
2026-09-12 19:21:48 +00:00
Sergio 53520c24b4 recetas: ncdu, wireguard-tools y cliphist — tres huecos del userland, sellados
Primera tanda del barrido de huecos del catálogo moderno. Las tres SELLAN en el hub:

  ncdu             b3:455589610a4d0378299a2a428f85d77c4d1998f71dbdb68bb704bd64a4ef40c5
  wireguard-tools  b3:9283f272e7833d55ec50ac854c98a5abdee81ad5ca01ce90de4ce6f241744bac
  cliphist         b3:86597f25894ab7fce9df1af6e7a6942de5e677546fcc40d91fc087778c059343

- ncdu 1.22 y NO la 2.x: la 2 esta reescrita en Zig y exige una version concreta del compilador;
  84 recetas ya pinean zig_version=0.13.0 y el zig del lab es rodante. La 1.22 es la ultima de la
  rama C y hace lo mismo.
- wireguard-tools va link="dynamic" a proposito: libmnl canonica es --disable-static, o sea que en
  el store NO hay libmnl.a. Forzar static no daria un estatico sino un enlace contra el .a del
  sysroot Alpine DEL LAB — la misma fuga que documenta el perfil de sway con zlib/expat/libffi.
- cliphist habla wlr-data-control: sirve en sway y COSMIC, NO en KDE ni GNOME (mismo muro que
  wf-recorder). Declararlo donde no funciona seria peor que no tenerlo.

Las tres licencias VERIFICADAS contra el LICENSE/COPYING del arbol, no adivinadas.
Ninguna esta declarada todavia en targets.toml: sellado != instalado (la leccion de foot).
2026-09-12 19:20:06 +00:00
Sergio 0949c0895d estado: cosecha granja 2026-09-12T19:01:53Z — avance del árbol KDE 2026-09-12 19:01:53 +00:00
Sergio 4744951980 estado: cosecha granja 2026-09-12T18:32:19Z — avance del árbol KDE 2026-09-12 18:32:19 +00:00
Sergio 86de78c0e5 estado: cosecha granja 2026-09-12T18:02:22Z — avance del árbol KDE 2026-09-12 18:02:22 +00:00
Sergio ab048a9ed8 estado: cosecha granja 2026-09-12T17:32:27Z — avance del árbol KDE 2026-09-12 17:32:27 +00:00
Sergio dad5e14a8e estado: cosecha granja 2026-09-12T17:02:20Z — avance del árbol KDE 2026-09-12 17:02:20 +00:00
Sergio 5a2e504a44 estado: cosecha granja 2026-09-12T16:32:21Z — avance del árbol KDE 2026-09-12 16:32:21 +00:00
Sergio e54a22d2fa estado: cosecha granja 2026-09-12T16:01:59Z — avance del árbol KDE 2026-09-12 16:01:59 +00:00
Sergio fe3d3c1d84 estado: cosecha granja 2026-09-12T15:31:52Z — avance del árbol KDE 2026-09-12 15:31:53 +00:00
Sergio da76749d22 estado: cosecha granja 2026-09-12T15:02:20Z — avance del árbol KDE 2026-09-12 15:02:20 +00:00
Sergio 0fa2083e6c estado: cosecha granja 2026-09-12T14:32:17Z — avance del árbol KDE 2026-09-12 14:32:17 +00:00
Sergio dc71b45eab estado: cosecha granja 2026-09-12T14:02:21Z — avance del árbol KDE 2026-09-12 14:02:21 +00:00
Sergio d8ce87c595 estado: cosecha granja 2026-09-12T13:32:17Z — avance del árbol KDE 2026-09-12 13:32:17 +00:00
Sergio c88b2c96de estado: cosecha granja 2026-09-12T13:02:31Z — avance del árbol KDE 2026-09-12 13:02:31 +00:00
Sergio 16c79f6b2c estado: cosecha granja 2026-09-12T12:32:16Z — avance del árbol KDE 2026-09-12 12:32:16 +00:00
Sergio b476e63156 estado: cosecha granja 2026-09-12T12:02:54Z — avance del árbol KDE 2026-09-12 12:02:54 +00:00
Sergio 1608262a9a estado: cosecha granja 2026-09-12T11:35:29Z — avance del árbol KDE 2026-09-12 11:35:29 +00:00
Sergio 21d44c13cd hydrate: instalar a otro filesystem ya no muere — EXDEV se copia, que es lo único posible
Lo encontró la instalación del modelo opcional del §6.3: `takana install --prefix` murió con
`Invalid cross-device link (os error 18)` justo en el caso que su propia ayuda promete por escrito
(«útil para tests offline o staging en otro filesystem»).

⚠ Y no hace falta tener dos discos para pegarse con esto: `linkat` da EXDEV **entre dos MOUNTS del
mismo dispositivo**, y el store de esta máquina es un bind-mount del volumen. O sea que el caso es
normal, no exótico.

Ahora, si el hardlink da EXDEV —y sólo si da EXDEV; cualquier otro error sigue siendo un error— se
copia. El precio es el espacio: el fichero deja de compartir inode con el store. Está aceptado,
porque la alternativa es no poder instalar. El encabezado del módulo, que prometía «cero copia», dice
ahora la excepción.

Test con el caso real (tmpfs de /dev/shm contra el temporal, que son mounts distintos) y comprobado
en los dos sentidos: quitando la excepción de EXDEV, el test cae con el mismo error que reportaba el
instalador. Si en alguna máquina esos dos caminos fueran el mismo mount, el test lo DICE en vez de
saltarse en silencio.

De paso: `swm_bridge.rs` tenía un constructor de test sin el campo `strip_debug` que agregó 9bc51889,
y eso dejaba al crate ENTERO sin compilar sus tests. Completado.
2026-09-12 11:34:49 +00:00
Sergio a4c33914e8 estado: cosecha granja 2026-09-12T11:32:19Z — avance del árbol KDE 2026-09-12 11:32:19 +00:00
Sergio ec1d43efbf ia: el modelo de embeddings entra como DESCARGA OPCIONAL, y el navegador dice cómo conseguirlo
Decisión del usuario. El motor (199 M) y el modelo de chat (1,04 GiB) van en las cuatro imágenes
porque la barra lateral está en las cuatro; el de embeddings (610 MiB) no, porque es para una función
—preguntarle al archivo por significado— que no todo el mundo usa.

Y «opcional» no significa «lo armás vos»: el modelo ya es receta del corpus, así que la maquinaria de
la Etapa F lo vuelve paquete sin trabajo extra. Publicado en `dist/repo` con su `expected_hash`
anclado, junto con las deps que `install` necesita para reproducirlo — `llama-cpp` faltaba en el
catálogo, y sin ella el paquete no se puede instalar aunque exista. De paso entraron nftables, libmnl
y libnftnl, que tampoco estaban.

⚠ Tres de esos paquetes se habían publicado con el ancla de sanidad por default (`/usr/bin/<nombre>`),
que en una librería o en un modelo NO EXISTE: `install` habría fallado al verificar. Re-empaquetadas
con su ancla de verdad (`/usr/bin/llama-server`, `/usr/sbin/nft`, `/usr/lib/libmnl.so.0`…).

Lo que hace que esto sea opcional de verdad es una línea: la receta NO está declarada en ningún
perfil. Está escrito en el SDD para que nadie lo «arregle» agregándola.

Y la mitad que separa «opcional» de «invisible»: con el modelo ausente el host ya no dice sólo «no
está» sino cómo conseguirlo — «es una descarga opcional — instalalo con `takana install
ia-modelo-embeddings`». Medido en el control negativo del guardián.
2026-09-12 11:29:31 +00:00
Sergio d4d120a079 brotli y json-c: selladas y rotas a la vez — las dos baratas del censo, arregladas
El barrido con `verificar-repro.sh` sobre las 15 recetas CMake baratas del corpus dio
**5 que no construyen hoy**. Éstas son las dos cuyo arreglo no cuesta nada (radio 0 y 3 rebuilds).

Diagnosticada `json-c` en vez de suponerla: apartando su artefacto y reconstruyendo con la salida
capturada, muere con el mismo `Error running link command: Segmentation fault` que `dwarves` y que
los `protoc-gen-upb*` de protobuf. Un `-DCMAKE_LINK_DEPENDS_USE_LINKER=OFF` en cada una y listo — el
`lld` de zig 0.16.0 segfaultea con el `--dependency-file` que CMake ≥3.27 emite.

⚠ **Lo que importa de este commit no son las dos recetas: es que el fallo no era un caso aislado.**
Cuando apareció en protobuf lo esquivé con `compiler = "gcc"` creyendo que era cosa de esos plugins.
Ya van CINCO proyectos sin relación entre sí con el mismo crash, y otros tres medidos y pendientes.

`crun` cayó a deuda (json-c es dep suya) y se reconstruyó: sigue siendo estático con 0 NEEDED y
**vuelve a arrancar un contenedor de verdad** con el busybox del corpus como rootfs. Las tres
REPRODUCEN bit a bit.

Queda planteado con el número delante, sin arrancarlo: los otros tres del censo son
`libtiff-shared` (12 rebuilds), `libjpeg-turbo` (17) y `libjpeg-turbo-shared` (23) — ~52 en total y
tocan los stacks gráficos de los escritorios. Y el censo cubrió 15 de las 23 CMake del corpus y
NINGUNA de las ~130 de las colas: el número real de rotas es mayor que 5.
2026-09-12 11:29:01 +00:00
SergioandClaude Opus 5 8f43b7ad03 ADR 0017: el kexec SALTÓ — dos kernels, un solo paso por el firmware
Verificado en OVMF con el kernel linux-metal-kexec recién construido
(b3:965acc37…, CONFIG_KEXEC_FILE=y confirmado en el .config sellado):

  BdsDxe: starting Boot0002 "UEFI Misc Device"   ← el firmware, UNA vez
  KEXEC-PRUEBA: kernel = 6.16.12
  ✓ kernel cargado en memoria
   saltando — el userspace muere ACÁ. Esto no vuelve.
  KEXEC-PRUEBA: kernel = 7.1.2
  KEXEC-PRUEBA-LLEGADA: este kernel NO lo arrancó el firmware

La prueba no es que aparezca el 7.1.2: es que "BdsDxe: starting" aparece
UNA SOLA VEZ. Dos kernels distintos corrieron y el firmware sólo
intervino en el primero. Y el 7.1.2 vive dentro del initramfs, sin
entrada de arranque, así que el firmware no podría haberlo lanzado.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HHAKWoBqof9XvsYCvDicEj
2026-09-12 11:26:43 +00:00
Sergio 01e721db84 verificar-repro: decir que además es el CENSO de la deuda invisible, con el número medido
`no construyó` no es ruido del verificador: es EL hallazgo. Un `sealed` en el grafo dice que alguien
construyó eso alguna vez con algún lab, no que se construya hoy — y el lab rueda desde Alpine edge.
Este script es lo único que convierte esa sospecha en un número SIN RIESGO, porque aparta en vez de
borrar y restaura si el build falla.

Barriendo las 15 recetas CMake baratas del corpus: REPRODUCEN 9 · DERIVA 1 · no construyeron 5.
Cinco selladas y rotas a la vez, todas por el mismo crash del lld de zig con `--dependency-file`.

Y la nota de método que hace legible el censo: barrer por FAMILIA de sistema de build. Si el fallo es
del toolchain se concentra en una familia y el patrón salta; barrer al azar lo diluye.
2026-09-12 11:21:34 +00:00
Sergio 896c7888a8 SDD 30: la tabla de estado incluye el vigía en el latido y su primera lectura 2026-09-12 11:13:50 +00:00
Sergio eb85c5976e latido: el vigía de servicios entra al cron — 18 demonios se embarcan y nadie los arranca
Contesta la pregunta que ni el grafo ni `vigia-sonames` contestan: no «¿está
sellado?» ni «¿arranca el binario?» sino **«¿hay alguien que lo LEVANTE?»**. Un
demonio puede estar sellado, con contenido, con todos sus sonames resueltos, y
que ninguna imagen lo arranque nunca.

Va al latido por la lección que `vigia-sonames` ya dejó escrita doce líneas más
arriba —un vigía que hay que acordarse de invocar no se distingue de no tenerlo—
y con más motivo: su entrada son DOS ficheros que cambian por separado (las
recetas y `targets.toml`), así que la divergencia entre «declarado» y
«habilitado» aparece sola, sin que nadie toque el vigía.

Corre PRIMERO su propio `--selftest`: si el guardián está roto, su silencio no
es una respuesta.

Primera lectura, ya en el repo: 0 errores y 18 avisos. El más ruidoso es
`dbus-system`, que viaja en SEIS perfiles y sólo GNOME lo arranca.
2026-09-12 11:13:12 +00:00
Sergio 30c8d18924 SDD 30: el doc al día con §4a y §4c — incluido el hallazgo de los dos compat sin perfil 2026-09-12 11:09:01 +00:00
Sergio 1b56b16402 SDD 30 §4a+§4c: los 9 demonios de GNOME declarados — y aparecieron dos que no estaban en NINGÚN perfil
Lo que el script de sesión lanza con `&` ahora está declarado en las recetas y
habilitado en el perfil. Ninguna receta movió su hash: 9/9 idénticos a los que
los grafos ya registraban.

EL HALLAZGO, y no lo buscaba: la comprobación inversa del resolutor rechazó
`arje-logind-compat` y `arje-polkit-compat` porque están en CERO perfiles — y
sin embargo qemu-desktop-image.sh los copia al rootfs a mano y el de COSMIC hace
`exit 1` si falta logind-compat. Dos binarios imprescindibles, presentes en la
imagen y ausentes del destino declarado: la misma forma del agujero de `foot`,
encontrada por una comprobación en vez de por una imagen inusable. Son raíces de
escritorio-gnome (los dos) y de escritorio-cosmic (sólo logind, verificado que
sus scripts no nombran polkit).

DOS COSAS QUE NO SON TRANSCRIPCIÓN:
- `dbus-daemon --fork` no se traduce tal cual: arje supervisa al HIJO DIRECTO y
  Type=forking no existe, así que un daemon que forkea y sale deja a arje viendo
  morir al padre con éxito y reencarnándolo para siempre. La card usa --nofork.
- `scope = system|session` decide DÓNDE va la card. Las de sesión necesitan
  XDG_RUNTIME_DIR y usuario logueado; en el genesis arrancarían antes de que
  exista ninguno. Y fuera de mirada NADIE entrega cards de sesión todavía, así
  que salen con AVISO: el hueco queda contado, no omitido.

Correcciones propias: la unicidad del label es DENTRO del perfil, no del corpus
(upower vive legítimamente en dos colas); la membresía se lee de los CINCO
grafos, no sólo el del corpus; una RAÍZ manda sobre el grafo, que es derivado y
lo regenera el cron; y la flag nace en inglés (`--services`) como manda la
regla 4, aunque `--lista` sea deuda vieja del mismo fichero.

`--selftest`: 7 casos, el primero es el CONTROL que tiene que pasar en verde.
2026-09-12 11:08:58 +00:00
SergioandClaude Opus 5 0b5dae7812 censar: 26 repositorios existen SÓLO en la máquina que se va a borrar — el paso 1 del plan
Buscando cómo escribir la receta de `tawasuyu` apareció que su ÚNICO remoto es el gitea de gioser
(`ssh://gitea@git.tawasuyu.net:2345/…`, y ese nombre resuelve a 204.168.193.248 = gioser). Al mirar
el resto: **28 repositorios con remoto en esta máquina, 26 SIN NINGUNA copia fuera**. Sólo `takana` y
`llimphi-standalone` tienen espejo externo.

Apagar el origen no borra unos servicios: borra EL CÓDIGO CON EL QUE SE VOLVERÍAN A CONSTRUIR, y los
clones de trabajo están en el mismo disco que también muere. Entre los 26 está `tawasuyu`, que
produce 10 de los 13 binarios que nadie más provee — la dependencia circular completa.

No se ve desde ninguna otra parte del censo: un repo no es un proceso, ni un puerto, ni un dominio.
Se descubre cuando ya no hay de dónde sacarlo.

· `censar.py` lo mira ahora (`[[repo]]`), y reporta NO «tiene remoto» sino si alguno de sus remotos
  NO es esta máquina: un remoto que apunta afuera es la prueba de que el código sobrevive. La lista
  de «esta máquina» sale del censo mismo (sus IPs + los dominios que sirve), no de nombres cableados.
· `planear.py` lo emite como PASO 1, por delante del rescate de binarios: aquello pierde un servicio,
  esto pierde la posibilidad de reconstruirlo. El arreglo ya está escrito en el repo —takana usa
  `pushurl` doble por `scripts/espejo-setup.sh`.

Y una corrección de algo que dije antes: la perilla por receta que vi en `recipe.rs` es `strip_debug`,
no una versión de rust. NO existe `rust_version`; sólo `zig_version`. Pinear rustc por receta para
honrar el `rust-toolchain.toml` de tawasuyu (1.96.0, contra 1.97.0 del lab) sería código nuevo en
takana-core, no una opción ya disponible.

De paso, medido el subárbol de los diez binarios por separado: cuatro (`willay-daemon`,
`sandokan-seguridad-core`, `pacha-secretos`, `tupu-cli`, entre 84 y 153 deps) NO arrastran
criptografía en C; cuatro traen `ring` y dos `aws-lc-sys`. O sea que hay un escalón por donde
empezar sin pelear con cmake.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RomoxEGZUhaT4pob1QSX5x
2026-09-12 11:06:52 +00:00
Sergio 35afe8260d estado: cosecha granja 2026-09-12T11:03:33Z — avance del árbol KDE 2026-09-12 11:03:33 +00:00
Sergio 556fcad5fa SDD 30 §4a: el perfil ya sabe HABILITAR — y avisa del demonio que nadie arranca
`paquetes` decía qué se INSTALA; no había dónde decir qué se LEVANTA. El sshd
del producto arrancaba porque su Card estaba escrita a mano en una constante de
Rust, no porque nadie lo hubiera declarado.

`servicios = [...]` por perfil (se hereda como `paquetes`, mismo orden y dedup)
+ `targets.py --servicios <perfil>`, que cruza label → receta → exec contra los
`[[service]]` del corpus y la membresía de perfil de build-state.json.

Lo que vale más es la comprobación INVERSA: avisa de los paquetes que están en
la imagen, TRAEN un demonio y el perfil no arranca. Es la versión servicios de
la lección de `foot` —la métrica mide la clausura de lo DECLARADO y no ve lo que
falta en la declaración— y no es hipotética: antes de escribir `servicios =
["sshd"]` el resolutor ya avisaba «openssh está en la imagen y TRAE este
servicio, pero el perfil no lo arranca».

Probado con roturas A PROPÓSITO, 5/5, y con un control que TIENE que pasar:
habilitado sin declarar (ERROR) · dos recetas con el mismo label (ERROR) · lo
declara una receta que no está en el perfil (ERROR: el card apuntaría a un
binario ausente y arje lo encarnaría con ENOENT en cada backoff) · la inversa
(AVISO, no rompe el cron) · el caso bueno (rc=0). Los 8 perfiles siguen
expandiendo igual y los llamadores de shell no cambian.
2026-09-12 10:59:59 +00:00
SergioandClaude Opus 5 1445f2f91e SDD 29: los 13 binarios sueltos son casi un solo árbol — y los dos pines de rustc no coinciden
De los 13 servicios cuyo binario NADIE provee —los que se pierden al apagar gioser— DIEZ salen del
mismo repositorio (`tawasuyu`, hoy `bad13117c`): matilda, pacha (paquete `pacha-cli`),
pacha-secretos, sandokan-watch (`sandokan-seguridad-core`), shuma-daemon, shuma-gateway, tejido, tupu
(`tupu-cli`), willay-crosscheck (`willay-cruce`) y willay-daemon. Los otros tres son ajenos
(act_runner, adb, y el `puerta-…` de target/debug). Una receta cubre diez servicios.

**El tamaño real es una quinta parte del aparente.** El Cargo.lock del workspace tiene 2823 crates,
pero eso incluye su stack gráfico, audio y Android; el subárbol que esos diez binarios necesitan son
524. Y sólo CINCO traen C: `aws-lc-sys` y `ring` (criptografía, compilan C/asm y piden cmake) más
`dirs-sys`, `inotify-sys` y `netlink-sys`, que son bindings puros sin librería externa.

⚠ **Lo que hay que decidir antes de escribirla.** `tawasuyu/rust-toolchain.toml` fija 1.96.0 y lo
argumenta en el propio fichero: una distro que promete builds deterministas y atestación firmada no
puede tener el compilador flotando. El lab de takana trae 1.97.0 y es RODANTE por diseño —
`lab-toolchain.lock` detecta la deriva, no la evita. Una receta takana compilaría con un rustc
distinto del que tawasuyu exige: el binario NO sería el mismo que corre, y rompería el contrato de
atestación del otro frente. Tres salidas, y es decisión, no trámite: pinear 1.96.0 para esta receta
(como las 84 que pinean zig 0.13.0), mover el pin de tawasuyu, o llevar los binarios tal cual
sabiendo que no reproducen.

Y no se construye en el origen: 4 núcleos y ~2 G disponibles. Eso va al worker dev.gioser.net.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RomoxEGZUhaT4pob1QSX5x
2026-09-12 10:57:04 +00:00
Sergio 29831e6296 descargas: el guardián estaba ROJO hace dos días y nadie lo corría
La barrida de regresión del frente (14 guardianes tras rehacer host y navegador) encontró uno en
rojo: `test-atuq-descargas.py` buscaba el CAS en `<estado>/descargas-cas` y el host lo escribe en
`<estado>/cas` desde el commit del archivo personal (357791a85, 2026-09-10) — el §6.3 UNIFICÓ los dos
CAS, que es justo lo que hace que una página archivada y un fichero bajado con el mismo contenido
sean un solo objeto. Lo renombré yo y no actualicé este guardián.

Lo que importa no es el renombre: es que el guardián estuvo rojo dos días sin que nadie se enterara,
porque **un guardián que no se ejecuta no protege de nada** — la misma familia que el cache-hit que
congela regresiones. Los otros 13 pasan.

Arreglado el path, y el README dice ahora por qué el directorio se llama `cas` y no `descargas-cas`.
2026-09-12 10:51:10 +00:00
Sergio 432a0e2561 estado: cosecha granja 2026-09-12T10:48:45Z — avance del árbol KDE 2026-09-12 10:48:45 +00:00
Sergio c0a25cef22 protobuf/abseil vuelven a zig: la causa raíz quita el escape a gcc — y lo valida en un segundo proyecto
Ayer estas dos huyeron a `compiler = "gcc"` para esquivar un crash del linker en los tres
`protoc-gen-upb*`. **Esquivé el fallo sin conocer su causa, y salió caro:** al mover sólo protobuf, el
link murió con `undefined reference to std::__1::basic_string<…>` —el `__1` de libc++— porque abseil
seguía en zig, así que hubo que arrastrar las dos fuera del toolchain por defecto.

La causa apareció al día siguiente en `dwarves`, bisecando la línea de enlace real:

    tal cual                      → exit 139 (SIGSEGV)
    quitando `-static`            → exit 139     ⇒ no es el enlace estático
    quitando `--dependency-file`  → **exit 0**   ⇒ ES ESO

El `lld` de zig 0.16.0 segfaultea con el `--dependency-file` que CMake ≥3.27 mete en la línea de
enlace. Con `-DCMAKE_LINK_DEPENDS_USE_LINKER=OFF` **los cuatro binarios de protobuf enlazan con zig**,
incluidos los tres plugins que se caían.

Esto es, además, la validación de la causa raíz en un proyecto INDEPENDIENTE de dwarves: dos
proyectos sin relación, mismo síntoma, misma perilla, los dos arreglados.

Con el escape se va también el `-static-libstdc++`, que sólo hacía falta porque g++ enlaza contra la
libstdc++ de GNU. Comprobado sobre el artefacto: el único NEEDED de `protoc` es `libc.so`, que provee
`musl-shared`.

Verificado de punta a punta, no por el código de salida: `protoc --version` → `libprotoc 36.1`, y un
`.proto` compila a `m.pb.h`/`m.pb.cc` **y** a `p/m.pb.go` pasando por `protoc-gen-go` — o sea que la
cadena plugin↔driver que abrí anteayer sigue entera. Las dos REPRODUCEN bit a bit.

Se deja escrito el camino completo en las recetas, diagnóstico corto incluido, porque la lección no
es la perilla: es que **un escape que funciona sin explicar el fallo se paga después**, y acá se pagó
con dos recetas fuera del toolchain por defecto y un choque de runtimes de C++ que sólo apareció
porque el escape era parcial.
2026-09-12 10:46:19 +00:00