Commit Graph
113 Commits
Author SHA1 Message Date
SergioandClaude Opus 5 22511e7b3d shuma-askpass se retira de la cola: no construye — y, mejor aún, no hace falta acá
Era la décima de la tanda y es la única que no selló. Dos hallazgos, y el segundo vuelve irrelevante
al primero.

1. NO CONSTRUYE. Su dependencia `atspi-common` muere con `custom attribute panicked — message: File
   has no extension.` en el proc-macro `#[validate(signal: …)]`: lee un fichero en tiempo de
   compilación y no resuelve la ruta dentro del sandbox (el árbol vive en `/src/...`). De ahí salen
   292 errores en cascada (`ObjectRef` sin declarar), que es lo que se ve primero y no es la causa.

2. NO HACE FALTA. Su propio Cargo.toml la describe como «Mini-ventana Llimphi compatible con
   SUDO_ASKPASS»: es una VENTANA (llimphi-ui, theme, widget-text-input, clipboard). En un servidor
   sin pantalla no tiene dónde dibujarse — y las sesiones de shuma son PTYs, así que el prompt por
   TTY no es una degradación, es el camino correcto.

El aviso que el daemon imprime al arrancar («askpass: no encontré shuma-askpass … pedirán la clave
por el TTY») es para el escritorio, no para el servidor. Queda escrito en la cabecera de
`recipes/shuma-daemon.toml`, que es donde alguien va a leerlo cuando vuelva a ver el aviso.

Balance de la tanda: 9 de 10 selladas y declaradas; la décima retirada con motivo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 23:04:17 +00:00
SergioandClaude Opus 5 ec469aef6b los nueve daemons propios declarados — y la línea entre «se muda» y «se INTERCAMBIA»
Nueve de las diez sellaron y están promovidas. Cinco corren en la caja (matilda, tupu, pacha,
pacha-secretos, willay-daemon, más el par de shuma de ayer); cuatro quedan instaladas y FRENADAS a
propósito, cada una con su guarda diciendo qué falta.

⚠ LA PAUTA DE LOS VHOSTS NO SIRVE PARA UNA IDENTIDAD. Con los sitios la regla fue «mudá el DNS y
dejá el origen encendido, así volver cuesta un minuto» (§6.26). Con `tejido` es justo lo contrario:
su README dice que la clave que el roster atesta ES la identidad de transporte libp2p
(`~/.tejido/device.seed`), así que dos máquinas con la misma semilla no son dos réplicas — son el
MISMO PeerId en dos sitios, dos impostores mutuos para la flota. `tejido` se INTERCAMBIA: se apaga
allá, se enciende acá, en ese orden. Todo listo para el intercambio (binario, cuenta 964, identidad
700 instalada) y su Card en `cards.d` pero NO en el `genesis`, para que un reinicio no lo encienda.

Y arrastra a `willay-crosscheck`, que no es independiente: corriendo su línea a mano dice «no hay
roster en /root/.tejido/roster.postcard — emparejá primero». Vive dentro de la red de tejido.

`thasnuna` tampoco puede: su INSTALAR.md —escrito hoy por el frente tawasuyu para esta mudanza—
pide `sandokan-mcp` y `claude` AUTENTICADO, y el CLI de claude es glibc de ~300 M (jaula qorpa).
De ahí sale un hallazgo que vale para el respaldo entero: la Card `openrc-openclaw` de gioser lleva
la API key de su proveedor EN CLARO dentro del JSON de /etc/arje/cards.d/, que se respalda y se
copia. Un secreto dentro de una Card viaja a todas partes.

`--label` de willay-crosscheck NOMBRA A LA MÁQUINA: en gioser decía `momento`. Ahora sale de
`hostname` y la guarda frena si no hay.

Y tres veredictos FALSOS en una tarde, los tres por probar con lo que la caja no tiene: `/dev/tcp`
(busybox ash no lo tiene) dio los 5 puertos de gioser «cerrados»; la expansión de llaves dijo que
los artefactos no habían llegado; y `find -newermt "-2 minutes"` dijo que tupu no escribía. Tupu SÍ
escribe: su fichero tiene tamaño CONSTANTE —es una serie fija— así que ni los bytes ni ese find
prueban nada; lo que decide es el mtime, medido dos veces con 40 s de por medio.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 20:57:44 +00:00
SergioandClaude Opus 5 98cd672a10 cuatro daemons propios corriendo en la caja — y la máquina se llamaba «(none)»
Sellaron `matilda`, `pacha`, `pacha-secretos` y `sandokan-watch`; las cuatro promovidas a canónicas
(hash idéntico antes y después de moverlas) y las tres primeras ya supervisadas por arje.
`matilda` archivó 78 ficheros leyendo el access log de caddy; `pacha` corre con SUS reglas y no con
las de fábrica; `pacha-secretos` vuelve a existir como binario — en gioser era un inodo borrado.

TRES CORREN COMO ROOT, declarado en vez de heredado. No es descuido: `matilda` lee
`/var/log/caddy/requests.json`, que caddy crea `-rw------- root root` y recrea igual en cada
rotación; y los tres del trío escriben en el MISMO `/var/lib/tupu`, cuyos 322 ficheros en gioser son
root:root — bajar a uno solo deja mezcla de dueños en un árbol compartido. O los tres, o ninguno. La
salida limpia (caddy con `mode 640` + cuenta propia del árbol) queda anotada en la receta. `pacha` y
`pacha-secretos` sí bajan a cuenta propia: en gioser tampoco corrían como root.

🕳️ LA CAJA NO TENÍA HOSTNAME. `hostname` decía `(none)` y `/etc/hostname` no existía — NINGUNA caja
takana lo fija: ni netup, ni el product-rootfs. Nunca importó porque nada archivaba por nombre,
hasta que llegó matilda: sus primeros 72 ficheros fueron a `/var/lib/tupu/none/`, y dos máquinas
distintas archivarían en la misma carpeta sin que nada falle. Puesto `/etc/hostname` + una Card
OneShot en el genesis para que sobreviva al reinicio. Lo correcto es que lo haga `netup`.

🛡️ Y `sandokan-watch` quedaba VERDE SIN VIGILAR: en takana no hay `auth.log` ni journalctl, así que
arrancaba, decía «sin fuente de accesos: no se guarda nada» y se quedaba «corriendo · 0 reinicios».
Su Card ahora sale 78 nombrando el problema y NO entra al genesis: un vigía que no vigila es peor
que uno caído, porque el caído se ve.

De paso, dos veredictos FALSOS en una tarde por probar con algo que la caja no tiene: `/dev/tcp` no
existe en busybox ash (dio «cerrado» para los cinco puertos de gioser, incluidos :80 y :443, que
sirven) y la expansión de llaves tampoco (dijo que los artefactos no habían llegado; habían
llegado). Misma familia que el §6.23.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 20:25:05 +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 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
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 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
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
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
SergioandClaude Opus 5 a9911785e1 lld21: el enlazador de la distro — porque el bootstrap de rust se NIEGA a construirlo
La vía (a) está CERRADA, y lo dice el propio bootstrap en una línea:

    Cannot enable LLD with `rust.lld = true` when using external llvm-config.

Había leído el paso `Lld` —que compila desde el `src/llvm-project/lld` del tarball y reusa el
`llvm-config` externo— y me faltó mirar la VALIDACIÓN de config, que rechaza la combinación antes de
llegar a ese paso. La guarda tiene sentido: LLD y LLVM comparten ABI de C++, y con un llvm-config
externo el bootstrap no puede garantizar que casen. O sea: mientras usemos el `llvm21` del corpus
—que es lo que queremos— el toolchain NO se va a construir su propio `rust-lld`.

⇒ `recipes/lld21.toml` construye el MISMO `lld`, del mismo `llvm-project` (mismo tarball y mismo
sha256 que `llvm21`, byte por byte), pero SÓLO el subproyecto: `cmake -S lld` contra el LLVM ya
instalado por la dep. Minutos en vez de horas, y sin re-hashear `llvm21` —que encender
`LLVM_ENABLE_PROJECTS=lld` ahí dentro habría arrastrado a `rust` con él.

⚠ Y al revertir el flag aprendí algo que vale para todas las recetas con heredoc: el texto del
`bootstrap.toml` que la fase escribe **es parte de la fase, o sea ENTRADA DE HASH**. Mi comentario
explicando el fallo, puesto ahí adentro, cambiaba el hash del compilador entero: hora y media de
granja por un párrafo. Va fuera, como comentario de la receta, y el hash vuelve a `015a07fb…` — el
artefacto que ya está sellado.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 01:02:49 +00:00
SergioandClaude Opus 5 d3dcd739cc sacar el kernel de la cola de la granja: se construyó en la caja
`recipes/incoming/linux-generic.toml` entró a la cola y salió el mismo día. El motivo es concreto:
la cola del worker se muele EN SERIE y `rust` está horas adentro, así que el kernel —que era lo
urgente, porque sin él no hay cortafuegos— habría esperado a que rust terminara. Se construyó en la
propia caja (4 cores, 4,6 G libres, CPU ociosa) en 21 minutos.

Dejarlo encolado no era gratis: el worker no tiene ese artefacto en su store —la cosecha va
worker→hub y nunca al revés— así que lo habría reconstruido entero para llegar al mismo b3.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 22:00:10 +00:00
SergioandClaude Opus 5 de16c4ba24 rust: el triple de Alpine, DENTRO del compilador — el sexto muro, atacado
`recipes/rust-alpine-target.patch` registra `x86_64-alpine-linux-musl` en `rustc_target`: un spec
copiado del canónico y una línea en `supported_targets!`. Es lo que hace Alpine en su APKBUILD, y es
la única forma que vale para el triple del HOST (un `.json` por `RUST_TARGET_PATH` no alcanza).

La única diferencia real con el spec canónico es `crt_static_default = false`, que es lo que habilita
dylibs y con ellos los PROC-MACROS: un rustc con crt-static por default no compila `serde_derive` ni
`clap_derive` — ni las 44 recetas `cargo-*` del corpus que usan `derive`.

⚠ PROBADO EN SECO ANTES DE ENCOLAR UNA HORA DE BUILD (`patch -p1 --dry-run` contra el árbol real del
worker), y no de primera: la cabecera `@@ -0,0 +1,38 @@` del fichero nuevo tenía 37 líneas y `patch`
murió con «malformed patch», y el hunk de `mod.rs` lo escribí con números a ojo y falló. El segundo
lo generé con `diff -u` de verdad contra una copia. Un parche se COMPRUEBA, no se redacta.

⚠ Y EL `.patch` HAY QUE ENCOLARLO TAMBIÉN: `source.patches` resuelve contra el directorio de la
receta, así que con la receta enlazada en `recipes/incoming/` el parche se busca AHÍ. Es exactamente
el corolario que `farm-worker-loop.sh` documenta («los `.patch` NO viajan con la receta»), visto
desde el otro lado. Con los dos enlaces, el hash de la cola y el canónico coinciden: `b3:53c7f991…`,
y el worker calcula el mismo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 21:59:55 +00:00
SergioandClaude Opus 5 743d83d5e9 el kernel genérico enciende nf_tables — y rust entra a la cola de la granja
Dos cosas a moler, las dos en el worker (que tiene 6 cores, 16 G y 94 G libres), encoladas por
ENLACE a la receta canónica y no por copia: `takana hash` da el MISMO b3 por el enlace que por el
fichero real, así que la cola no puede divergir de lo canónico — que es justo el defecto que el
propio `farm-worker-loop.sh` documenta de las colas viejas («su copia aparcada era la versión
ANTERIOR y seguía leyéndose como deuda abierta»).

· `linux-generic` (b3:63fdd57c…, antes 23f1cc43…): `NETFILTER_ADVANCED`, `NF_TABLES`,
  `NF_TABLES_INET`, `NFT_CT`, `NFT_LIMIT`, `NFT_COUNTER`, `NFT_LOG`, `NFT_REJECT{,_INET}` y
  `NETFILTER_SYNPROXY`/`NFT_SYNPROXY`. Es lo que pide el cortafuegos de tawasuyu (SDD-ENTRADA): la
  tabla `inet`, el estado de conexión y el `limit rate` POR ELEMENTO de set, que es el ban por IP
  dentro del kernel y el reemplazo de fail2ban. SYNPROXY va ahora porque encenderlo después cuesta
  otro kernel y otro reinicio de producción.
· `rust` (b3:aa5d81e8…): el escalón 2 del SDD 31, que estaba en `never`. El worker ya tiene `llvm21`
  sellado con el MISMO hash que el hub (95956a16…), así que arranca desde ahí y no lo reconstruye.

Los dos hashes coinciden hub↔worker, comprobado antes de sembrar: el worker va a sellar exactamente
lo que sellaría acá.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 21:12:12 +00:00
Sergio e1413d5e8d qdrant: promovida al corpus — limpia, reproducible, y la familia «base vectorial» deja de estar vacía
El worker selló la versión con el `install` que limpia `/out/src`: **70 M en vez de 139**, sólo
`usr/bin/qdrant`, sin NEEDED. Y REPRODUCE bit a bit (verificado allá, donde vive el artefacto).

    corpus 890/890 sellado · deuda 0 · el grafo CIERRA

Control de la promoción, en los dos sentidos: el hash antes y después del `git mv` es el mismo
(`4bd8feca…`) — la ruta no entra en `hash_inputs`, así que mover de cola al corpus no re-hashea nada.

De las cuatro familias que la tabla de `planear.py` daba vacías al empezar la noche quedan sólo
«contenedores», y eso es HONESTO aunque `crun` ya esté sellado: crun es el runtime OCI, la capa de
abajo — no sustituye a docker/podman/containerd, los ejecuta. Meterlo en esa casilla sería declarar
resuelta una decisión que sigue abierta.

El artefacto vive en el store del worker y el hub lo cuenta por manifiesto, que es como está
diseñado desde que el store se mudó al volumen.
2026-09-11 23:31:11 +00:00
Sergio 733065b1c4 qdrant: CONSTRUYE y ARRANCA — pero el artefacto venía con 69 M de basura, y la causa es del lab
Selló en el worker con el arreglo del `compiler = "gcc"`. Verificado allá, corriéndolo y no por el
código de salida: binario estático de 70 M sin NEEDED, `qdrant --version` → `qdrant 1.19.1`, y
levantándolo de verdad:

    Qdrant HTTP listening on 6399
    Qdrant gRPC listening on 6334
    Access web UI at http://localhost:6399/dashboard

⚠ **Y al mirar el ÁRBOL del artefacto antes de promoverlo, pesaba 139 M — la mitad, basura.** 140
ficheros bajo `src/target/release/build/protobuf-src-*/out/install/include/google/protobuf/…`: las
cabeceras y libs del protobuf que `protobuf-src` compila para su uso interno.

**La causa no es de esta receta, y por eso vale escribirla.** El sandbox exporta **`DESTDIR=/out` de
forma GLOBAL** (`sandbox.rs`), para que el `make install` de las recetas autotools funcione.
`protobuf-src` hace su propio `make install` DENTRO de la fase compile, con
`--prefix=/src/target/release/build/…/out/install`, y ese install anidado **hereda el DESTDIR** ⇒ su
prefijo aterriza en `/out/src/target/…`. Nadie lo pidió, nada falla, y el artefacto sella con el
doble de tamaño y un `/src` en la raíz que al hidratar se proyectaría sobre el FHS de la imagen.

Le puede pasar a cualquier receta cuyo build ejecute un `make install` anidado — los crates `*-src`
son la familia entera. Se limpia en la receta y NO en el lab: quitar el `DESTDIR` global cambiaría el
comportamiento de todas las recetas autotools del corpus, que es una campaña con su propia
verificación. `/out/src` nunca es salida legítima — la raíz del artefacto es un FHS y `/src` es el
nombre del bind del lab.

Queda en `incoming/` hasta que el worker selle la versión limpia; promover a `recipes/` con el
artefacto sucio sería meter los 69 M al grafo.
2026-09-11 21:36:20 +00:00
Sergio 07cc386580 qdrant: murió a los 408 crates por el NOMBRE del wrapper del lab, no por qdrant
Primer intento en el worker: 1,5 h, 408 crates compilados, y esto:

    "/src/vendor/protobuf-src/protobuf/configure" … "--host=/src/.hammer-zig"
    Invalid configuration `/src/.hammer-zig': machine `/src/.hammer-unknown' not recognized

La cadena es qdrant → `raft-proto` (tikv/raft-rs) → `protobuf-build` → **`protobuf-src`**, que
compila protobuf 21.5 DESDE FUENTE con el crate `autotools` — o sea que ni siquiera usa el `protoc`
que acabo de meter en el catálogo. Y `autotools` adivina el triple `--host` **recortándole el sufijo
al nombre del compilador**. Leído en `vendor/autotools/src/lib.rs` del árbol de post-mortem, no
supuesto:

    let host = cc_path.strip_suffix("-cc").or_else(|| cc_path.strip_suffix("-gcc"));
    if let Some(host) = host { args.push(format!("--host={}", host)); }

El lab exporta `CC="$PWD/.hammer-zig-cc"` ⇒ recortar `-cc` deja `/src/.hammer-zig`, que viaja como
triple. **El fallo no tiene nada que ver con qdrant ni con protobuf: lo causa cómo se llama nuestro
wrapper.** Cualquier receta Cargo que arrastre el crate `autotools` va a chocar igual.

Con `compiler = "gcc"` el lab exporta `CC="gcc"`, al que no se le puede recortar `-cc` ni `-gcc` ⇒ el
crate **no añade `--host`** y configure corre nativo. El propio crate ya tiene un caso especial
`cc_path != "musl-gcc"`, señal de que la heurística es frágil y upstream lo sabe.

⚠ **Y NO se arregla renombrando el wrapper del lab, aunque sea lo obvio:** ese nombre vive dentro de
la cadena de la fase `compile`, que entra en `hash_inputs` ⇒ tocarlo re-hashea las **234 recetas Rust
del corpus**. Es una campaña con su propia verificación, no un arreglo de paso. La palanca por receta
es la correcta, y queda escrito en la receta para que el próximo que lo vea no reabra la discusión.
2026-09-11 20:46:05 +00:00
Sergio 37bf7077e7 qdrant: a la cola del worker — y dos comprobaciones previas que podían haberla matado
La familia «base vectorial» de la tabla de `planear.py` sale SIN NADA en el catálogo (ni qdrant, ni
milvus, ni weaviate), y el censo del servidor de origen encontró `qdrant` CORRIENDO como binario
suelto en `/usr/local/bin` — de los que nadie provee y se pierden al apagar la máquina vieja. Si la
mudanza llega a ese servicio sin receta, se para.

Va a `recipes/incoming/` y no a `recipes/`: son 912 crates, no está construida todavía, y el hub
clasifica DESPUÉS de que el worker selle. El worker está ocioso y es gratis — ése es su trabajo.

Lo que la destrabó fue el `protoc` del commit anterior: su `build.rs` genera los stubs gRPC con
tonic/prost, que lo invocan. Es dep declarada, no accidente del lab.

Dos cosas comprobadas ANTES de escribir la receta, cada una capaz de matarla:

1. **MSRV.** Pide `rust-version = "1.97"` y el lab trae **exactamente** `rust-1.97.0-r0`. Margen
   CERO — y el toolchain del lab sale de Alpine edge, que es rodante: esto entra hoy porque edge ya
   movió. Queda escrito en la receta para que el día que falle no se busque en otro lado.
   (De paso: la nota que yo tenía de «techo MSRV 1.96» está vencida; el lock dice 1.97.0.)

2. **Qué `*-sys` arrastra**, que es la frontera conocida de las recetas Cargo. Grep sobre el
   `Cargo.lock`: **no hay rocksdb, ni librocksdb-sys, ni openssl-sys, ni bindgen** — qdrant migró a
   Gridstore y se sacó RocksDB de encima. Queda `tikv-jemalloc-sys`, que compila jemalloc desde
   fuente (de ahí `make`). Sin ese grep, la suposición razonable era «qdrant = rocksdb = C++ +
   libclang», media tarde de trabajo que no hacía falta.
2026-09-11 19:01:32 +00:00
Sergio e852f48491 takana etapa 5a: los comentarios de las 741 recetas
Barrido de TEXTO puro: 1427 líneas de comentario TOML. Cero ArtifactHash
movidos, y eso está MEDIDO, no deducido: hasheé las 741 antes y después y los
ficheros de hashes son idénticos byte a byte (723 con hash real + 18 que ya no
hasheaban de antes).

El guardián valió la pena: el primer barrido, filtrando por 'la línea empieza
con #', movió el hash de helix, lsof y steam-runtime-sniper. La causa es que una
fase se escribe como compile = <triple> ... <triple> y sus comentarios de SHELL
también empiezan con #, pero viven dentro del VALOR — y las fases sí entran en
hash_inputs. El barrido ahora calcula los rangos de las cadenas multilínea de
TOML y no entra ahí.

Quedan intactos a propósito: .hammer-zig-cc y .hammer-cargo-vendor (literales
dentro de fases), hammerd, hammer-recover y toda ruta que empiece por /
2026-09-09 19:23:26 +00:00
SergioandClaude Opus 5 75b402d1bf deferred: system-libs.patch es de kalker — va con su receta
Al verificar la resolucion estricta de parches salio la unica referencia rota
del arbol: `.deferred/kalker.toml` pide `system-libs.patch` y el fichero estaba
en `recipes/`. Los patches se resuelven `base_dir.join(nombre)` sin fallback, asi
que la receta nunca lo habria encontrado.

No es una rotura nueva: `.deferred/system-libs.patch` no existio jamas (el
importador dejo la receta en .deferred y el parche en recipes/). Y es
inequivocamente de kalker — parchea `kalk/Cargo.toml` — ademas de que ninguna
receta lo citaba desde recipes/, o sea que ahi era un huerfano.

Ningun hash se mueve por esto. Referencias de parche: 95 resuelven, 0 rotas.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LykB7vw38b4Ck1Zij15RQ4
2026-09-01 20:04:43 +00:00
Sergio 17b6a284f7 estado: cosecha granja 2026-09-01T20:02:56Z — avance del árbol KDE 2026-09-01 20:02:56 +00:00
sergioandClaude Opus 4.8 ecc4a0dc6f openrc 0.62.6: + libcap (requerido en Linux sin toggle) → sella; promovido a canónico
openrc es el supervisor de servicios (rc-service/rc-status/rc-update/start-stop-daemon)
que faltaba para una distro instalable — arje-zero es PID1, openrc gestiona /etc/init.d.
El build fallaba por libcap: meson.build lo pide incondicional en Linux (dependency
'libcap' >=2.33, sin -Dlibcap). Añadido → binarios estáticos-musl sellados.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 16:16:59 -04:00
sergioandClaude Opus 4.8 6fa19a6332 openrc 0.62.6: receta del supervisor de servicios (meson, musl-static)
El init/service-manager de Gentoo y Alpine — musl-clean por diseño (Alpine lo corre sobre
musl en prod). Enlace static-musl vía zig-cc; deps opcionales (audit/selinux/pam/libcap)
desactivadas para clausura mínima. Encolado en incoming/; el worker lo muele tras la pasada
KDE. Es la pieza de supervisión que falta para la distro instalable (arje-zero=PID1 + openrc
sobre /etc/init.d). hash dry-run: b3:78502dcb.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 20:15:16 -04:00
sergioandClaude Opus 4.8 fa8dff08b1 granja: borrar la cola gráfica obsoleta de incoming/ (no había otro agente)
Las 7 recetas del stack gráfico (libdrm/mesa/meson/samurai/seatd/wayland/wayland-protocols) +
6 patches eran imports crudos de Alpine, redundantes: las 7 ya tienen receta CANÓNICA en recipes/
(mesa pineada a 24.0.9 iris-only A PROPÓSITO, no la 26.1.1 cruda con FIXME-sha256). Su trabajo
aterrizó por la vía canónica (7131cd4) hace 3 semanas; la cola quedó de cruft rompiendo cada ciclo.

fa45978 las sacó de QUEUES creyéndolas de 'otro agente' (5126a8b). Confirmado que NO hay otro
agente ⇒ borradas. recipes/incoming/ vuelve a ser cola de staging general y REGRESA a QUEUES; el
guard ls-vacío la salta si no hay nada. recipes/incoming/.deferred/ (24 recetas aparcadas con
diagnóstico, git con muro en libgit.a) NO se toca: el glob de QUEUES es top-level, no la muele.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 11:26:42 -04:00
sergio 5126a8b679 Etapa G: devuelve el stack gráfico Mesa a recipes/incoming/ (es de otro agente, tawasuyu)
Revierte el parqueo de 370e7b7: mesa/wayland/wayland-protocols/libdrm/seatd/samurai/meson +
patches son trabajo en curso de otro agente para el escritorio tawasuyu (commit 00339b6), no
cruft. samurai queda en su versión desarrollada (clon C de ninja, zig 0.13.0). syncthing sigue
diferido (es de go-12, build especial).
2026-06-27 00:33:22 -04:00
sergio e6ee70d783 Etapa G: cosecha go-12 (18) — terraform/infra/k8s (opentofu/helm/packer/rclone/terragrunt/...) 2026-06-26 23:52:01 -04:00
sergio 370e7b7a20 Etapa G: limpia cola go-12 — parquea batch gráfico C a hold-nongo + difiere syncthing
- mesa/wayland/wayland-protocols/libdrm/seatd/samurai/meson + patches: batch C de gráficos previo
  que jamás se mandó al worker, arrastrado en incoming/. Parqueado en tandas/hold-nongo/.
- syncthing: build especial (genera la GUI embebida 'auto.Assets' vía go generate/build.go) ⇒
  diferida a staged-fallidos con el motivo. Quedan 18 go-12 limpias en la cola.
2026-06-26 23:51:05 -04:00
sergioandClaude Opus 4.8 00339b625e Etapa G: cola del stack gráfico Mesa (iris) para el escritorio tawasuyu
Importa de Alpine aports (con parches musl) las recetas del stack que el greeter
real de mirada necesita en el rootfs de producto: libdrm 2.4.134, wayland 1.25.0,
wayland-protocols 1.48, seatd, mesa 26.1.1, + build-tools meson 1.11.1 y samurai
(ninja). Quedan en recipes/incoming/ como puntos de partida: traen los parches
musl de Alpine pero usan helpers de abuild — falta adaptarlas a fases hammer
(meson/samurai directos, link=dynamic), como elfutils.

docs/14-mesa-stack.md fija el plan: iris-only ⇒ SIN LLVM/Vulkan/X11 (el driver
gallium iris no necesita LLVM), lo que recorta clang/llvm/libclc/spirv/bindgen.
DAG de build (hojas→raíz) + estado por receta + el lado tawasuyu (recetas Cargo
arje-splash/net-bring-up estáticas ya construibles; mirada-greeter dinámico,
bloqueado por mesa). Contraparte de la seed arje-tawasuyu del monorepo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 23:41:34 -04:00
sergio 06ba417336 Etapa G: granja Go pesada — watchdog no purga modcache con vendor activo + syncthing main en cmd/
go-12 (terraform/k8s) destapó la race: con árboles de deps de varios GB en paralelo, el disco
cruza DISK_HIGH y el watchdog corría 'go clean -modcache' a mitad de los 'go mod vendor' en vuelo
(.partial: no such file) ⇒ 5 recetas no convergían. Ahora difiere la purga del modcache si hay un
vendor de host activo (la purga de work/sources ya libera lo grueso y es segura). syncthing: main
real en ./cmd/syncthing (la raíz tiene build-constraints que excluyen todo).
2026-06-26 23:32:12 -04:00
sergio 5fb24e0deb Etapa G: corrige misimport helm (mtytel/synth → helm/helm k8s v4.2.1) 2026-06-26 23:26:03 -04:00
sergio 9af81626e9 Etapa G: manda go-12 al VPS (terraform/infra/k8s: opentofu/helm/packer/rclone/syncthing/...) 2026-06-26 23:19:35 -04:00
sergio f2e5aede14 Etapa G: cosecha go-11 (19) — recon/projectdiscovery (alterx/asnmap/cdncheck/tlsx/uncover/...) 2026-06-26 23:18:03 -04:00
sergio f068627e98 Etapa G: manda go-11 al VPS (recon/projectdiscovery) 2026-06-26 22:51:41 -04:00
sergio a5d2442211 Etapa G: cosecha go-10 (16) — config-lang/k8s-dev/recon 2026-06-26 22:51:31 -04:00
sergio ca121b5961 Etapa G: manda go-10 al VPS (jsonnet/cue/ytt/kpt/recon) 2026-06-26 22:36:48 -04:00
sergio 681ca509a0 Etapa G: cosecha go-9 (16) — linters/dev-tools Go 2026-06-26 22:36:36 -04:00
sergio ea4efdc8b6 Etapa G: manda go-9 al VPS (linters/dev-tools: shfmt/vale/goawk/gotestsum/...) 2026-06-26 22:26:52 -04:00
sergio ce126dd5ee Etapa G: cosecha go-8 (13, repo 444->457) — k8s grandes (cilium-cli/istioctl/gitea) 2026-06-26 22:26:44 -04:00
sergio 89a8678238 Etapa G: fuel-go-8 al VPS (devops/cloud/policy: opa/conftest/k0s/talosctl/...) 2026-06-26 20:18:35 -04:00
sergioandClaude Opus 4.8 cd0a52d18b Etapa G: cosecha go-7 (9, repo 435->444) — caddy/hugo/doctl/hcloud/earthly/...
Incluye binarios Go grandes (caddy web server, hugo SSG) que construyen OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 20:13:42 -04:00
sergioandClaude Opus 4.8 0cad0a7694 Etapa G: cosecha go-6 (16, repo 419->435) + manda go-7 al VPS
go-6: terraform-docs/tflint/tfsec/s5cmd/nerdctl/amass/infracost/kail/... yield
16/19, disco estable 65% con el watchdog nuevo (load bajo de 23 a 0.76).
go-7 (11): hcloud/doctl/flyctl/dagger/earthly/apko/scorecard/sake/... a la cola.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 17:46:23 -04:00
sergio 7883bbf804 Etapa G: fuel-go-6 al VPS — infra/recon (terraform-docs/tflint/tfsec/s5cmd/nerdctl/amass/...) 2026-06-26 17:27:41 -04:00
sergioandClaude Opus 4.8 11783a468a Etapa G: cosecha go-5 del VPS — 25 tools (repo 394->419)
delve/gopls/staticcheck/gofumpt/buf/sqlc/goose/atlas/dolt/restic/kopia/
nats-server/charm/pop/wishlist/headscale/rqlite/nsq/dbmate/... yield 25/27.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 17:25:15 -04:00
sergioandClaude Opus 4.8 d7e5d206b5 Etapa G: manda reserva go-5 al VPS (27) + archiva 22 fallidos
Cosechados 61, archiva los 22 que fallan a tandas/staged-fallidos/, manda la
reserva premasticada go-5 (delve/gopls/staticcheck/buf/sqlc/atlas/dolt/restic/
kopia/nats-server/charm/headscale/...). Disco VPS limpiado 90->79%.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 16:09:35 -04:00
sergioandClaude Opus 4.8 25fc85db90 Etapa G: cosecha del VPS 4-cores — 61 tools (repo 333->394)
Mayor cosecha de la sesion. Mayoria Go (fuel-go-2/3/4 + restos fuel-6+7):
age/argocd/cosign/trivy/trufflehog/k9s/kubectx/nuclei/vhs/soft-serve/
golangci-lint/goreleaser/ffuf/katana/gitleaks/sops/step-cli/helmfile/
gomplate/dasel/lf/sttr/usql/vegeta/bombardier/... + tokio-console (Rust).
yield VPS 61/83. Corpus FIRMADO = 394.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 16:08:50 -04:00
sergioandClaude Opus 4.8 9c99a78276 Etapa G: premasticado Go (fuel-go-3/4) — buffer de 40 al VPS de 4 cores
Premasticado (import+pin local, build en el VPS): 40 CLI Go k8s/devops/charm/
security: argocd/cosign/crane/trivy/trufflehog/vhs/soft-serve/k3d/kind/
kustomize/golangci-lint/goreleaser/air/stern/kubectx/helmfile/gomplate/...
Cola del VPS ahora ~83. Aprendizaje: Rust cola-larga de crates.io NO esta en
nixpkgs (0/7); Go es la veta (en nixpkgs, 100% yield). import-batch: usar -f
<file>, no args sueltos (zsh no splitea).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 14:55:23 -04:00
sergioandClaude Opus 4.8 465adc1374 Etapa G: fuel-go-2 + restos fuel-6+7 — recarga el VPS de 4 cores
Estrena el VPS repotenciado (CCX23, 4 cores/16GB, disco saneado 94->54%).
Cola 43: 28 Go nuevas (import 31/32 automatico is_go; age/sops/k9s/ffuf/
nuclei/gitleaks/dasel/vegeta/frp/chisel/lf/sttr/usql/subfinder/katana/...)
+ 15 restos Rust de fuel-6+7 (oxipng/grass/tokio-console/cargo-c/...).
syft/grype/gf a hold (vinieron de alpine, sin plantilla Go).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 14:29:20 -04:00
sergioandClaude Opus 4.8 b097782d1b Etapa G: cosecha fuel-go-1 — 21 CLI Go (repo 312->333), 100% yield
Primera cosecha Go a escala con el frente automatizado: import automatico ->
VPS construye 21/21 en paralelo (go cache-hit, sin race) -> cosecha trust-free
(of_tree identico cross-machine, p.ej. duf b3:1dbbedde laptop=VPS).

chezmoi/dive/duf/fx/fzf/gdu/glow/gobuster/gojq/go-task/grpcurl/gum/hey/jid/
lazydocker/lazygit/mage/mods/pet/skate/yq-go. Todos Go estaticos.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 13:31:26 -04:00
sergioandClaude Opus 4.8 0629d79cde Etapa G: fuel-go-1 — primera tanda Go con importador automatizado
22 CLI Go importadas 21/22 con plantilla Go automatica (deps.build=[go], sin
phases): chezmoi/dive/duf/fx/fzf/gdu/glow/go-task/gobuster/gojq/grpcurl/gum/
hey/jid/lazydocker/lazygit/mage/mods/pet/skate/yq-go. Smoke local: jid+fx OK.
Restos de fuel-6+7 a hold (retomar del store). glab descartado (vino de Alpine).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 12:45:19 -04:00
sergioandClaude Opus 4.8 8237635256 Etapa G: cosecha fuel-6+7 — 13 CLI-Rust (repo 299->312)
fuel-6: cargo-bundle-licenses/taskwarrior-tui/tenere/termsnap/the-way
fuel-7 (sistematico): cargo-ndk/cargo-sbom/espflash/grcov/maturin/
parallel-disk-usage/xwin/zizmor. El metodo crates.io entrego binarios reales.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 12:18:18 -04:00
sergio b06bdd4251 Etapa G: fuel-7 .patch acompañante a la cola 2026-06-26 11:36:39 -04:00