c33de600125129dc747085bf075a74bd7bb4cf70
981
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e6ab5a5016 |
atuq: la bóveda estaba SELLADA y en ninguna imagen — y estar en la imagen no es poder abrirla
El §7.novies dio la función por cerrada: las seis etapas del guardián de metal en verde, con el
navegador de verdad y el diálogo a la vista. Lo que seguía abierto era la decisión 1 del §7.sexies
—«en qué imágenes se declaran»—, escrita como NO mientras ninguna app llimphi pudiera pintar. Ese
motivo se cayó el 2026-09-18, así que antes de tomarla se volvió a medir en vez de darla por sabida:
atuq sealed perfiles=[cosmic, gnome, kde, sway]
puriy-costura sealed perfiles=[cosmic, gnome, kde, sway]
boveda sealed perfiles=[]
shuma-pregunta sealed perfiles=[]
`sealed` con `perfiles: []` es sellado ≠ instalado: la lección de `foot`, que targets.toml repetía
QUINCE veces antes de hoy y que igual volvió a morder. Las dos entran a los cuatro perfiles de
escritorio, las dos o ninguna —sin el dueño `vault.match` no ofrece nada; sin el diálogo,
`Command::new` falla y TODO `vault.fill` se deniega—: media bóveda es una que niega todo en
silencio. ~43 M por imagen (22 M + 21 M medidos), contra los ~1,25 GiB que ya lleva el §6.7.
Y al declararlas apareció el hueco de una capa más arriba: la receta instalaba `/usr/bin/boveda` y
nada más, y los lanzadores de los cuatro escritorios leen `/usr/share/applications`. La app viajaría
en la imagen sin existir para quien la usa — la misma forma de fallo que esto viene persiguiendo.
Entra `boveda.desktop`, con tres cosas medidas antes de escribirlo:
· el icono existe: `dialog-password` está en breeze-icons (6), adwaita (1) y cosmic-icons (2). El
cuarto perfil lleva sólo hicolor, que no trae iconos: ahí cae al genérico, que es degradarse;
· lo acepta el `desktop-file-validate` del store, con `atuq.desktop` de control. Deja un hint sobre
`Security`, y las dos formas de callarlo lo cambian por uno PEOR (dos categorías principales ⇒ la
app aparece dos veces en el menú). Se queda como está;
· ⚠ y lo que NO puede hacer: emparejar la ventana con el lanzador. `llimphi_ui::run` no llama nunca
a `with_name` ⇒ winit no manda `set_app_id` y la ventana sale SIN app_id y con el título
"llimphi". Por eso no hay `StartupWMClass`. Vale para toda app llimphi; se arregla en llimphi.
La receta se reconstruyó en el worker con la guarda del §7.quinquies puesta (`### receta verificada
3f1072cc` antes de compilar nada, porque el latido revierte la receta cada media hora y un acierto
de caché sobre la vieja imprime SELLADA en cero segundos): `b3:b0c6adc4` ⇒ `b3:3f1072cc`, 22 M, con
el árbol mirado por dentro y la entrada dentro del artefacto.
Y el guardián de coherencia pasa de CINCO lugares a SEIS: el sexto es `targets.toml` —quién DECLARA
al dueño en la imagen—, con control positivo (`atuq` tiene que estar, o el chequeo está leyendo el
campo equivocado) y su propio control negativo, el tercero. Probado en los dos sentidos: cuatro
perfiles en verde, y `--negative-control-perfil` en rojo.
Abierto, y dicho como lo que es: quién levanta la app con la sesión (atado a la decisión 2 del
§7.sexies, la raíz de las claves), y que el único proveedor de GL de las cuatro imágenes es iris
—mesa-llvmpipe en ningún perfil—, que la bóveda hereda y no agrega.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
2f9253886f |
tres arreglos que pidió el agente de adentro, y uno era mío
1) `publicar-webs.sh` corría como root y hacía el `git pull` igual: git dejó 24 entradas de root dentro del .git de /work/sergio/tawasuyu —refs, logs, config, directorios de objetos— y el dueño se quedó sin poder ni hacer `fetch` («unable to append to .git/logs/refs/remotes/origin/main»). El clon quedó congelado 21 commits atrás sin que nada fallara del lado de root. Ahora el pull va COMO EL DUEÑO, y los cuatro clones quedaron con sus permisos. 2) `cc-por-zig.sh` elegía el rust con `ls -d …/*-rust | tail -1`, que es el último ALFABÉTICO: certificaba `fe277b32…` mientras la jaula usaba el vigente `6441302d…`. Dos artefactos distintos, uno certificado y otro en uso. Ahora pregunta por el hash vigente de la receta y sólo cae al más reciente —con el nombre exacto— si no puede. Lo detectó el agente comparando los dos guiones. 3) `rustdoc` entra en `tools`: el artefacto salía con cargo y rustc y SIN rustdoc, o sea que en una caja takana `cargo doc` no existe. `docs = false` se queda —la documentación de la std es otra decisión, cientos de MB—. Radio medido: 0 dependientes de build. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
0f46c0976b |
atuq: un .pyc invisible movía el hash — el hub sellaba algo que un clon limpio no reproduce
Buscando si los cambios de atuq habían llegado a la caja apareció esto: el hub y el worker calculaban `b3:e556024b` y un clon limpio `b3:5156cb8f`, con los 52 ficheros versionados de `recipes/atuq/` byte a byte IGUALES en las tres máquinas y la receta con el mismo md5. La diferencia era un fichero de más: `tools/__pycache__/rebrand.cpython-314.pyc`, bytecode que dejó alguien al correr `rebrand.py` dentro del repo. Comprobado en los dos sentidos — metiendo y sacando ese .pyc en un clon limpio, el hash salta de `5156cb8f` a `e556024b` y vuelve. Lo traicionero es que `__pycache__/` está en `.gitignore`: el árbol se ve limpio en `git status` mientras el hash ya es otro. Y el artefacto sellado en el store era el de `e556024b` — o sea uno que un clon limpio no puede reproducir jamás. Es la regla 3 al revés: no un vacío que pasa por lleno, sino basura invisible que pasa por fuente. `ArtifactHash::of_tree` no sabe de `.gitignore`, y son dos cosas legítimamente distintas; pero hoy divergen por descuido y no por decisión. Queda escrito en la receta, con la comprobación barata al lado, para las cuatro que usan `source.dir`. El `.pyc` se barrió del hub y del worker: las tres máquinas ya convergen en `5156cb8f`. |
||
|
|
3b36e9df0a |
zsh: dejar de pedir install.info — fallaba siempre y sellaba un /usr/share/info VACÍO
`makeinfo` no está en el lab, así que `make … install install.info` moría con `/bin/sh: makeinfo: not found` ⇒ `Error 2` en TODOS los builds. Y el artefacto sellaba igual: las fases corren con `/bin/sh -c` sin `-e` (`takana-build/src/sandbox.rs:332,491`), o sea que un fallo a mitad de fase no aborta — sólo cuenta el estado del ÚLTIMO comando, que acá era el bucle de guardianes y daba 0. Lo que llegaba al store era un zsh por lo demás correcto (estático, con sus módulos, con `=~`) pero con un `/usr/share/info` vacío adentro. Es la regla 3 de CLAUDE.md a escala de fase en vez de artefacto: un ausente falla ruidosamente, un vacío llega hasta el final diciendo que todo fue bien. Lo que salvó al artefacto no fue el estado de salida sino los dos guardianes que la receta ya traía escritos a mano. Una receta sin guardianes propios no tiene esa red — eso es el hallazgo general, y va aparte. |
||
|
|
bd8f9fbbb2 |
atuq: la bóveda ANDA hasta la etapa D — y con el navegador abierto quedaba muda por un tercer fallo
Con el arreglo de llimghi sellado, el guardián de metal pasó de la A a la D:
A ✓ sin la app dueña, el host contesta locked:true (y con ok:true, que es la trampa)
B ✓ con la app, vault.status dice ABIERTA — el socket sube en 1 s
C ✓ el diálogo ABRE en el compositor y se lo CONTESTA: «1» ⇒ yes, «2» ⇒ no (los dos sentidos)
D ✓ vault.save con consentimiento real guarda, y vault.match la encuentra SIN contraseña
E ✗ el navegador pide la contraseña y no llega nunca
La E destapó un fallo que no es de atuq ni de llimphi: el dueño de la bóveda atendía de a UN cliente
—`atender_cliente` no vuelve hasta que el cliente se va, y se lo llamaba en el hilo del accept—, así
que la primera conexión se quedaba con él mientras viviera. Y el caso normal es ése: Gecko lanza un
`puriy-costura` por PUERTO, ocho en atuq, y todos conectan al arrancar. La extensión de la bóveda
mandaba `vault.match` y no volvía nunca: sin insignia, sin log y sin error, indistinguible de «este
sitio no tiene contraseñas».
Control sin navegador, en los dos sentidos: un solo cliente contesta en milisegundos; con otro host
conectado y quieto, la misma pregunta queda colgada y la mata el timeout a los 30 s.
Arreglado en tawasuyu (`cf3540460`, un hilo por conexión; los diálogos los serializa ahora el Mutex
de la bóveda) con su test de regresión, que además cazó que el arreglo obvio —clonar el Dueno— borra
el socket en el Drop del primer hilo que termina. Los siete tests que ya había no podían ver el fallo:
abrían un cliente por vez, que es justo lo que producción nunca hace.
⚠ Y subir el pin volvió a chocar con el `Cargo.lock` abierto de tawasuyu. Lo que importa para la
próxima es CUÁL operación lo cierra: `cargo metadata` sin `--locked` da **1 línea** de diff y cero
checksums movidos; `cargo generate-lockfile` da 6.305 líneas y 750 checksums, e invalidaría el
vendoreo de todos. Publicado en `b80f7567c` con índice temporal (estaba MM).
Del lado del guardián, tres cosas que salieron de fallar:
· el contestador INSISTE hasta que la ventana se va — con el mismo `wtype rc=0`, una corrida
contestaba y otra volvía `denied`: la ventana entra al árbol del compositor antes de que llimphi
tenga el teclado enganchado, y un sleep más largo sólo mueve el borde;
· el contestador busca la ventana POR PATRÓN: con el navegador abierto, teclear «la enfocada» le
contestaría a la página, y eso es un sí que nadie dio;
· la sonda del chrome mira `isShownForTab` y la insignia ANTES de apretar — `triggerClickOrPopup`
sale por la puerta de atrás si la acción no está mostrada, y un click que no llega se ve igual que
una bóveda que no contesta. (Y `WebExtensionPolicy` no es global en el scope de una ventana: sale
del módulo. Eso costó una corrida.)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
063200214c |
atuq: el muro de llimphi, arreglado en llimphi — y las dos recetas re-pineadas a ese commit
El §7.septies dejó el diagnóstico: sin display handle, el camino de escritorio de llimphi abre el display EGL surfaceless, la surface no tiene un solo formato y la app panica. El arreglo está empujado allá (`eed3120b6`) y son dos ficheros: `Hal::new_con_display` —que usa el `instancia_con` que YA existía para el camino layer-shell— y el llamador de escritorio pasándole la `window`, que estaba ahí, creada una línea antes para hacerle la surface. La pieza no faltaba: faltaba enhebrarla. Control antes de empujar, porque hasta reconstruir no se puede medir: `cargo check -p shuma-pregunta` pasa con el parche y FALLA con una rotura a propósito en la línea tocada — un check que no compila el fichero se ve igual que uno que sí. Commiteado allá con índice temporal (GIT_INDEX_FILE + commit-tree + push <sha>:main), que es lo único que publica dos rutas sin llevarse por delante los 181 ficheros que otra sesión tiene en vuelo; el control (`git diff-tree -r --name-only`) nombra dos. El primer push fue rechazado porque el remoto se movió: se rehízo el commit-tree sobre el FETCH_HEAD nuevo, comprobando antes que esos dos ficheros no habían cambiado allá. ⚠ Con esto el pin de las dos recetas DIVERGE del `23a292863` de sus once hermanas del monorepo, y eso cuesta un árbol de fuentes propio — otro vendoreo de 2,4 G, porque el árbol se comparte por `<repo>-<sha>`. Queda dicho en las dos recetas. ⚠ Y el sello todavía no está: las dos están encoladas en el worker detrás del build de rust. Hasta que sellen y la etapa B del guardián pase, esto es un arreglo compilado, no un arreglo medido. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f611751f86 |
atuq: el diálogo de la bóveda no abre, y el muro no es de la bóveda — ninguna ventana llimphi pinta
`boveda` (b3:59ffd74b) y `shuma-pregunta` (b3:99763eca) sellaron en el worker. Ninguno de los dos abre
ventana, y el error no habla de contraseñas:
panicked at llimphi-hal/src/lib.rs:1032: index out of bounds: the len is 0 but the index is 0
Esa línea es `caps.formats[0]`: la surface no tiene NI UN formato. La cadena, medida eslabón por
eslabón con RUST_LOG=wgpu_hal=debug:
No (or unknown) windowing system ((None, Some(..))) present. Using surfaceless platform
Trying native-render → No config found! · Trying presentation → No config found!
El `None` es `raw_display_handle`, y no es del arnés: es lo que llimphi hace A PROPÓSITO en su camino
de escritorio, con el comentario al lado («Sin display: este camino no tiene ventana todavía»). Sin
display handle wgpu abre el display EGL surfaceless, que no publica configs con WINDOW_BIT ⇒ la
surface no es presentable ⇒ cero formatos ⇒ panic.
No se nota en una máquina con Vulkan, porque ese camino elige Backends::PRIMARY y a Vulkan el display
no le hace falta. Y **ninguna imagen de takana tiene Vulkan**: las tres recetas de mesa se compilan
con `-Dvulkan-drivers=` vacío, y `vulkan-loader` sólo existe en incoming-kde sin que ningún perfil lo
declare (y un loader sin driver no es un driver). ⇒ toda app llimphi de escritorio cae al camino GL y
no puede abrir ventana. Reproducido en TRES binarios y dos versiones de wgpu: shuma-pregunta y boveda
(29) y llimphi-counter (27).
Los controles, porque la conclusión es fuerte: pedir Vulkan explícito da NoAdapter y no hay ICD ni
libvulkan en ninguna capa (la premisa está medida); con softpipe el fallo es OTRO y anterior —wgpu
pide compute shaders y softpipe se queda en GL 3.3—, así que llegar hasta acá ya exige llvmpipe; y el
compositor está levantado con su socket y su WAYLAND_DISPLAY.
Lo que esto dice del producto: el consentimiento de la bóveda no puede pedir permiso en ninguna imagen
de hoy, y como un lanzamiento fallido se traduce a «no» (Command::new falla ⇒ return false), el usuario
vería una bóveda que niega todo sin un solo error.
Se arregla en llimphi (que pase el display handle; la función `instancia_con` ya existe ahí al lado) o
con un driver Vulkan por software en el corpus. No se arregla en takana ni en el arnés.
Entra igual lo que sí se puede afirmar:
· `scripts/test-atuq-boveda-metal.py`, seis etapas declaradas, la A en VERDE — sin la app dueña el
host contesta locked:true, que es la medición del §7.sexies ahora vigilada. Cada etapa dice qué
afirma y la B nombra el muro en vez de dejar que se rediagnostique;
· `recipes/wtype.toml` — el corpus no tenía NINGUNA forma de meter una tecla en un compositor: todos
los arneses de scripts/wlr miran, ninguno toca. Sellado y en ningún perfil: es instrumento.
⚠ Y una trampa del arnés, mía, que costó tres corridas: exportaba GALLIUM_DRIVER=softpipe, o sea que
yo mismo lo clavaba al driver débil. mesa-swrast y mesa-llvmpipe se ven como dos nombres de lo mismo
—«mesa por software»— y la diferencia decide si el arnés existe.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
589c656262 |
atuq: la bóveda del navegador contesta CERRADA — faltaban el dueño y el diálogo, no el guardián
El §7.quinquies.bis cerró la unidad 12 diciendo que el guardián de METAL «ahora sí se puede escribir
porque hay con qué correrlo». No se podía, y la primera pregunta que ese guardián iba a hacer lo dice
en veinte segundos, contra el artefacto sellado y por marcos de 4 bytes:
← {"id":1,"ok":true,"verb":"ping","version":"0.1.0"} ← el control: el host ESTÁ
← {"id":2,"ok":true,"verb":"vault.status","locked":true,...}
← {"id":3,"ok":true,"verb":"vault.match","locked":true,"items":[]}
stderr: puriy-costura: sin bóveda (No such file or directory): los verbos vault.* dirán «cerrada»
Lo que engaña es el `ok:true`: **«cerrada» es una respuesta exitosa**, así que ningún log, ningún
reintento y ninguna insignia la distinguen de un usuario que todavía no desbloqueó la suya. Hoy, en
las cuatro imágenes de escritorio, atuq instala la décima extensión y la función está apagada.
Las dos mediciones del §7.quinquies eran correctas y lo siguen siendo —`strings` da `vault` 10 veces,
`vigia-atuq-verbos` da cero verbos sin dueño—, pero las dos preguntan si el host CONOCE el verbo.
Ninguna pregunta quién contesta del otro lado del socket: el host no abre la bóveda nunca, a propósito
(sled toma un lock exclusivo y el proceso que lanza el navegador muere con cada pestaña), así que le
habla a un DUEÑO — y el dueño no estaba en el corpus. Saber el verbo no es poder contestarlo.
Entran las dos piezas que faltaban, las dos con el mismo efecto de «se ve apagado y nada falla»:
`boveda` (pacha-boveda-llimphi, el dueño único de la base, que levanta el socket del navegador) y
`shuma-pregunta` (el diálogo que lanza `PorDialogo`; sin él `Command::new` falla y **todo vault.fill
se deniega**, indistinguible de que el usuario haya dicho que no).
Las dos pineadas al MISMO 23a292863 que ya comparten puriy-costura, shuma-* y pacha-* —un pin
distinto es otro vendoreo de 2,4 G— y con la forma de mirada-greeter, que es el patrón de una llimphi
GUI: link dinámico (winit/wgpu dlopean EGL/Vulkan/wayland) y la inyección de LOCKSTEP_XML_PATH que
evita el panic de zbus-lockstep-macros en el subdir xml/schemas/ de atspi.
⚠ El sello TODAVÍA NO ESTÁ: las dos están encoladas en el worker detrás del build de rust, bajo
`flock -o`. Hasta que sellen, estas recetas son una hipótesis escrita, no un artefacto medido.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
e49545e0a7 |
gcc-libs enviaba un ld script que pedía una librería que nadie tenía
`/usr/lib/libgcc_s.so` no es una librería: es un ld script —`GROUP ( libgcc_s.so.1 -lgcc )`— y ese `-lgcc` es libgcc.a, que ninguna receta del corpus proveía. Esta misma la borraba: el `find -name '*.a' -delete` de la poda, y de paso el `rm -rf /usr/lib/gcc` se llevaba el original. Medido en la caja con el rust recién sellado: los binarios estáticos compilan y corren, pero cualquier dylib —y eso incluye TODAS las proc-macros— muere con `unable to find library -lgcc`. O sea `cargo build` con `derive` imposible sobre takana, con el compilador perfecto. Y no alcanza con dar `-L /usr/lib`: con eso se resuelven `-lc` y `-lgcc_s`, y entonces aparece justo este `-lgcc`. Es la misma familia que el hueco que originó esta receta —todo presente, todo reproducible, y el camino que hace falta no existe—, sólo que del lado del ENLACE en vez del arranque. libgcc.a se copia a /usr/lib (donde el -L del enlazador ya mira; el gcc completo no está en esta distro) y se salva de la poda. Y entra un GUARDIÁN 3 que compara lo que el ld script PIDE contra lo que el artefacto TRAE: si vuelve a quedarse sin libgcc.a, corta. Radio medido con yupana antes de tocar: 7 dependientes directos, 9 transitivos, 7 imágenes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
2720253a41 |
rust: el enlazador pasa a ser gcc — dejo de tapar síntomas de la misma causa
Tres intentos persiguieron el mismo problema por partes: `-lgcc` no se encuentra, después `-lgcc_s` y `-lc` en los build scripts del stage2. La causa es una sola: un enlazador invocado SIN driver de C no conoce los caminos del sistema. Ese `-L /usr/lib`, el directorio privado de gcc y las libs implícitas las agrega `gcc`, no `ld`. Dárselos a mano es una lista sin fondo, porque cada etapa del bootstrap enlaza cosas distintas. Y el intento de dárselos por RUSTFLAGS (_BOOTSTRAP y _NOT_BOOTSTRAP) NO llegó a los build scripts: comprobado mirando el renglón de enlace, donde `/usr/lib` seguía sin aparecer. Así que la cura va donde corresponde: `linker = "gcc"` en el `[target.x86_64-alpine-linux-musl]` de bootstrap.toml. De paso, con gcc de driver los `-Wl,-rpath,…` del bootstrap vuelven a ser válidos —eran lo que había obligado a `rpath = false`, que se deja igual porque sigue siendo lo correcto con prefijo /usr—. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
7deb512425 |
rust: los build scripts del stage2 tampoco tienen /usr/lib en su línea de enlace
Con `-lgcc` resuelto, el build avanza y muere más adentro: los build scripts de libc, proc-macro2 y quote no encuentran `-lgcc_s` ni `-lc`. Mirando el renglón de enlace entero, sus únicos `-L` son sus propios directorios de build: NO lleva /usr/lib. El enlace de `std` sí lo llevaba —de ahí `musl-root = "/usr"`—, pero eso aplica al TARGET, no a los binarios de HOST que el bootstrap compila por el camino. Es la misma causa de las tres veces: sin driver de C, nadie agrega los caminos del sistema. Se los damos por RUSTFLAGS en las dos variantes que mira el bootstrap (_BOOTSTRAP para lo que compila el stage0, _NOT_BOOTSTRAP para stage1+). libc.so, libc.a y libgcc_s.so están los tres en /usr/lib del lab: comprobado, no supuesto. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
58930769d9 |
rust: el arreglo de libgcc iba en la fase que enlaza, no en configure
El primer intento dejó el enlace en `configure` y lo comprobó ahí mismo: la comprobación dio ✓ y el build murió igual, con el log mostrándolo con claridad cruel —«rust: libgcc.a enlazada desde /usr/lib/gcc/…» y, tres pantallas después, «ld.lld: error: unable to find library -lgcc»—. La causa es que LAS FASES NO COMPARTEN SISTEMA DE FICHEROS: cada una es un bwrap nuevo con `--tmp-overlay /`, que es una capa tmpfs DESCARTABLE (lo dice el propio comentario de sandbox.rs). El enlace se evaporó entre configure y compile. Un guardián que comprueba en la misma fase en la que escribe confirma algo que ya no será cierto cuando importe: lo que cambia el entorno de una fase se hace EN esa fase. Ahora va al principio de `compile` y de `install`, que son las que enlazan. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
5541900132 |
rust: -lgcc no se encuentra cuando el enlazador es ld.lld sin driver de C
El build muere a los 6 minutos enlazando libstd.so: `ld.lld: error: unable to find library -lgcc`. Es la otra cara de lo que la receta ya documentaba para `rpath = false`: al poner ld.lld como enlazador del triple, se invoca DIRECTO, y el `-L` del directorio privado de gcc lo agrega gcc, no ld. libgcc_s.so sí está en /usr/lib —por eso `-lgcc_s` pasa y sólo falla el estático—, pero libgcc.a vive en /usr/lib/gcc/<triple>/<version>/. Se enlaza a /usr/lib, que el propio renglón de enlace que falla ya busca. La ruta sale de `gcc -print-libgcc-file-name` y no escrita a mano a propósito: la versión es del LAB, que no entra en hash_inputs, así que una ruta literal se rompería en silencio el día que el lab mueva de gcc. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
a8077003c4 |
wireless-regdb: la base regulatoria del WiFi ya no viene en linux-firmware
`firmware-tigerlake` cortaba con «falta regulatory.db», y no era un fallo suyo: upstream sacó ese fichero del tarball de linux-firmware y hoy sólo se publica en su propio proyecto de kernel.org. Comprobado sobre el artefacto sellado de linux-firmware 20260910: `find -name "regulatory*"` no devuelve nada. Lo que pasa sin ella no es «no hay WiFi», que sería fácil de notar: cfg80211 arranca, la tarjeta asocia, y se queda en el dominio `world` —pierde canales de 5 y 6 GHz y emite a la potencia mínima—. Un WiFi que funciona y va mal. La receta NO compila nada: el `make` del proyecto regenera la db y la firma con otra clave, y el kernel valida contra la que lleva compilada, así que regenerarla la rompería. Copia `regulatory.db` y su `.p7s` tal cual, y corta si la firma falta —sin firma, cfg80211 ignora la base y volvemos al dominio world, que es justo lo que veníamos a arreglar—. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
a37485365c |
linux-firmware: los 337 enlaces «sin destino» eran mi comprobación, no el tarball
Los que faltaban son casi todos de la forma `ath11k/WCN6855/hw2.1/regdb.bin -> ../hw2.0/regdb.bin`: un `..` no resuelve si el directorio desde el que cuelga todavía no existe, y yo probaba el destino ANTES del mkdir. Con el directorio creado primero resuelven los 2415 de 2415 — medido sobre el árbol desempaquetado, no deducido. Queda dicho en la receta porque la lectura fácil era la contraria: «WHENCE declara enlaces a blobs que el tarball no trae», que habría llevado a bajar el umbral y sellar un artefacto con 337 firmwares inalcanzables. Y si el destino de verdad no existe, ahora se borra el directorio vacío que el mkdir haya dejado: un directorio vacío en el artefacto es exactamente lo que el §3 de CLAUDE.md prohíbe. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
d1032c0336 |
linux-firmware: los enlaces de WHENCE se encadenan, así que van en tres pasadas
Primer intento con el arreglo: 2078 de 2415 (86 %), y el guardián cortó. La causa es que WHENCE encadena —declara `a -> b` donde `b` es a su vez un enlace que aparece más abajo—, así que en una sola pasada el destino todavía no existe cuando toca crear el primero. Se repite hasta que una pasada no agregue nada, con tope de tres. Y ahora salta los que ya existen, para no recontar. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f7efbdb806 |
linux-firmware: los ~2400 enlaces que el tarball NO trae, y una aserción que envejecía mal
Dos defectos medidos el 2026-09-17 al construirla por primera vez en la caja. 1) La receta decía «cp -a preserva los symlinks internos, que es lo que el kernel espera». La premisa es FALSA: `find -type l` sobre el árbol desempaquetado da 0. Los ~2400 enlaces los crea copy-firmware.sh al instalar, leyéndolos de WHENCE, y esta receta evita ese script porque pide rdfind. El resultado habría sido un artefacto de 1,9 G, sellado y reproducible, con iwlwifi MUDO: el driver pide `iwlwifi-QuZ-a0-hr-b0-77.ucode` en la raíz y el blob vive en intel/iwlwifi/. Justo el metal al que apunta firmware-tigerlake (TigerLake/AX201) se quedaba sin WiFi. Ahora se crean desde WHENCE, cuyo destino es relativo al directorio del enlace, y sólo si el destino existe. 2) La aserción de completitud era `> 5000 ficheros`, medida sobre una versión vieja. La 20260910 trae 4889 y el guardián la rechazaba POR COMPLETA. Un umbral escrito a mano envejece y miente en la dirección cara: frena lo bueno y hace dudar del tarball, que estaba pineado por sha256 y era el correcto. Ahora se le pregunta a WHENCE, que viaja dentro del tarball y declara cuántos blobs hay. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
c8744ace18 |
zsh sella estático, con sus módulos y con =~ — y dos teorías mías que eran falsas
El primer build confirmó la predicción que la propia receta traía escrita: `link = "static"` salió
DINÁMICO, contra la libncursesw del lab, y moría con `Error relocating ... symbol not found` —o sea,
habría arrancado en el sandbox de Alpine y no dentro de una imagen—. La causa de fondo es que zsh
carga sus módulos con dlopen; por eso va `--disable-dynamic`, que los mete en el binario.
Pero `--disable-dynamic` solo dejaba un zsh sin `=~`:
zsh:1: failed to load module: zsh/regex
zsh:1: -regex-match not available for regex
Dos explicaciones mías fueron falsas antes de la buena, y quedan escritas en la receta porque las dos
son plausibles y costaron un build cada una: (1) «quedan en link=dynamic, hay que sedearlos a static»
—el sed no cambió nada, los disponibles ya salían static—; (2) «el .mdd evalúa $ac_cv_func_regcomp y
config.status no tiene esas variables, hay que exportarlas» —el configure contesta yes a las cuatro y
el módulo seguía fuera—.
Lo zanjó `configure.ac`, que no opina: con dynamic apagado, un módulo que su .mdd declara `dynamic`
se DESCARTA (link=no) y sólo los que declaran `either` pasan a estático. regex.mdd dice `dynamic` y
complete.mdd dice `either`: por eso había completado y no había `=~`. El arreglo va sobre los .mdd,
antes del configure, y sobrevive a que make regenere config.modules.
Además `--enable-pcre` era una etiqueta, no un hecho: zsh 5.9 sólo habla PCRE1 y el corpus tiene
pcre2; el configure lo decía tres veces. Se quitan la bandera y la dep, que mentían sobre el cierre.
Y el control va EN LA RECETA: la instalación corta si el ELF tiene INTERP o si falta alguno de
{regex, complete, zle, parameter} dentro del binario. Ese guardián es quien atajó los dos intentos
fallidos en vez de sellarlos. Medido sobre el artefacto: statically linked, 16 módulos cargan,
`=~` contesta, 1663 completadores, 14 M.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
7f95035332 |
git vuelve a clonar por HTTPS: la causa era el configure, no el Makefile
El git sellado no traía `git-remote-http` —ni `-https`, ni `git-http-fetch`— pese a tener `curl` en
[deps], y el artefacto mostraba la forma exacta que deja el Makefile cuando NO_CURL está puesto:
`git-http-backend` (el lado servidor, que no usa curl) presente y los tres helpers ausentes.
La causa estaba un paso antes. El tarball de git trae `configure` y takana lo corre; su
`AC_CHECK_LIB` enlaza `conftest.c -lcurl` y nada más, y con libcurl ESTÁTICA eso no resuelve: le
faltan `-lssl -lcrypto -lz`, que son sus privadas. El test falla en silencio, `config.mak.autogen` se
lleva `NO_CURL=YesPlease` y el build TERMINA EN VERDE sellando un git mutilado:
checking for SHA1_Init in -lcrypto... yes
checking for curl_global_init in -lcurl... no ← acá
checking for XML_ParserCreate in -lexpat... no
La cura son tres líneas: `LIBS="$(curl-config --libs)"` al configure (sale de curl-config, no escrito
a mano: si curl gana privadas mañana, las trae solo), `NO_EXPAT=1` porque con curl encendido el
Makefile agrega http-push.o y expat no está en deps, y un GUARDIÁN que corta si `config.mak.autogen`
quedó con NO_CURL=YesPlease — el modo de fallo es silencioso, así que se comprueba el HECHO.
Medido sobre el artefacto, no sobre el git del host: b3:215742cb… trae git-remote-http,
git-remote-https, git-http-fetch y los ftp; y CLONA por HTTPS de verdad —clone, no ls-remote, que es
donde murió la vez del ubsan—: árbol en disco y rev-list contesta.
Radio, medido con yupana: git tiene CERO dependientes transitivos ⇒ el re-sello no arrastra ninguna
reconstrucción. Toca las 7 imágenes que lo incluyen, que es otra cosa.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
80ee577b40 |
receta de shuma-tui: así se instala software de tawasuyu en la caja
Responde a «¿cómo instalo shuma-tui?». En gioser se instalaba con `actualizar-servidor.sh`: cargo build --release + install -m755 a /usr/local/bin. Eso deja un BINARIO SUELTO QUE NADIE PROVEE — la clase que la mudanza encontró irreproducible (2,7 G de ellos, §6.35). Acá el camino del corpus: receta pineada ⇒ takana build ⇒ artefacto sellado por hash ⇒ se instala desde el store o desde el repo firmado. El binario de mañana se puede volver a fabricar bit a bit; el de install -m755, no. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
e7b77ff657 |
la cuenta de sergio en la caja, su jaula propia, y shuma corriendo como él
Pedido: «crea mi cuenta sergio con la clave tawasuyu, desde ahí abrir los claudes como lo estoy
haciendo acá con shuma sobre los proyectos».
· cuenta `sergio` uid 1001 (el mismo que en gioser), home /home/sergio, clave verificada
· su propia jaula `claude-sergio`, que concede SU home —su `.claude`: credenciales y memoria— y
NO el de root. Con la instancia de root, sergio moría en «bwrap: Can't mkdir /root/.claude»
· `claude` elige instancia por usuario; `PROY=/otra/ruta claude` abre el agente sobre otro proyecto
· shuma-daemon y shuma-gateway pasan a correr como `sergio`, no como la cuenta de servicio `shuma`:
shuma es su CONSOLA, y cada pestaña que abre tiene que ser una sesión suya — si no, `claude`
buscaría una jaula `claude-shuma` que no existe
⚠ NO se eleva con doas/sudo: en esta caja el setuid NO TOMA («doas: Operation not permitted», con
NoNewPrivs 0 y `/` sin nosuid — queda como deuda entender por qué). No hace falta: `qorpa run`
levanta la jaula con user namespaces y anda sin privilegio, siempre que el directorio de la
instancia sea del usuario.
⚠ Y un detalle que costó una vuelta: sin `shift 2`, el HOME y el proyecto que el lanzador pasa como
posicionales se cuelan COMO ARGUMENTOS del agente — la primera sesión se abrió con el prompt
«/home/sergio», y el agente contestó, con razón, que eso es una ruta y no un comando.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
897b4eaf28 |
INTERCAMBIO de tejido hecho: la identidad cambió de máquina, no de dueño
Apagados en gioser (relay, serve y willay-crosscheck), encendidos en la caja: `tejido` en :4102 y `willay-crosscheck` en :4103, los dos alcanzables desde fuera. La prueba de que la identidad VIAJÓ no es que el servicio arranque —eso pasaría igual con semillas nuevas, que es el fallo silencioso que esto existe para evitar— sino que la semilla sea la misma: `device.seed` y `roster.postcard` con sha256 IDÉNTICO a los dos lados. El PeerId sale de ahí, así que sigue siendo 12D3KooWBw2u…. ⚠ LO QUE SÍ CAMBIA: el multiaddr que los clientes tienen configurado lleva la IP. antes /ip4/204.168.193.248/tcp/4102/p2p/12D3KooWBw2u… ahora /ip4/2.29.29.217/tcp/4102/p2p/12D3KooWBw2u… (mismo PeerId, otra IP) 🧱 SIN EL CORTAFUEGOS HABRÍA SIDO UN VERDE FALSO: el reglaset abría 80/443/1137/2345/22022 y nada más. Con el relay encendido y el 4102 filtrado, `status` diría «corriendo · 0 reinicios» y la flota no llegaría. Abiertos 4102 y 4103 con su ban por tasa; NO el 33097, que era el puerto efímero de un `tejido serve` cliente. Y el fichero quedó IDEMPOTENTE (crear+borrar la tabla antes de definirla), que era deuda del §6.33: 15 reglas dport antes, 21 después — no 36. ⚠ La política que genera ese reglaset NO EXISTE en ningún disco: ni la ruta que su cabecera nombra ni el binario `cortafuegos`. El generado sobrevivió a su fuente, así que hoy se edita a mano. 🆔 Y takana acepta ULIDs que arje-zero RECHAZA: la card no encarnaba por `invalid character`, y era la `L` de «RELAY» — carácter excluido del alfabeto Crockford. `service-cards` lo dio por bueno («26 alfanuméricos») y el consumidor lo tiró. El validador del productor más laxo que el del consumidor siempre termina en un fallo lejos de donde se escribió. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
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. |
||
|
|
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>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
201973b8f6 |
lld21: dinámico y con zlib — dos fallos que sólo se ven USÁNDOLO
El primer `lld21` selló, arrancó y se moría en cuanto hacía algo: `--version` y `--help` contestaban bien, y CUALQUIER enlace —incluso uno que sólo debía dar un error, como un fichero de entrada inexistente— terminaba en SIGSEGV con el banner de LLVM y un «Stack dump:» vacío. 🧨 Y no era culpa de esta receta: **las 79 herramientas que publica `llvm21` tienen el mismo defecto** —`llc --version` también crashea, y también en el worker— porque salen `static-pie` y el enlace estático descarta los constructores globales de los que dependen los registros de LLVM (`cl::opt`, `TargetRegistry`). Lo que funciona es lo que no los necesita (`llvm-ar`, `llvm-config`), y por eso nadie lo había visto: `rust` usa `llvm-config` y las `.a`, nunca una herramienta. ⇒ `link = "dynamic"` en esta receta (como `openssl-threads`, y por lo mismo: el flag global decide cosas que la receta no dice). Control en los dos sentidos: con `static`, SIGSEGV; con `dynamic`, `ld.lld: error: cannot open /no/existe.o: No such file or directory` — un error limpio. Y el segundo, ya enlazando de verdad con nuestro rustc: lld: error: …/self-contained/crtn.o:(.debug_line) is compressed with ELFCOMPRESS_ZLIB, but lld is not built with zlib support Los objetos `crt*` del sysroot de rust llevan las secciones de depuración COMPRIMIDAS. Para `llvm21` apagar zlib era gratis; para el ENLAZADOR no lo es. ⇒ `-DLLVM_ENABLE_ZLIB` encendido y `zlib` a las deps — copiar los flags del hermano sin preguntarse qué hace cada uno es lo que lo causó. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
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>
|
||
|
|
b7f70f37a8 |
rust: lld = true — el compilador que no podía enlazar ahora trae su enlazador
Muro 8, cerrado por la vía (a): el toolchain se construye su propio `rust-lld` en vez de depender de un `cc` que en una caja takana no existe. Lo que lo destraba es una línea del log que parece informativa: `skipping llvm-tools (…): external LLVM`. Al usar un LLVM externo —que es lo que queremos, porque `llvm21` es del corpus— x.py se salta las herramientas de LLVM, y `rust-lld` es una de ellas. El prebuilt oficial sí la trae, y por eso el escalón 1 enlazaba y el 2 no. Comprobado ANTES de encolar dos horas de build, leyendo el bootstrap y midiendo los artefactos: · el paso `Lld` compila desde `src/llvm-project/lld`, que YA VIENE en el tarball (1,1 G de fuente); · usa el `llvm-config`/cmake del LLVM EXTERNO y NO dispara un build de LLVM entero; · `llvm21` publica `lib/cmake/llvm/LLVMConfig.cmake`, que es justo lo que ese paso necesita; · `dist.rs` copia `rust-lld` al sysroot SÓLO `if builder.config.lld_enabled`; · y `llvm21` no servía de repuesto: sobre sus 1,6 G no publica NINGÚN `lld`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
ac856501b2 |
rust: el séptimo muro es el openssl de cargo — y va la variante CON THREADS
El parche del triple FUNCIONÓ: el build pasó el stage 2 —donde moría— y llegó hasta las herramientas.
Ahí cortó otra cosa:
error: failed to run custom build command for `openssl-sys v0.9.114`
The system library `openssl` required by crate `openssl-sys` was not found.
`tools = ["cargo"]` arrastra `openssl-sys`, y eso pasa DESPUÉS de compilar las ~400 crates del
compilador, o sea a la hora y media de build.
La dep que entra es `openssl-threads` y NO la canónica, aunque las dos publiquen sólo `.a`: el
`Configure` de openssl APAGA LOS THREADS en cuanto ve `-static` en LDFLAGS, y la canónica se
construye así. Un cargo —masivamente multihilo— enlazado contra un openssl sin soporte de hilos es
la clase de fallo que no se ve al construir ni al arrancar. La variante ya existía por exactamente
lo mismo para `python3`, y el worker la tiene sellada con el mismo hash.
Van también `OPENSSL_STATIC=1` y `OPENSSL_DIR=/usr`: el lab publica `.a` y ningún `.so`, y sin
decírselo `openssl-sys` busca la dinámica y falla con un mensaje que habla de pkg-config.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
24a6dd3b2f |
el cortafuegos puesto en la caja — y el primer baneado fui yo
`table inet tawasuyu_input` con policy drop, 15 reglas de puerto, y el set `ban4` llenandose solo: a los pocos minutos, 27 IPs baneadas y paquetes tirados por el contador. El reemplazo de fail2ban funcionando sobre trafico real, dentro del kernel y sin daemon. 🧨 EL PRIMER BANEADO FUI YO, EN SEGUNDOS. Aplicada la primera version: ssh y https bien, y `http`, proxy y git-ssh muertos; al minuto la caja entera dejo de contestarme. La causa no es una regla mal escrita: **el set @ban4 es UNO SOLO para todos los servicios** y `ip saddr @ban4 drop` esta antes que todo, asi que pasarse de tasa en UN puerto te tira en TODOS — y el `nuevas_por_min: 5` del puerto de administracion es exactamente lo que me pasa a mi, porque cada comando remoto es una conexion nueva. Lo devolvio el INTERRUPTOR DE HOMBRE MUERTO (un `nft flush ruleset` programado a 180 s que sólo se desarma si la verificacion externa sale bien). Sin consola serie, esa es la diferencia entre un susto y un rescue. ⚠ Y el tipo ya lo avisaba: `PoliticaEntrada` tiene un campo `confiables` cuyo comentario describe palabra por palabra lo que me paso. Copie el .ron de EJEMPLO en vez de leer el TIPO. La cura fue una linea con el hub y el worker, que se aceptan ANTES de la logica de tasa. ⚠ `nft -c` rechazo 5 reglas antes de aplicar nada: `ct count over N` es CONFIG_NFT_CONNLIMIT y este kernel no lo trae. Quedan COMENTADAS y no borradas en el fichero que se aplica — lo que la politica declara y el kernel no puede tiene que verse. El simbolo ya entro a la receta del kernel. Y para que sobreviva al reinicio, `nftables` declara su [[service]] con `lifecycle = "oneshot"`: cargar un reglaset no es un daemon, es un acto. Va PRIMERO en el genesis — entre que la red esta y que las reglas cargan, la caja esta abierta. Probado con `nft flush ruleset` + `arjectl start`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f57c18ab7f |
kernel con nf_tables: construido y verificado — y NFT_COUNTER ya no existe
`b3:63fdd57c…` sellado EN LA CAJA (gioser tiene 2 G disponibles y SWAP 0; el worker está horas con
rust) en 21 minutos. Los dos controles, sobre el `.config` SELLADO y no sobre la receta:
· lo que se quería encender: NETFILTER_ADVANCED=y, NF_TABLES=y, NF_TABLES_INET=y, NFT_CT=y,
NFT_LIMIT=y, NFT_LOG=y, NFT_REJECT{,_INET,_IPV4,_IPV6}=y, NFT_SYNPROXY=y.
· lo que NO podía romperse (el muro 1 del §6.4, que dejó una caja sin ver su disco): SCSI_VIRTIO=y,
VIRTIO_BLK=y, VIRTIO_NET=y, VIRTIO_PCI=y, SCSI=y, EXT4_FS=y. Los seis siguen.
⚠ `NFT_COUNTER` salió AUSENTE — y está bien: en 7.1 ese símbolo **ya no existe** (los contadores son
parte del core de nf_tables), así que no aparece en el `.config` ni como `# … is not set`. La línea
`-e NFT_COUNTER` es inerte y se deja escrita CON LA NOTA, porque sin ella el próximo que compare la
receta con el `.config` va a leer esa ausencia como un fallo. El comentario no re-hashea: el hash
sigue en `63fdd57c…`, comprobado.
El kernel nuevo queda EN `/boot/bzImage.nuevo`, al lado y no en su sitio, con el vigente copiado a
`/boot/bzImage.sin-nftables`. Hasta que alguien decida, la caja arranca lo de siempre — y ese
camino de vuelta es el único que hay: **hcloud no tiene consola serie**, así que un kernel que no
arranca se arregla con rescue + restaurar el bzImage, no apretando una tecla en el menú de grub.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
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>
|
||
|
|
0a7afebe9c |
la caja tiene HORA, LATIDO y ROTACIÓN — y el respaldo del gitea dejó de ser a mano
`planear.py --revisar` sobre el censo ordena lo que queda, y lo primero no eran los servicios del usuario sino TRES CAPACIDADES que ninguna metrica reclama: el disparador periodico, la hora y la rotacion de logs. Los tres paquetes ya estaban sellados y declarados en `perfil.servidor` desde que ese perfil nacio — lo que faltaba era el eslabon que los ARRANCA, igual que con squid. · `chronyd`: la caja iba **15 s atrasada** y nadie la corregia. Ahora stratum 3 contra los NTP de Hetzner, 0,000005 s de NTP. Sin hora no hay TLS ni firmas, y el sintoma no se parece a la causa. · `crond`: no existia el latido. Verificado con una entrada `* * * * *` en el crontab REAL. · `logrotate`: `/var/log/squid` sin rotar. Diario, con `squid -k rotate` (squid mantiene los ficheros abiertos: un rename a secas lo deja escribiendo en un inode que nadie puede leer). · `scripts/respaldo-gitea.sh` + `17 3 * * *`: cierra el hueco del §6.15 — los 44 repos vivian en UNA copia y el respaldo se hacia a mano. Sube 23+21 repos (1,5 G) y un `gitea.db` de 332 M tomado con `.backup`, consistente con el servidor vivo. El control no es que el script salga 0: es CONTAR los repos de los dos lados. `chrony` y `cronie` NO declaraban `[[service]]` — el paquete llegaba a la imagen y no lo arrancaba nadie. Ahora lo declaran (fuera de `hash_inputs`: los hashes no se movieron) y el perfil los habilita. TRES MEDICIONES que valen mas que el resultado: 1. **La deriva era de gioser, no de la caja**: despues de sincronizar, el HUB quedo 3 s adelantado. Medir «contra el otro» sin un tercero no dice quien esta mal. 2. **El spool de cronie es `/var/spool/cron/<usuario>`**, no `…/crontabs/<usuario>`: `crontab -l` mostraba las entradas y `crontabs/` estaba vacio. Un crontab restaurado en el sitio equivocado es un fichero perfecto que nadie lee. 3. 🧨 **`sqlite3` seguia INERTE en la caja** (`compressBound: symbol not found`): el ultimo de los 23 del §6.4. Le faltaba `zlib-shared`, sellado y declarado en `perfil.base` desde el 11-09 — pero la caja se instalo antes. Sin el no habia snapshot consistente. Un paquete declarado no es un paquete instalado: en una caja viva vale lo que el `upgrade` proyecto. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
b927eeffcb |
squid corre desde el corpus: la jaula duró unas horas y se tiró
`b3:932ba096…` proyectado en la caja y arrancado por arje SIN bwrap: `pid 11548 · uid=968 · exe=/usr/sbin/squid`, con la cuenta `proxy` que declara la receta. La instancia `qorpa/squid` se borró — el manifiesto es descartable por diseño (ADR 0015 D3) y esto es para lo que existía. El arreglo de esta tanda: **`--disable-log-daemon-helpers` compilaba perfecto y no arrancaba**. El default de `access_log` es `daemon:`, asi que sin `log_file_daemon` squid muere con `FATAL: logfile_daemon /usr/lib/squid/log_file_daemon: (2) No such file or directory`. Sellaba, hasheaba y pasaba `-k parse` — se ve SOLO levantando el servicio con la config real. Familia [[subcomando-sin-driver]]. El control que lo caza, y que corre en el hub antes de tocar produccion: con la config REAL del origen y en un puerto aparte, arranque completo + CONNECT a claude.ai y api.anthropic.com con TCP_TUNNEL/200 + el access.log escrito por el log daemon + `basic_ncsa_auth` leyendo el `passwd` de verdad (control negativo: clave mala ⇒ `ERR Wrong password`). Los DOS primeros intentos de esta receta habrian llegado a produccion sin ese control: el binario estaba sellado y el hash era estable las dos veces. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
a394dda26a |
receta: squid 7.7 entra al corpus — y el --export-dynamic que desactivaba el estático
`b3:54070b26…`, 8,8 M, **estático de verdad** (binario y los tres helpers), y probado con la CONFIG REAL de produccion: parsea sin FATAL, tunela `CONNECT claude.ai` y `CONNECT api.anthropic.com` con TCP_TUNNEL/200, y su `basic_ncsa_auth` lee el `passwd` de los tres usuarios (control negativo: con una clave mala contesta `ERR Wrong password`). Es la respuesta definitiva a lo de ayer: el proxy se levanto primero en una jaula qorpa porque estaba EN USO y eso lo destrabo en minutos, pero squid es C++ y el lab lo construye. La diferencia con php-fpm importa: PHP no queremos que entre al corpus, squid si. ⚠ LA FUENTE NO SALE DE squid-cache.org: esa URL devuelve **200 con una pagina HTML de 8985 bytes**, no el tarball. Pinear su sha256 habria anclado la receta a una pagina de error. Va el release de GitHub, que ademas trae `configure` ya generado. 🧨 EL MURO, y es del lab: el primer sellado salio con `usr/sbin/squid` **dinamico y `NEEDED libc.so`** mientras sus helpers salian estaticos — o sea inerte en cualquier imagen sin cargador ([[needed-colgante-libstdcxx]]) pese a `link = "static"`. La cadena: `squid_LDFLAGS` trae `-export-dynamic` (para modulos eCAP, que estan apagados) ⇒ **el wrapper del lab quita `-static` de cualquier enlace que mencione `--export-dynamic`**, a proposito, para poder enlazar las `.so` dlopen-ables de Python y companhia. Y no alcanza con sacarlo de la variable: **libtool lo vuelve a anhadir solo** en cuanto hay un `-dlopen`. Se vacia `export_dynamic_flag_spec` en el `libtool` GENERADO (local al build, sin tocar la fuente) y con guarda: si el campo no aparece, aborta — un `sed` que no acierta deja pasar el problema y el binario sale dinamico sin que nada falle. ⚠⚠ Y `-dlopen force` NO sobra, aunque lo parezca: vaciar `squid_LDFLAGS` entero rompe el enlace con `undefined symbol: lt__PROGRAM__LTX_preloaded_symbols`, que emite el propio libtool **porque hay un `-dlopen`**. De los dos flags, el que estorba es uno solo. Distinguirlos costo un build; adivinar cuesta lo mismo y no ensenha nada. Declarado en `perfil.servidor` como paquete Y en `servicios`, con su `[[user]] proxy` y su `[[service]]` (SDD 30) — que comprueba la config del sitio y la cuenta, y sale 78 nombrando cual falta en vez de dejar un bucle de reinicios. El hash NO cambio al declararlos: `[[user]]` y `[[service]]` estan fuera de `hash_inputs`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
1e0e249d44 | Merge remote-tracking branch 'origin/main' | ||
|
|
dbfb7d492b |
la jaula no viajaba en NINGUNA imagen: bwrap y harkaq-exec entran a perfil.base
Mudando `api.sergio.gioser.net` a la caja de produccion, `takana qorpa provision` aborto:
Error: no encuentro harkaq-exec en /root/.cache/harkaq/harkaq-exec
construilo: gcc -O1 -Wall -static -o ... scripts/harkaq/harkaq-exec.c
El mensaje es bueno y la receta que propone es IMPOSIBLE de seguir: en una caja instalada no hay
gcc, ni `scripts/`, ni arbol de desarrollo. El binario solo existia como un `gcc` a mano en la
cache de `$HOME` del hub, o sea que la jaula del ADR 0015 funcionaba unicamente en la maquina
donde alguien la habia compilado.
Y su companero estaba igual, medido en `build-state.json`: `bwrap` sellado desde hace meses con
`"perfiles": []` — CERO perfiles. Lo invocan por PATH tanto `qorpa` como el sandbox de
`takana build` (`takana-build/src/sandbox.rs`), asi que **ninguna imagen de takana podia enjaular
nada, ni construir**. Es [[subcomando-sin-driver]] un piso mas abajo: el CLI que los llama viaja
en todas las imagenes y sus herramientas en ninguna.
Tres piezas:
· `recipes/harkaq-exec.toml` — nueva. Estatico musl, `b3:cd34954f...`, 269 K. El pin va al commit
que toco la FUENTE (`1d9ddcee`, 2026-09-03) y no a HEAD: el `.c` no se mueve desde entonces y el
repo commitea cada media hora por el cron de la cosecha — pinear HEAD re-hashearia la receta cada
media hora sin que su fuente cambiara. La fuente sigue en `scripts/harkaq/` y no en un arbol
propio porque tres scripts la compilan desde ahi y dos copias divergen en silencio.
· `qorpa.rs` — busca el binario tambien en `/usr/bin`, que es de donde sale en cualquier maquina
que no sea el hub. El orden es HARKAQ_BIN (lo que el operador declara) → arbol de desarrollo →
paquete, para que un cambio en la jaula se pruebe sin instalar nada. Y el error ya nombra las
dos salidas, no solo la del hub.
· `targets.toml` — los dos en `perfil.base`.
Medido en la caja de produccion tras aplicarlos: `bwrap 0.11.0` + harkaq-exec responden, y
`takana qorpa provision sergioh-api` instala python 3.14.7 con pacman DENTRO de la jaula
(`[harkaq] jaula puesta: ABI 9`). El 3.14 no es casualidad: el venv de gioser trae extensiones
`cpython-314-...-gnu.so`, asi que la imagen de Arch pineada da la misma serie.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|