Commit Graph
2954 Commits
Author SHA1 Message Date
SergioandClaude Opus 5 cec3c06ace las decisiones de la mudanza pasan al repo, y el corral de respaldo queda armado
`work/` está en .gitignore, así que el fichero donde vive lo que el usuario decidió —con el motivo de
cada línea— no sobrevivía a la máquina que la mudanza borra. Ahora es `docs/state/`.

Nueve entradas marcadas `respalda`: terapeuta.ec (279 M, sin DNS hace tiempo), los cuatro «valens»,
`los-grandes-mensajes.pdf`, `kkk` (46 B, credencial en claro) y los tres clones de terceros CON
cambios sin commitear — lo commiteado se vuelve a clonar, lo de encima existe sólo en este disco.

Juntas en `/mnt/cosecha/respaldo-mudanza` (475 M) con LEEME y SHA256SUMS de 5472 ficheros. El
control se hizo ANTES del manifiesto: ficheros contados en origen y en corral, las nueve coinciden
(3805, 1243, 183, 1, 164, 1, 1, 72, 1).

⚠ NO entraron `~/hammer`, `~/takana` ni `~/tawasuyu`: son SYMLINKS a /mnt/vvv. El censo los veía
como entradas de 0 bytes CON remoto git —porque `git -C` sigue el enlace— y la recomendación
automática decía «respalda» por tener cambios sin commitear. Respaldarlos habría guardado tres
enlaces rotos. Un dato que parece del objeto y es del enlace.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 19:49:08 +00:00
Sergio cf13ac2155 estado: cosecha granja 2026-09-16T19:31:26Z — avance del árbol KDE 2026-09-16 19:31:26 +00:00
SergioandClaude Opus 5 9c41d13721 regla 2 ter: git pull --rebase descartó un commit entero, y el reflog es lo único que lo dice
Medido hoy en este repo compartido: commit propio con 10 ficheros → push rechazado porque otro
agente empujó → `git pull --rebase` → el commit YA NO ESTÁ, ni en el log ni en el árbol (los diez
ficheros desaparecidos del disco).

El reflog lo explica: entre `pull --rebase (start)` y `(finish)` no hay ni un `pick`. El rebase no
encontró nada que reaplicar porque, para cuando corrió, el commit ya no colgaba de `main` — los tres
commits que trajo el pull tienen de padre al commit ANTERIOR al mío, o sea que otro agente movió la
rama hacia atrás. Con `-q`, el resultado se ve igual que un pull limpio.

La recuperación es `git reflog` + `git cherry-pick <sha>`: vuelve entero. Y la comprobación que
evita el susto es mirar `git log --oneline -1` después de cada `pull --rebase`.

De paso, el corolario del espejo: el push doble puede triunfar en un remoto y fallar en el otro
(gitea rechazó, GitHub aceptó), así que tras recuperar queda un sha huérfano en GitHub con el mismo
contenido. Se repara empujando SÓLO esa URL con `--force-with-lease=main:<huérfano>`, después de
comprobar con `git diff --stat` que no se pierde nada.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 19:29:17 +00:00
SergioandClaude Opus 5 0ab57ba0fb los 9 daemons propios entran al catálogo, más el askpass que shuma pidió al arrancar
Decisión del usuario: «viven todos los tawasuyu». Se construyen, no se copian — y no es preferencia:
tres de ellos (`tejido`, `pacha-secretos` y el `shuma-gateway` de ayer) corren en gioser desde un
INODO BORRADO, o sea que el binario ya no existe en disco y el proceso vive porque nadie lo mató.

Las diez, todas contra el mismo pin `23a292863` que `shuma-*` y `puriy-costura` — el árbol de
fuentes se comparte por `<dep>-<sha>`, así que un pin distinto es otro vendoreo de 2,4 G:

  willay-daemon · willay-crosscheck · tejido · tupu · matilda · thasnuna · sandokan-watch ·
  pacha · pacha-secretos · shuma-askpass

⚠ CUATRO NO SE LLAMAN COMO SU PAQUETE, y por eso `-p` y `--bin` no son redundantes:
`willay-crosscheck`←`willay-cruce`, `tupu`←`tupu-cli`, `thasnuna`←`thasnuna-daemon`,
`sandokan-watch`←`sandokan-seguridad-core`, `pacha`←`pacha-cli`. Comprobado crate por crate en el
commit pinneado: los diez son miembros del workspace, así que `-p` resuelve.

Cada cabecera lleva lo que MIDIÓ el censo y que la receta sola no dice: `willay-crosscheck` escucha
con `--label momento`, que nombra a la MÁQUINA y no puede viajar tal cual; `tupu`, `matilda` y
`sandokan-watch` escriben los tres en `/var/lib/tupu`, así que necesitan el mismo dueño o dos fallan
en silencio; `matilda` lee el access log de caddy; `tejido` y `thasnuna` tienen identidad y token que
NO son reproducibles —generar otros es ser otra máquina para la flota, o un bot sin sus teléfonos—,
así que su Card tendrá que exigirlos, no crearlos.

`takana hash` da los diez sin construir. Van a `recipes/incoming/`, que es la cola que el worker
muele; se promueven a canónicas cuando sellen, como shuma.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 19:28:07 +00:00
sergioandClaude Opus 5 11a9ead671 perfiles: metal-tigerlake es una CAPA DE HARDWARE componible, no otra lista por escritorio
El SDD 27 §2 dice que el repo mezcla tres capas —piso, escritorio, extras— en una sola
lista por escritorio, y que esa es la causa de que la composición no esté definida. El
firmware es un cuarto caso que el SDD no nombra y que sigue la misma lógica: no es un
escritorio ni un toolbox, es lo que hace falta para que un METAL CONCRETO arranque con todo
su hardware vivo.

Por eso va como perfil propio y se compone, en vez de duplicarse en los cuatro escritorios:

    scripts/targets.py cli metal-tigerlake escritorio-kde

Otro metal = otro perfil de estos con su propia receta firmware-<plataforma> derivada del
mismo linux-firmware. Ese es el punto de haber partido el firmware en base + derivada.

La máquina, medida con lspci/cpuinfo sobre el metal real:

    CPU    i7-11370H · family 6 · model 140 (0x8c) · stepping 1   ⇒ intel-ucode/06-8c-01
    GPU    TigerLake-LP GT2 [Iris Xe] [8086:9a49]                 ⇒ i915 / xe
    WiFi   Intel Wi-Fi 6 AX201 [8086:a0f0]                        ⇒ iwlwifi
    Audio  500 Series HD Audio [8086:a0c8]                        ⇒ snd_sof_pci_intel_tgl

Y zsh entra en `cli`, no en `base`: base define el shell del SISTEMA (bash) y esto es el
del usuario. Dos hechos distintos, como `paquetes` y `servicios` un piso más abajo.

El runbook deja el encargo para el worker, y su parte útil son los dos muros que aparecieron
al cruzar ficheros que nadie había leído juntos:

  1. takana-live-install.sh:275 bifurca «UEFI ⇒ rama EFI-stub soberana», y metal-usb-sdboot.sh
     dice que el EFI-stub «en el firmware del usuario se cuelga tras Measured initrd PCR 9».
     ES EL MISMO FIRMWARE. El lazo de instalación EFI está validado en OVMF, que no tiene ese
     quirk ⇒ el instalador va a pasar la prueba y colgarse en el metal de destino. La salida
     es llevar el instalador a systemd-boot, que es el camino ya probado en esta máquina.
  2. El instalador reparticiona en MBR el disco entero, y ese disco tiene /home con 893 G
     usados. Si la instalación conserva /home o se lleva el disco con respaldo previo es
     decisión del usuario, no del runbook — y hasta que se decida, no correrlo sobre el NVMe.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 15:12:29 -04:00
sergioandClaude Opus 5 38c2874e48 zsh: el shell de login del usuario, que no tenía receta en ninguna de las cinco colas
Salió de barrer la máquina del usuario y cruzar sus 481 paquetes explícitos contra las
1181 recetas del corpus y las cuatro colas. zsh es su shell —medido en su historial: 1611
`cd`, 1054 `cargo`, 134 `zellij`— y no estaba en ningún lado. Una imagen de takana
instalada en su laptop lo dejaba en bash: funciona, pero no es su máquina.

Es el mismo hueco de RUNTIME que bash-completion: nadie lo alcanza por deps de build, así
que ninguna métrica de deuda puede verlo. Sólo se ve mirando la máquina de quien la usa.

Sus tres deps ya estaban selladas (ncurses, pcre2, libcap) ⇒ no arrastra tanda.

Los seis parches son de main/zsh de aports y son el trabajo de portabilidad a musl que un
import de nix pierde. implicit.patch (16 K) es el gordo: declaraciones implícitas que
gcc14/clang rechazan como error.

⚠ RIESGO CONOCIDO para el primer build, heredado de bash.toml: si el configure mete
-rdynamic en la línea de enlace, el wrapper de cc del lab tira el -static y el binario sale
contra libncursesw.so.6, que NINGÚN artefacto del corpus provee ⇒ arrancaría en el sandbox
de Alpine y no dentro de una imagen de takana. Síntoma: `Error relocating ... symbol not
found`. El arreglo de bash fue `make LOCAL_LDFLAGS=` y vale igual. Verificar el primer
artefacto con `file`: debe decir `statically linked`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 15:12:08 -04:00
sergioandClaude Opus 5 099226b2d1 firmware del metal: el TODO de soberanía cerrado — los blobs dejan de copiarse del host
`scripts/metal-firmware.sh` llevaba desde que se escribió con este pie:

    TODO(soberanía): reemplazar FWSRC=host por un pin a un commit de linux-firmware

Eso significaba que una imagen de takana para el metal sólo se podía armar desde una
máquina que YA tuviera el firmware instalado por otra distro. Un instalador que sólo se
puede construir desde la distro a la que viene a reemplazar no es un instalador.

Cuatro recetas, y la partición entre ellas es la decisión:

  · linux-firmware  — tarball 20260910 pineado. 648 MB, ~2 GB extraídos. Es una BASE y no
    entra en ningún perfil: nadie manda eso en una imagen de escritorio.
  · firmware-tigerlake — DERIVADA, recorta ~25 MB: las tres familias que este metal pide.
    Es la que viaja. Otro metal = otra derivada de dos líneas, no otro fetch de 648 MB.
    Misma economía que atuq sobre firefox (SDD 26).
  · sof-firmware  — porque el SOF NO viene en linux-firmware. Medido, no supuesto:
        entradas del tarball ... 5323
        intel/sof .............. 0     ✗
        i915/tgl ............... 15    ✓
        iwlwifi ................ 201   ✓
  · intel-ucode   — tampoco viene: trae amd-ucode pero el de Intel lo publica Intel.

Y una contraintuitiva que queda escrita para no re-tropezarla: TigerLake va por IPC3, no
por IPC4. Lo esperable era tomar la serie más alta de sof-bin (v2.14.x); medido, esa serie
no contiene NINGÚN fichero tgl. El firmware de TGL sólo existe en la rama IPC3, y el más
nuevo que lo trae es v2.2.x/sof-v2.2/sof-tgl.ri.

El sha256 de linux-firmware se contrastó contra el sha256sums.asc que kernel.org publica
firmado — no contra el fichero que bajamos, que sería comprobar que un fichero es igual a
sí mismo.

⚠ NINGUNA ESTÁ SELLADA: escritas desde el laptop, que no tiene lab ni store. Las aserciones
de cada `install` están puestas para que el primer build falle ruidoso en vez de producir
un /lib/firmware a medias — que no falla al construir y falla meses después en el metal
como «no hay WiFi», sin una línea que lo asocie con esto (CLAUDE.md §3).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 15:12:08 -04:00
SergioandClaude Opus 5 f32b28c63e CUTOVER de sergio.gioser.net: el último vhost sale de gioser — ya no queda ninguno
`https://sergio.gioser.net/` y `/shuma/` contestan 200 contra 2.29.29.217, con TLS público.
**Ningún dominio resuelve ya a gioser.**

⚠ Y el 200 de `/shuma/` había que mirarlo dos veces: el bloque termina en `try_files … /index.html`,
así que CUALQUIER ruta inexistente devuelve 200 con la SPA — un `curl -o /dev/null` habría dado el
mismo verde con el proxy mal puesto. Lo que decide es el cuerpo (17 bytes: «shuma-gateway ok») y el
control es compararlo con lo que el origen viejo sigue sirviendo. Igual con `/shuma/rpc`: las dos
máquinas contestan el mismo 400 con el mismo JSON.

Lo construido, en orden: las dos recetas sellaron en el worker con los hashes anticipados y salen
`statically linked` (nada de cargador, que era lo que le faltaba al binario glibc de gioser) · la
cuenta `shuma` declarada con `[[user]]`, uid 967, y el descenso con `setuidgid` en el argv de la
Card porque el payload Native de arje NO tiene campo de usuario · la config que no se regenera
(`gateway-token`, `identity.x25519`) instalada, y la guarda de la Card la EXIGE en vez de crearla:
un token nuevo deja fuera a los clientes ya emparejados · las dos Cards en `cards.d` Y en el genesis
de la semilla · las dos recetas y los dos labels declarados en `perfil.servidor`.

⚠ LA SHELL DE LA CUENTA NO ES UN DETALLE: el default de `[[user]]` es `/bin/false` —correcto para
gitea o squid, exactamente lo contrario para un demonio que abre PTYs—. Con la shell inerte el
servicio arranca, se supervisa, contesta 200 y cada pestaña muere al instante: un fallo que no se ve
al desplegar, se ve al usarlo. Va `shell = "/bin/sh"`.

`[[user]]` y `[[service]]` están fuera de `hash_inputs`: declarar todo eso no movió ningún
ArtifactHash, comprobado antes y después en los dos.

Y una corrección al §6.25: para cambiar el VALOR de un rrset no hace falta DELETE+POST (que deja una
ventana sin registro). La API tiene
`POST /v1/zones/<id>/rrsets/<n>/<t>/actions/set_records`, que es atómica. Con TTL 60 la resolución
pública cambió en menos de 8 segundos.

El origen de gioser sigue corriendo a propósito, como en §6.26: volver atrás es una llamada.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 19:07:20 +00:00
Sergio 15157f8cfe estado: cosecha granja 2026-09-16T19:02:01Z — avance del árbol KDE 2026-09-16 19:02:01 +00:00
Sergio 6da0173498 estado: cosecha granja 2026-09-16T18:31:37Z — avance del árbol KDE 2026-09-16 18:31:37 +00:00
SergioandClaude Opus 5 90c1cf3cf1 shuma SELLADO y promovido a canónico — el binario del último vhost ya no depende de gioser
El worker molió las dos recetas: `b3:107dfb54…-shuma-gateway` (6,3 M) y `b3:f9b92acc…-shuma-daemon`
(5,6 M), los hashes que `takana hash` había anticipado antes de encolarlas.

Y el control que vale no es que sellen ni que reproduzcan, sino CORRER LA HERRAMIENTA del artefacto
(la lección de las 79 de llvm21). `file` dice «statically linked» — nada de cargador, que era
exactamente lo que le faltaba al binario glibc de gioser — y al ejecutarlo arranca, inicializa y
llega a escuchar:

    INFO shuma_gateway: UnifiedPush endpoints cargados endpoints=0
    Error: Address in use (os error 98)

El puerto estaba tomado por el `shuma-gateway` que YA corre en esa máquina (pid 1127226 en
127.0.0.1:7378): el fallo es del entorno, no del binario.

Promovidas de `recipes/incoming/` a `recipes/` con el control que la memoria de colisiones pide: no
hay receta homónima previa y el ArtifactHash NO se movió al cambiarlas de sitio (la resolución de
deps es hermano→padre, así que un fichero idéntico en otra cola PUEDE sellar distinto; acá no, no
tienen deps). Ahora se pueden declarar en `perfil.servidor`.

Falta la tarjeta de arje —con la cuenta sin privilegio, que el payload `Native` no sabe expresar— y
el corte del vhost.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 18:03:42 +00:00
Sergio aa36ecc0b9 estado: cosecha granja 2026-09-16T18:01:53Z — avance del árbol KDE 2026-09-16 18:01:53 +00:00
SergioandClaude Opus 5 1c237f9da2 mudanza: decidir SIN teclas unitarias, /mnt/vvv entra al censo, y 25 rutas de secretos más
Tres cosas que salieron de usar la herramienta de verdad.

1. `--decidir <fichero>`: decidir EN LOTE desde `<ruta-o-nombre> <decision>` por línea.

   El usuario: «no sé cómo activar o desactivar cosas aquí desde shuma llimphi remoto, que las
   opciones son con teclas unitarias». El modo interactivo lee una tecla por entrada, y hay
   terminales donde eso no se puede usar — una herramienta cuya única forma de decidir exige un
   tipo de terminal no es una herramienta, es una herramienta PARA ESA TERMINAL. El fichero anda en
   cualquiera, se revisa antes de aplicarlo, se versiona y se vuelve a correr.

   Una clave que no empareja con nada, o que empareja con varias, es ERROR RUIDOSO y no se escribe
   NADA: un lote a medias deja decidido lo que nadie revisó.

2. `/mnt/vvv` entra a las raíces del censo. No estaba, y ahí vive el trabajo: los repos de la
   persona, el monorepo, el store, work/sources. El agujero se vio preguntando por `humanoid`: el
   censo sólo conocía `/home/sergio/humanoid` —200 M de `build/` de junio— mientras el proyecto de
   verdad, con su `.git`, estaba en `/mnt/vvv/humanoid`, fuera de toda raíz censada. `repos_git` SÍ
   lo miraba: una parte del censo conocía el árbol y la otra no.

3. 25 rutas más en `rutas-fuera-de-git.txt`, del barrido que hizo el frente tawasuyu sobre su home:
   `~/.wawa/seeds` (sin él ninguna app nueva del génesis nace), `~/.tejido` (la identidad de esta
   máquina en la flota), `~/.local/share/agora`, `~/.config/{wawa,minga,thasnuna,shuma,mirada,hcloud}`,
   `~/keys` y `~/fdroid` (⚠ firma de apps Android), `~/.gnupg`, `~/.pgpass`, `/etc/wireguard`,
   `/etc/{shuma,sandokan,tawasuyu/agente,local.d}`. Son identidades y semillas: no se «vuelven a
   generar», porque generar otras significa ser OTRA máquina para el resto de la flota.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 18:01:16 +00:00
Sergio b057c057db estado: cosecha granja 2026-09-16T17:32:03Z — avance del árbol KDE 2026-09-16 17:32:03 +00:00
Sergio ae2a73a9ae estado: cosecha granja 2026-09-16T17:01:33Z — avance del árbol KDE 2026-09-16 17:01:33 +00:00
Sergio b0879acdb0 estado: cosecha granja 2026-09-16T16:31:33Z — avance del árbol KDE 2026-09-16 16:31:33 +00:00
SergioandClaude Opus 5 5ec4e2b213 mudanza: el tercer camino — mudar, RESPALDAR o abandonar, cosa por cosa y con su descripción
Pedido del usuario: «una lista de cada cosa con una corta descripción y la opción de yo elegir mudar,
mover a un directorio para respaldar ese directorio, o abandonarlo». Eran tres huecos distintos.

1. «CADA COSA». El censo medía RAÍCES: `/home` era UNA entrada de 25 G y UNA decisión, con repos,
   SDKs, 4,3 G de caché y trabajo irrepetible adentro. Ahora emite un renglón por cosa —169 en
   gioser contra 5—, un nivel hacia adentro de cada raíz y DOS en `/home`, porque su primer nivel
   son usuarios y la decisión no es por usuario. `--solo-totales` conserva la vista vieja, que es la
   que dimensiona la mudanza; las dos viajan en el censo (`datos` y `datos_raiz`).

   ⚠ El primer intento mandaba las ~110 sondas en UNA llamada, se pasaba del timeout y devolvía
   lista VACÍA: «no hay datos» en vez de «no pude medirlos». Va en tandas, y una tanda que falla se
   nombra.

2. «UNA CORTA DESCRIPCIÓN», y son hechos: lo sirve el servidor web · lo usa un proceso vivo · es
   repo git y a dónde apunta · tiene cambios sin commitear · adentro hay node_modules/target/venv ·
   lo más nuevo que hay dentro. «Sin señales» también es un hecho, y es el que dice dónde mirar.

3. «ELEGIR ENTRE TRES»: DECISIONES pasa de (muda, muere) a (muda, RESPALDA, muere). Faltaba el
   camino que se usa de verdad —no lo quiero corriendo allá, tampoco lo quiero perder—; con dos
   opciones, todo lo dudoso se marcaba `muda` y la mudanza engordaba.

   La regla de fondo no cambió (qué datos VALEN no lo dice la máquina), pero cuatro hechos sí los
   sabe: servido/usado ⇒ muda · caché ⇒ muere · repo limpio con remoto ⇒ muere · repo sin remoto o
   sucio ⇒ respalda. Y el cruce que evita el peor error: un remoto que apunta a ESTA MISMA máquina
   no es un respaldo, es el mismo disco (medido: /mnt/vvv/humanoid → ssh://git@127.0.0.1:2345).

4. LAS DECISIONES SE GUARDAN. `--decide` las usaba sólo para el plan de esa corrida: cerrabas la
   terminal y se perdían las 169. Ahora reescribe el censo (temporal+fsync+rename, `.bak`, y releído
   antes de pisar nada; aborta si perdió alguna). Para eso hubo que hacer el emisor IDEMPOTENTE:
   escribía `decision = ""` fijo, así que re-emitir un censo decidido duplicaba la clave y el TOML
   dejaba de parsear — la herramienta no podía reescribir su propio fichero.

5. EL PASO `respaldo`: corral por defecto leído de respaldo-storagebox.sh (no una segunda dirección
   a mano), nombre aplanado, y NO se instala en el destino. Sin corral, aborta: un rsync a ninguna
   parte devuelve 0 y se lee como un respaldo. Probarlo con rotura a propósito Y con el control que
   tiene que pasar destapó dos bugs: `--mkpath` es obligatorio (el primer respaldo siempre estrena
   un nivel) y un FICHERO no lleva barra final — `rsync fichero/ dst/` es un error, y el paso de
   `datos` tenía el mismo defecto latente. La verificación es rsync en seco contra el destino real,
   no `du` ni `find`: el Storage Box no tiene find, no acepta tuberías, y su `du` comprime.

6. De paso: `aplicar.py --dry-run` decía « todos los pasos ejecutados y verificados» sin haber
   ejecutado nada. Ahora dice EN SECO: N mostrados, NINGUNO ejecutado y NINGUNO verificado.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 16:20:32 +00:00
SergioandClaude Opus 5 628abdbb51 mudanza: movidos los guiones, la memoria, los secretos y el estado — verificando en DESTINO
Con las decisiones puestas, se movió lo que no dependía de nada más. Cada copia se verificó del lado
del destino, que es lo que el rsync con exit 0 y 1367 artefactos vacíos dejó escrito:

  27 guiones (75 KB)          → takana:/work/rescate-guiones      sha256sum -c ⇒ 27 OK
  memoria de Claude (6,3 M)   → takana:/root/.claude              733 ficheros = 733
  transcripts (1,3 G)         → StorageBox claude-gioser          rsync -an ⇒ 1 pendiente (el vivo)
  clave PRIVADA de release    → takana:/root/.config/takana/keys  sha256 igual + pública == trust/
  credenciales y config       → takana:/work/mudanza-secretos     27 ficheros = 27
  estado de sigma/tupu/willay → takana:/work/mudanza-estado       351 ficheros, 68 M

Las credenciales NO se instalaron en su sitio a propósito: la caja ya tiene su /root/.ssh, su
crontab y su Caddyfile, y pisarlos rompe lo que funciona. El .gitconfig es el caso más claro — trae
los `insteadOf` que reescriben remotos. Se instalan cuando se mude el hub. La excepción es la clave
de release, que sí fue a su ruta canónica: sin ella nadie puede volver a firmar el repo, y eso no
falla el día que se borra gioser sino la próxima vez que alguien publica.

Y un «576 M contra 1,3 G» que parecía copia truncada: el Storage Box COMPRIME, y su shell
restringida no tiene find ni acepta tuberías, así que el conteo de ficheros ahí no se puede hacer.
Lo que sí: preguntarle a rsync en seco, que compara contra el destino real. Un número que no cuadra
merece una segunda medición antes de un diagnóstico.

No se movieron ~10 G de árboles personales de /home ni /opt: qué datos valen no se deduce de la
máquina, y ésos son proyectos del usuario, no servicios de un censo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 16:02:04 +00:00
Sergio 9816fb98fd estado: cosecha granja 2026-09-16T16:01:56Z — avance del árbol KDE 2026-09-16 16:01:56 +00:00
Sergio 2098e86ba4 atuq: la boveda ANDA — 19 guardianes en verde, y el bloqueo de tres semanas era un fichero sin empujar
El pin de `puriy-costura` subio a `23a292863` y con eso se apagaron los dos rojos del cable. La suite
entera sobre `b3:e556024b`: **19 verdes, 0 rojos, 32,1 min**. No se toco ningun guardian — que la
suite existiera ANTES del arreglo es lo que permite afirmarlo: el cuadro de ayer y el de hoy son el
mismo instrumento.

La medicion que cierra es la que abrio el §7.quinquies, leida al reves: `strings` sobre el binario
sellado da `vault` **10** veces donde daba 0, con `cas`/`sct` de control; y `vigia-atuq-verbos` pasa
de 3 verbos sin dueno a cero, con su control positivo intacto.

Lo destrabo publicar el `Cargo.lock` de tawasuyu (`23a292863` alla), regenerado en un arbol limpio:
215 lineas, todas de contabilidad de deps por ruta, cero `checksum` y cero `source` movidos. Y el
remate, que es la leccion: **ese lock era byte a byte el que la otra sesion ya tenia en su arbol sin
commitear**. Tres semanas de bloqueo y el fichero correcto estaba escrito, sin empujar, a un
directorio de distancia. Antes de decir «bloqueado por otro repo», mirar si lo que falta no esta ya
hecho y sin publicar.

Commiteado alla con indice temporal (`GIT_INDEX_FILE` + `commit-tree`), que es la unica forma de
publicar una ruta en `MM` sin llevarse por delante lo del otro agente: su arbol quedo byte a byte
igual, comprobado con `cmp` antes y despues.

⚠ Y la cabecera del runner se desmintio SOLA dos veces: anuncio «un rojo» cuando eran dos, y «dos»
cuando ya no quedaba ninguno. Un numero escrito como prediccion envejece callado. Con todo en verde
el numero ya no distingue un producto sano de un runner que no corre nada, asi que lo que sostiene la
corrida queda escrito: la puerta del sello (verificada contra un store vacio) y el control interno de
cada guardian.
2026-09-16 15:55:30 +00:00
Sergio faa9e0f952 estado: cosecha granja 2026-09-16T15:32:40Z — avance del árbol KDE 2026-09-16 15:32:40 +00:00
SergioandClaude Opus 5 aa2752fa7b los sueltos, desglosados: 2,7 G de los que lo irreemplazable son 27 guiones de 1 M
El usuario pidió el detalle de los binarios que ningún paquete provee, que es lo que la mudanza no
puede reconstruir. Medido en los tres directorios (`/usr/local/bin`, `~/.local/bin`,
`/root/.local/bin`):

  tawasuyu            57 ficheros  1003 M   salida del monorepo ⇒ se reconstruye
  terceros            10 ficheros   841 M   kiro-cli 571 M, kcl, qdrant, listmonk… ⇒ se re-bajan
  respaldo/duplicado  21 ficheros   876 M   /root/.local/bin es una COPIA de kiro-cli + el CLI claude
  guiones             27 ficheros    <1 M   git-deploy, webhook-deploy.py, mirada-session… ⇒ NADA los provee

Lo caro no es lo valioso: 1,8 G de los 2,7 son reconstruibles o duplicados, y lo único que no está
en ningún repo ni paquete son 27 guiones que suman menos de un megabyte. Y los 572 M que el censo no
veía (§6.34) eran justamente la copia duplicada de kiro-cli.

De `.claude` decide mi criterio, por pedido: de 6,8 G viajan 15 M — `projects/*/memory` (6,2 M),
`settings.json`, `plugins` e `history.jsonl`. `jobs` (5,3 G), `downloads`, `archivo-sesiones` y los
caches no viajan; los transcripts crudos (973 M) van al Storage Box, no a la caja: no hacen falta
para funcionar, la memoria es su destilado.

⚠ Y la trampa que haría inútil todo eso: la memoria se indexa POR RUTA (`-mnt-vvv-takana`), y en la
caja el repo está en `/opt/takana` — copiarla tal cual deja 163 ficheros que NO se encuentran, sin
que nada falle.

⚠ Segundo hallazgo: la caja no tiene usuario `sergio` (sólo root, sshd, gitea, proxy) y shuma corre
sin privilegio en gioser. La tarjeta que lo declare tiene que crear la cuenta, y el payload Native
de arje no tiene campo de usuario.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 15:22:50 +00:00
SergioandClaude Opus 5 fd96229ce2 shuma entra al catálogo: el último vhost de gioser se DECLARA en vez de copiarse
Decisión del usuario: `/shuma/*` —lo único que todavía ata `sergio.gioser.net` a la máquina que se
borra— se construye desde el monorepo de tawasuyu, no se muda como binario.

Y no es una preferencia de estilo: el `shuma-gateway` que corre hoy en gioser es ELF **glibc**,
puesto a mano, y su **inodo está BORRADO del disco** — vive mientras el proceso no muera. El
`shuma-daemon` igual. Copiarlos sería mudar dos binarios que nadie puede reconstruir a una caja que
no tiene su cargador.

Dos recetas Cargo contra el monorepo, pinneadas a `23a292863` — **el mismo commit que ya usa
`puriy-costura`**, a propósito: el árbol de fuentes se comparte por `<dep>-<sha>`, así que dos pines
distintos son dos vendoreos de 2,4 G en vez de uno. Estáticas musl con zig-cc, que es lo que pide un
servicio que arranca el init de la caja.

Comprobado antes de encolar: los dos crates son miembros del workspace en ese commit, el
`Cargo.lock` está commiteado, `rust-version = 1.80` contra el 1.97.0 del lab, y reqwest va por
rustls (nada de openssl). `takana hash` da b3:107dfb54 (gateway) y b3:f9b92acc (daemon), ninguno
sellado todavía.

Van a `recipes/incoming/` —la cola que el worker muele, primera en QUEUES— y no a `recipes/`
canónico: se promueven cuando sellen, que es el orden documentado. Un fichero en `recipes/` a secas
NO lo muele nadie.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 15:21:33 +00:00
SergioandClaude Opus 5 e2bb4f9b89 censar: «no existe» y «no puedo mirar» se confundían — 572 M invisibles, y el censo de hoy
El censo ya tenía tres estados a propósito (`ausente` / `sin_permiso` / `ok`), pero el tercero sólo
se detectaba sobre la PROPIA ruta: cuando el que no deja pasar es un ANCESTRO, `[ -e "$p" ]`
contesta que no existe y la ruta caía en `ausente`, que el censo descarta sin decir nada.

Medido en gioser: `/root/.local` es 0700 ⇒ un censo corrido como `sergio` daba `/root/.local/bin`
por AUSENTE. Como root son 572 M de binarios puestos a mano que ningún paquete provee — justo la
clase que la mudanza no puede reconstruir.

Arreglado: si un ancestro existe y no es atravesable, el estado es `sin_permiso`. Probado en los dos
sentidos, que es lo que separa un guardián de un adorno:

  ancestro 0700 de otro dueño   →  sin_permiso   (sale en el ⚠ del resumen)
  ruta que NO existe de verdad  →  ausente       (no se reporta)   ← el control que tiene que pasar

Con el arreglo, el censo sin privilegio pasa de 2 rutas ciegas a 13, entre ellas el home entero de
`artix`, que antes no figuraba de ninguna manera.

Y el §6.34 con el estado MEDIDO de la mudanza hoy: de los 29 dominios queda UNO sirviéndose desde
gioser (`sergio.gioser.net`); los otros seis vivos ya contestan 200 contra 2.29.29.217. El rescate
del §6.20 sigue coincidiendo bit a bit con cuatro de los seis procesos que corren desde un inodo
borrado, y los otros dos tienen en disco una versión más nueva. Lo que queda abierto son los pasos 6
y 7: el montón de daemons propios (shuma, willay, pacha, tejido, tupu, matilda…) y los datos.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 15:11:16 +00:00
Sergio fff28ad53f estado: cosecha granja 2026-09-16T15:01:36Z — avance del árbol KDE 2026-09-16 15:01:36 +00:00
Sergio ffe959d567 estado: cosecha granja 2026-09-16T14:31:36Z — avance del árbol KDE 2026-09-16 14:31:36 +00:00
Sergio fde7cb8ef2 puriy-costura: el pin sube a 23a292863 — la boveda de atuq deja de hablarle a un host sordo
El pin viejo (`e19bb0e5`) era ANCESTRO del commit que agrego los verbos de la boveda, asi que `atuq`
mandaba `vault.match` y el host contestaba «verbo desconocido»; la extension lo lee como «no hay
boveda», borra la insignia y se calla. Navegador sin la funcion y ficheros en orden — el fallo mas
caro de encontrar que tiene este cable (SDD 26 §7.quinquies).

Estaba bloqueado por algo que no era de takana: el `Cargo.lock` de tawasuyu no cerraba para este
crate. Publicado alla como `23a292863`, regenerado en un arbol LIMPIO del commit: 215 lineas, todas
de contabilidad de deps por ruta, **cero `checksum` y cero `source` movidos** — ninguna version de
registry se toco. Y el lock publicado resulto ser BYTE A BYTE el que la otra sesion ya tenia en su
arbol sin commitear, asi que no compite con su trabajo: es el suyo.

Commiteado alla con un indice TEMPORAL (`GIT_INDEX_FILE` + `commit-tree`) porque ese fichero estaba
en vuelo en el clon compartido y `git commit -- Cargo.lock` se habria llevado el arbol pisando lo
que el otro agente tuviera stageado (regla 2 de CLAUDE.md, el segundo aviso).

⚠ El artefacto todavia NO esta: el vendoreo son 2,4 G y el disco del hub esta al 99% (lo llena
`tawasuyu/target`, que no es mio para podar), asi que se construye en el worker. Hasta que vuelva,
los guardianes que usan el host quedan en rojo por ausencia del artefacto, no por rotura.
2026-09-16 14:24:25 +00:00
Sergio fb7dba530d atuq: el que estaba «nombrado como hueco» entra a la suite — 17 verdes y 2 rojos en 32 min
La primera version dejaba afuera al guardian de notificaciones (`dunst-headless.sh --via-atuq`) con
la excusa de que vive en el arnes de sway, y lo escribia en la cabecera «para que su ausencia no se
lea como cobertura». Eso dura tres dias: al cuarto la lista ES la cobertura y el parrafo no lo lee
nadie. Corrido aparte: verde en 180 s. Entra.

Es ademas el que mide lo que ningun auditor de ELF puede ver: una pagina llama `new
Notification(...)`, `libxul` hace `dlopen("libnotify.so.4")` —que no es NEEDED de nada—, el bus
activa dunst y dunst DIBUJA. Cinco piezas y la unica forma de saber que estan las cinco es verlo.

Para que entrara, la lista pasa a llevar el COMANDO de cada guardian en vez de su nombre de fichero:
lo que lo tenia afuera era el despacho por extension, no una decision.

Corrida entera de los diecinueve sobre `b3:e556024b`: **17 verdes, 2 rojos, 32,2 min**, que es
exactamente lo que la cabecera predice — y la cabecera es el control, no un adorno.

Los caros: sct 242 s, archivo semantico 238 s, ia 182 s, instalacion 180 s, notificaciones 180 s.
Los cuatro primeros salen en 5 s y no tocan el navegador.
2026-09-16 14:05:51 +00:00
Sergio 216b981484 estado: cosecha granja 2026-09-16T14:02:14Z — avance del árbol KDE 2026-09-16 14:02:14 +00:00
SergioandClaude Opus 5 eaa7d02725 el corte, con hora: 93 minutos — y en un servicio que ya autoriza no va límite por tasa
Del `access.log`, sin ambigüedad. La IP del usuario (`45.234.61.160`, autenticada como `sergio`,
2709 peticiones) tuvo tres silencios: **93,2 min (11:59:37 → 13:32:49 UTC)**, 50,1 min (10:44:58 →
11:35:06) y 10,0 min (11:45:06 → 11:55:05). Los tres son el `timeout` de 10 minutos del ban
disparándose una y otra vez: cada vez que volvía, su primera ráfaga lo baneaba de nuevo. El corte
grande terminó exactamente cuando vacié los sets.

🧨 Y LA EXENCIÓN QUE TENÍA NO SERVÍA: la ACL histórica de squid exime `45.234.60.0/24` y él entra
desde `45.234.61.160` — **una red de al lado**. Parecía cubierto y no lo estaba. La pertenencia se
MIDE (`ip in red`), no se deduce del parecido del prefijo.

DECISIÓN DE FONDO: en un servicio que YA AUTORIZA no va límite por tasa. El uso de esta caja es
INTENSIVO —varias sesiones de agente en paralelo, cada una abriendo túneles a la vez— y un límite
calibrado para «una persona normal navegando» no protege de nada: el atacante ajusta su ritmo, el
usuario no puede trabajar más despacio. Squid ya pide usuario y contraseña y tiene su ACL. El ban del
puerto queda apagado (60000/min, ráfaga 1000) y contra un flood queda el tope GLOBAL
`syn_nuevas_por_seg`, que no distingue usuarios ni banea a nadie por ser rápido.

Control tras aplicar: su túnel pasando —`45.234.61.160 … CONNECT api.anthropic.com:443 sergio`— y
`45.234.61.160 ∈ 45.234.60.0/23` comprobado con aritmética de redes, no a ojo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 13:38:54 +00:00
SergioandClaude Opus 5 618dcfd851 🧨 el cortafuegos baneaba a los usuarios del proxy — y squid nunca se cayó
Preguntaron si el proxy estaba caído. NO lo estaba: el ente llevaba horas corriendo con ↻ 0 y
contestando 407. Lo caído era el ACCESO — el cortafuegos de ayer baneaba a los autorizados.

La prueba en una línea: **154.197.1.2, una IP que está en la ACL de squid (gente con contraseña),
apareció en `@ban4`**, con el contador del ban en 38.246 paquetes tirados.

LA CAUSA NO ES LA TASA, ES LA RÁFAGA: `limit rate over 300/minute burst 5 packets` tolera cinco
conexiones por encima del promedio, y un navegador o un agente detrás de un proxy abre DECENAS de
CONNECT en el mismo instante aunque su promedio sea bajísimo. Y como @ban4 es UN SOLO set consultado
antes que todo, caer por el puerto del proxy te tira también el web y el git.

⚠ El tipo ya traía el campo `rafaga` (default 5) con un comentario que dice «para un servicio web va
alto (100-200)». Otra vez leí el .ron de EJEMPLO y no el TIPO.

Hecho, en orden de urgencia: flush de los sets (servicio restaurado en el acto) · los 21 IPs y 5
redes de la ACL de squid a `confiables` · `rafaga` por servicio según su clientela (ssh 5, git 20,
web 100, proxy 200) · proxy a 1200/min con ban de 60 s, que es red de contención contra un flood y
no control de uso. Control después: CERO autorizados en el set, 24 baneados (escáneres) y tráfico
real pasando —`154.194.14.37 … CONNECT api.deepseek.com:443 sigma`, 298 K tunelados—.

⚠⚠ Y un fallo de método que casi lo tapa: **`nft -f` SUMA a la tabla existente**. Cargué el reglaset
corregido encima del viejo y quedaron 30 reglas con las VIEJAS ADELANTE, así que los `confiables`
nuevos no se evaluaban nunca. Por eso `cortafuegos apply-input` borra la tabla antes de cargar.

La lección: un cortafuegos correcto y uno usable no son lo mismo, y la diferencia NO se ve al
aplicarlo. El control que lo habría cazado es el que no corrí: una ráfaga de conexiones desde una IP
que no esté en `confiables`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 13:33:50 +00:00
Sergio 9923aa2779 estado: cosecha granja 2026-09-16T13:32:44Z — avance del árbol KDE 2026-09-16 13:32:45 +00:00
SergioandClaude Opus 5 65dab8d262 rust: rpath = false, la pareja obligatoria de poner lld como enlazador directo
El build con `ld.lld` en el spec murió compilando `std`:

    ld.lld: error: unknown argument '-Wl,-z,origin'
    ld.lld: error: unknown argument '-Wl,-rpath,$ORIGIN/../lib'

Con el enlazador invocado DIRECTO (sin driver de C), los `-Wl,…` que el bootstrap añade para el
rpath de sus propios binarios llegan tal cual a lld, que no los entiende — esa sintaxis existe para
que un `cc` los traduzca.

El rpath sobra igual: con `prefix = "/usr"` las librerías quedan en `/usr/lib`, que ya está en el
camino del cargador. Es lo que hacen las distros que empaquetan rust.

Costó 6 minutos de build descubrirlo, que es lo que vale tener la cadena en la granja: cada intento
falla temprano y con el mensaje exacto.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 13:21:12 +00:00
SergioandClaude Opus 5 e903f486d9 el enlazador va DENTRO del compilador — /etc/cargo/config.toml es una ruta que cargo no lee
La prueba de la caja recién instalada —`cargo build` en un proyecto nuevo, sin flags ni rutas a
mano— falló con `linker `cc` not found`, y destapó que la pieza que había empaquetado era falsa:
**cargo NO LEE `/etc/cargo/config.toml`**. Sólo lee `$CARGO_HOME/config.toml`, los
`.cargo/config.toml` del proyecto y sus padres, y lo que se le pase con `--config` — que es lo que yo
venía pasando a mano en cada prueba, y por eso «funcionaba».

Y el arreglo no era mover el fichero: **el que enlaza es `rustc`, y rustc no lee la config de
cargo**. Las flags van DENTRO del compilador, en el spec del triple:

· `linker = "ld.lld"` + `linker_flavor = Gnu(Cc::No, Lld::Yes)` — sin esto rustc busca `cc`, que una
  caja takana no tiene.
· `crt_static_default = true` — sin esto enlaza dinámico y pide `-lgcc`, que no existe (la distro se
  construye con zig, que trae compiler-rt).
· `crt_static_allows_dylibs = true` — su pareja obligatoria: sin ella `crt-static` apaga los dylibs
  y con ellos los PROC-MACROS (serde_derive, clap_derive, las 44 recetas `cargo-*` con `derive`).
  El compilador en sí sigue dinámico: el `bootstrap.toml` fija `crt-static = false` para el build, y
  eso gana sobre el default del spec.

⇒ `cargo-config` (receta, árbol y copia en scripts/) se van enteros: un paquete que instala un
fichero que nadie abre es peor que no tenerlo.

Y de paso, `lld21` instala los cuatro alias como SYMLINKS y no como copias: cmake los duplicaba, 5 ×
96 M = 478 M de artefacto para 97 M de enlazador. Ahora 108 M, y `ld.lld` sigue despachando por
`argv[0]`, que es como upstream lo diseñó.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 13:07:56 +00:00
Sergio c57fcb214f estado: cosecha granja 2026-09-16T13:02:56Z — avance del árbol KDE 2026-09-16 13:02:56 +00:00
SergioandClaude Opus 5 0a894cfac1 perfil.servidor: fuera el prebuilt ajeno, entra el toolchain propio
Sale `rust-toolchain-bin` —799 M de bytes AJENOS sellados tal cual (`foreign`)—, que era el escalón 1
del SDD 31 y cumplió su función: con él se construyó el escalón 2, y el escalón 2 ya compila,
enlaza y corre.

Entran TRES, que son el mismo hecho («esta caja compila Rust») partido en piezas:
· `rust` (353 M) — el compilador y cargo, de la granja, desde fuente.
· `lld21` — el enlazador. NO es opcional: una caja takana no tiene `cc`, y sin enlazador `rustc`
  compila objetos y no produce un ejecutable.
· `cargo-config` — receta nueva que publica `/etc/cargo/config.toml` con las tres flags que unen a
  los dos. Sin ellas `cargo build` muere con «linker `cc` not found»: el toolchain estaría completo
  y MUDO, que es [[subcomando-sin-driver]] otra vez. Es config de SISTEMA y no de usuario a
  propósito — un `~/.cargo/config.toml` funcionaría para quien lo escribió y no para el siguiente.

⚠ Y `rust` se re-hashea otra vez (702094a8 → fe277b32) por una línea que descubrió el control de
PATH: **x.py instala en `/usr/local` por defecto, y el PATH de una caja takana es
`/bin:/usr/bin:/sbin:/usr/sbin`** — medido en la caja. O sea que el perfil habría proyectado un
`rustc` perfecto que nadie puede invocar: «existe ≠ se encuentra». Ahora `[install] prefix = "/usr"`,
como el resto del corpus.

Control previo que sí pasó: `rustc` y `cargo` corren SIN `LD_LIBRARY_PATH` — su `RUNPATH` es
`$ORIGIN/../lib`, así que la proyección del artefacto basta.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 12:38:15 +00:00
Sergio 240069801e estado: cosecha granja 2026-09-16T12:32:03Z — avance del árbol KDE 2026-09-16 12:32:03 +00:00
Sergio d22bc8443a estado: cosecha granja 2026-09-16T12:02:13Z — avance del árbol KDE 2026-09-16 12:02:13 +00:00
Sergio f8a900a923 estado: cosecha granja 2026-09-16T11:32:14Z — avance del árbol KDE 2026-09-16 11:32:15 +00:00
SergioandClaude Opus 5 72ba86c290 la cadena rehecha: llvm21 arreglado, lld enlaza, rust reconstruido — los seis controles pasan
Un cambio de dos líneas en `llvm21` re-selló tres artefactos y los molió la granja sola, en orden,
por dependencia: llvm21 95956a16→bd4a4094, lld21 27be53c1→95a4794b, rust 015a07fb→702094a8.

    llc --version        Stack dump: + segfault   →   LLVM 21.1.2, Optimized build
    opt --version        ídem                     →   LLVM 21.1.2
    ld.lld               «not built with zlib»    →   ENLAZA
    rustc --version                               →   1.97.0 (built from a source tarball)
    --print target-list                           →   x86_64-alpine-linux-musl
    cargo build + correr                          →   0,16 s y el binario habla

La config del sitio pasa a usar `lld` (más rápido); el `ld` de binutils queda documentado como
alternativa que también funciona.

LA REGLA QUE SE GANÓ SU LUGAR: **`link = "static"` en el encabezado decide cosas que la receta no
dice**. Van tres, todas medidas: apagó los threads de openssl, le mintió a libtool, y acá rompió los
registros estáticos de LLVM (`cl::opt`, `TargetRegistry`) porque el `static-pie` descarta sus
constructores globales. Con C++ grande la postura por defecto pasa a ser `dynamic` y medirlo — y el
control no es que selle: es CORRER UNA HERRAMIENTA del artefacto.

Y el corolario de por qué nadie lo vio en meses: el único consumidor de llvm21 era rust, que usa
`llvm-config` y las `.a`, nunca una herramienta. **Un artefacto puede estar roto en todo lo que nadie
usa** — como los 44 `cargo-*` sin cargo y los 23 binarios sin cargador.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 11:19:18 +00:00
Sergio 3a68db44b8 estado: cosecha granja 2026-09-16T11:02:38Z — avance del árbol KDE 2026-09-16 11:02:38 +00:00
SergioandClaude Opus 5 bad2b1c63a llvm21: dynamic y con zlib — las 79 herramientas dejan de crashear, y rust se rehace detrás
Dos cambios, los dos medidos, y los dos re-sellan la cadena entera (`link` y las deps son entrada de
hash): `llvm21` 95956a16… → bd4a4094…, `rust` 015a07fb… → 702094a8…, `lld21` → 95a4794b…

1. `link = "dynamic"`. Con `static`, las 79 herramientas que publica el artefacto CRASHEAN —`llc
   --version` incluido, y también en el worker, o sea que es el build y no el entorno—: salen
   `static-pie` y el enlace estático descarta los constructores globales de los que dependen los
   registros de LLVM (`cl::opt`, `TargetRegistry`). Funciona lo que no los necesita (`llvm-ar`,
   `llvm-config`) y revienta lo que sí. **No se notó en meses porque el único consumidor, `rust`, usa
   `llvm-config` y las `.a` — nunca una herramienta.** Lo destapó `lld21`, que enlaza contra estas
   mismas librerías: estático crasheaba con cualquier entrada, dinámico da errores limpios.
2. `-DLLVM_ENABLE_ZLIB=ON` + dep `zlib`. Sin eso, cualquier `lld` construido contra este LLVM hereda
   `LLVM_ENABLE_ZLIB 0` de `LLVMConfig.cmake` y no puede leer las secciones de depuración COMPRIMIDAS
   que trae la libc del lab. Encenderlo acá es la única vía: el build standalone de lld no puede
   contradecir a su LLVM.

Las `.a` que consume `rust` no cambian de contenido —el flag sólo quita el `-static` del enlace de
los EJECUTABLES— pero el hash sí, y eso es correcto: es lo que hace que la granja rehaga rust con un
LLVM cuyas herramientas funcionan.

Los tres hashes coinciden hub↔worker antes de sembrar.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 10:36:20 +00:00
Sergio 2ff2a31150 estado: cosecha granja 2026-09-16T10:31:47Z — avance del árbol KDE 2026-09-16 10:31:47 +00:00
Sergio 5d30ef4b58 estado: cosecha granja 2026-09-16T10:01:44Z — avance del árbol KDE 2026-09-16 10:01:44 +00:00
Sergio 10878bf4a7 estado: cosecha granja 2026-09-16T09:31:22Z — avance del árbol KDE 2026-09-16 09:31:22 +00:00
Sergio c936d55675 estado: cosecha granja 2026-09-16T09:02:07Z — avance del árbol KDE 2026-09-16 09:02:07 +00:00
Sergio 83f5ec6e66 estado: cosecha granja 2026-09-16T08:31:20Z — avance del árbol KDE 2026-09-16 08:31:20 +00:00
Sergio 3a58cc6cbe estado: cosecha granja 2026-09-16T08:01:51Z — avance del árbol KDE 2026-09-16 08:01:51 +00:00
Sergio c0fbf75353 estado: cosecha granja 2026-09-16T07:31:21Z — avance del árbol KDE 2026-09-16 07:31:21 +00:00
Sergio ba6680c7b2 estado: cosecha granja 2026-09-16T07:01:54Z — avance del árbol KDE 2026-09-16 07:01:55 +00:00