rustc desde fuente está compilando el stage1 en el worker. El documento recoge el frente entero: el
hueco medido (12 crates y 42 555 líneas de Rust, 44 recetas `cargo-*`, CERO de rustc, y el `rustc`
que construye todo eso saliendo del LAB — que ENTRA en el ArtifactHash), los tres escalones, y lo
que costó cada uno.
Los cinco muros del escalón 2, todos con un mensaje que no nombra la causa:
1. `llvm18` no sirve: `bad LLVM version, need >=21`. Mínimos medidos en el propio bootstrap
(1.87→18 · 1.90→19 · 1.93/1.95→20 · 1.97→21). Bajar de rustc no es salida porque el stage0 de N
es N-1 o N. De ahí `llvm21` — y `llvm18` se queda, que lo usa mesa.
2. **El toolchain musl oficial no puede producir proc-macros** (crt-static=true ⇒ sin dylibs):
muere compilando el propio bootstrap de rustc, que usa `clap` con derive. Sirve para compilar
programas, no para arrancar el build de rustc. El stage0 es el del lab.
3. x.py DESCARGA el stage0 si no le nombras el local: en un sandbox sin red, `RuntimeError: failed
verification` en `download_toolchain()`, que no menciona ni la red ni el stage0.
4. El triple de Alpine no es el canónico: sin fijarlo, la sección `[target.…-unknown-…]` no aplica a
nada y x.py se pone a construir LLVM solo; forzando el canónico, el stage0 no tiene su std.
5. cmake + zig = «compiler broken» en la prueba de ABI. CC=gcc, igual que llvm21 y cmake.
Y del escalón 1, lo que no estaba en el grafo: el prebuilt no ejecuta sin `musl-shared` (cargador) y
sin `gcc-libs` (`libgcc_s.so.1`) — dos paquetes sellados y en el perfil equivocado. Más una
propiedad que vale: no hace falta un `cc`, el toolchain trae su propio lld.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
Ordenando el protocolo numerado en los dos sentidos: cosmic-comp manda
configure_bounds(0,0)+configure(0,0) («elegi vos»), el cliente contesta
set_min_size(117,37), set_max_size(348,16332) y set_window_geometry(117,70),
y RECIEN ahi el compositor devuelve configure(117,70) teniendo 1280x692
para dar. No hay nada que arreglar en COSMIC.
El MOZ_LOG dice como: «Initial resize to 1 x 1» — Gecko crea la ventana de
1x1 y nunca la agranda; 117x70 es lo que queda cuando el chrome se mide a
si mismo. El frente se mueve a Gecko.
Las otras tres recetas cgo (sq, usql, gitea) dan DERIVA, no no-determinismo: sus dos
reconstrucciones coinciden entre sí y el artefacto guardado era el de antes del arreglo.
Ya están al día.
Y de paso se les fue una deuda que NO era de reproducibilidad sino de PORTABILIDAD: el
`x_cgo_sigaction` de sq y usql —código C de cgo, sin guarda de CPU en runtime— venía con
AVX2 horneado, de cuando el driver pisaba el `-mcpu=baseline`. Un binario así no falla al
construir ni al sellar: falla al EJECUTAR en una CPU sin AVX2, con SIGILL. Ahora los tres
salen baseline (cero ymm, cero zmm en esa función).
── El límite del libro, anotado en su encabezado ──────────────────────────────────────
`gocryptfs` acabó con CUATRO filas al MISMO hash: dos NO-DETERMINISMO y dos reproduce, y
las cuatro son ciertas. La clave (receta, hash) no puede distinguir antes y después de un
arreglo del FRAMEWORK, porque la fase generada no entra en `hash_inputs` — a propósito,
para no re-sellar 362 recetas cada vez que se toca un driver.
Corolario, que es lo caro: tras tocar un driver, lo sellado NO se rehace solo. Hay que
forzarlo receta por receta, y si nadie lo hace el store se queda con artefactos que ya
nadie construiría así.
`gocryptfs` era el último no-determinismo vigente del corpus. Ya REPRODUCE.
── La medición, que primero hice mal ──────────────────────────────────────────────────
Comparé los dos ficheros de `store/.divergen/` y salían 1.874.136 bytes distintos, con
`.text` entre ellos y funciones de OpenSSL cambiando de AVX2 a AVX-512. Era el par
EQUIVOCADO: `.divergen/<D>` es el artefacto VIEJO archivado, no una reconstrucción. El
par que define el veredicto es `<D>.r1` (1ª reconstrucción) contra el que queda en el
store (2ª).
Comparado bien, el no-determinismo son **7 bytes, todos en `.debug_str`**: los dígitos
de `go-build598798091` contra `go-build270591055`.
(Lo de AVX no era ruido: era DERIVA real contra el artefacto viejo, sellado antes de que
467a87cd pusiera `-mcpu=baseline` en el CC de cgo. Se trata aparte, abajo.)
── La causa ───────────────────────────────────────────────────────────────────────────
`-trimpath` reescribe rutas, pero cuál gana depende de dónde esté el work dir de Go:
dentro del módulo gana la reescritura del módulo y el componente ALEATORIO sobrevive;
fuera, Go reescribe el work dir entero a `/tmp/go-build` y el número desaparece. El
driver ponía `GOTMPDIR=/src/.gotmp`, que es justo dentro del módulo.
Con CGO off da igual —no hay fuentes C generadas, ninguna ruta del work dir entra en el
DWARF— y por eso las 15 recetas Go puras verificadas reproducen. Con cgo sí entra. Por
eso el cambio va acotado a `cgo = true`: las otras 358 no lo necesitan.
── Medido en los dos sentidos, con un módulo cgo de juguete y cachés limpias ─────────
· GOTMPDIR dentro ⇒ `go-build3806217352` en el binario; dos builds DIFIEREN
· GOTMPDIR fuera ⇒ ninguna cadena `go-build`; dos builds IDÉNTICOS
Y sobre gocryptfs de verdad: DERIVA primero (las dos reconstrucciones ya coincidían
entre sí y el guardado era el viejo), REPRODUCE en la pasada siguiente. En el binario
sólo queda `/tmp/go-build`, el marcador constante de trimpath.
── Va a `/cache` y no a `/tmp`, y se COMPRUEBA que exista ─────────────────────────────
El sandbox monta `--tmpfs /tmp` (~½ RAM) y un proyecto Go grande lo desborda: ésa era la
razón de poner esto en `/src`. `/cache` es un bind RW a disco (el de la caché de zig),
así que conserva el disco y queda fuera del módulo.
Y no se da por hecho que esté: con `--tmp-overlay /` la raíz es escribible, así que un
`mkdir -p /cache/gotmp` a ciegas TRIUNFARÍA creando el directorio en la capa tmpfs —en
RAM, el desbordamiento que se quería evitar, y en silencio. Si el bind falta, el build
muere diciéndolo.
`grep NO-DETERMINISMO` daba 3 y sugería tres problemas abiertos. Dos ya no existen:
kirigami y syntax-highlighting se arreglaron el mismo día y sus filas están clavadas
al hash VIEJO, que es justo lo que la clave (receta, hash) hace bien — pero quien
cuenta líneas no lo ve.
Se deja el veredicto medido intacto y se añade a qué hash fue superado. El único
no-determinismo VIGENTE al hash de hoy es `gocryptfs`, que no está en ningún perfil.
Los dos ya reconstruidos contra el syntax-highlighting arreglado.
REPRODUCEN 2 · DERIVA 0 · NO-DETERMINISMO 0.
Sellar de nuevo no demuestra nada por sí solo: lo que cierra el arreglo es que el
árbol reconstruido REPRODUZCA.
Como cosmic-comp no emite DEBUG (macros compiladas fuera), se le pregunto
por el protocolo con WAYLAND_DEBUG=1. Manda configure_bounds(0,0) al
mapear, despues bounds(1280,692) y configure(117,70): la ventana queda de
117x70. El pixel lo confirma — restando el cuadro de antes aparece un
cluster de 286x86 con la decoracion de COSMIC en (496,115).
Cae la hipotesis del §6.10.nonies: hay 43 wl_callback.done, o sea que SI
hay frame callbacks. Y la tasa 2 de 10 no medía «pinto/no pinto» sino
«ventana grande / ventana de 117x70».
Arnes: --wayland-debug y --set-rust-log (perilla por /etc/cosmic-mode, que
cosmic-start lee antes de RUST_LOG); margen de espera 420->780s porque con
carga ~13 la VM no llegaba al shell.
El arreglo movió el hash (4c1638a0… → 3db73c19…) y con él sus 4 dependientes
directos y 5 transitivos: kate, ktexteditor, plasma-desktop, plasma-workspace y
powerdevil. Comprobado aparte del log: para las seis existe
`store/<hash-de-hoy>-<nombre>`.
⚠ `kate` falló en el primer intento con «No space left on device» y esta vez NO era
el disco: `/mnt/vvv` tenía 15 G libres. El que se agotaba era un **tmpfs**, y un
tmpfs sin sitio significa RAM sin sitio — la caja tenía 855 MB disponibles, zram ya
con 6,3 G, otro agente compilando Rust y un QEMU encima. Al reintentar con 1,7 G
disponibles construyó en 242 s a la primera.
Que el mismo mensaje signifique dos cosas distintas —disco lleno o RAM llena— es
justo lo que hace caro el diagnóstico: hay que mirar QUÉ sistema de ficheros, no
sólo `df` del que uno tiene en la cabeza.
`rustc 1.97.0` y `cargo 1.97.0` responden en `2.29.29.217`, y un `fn main(){println!("ok");}`
compila y **corre**. El toolchain oficial de rust-lang, verificado por su sha256 y sellado tal cual
con `foreign = true` (son bytes ajenos, no un build nuestro: clase `ajeno`, fuera del recuento del
corpus).
Lo que costó hacerlo correr, y ninguna de las dos cosas se ve en el grafo porque las dos estaban
`sealed` y en el perfil equivocado:
1. **El cargador musl.** `rustc` es PIE dinámico (`NEEDED librustc_driver-*.so`, `NEEDED libc.so`).
En el worker ni arranca —`cannot execute: required file not found`, que es como se ve la falta
del intérprete—; en la caja sí, porque ahí está `musl-shared`.
2. **`libgcc_s.so.1`**: `Error loading shared library … _Unwind_Resume: symbol not found`. Lo
publica `gcc-libs`, sellado y declarado **sólo en los cuatro perfiles de escritorio**. Una línea
en `base`. Es la tercera vez HOY que aparece la misma figura —`tar`, `os-release`, `gcc-libs`—:
el paquete existe, está sellado, y no viaja en la imagen que lo necesita.
Y una propiedad que vale anotar: **no hace falta un `cc`**. El primer `rustc` falla con
`linker \`cc\` not found` y no hay que traer un compilador de C — el toolchain **trae su propio
lld** (`rustlib/<target>/bin/rust-lld`), y con `-C linker-flavor=ld.lld -C link-self-contained=yes`
enlaza y el binario corre. Una distro sin compilador de C puede compilar Rust igual.
Va en `perfil.servidor` y no en `base`: son 799 M y una imagen de escritorio no compila nada.
Pendiente, que es config del SITIO y no de la receta: que esas flags sean el default
(`/etc/cargo/config.toml`), para que `cargo build` funcione sin recordarlas.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
EL LOGO. El usuario pasó el PNG oficial. El ASCII no se inventa: se MIDE. Extraído celda por celda
del original — bbox 348×348 en un lienzo de 512, cuadrícula **7×7**, celda de 49,7 px — con cuatro
colores exactos y ninguno más:
#a63a25 ladrillo · #df6b2a naranja · #e3a63d dorado · #fff6de crema
La primera versión que puse era un martillo dibujado a ojo: era *un* martillo, no *el* logo. Cada
celda son DOS caracteres de bloque porque un carácter de terminal es alto y angosto, y `██` es lo que
conserva la geometría cuadrada del original; reconstruirlo a ojo la pierde y deja de ser el logo.
Van los dos ficheros: `logo.png` (el oficial, tal cual) y `logo.txt` (el mismo en ANSI de color
verdadero), más la config global de fastfetch con `file-raw` — con `file` los escapes se imprimirían
como texto. Y `os-release` se mueve de `cli` a **`base`**: toda imagen de takana debe saber decir qué
es, incluida la más pelada. «No sólo para esta máquina, para siempre en takana».
De paso, dos cosas que sólo se ven construyendo: `cp -a` aborta en el sandbox («failed to preserve
ownership»), va `cp -r`; y un config de fastfetch que sólo define `logo` dibuja el logo y NI UN DATO
— `modules` hay que listarlo aunque parezca redundante.
RUSTC, PASO 1. `rust-toolchain-bin` 1.97.0, el tarball oficial de rust-lang verificado por su sha256
y sellado tal cual, con `foreign = true` porque son bytes ajenos y no un build nuestro (clase
`ajeno`: no infla el recuento del corpus, ADR 0015). Target **musl**, no gnu: un toolchain gnu
traería el cargador de glibc y sería needed-colgante otra vez.
Por qué importa, y no es gusto: TODO el instrumental de takana es Rust —12 crates, 42 555 líneas— y
el `rustc` que los construye sale del LAB, un rootfs ajeno que ENTRA en el ArtifactHash. La distro
depende de bytes de otro para reconstruirse a sí misma. Y el corpus tenía **44 recetas `cargo-*` y
CERO de rustc**: subcomando-sin-driver a escala de toolchain.
Es el paso 1 de tres, y los otros dos no son opcionales: (2) rustc desde fuente con el `llvm18` que
YA está sellado (379 M), y (3) la cadena mrustc→1.91.1 que ya existe documentada en el selfhost pero
vive en el bootstrap, no en el corpus.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
`qorpa pull` de un `.tar.zst` moría imprimiendo **la ayuda de busybox** y un exit 1: ni una palabra
sobre `--zstd`, que es la opción que no entiende. El código ya elegía el descompresor por MAGIC y
pasaba las flags correctas; lo que faltaba era un `tar` de verdad.
Dos arreglos, y el segundo es de una línea:
· `untar` comprueba `tar --version` y, si no es GNU, ABORTA nombrando la causa y el arreglo. Diez
minutos de diagnóstico se vuelven una línea.
· **`tar` (GNU) entra en `perfil.base`.** Estaba sellado desde hace meses y declarado en UN solo
perfil (`escritorio-kde`). Es la lección de `foot` otra vez: el paquete existe y no viaja en la
imagen que lo necesita. Ya había costado dos veces — la caja tampoco podía desempacar su propio
LAB por lo mismo.
Y el logo: fastfetch dibujaba **el pingüino genérico de Linux** porque elige por el `ID` de
os-release y no conoce `takana`. Ahora la receta `os-release` publica también
`/usr/share/takana/logo.txt` (un martillo, que es lo que significa el nombre en quechua) y
`/etc/xdg/fastfetch/config.jsonc` — la config GLOBAL por XDG, no la de un usuario. Van en la receta
de la IDENTIDAD y no en la de fastfetch a propósito: mañana el que dibuje puede ser otro programa y
el logo seguirá siendo el mismo fichero.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
**curl ya valida**: `ca-certificates` re-sellado con **119 hash-links en el capath**, generados en el
build, y la caja baja por HTTPS sin apaño (200). Tardó tres intentos y los dos primeros los cazó la
guarda de la propia receta: `c_rehash` no estaba en el PATH (lo instala esa misma receta en
`/out/usr/bin`) y los certificados no están sueltos en `usr/share/ca-certificates/` sino en
`mozilla/`, así que sólo veía el bundle y lo saltaba —correctamente— con «does not contain exactly
one certificate». Sin la guarda habría sellado un capath vacío las tres veces.
**fastfetch 2.68.1 corre en la caja** (pedido del usuario) y al correrlo destapó que
**`/etc/os-release` no existía**: la distro era anónima para cualquier programa que no fuera suyo.
Ahora `OS: takana x86_64`. Va como receta propia (`source.dir`) y no como constante de
`takana-bootstrap`: meterlo ahí re-sellaría el product-rootfs —el baseline del selfhost— por cinco
líneas. Sin VERSION_ID ni fecha: un sello con la fecha del build cambiaría el hash cada día sin
motivo, y con él la clausura de toda imagen que lo lleve.
🧨 Y el hallazgo estructural: `upgrade apply` falló dos veces con **No space left on device teniendo
3 G libres en la raíz**. No era `/` ni los inodos (9%): el estado de generaciones vive en
**`/var/lib/hammer`, que es sda3 y mide 487 MB** — la partición «estado» del layout. Cada generación
guarda una copia del árbol aplicado (272 MB el nuestro), así que dos no caben. Movido a `/work` por
symlink, igual que qorpa, y la generación 6 entró. El layout de la imagen necesita revisión: 512 MB
no alcanzan para un mecanismo que guarda un árbol por generación, y el síntoma apunta al sitio
equivocado.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
**minga con su daemon escuchando.** Decisión del usuario: minga es la ventana oficial al mundo y git
queda como espejo de compatibilidad, así que el daemon no es opcional — es el punto de entrada. El
binario ya está sellado (`b3:121cf4a8…`, 22 M, static-pie) y ahora trae su `[[user]]` (uid 970, home
`/work/minga`: en la raíz no cabe y `/work` sobrevive a un re-`dd`) y su `[[service]]`:
`listen /ip4/0.0.0.0/tcp/4001` — la convención libp2p, libre en la caja (ocupados: 22022 admin,
2345 git-SSH, 3002 gitea en loopback, 80/443 caddy). Declarar ambos **no movió el ArtifactHash**.
⚠⚠ **La identidad no se sella ni se inventa.** El keypair lo genera el usuario con `minga init`;
tawasuyu avisó de que el suyo era provisorio. Si la card hiciera un `init` automático, la caja se
inventaría su identidad soberana en el primer arranque y todo lo que se firme después colgaría de
ella. La guarda comprueba que el repo exista y sale 78: un peer sin identidad decidida es peor que
un peer ausente.
**fastfetch** (2.68.1) entra al corpus y a `perfil.cli` — lo heredan servidor y los escritorios.
Receta CMake con `-DCMAKE_LINK_DEPENDS_USE_LINKER=OFF` (sin eso el lld de zig segfaultea y el error
no nombra a zig) y con la detección opcional APAGADA explícitamente: con `link = "static"` no hay
`dlopen`, y una detección que entra «porque la librería estaba en el lab ese día» produce artefactos
distintos bajo el mismo nombre.
Y `ca-certificates`: el rehash se llamaba por nombre y **`c_rehash` lo instala esta misma receta en
`/out/usr/bin`**, no está en el PATH del sandbox. Se invoca por su ruta. La guarda que añadí ayer
hizo su trabajo: el build falló ruidosamente en vez de sellar otra vez un capath sin índice.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
Al traer la primera imagen ajena, la caja falló con «curl failed to verify the legitimacy of the
server». El certificado del servidor estaba bien; lo que falta es de este lado:
* CApath: /etc/ssl/certs
* SSL certificate ... unable to get local issuer certificate (20)
$ curl --cacert /etc/ssl/certs/ca-certificates.crt ... → 200
El curl del corpus se compila con `--with-ca-path=/etc/ssl/certs` y SIN CAfile, y ese directorio
tiene un solo fichero: el bundle. Un capath necesita hash-links (`c_rehash`) — el ÍNDICE — y no los
hay. Los certificados están; el índice no.
Por qué faltan: la receta deja el hook `/etc/ca-certificates/update.d/certhash`, que en Alpine
ejecuta `apk` al instalar. **En takana no lo ejecuta nadie**: la distro proyecta artefactos, no corre
post-install. Todo presente, y el paso que lo conecta no existe.
Alcance: no es sólo `qorpa pull`. Es `install --repo https://…`, el mirror y cualquier curl/wget de
una caja instalada. No falla al construir ni al instalar: falla la primera vez que la máquina intenta
bajar algo. No se había visto porque el hub usa el curl de Artix.
Arreglado en la receta: los hash-links se generan EN EL BUILD (donde c_rehash y perl existen) y
viajan en el artefacto, con una guarda que falla ruidosamente si el rehash no produce ninguno.
Re-sella `ca-certificates`, raíz de `perfil.base`. Apaño mientras tanto: `CURL_CA_BUNDLE=…` (200).
Y el estado de qorpa en la caja: preflight de «BLOQUEA 1 · LIMITA 4» a «LIMITA 1» — qorpa movido a
/work (la raíz tenía 3 G), subuid provisionado y `setcap` aplicado a newuidmap/newgidmap SIN tocar el
artefacto del store (inodes distintos: en una caja instalada esos binarios son copias). El pull baja
y verifica el sha256, y muere al desempacar: el rootfs de Arch es `.tar.zst` y el `tar` de la imagen
es el de busybox. `qorpa pull` necesita `zstd -dc | tar -x` para `.zst`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
Antes de tocar `sergio.gioser.net` apareció lo urgente: CINCO procesos vivos cuyo binario ya no
existe en disco (`/proc/<pid>/exe` → «(deleted)»). Sólo vivían como inode huérfano: si el proceso
muere o la máquina se reinicia, se pierden. Es el «paso que caduca» del SDD 29, caducando de verdad.
tejido · sandokan-mcp · pacha-secretos · puerta-f6e393ffbef3999e · shuma-gateway (240 M)
Recuperados leyendo `/proc/<pid>/exe` con el proceso vivo, y ya están FUERA de gioser: en
`/work/rescate-binarios/` de la caja y en el Storage Box. Cinco de los trece binarios que nadie
provee dejaron de depender de que nadie reinicie nada.
Y `sergio.gioser.net` son tres piezas, de las que sólo una se muda hoy:
· frontend: 117 M de estático ⇒ copiado a `/work/www/sergioh` ✅
· `/shuma/*`: `shuma-gateway` en :7378, ELF dinámico y con el binario borrado ⇒ hay que construirlo
desde tawasuyu (es Rust del monorepo, factible)
· `api.sergio`: uvicorn con un venv de **405 M** — fastapi + pydantic + google-generativeai +
**langchain**, con extensiones `cpython-314-x86_64-linux-GNU.so` ⇒ **glibc**. Reempaquetar ese
árbol de PyPI como recetas no es realista y en musl no corre. Es el caso canónico del ADR 0015
(qorpa), que sigue PROPUESTO.
Por eso el DNS de `sergio` NO se movió: mover el nombre sin backend deja el sitio servido y la
consola rota. El frontend queda copiado y esperando.
Esto es lo que decide la fecha de borrado de gioser: no es «mudar dominios», es que un servicio vivo
no tiene hoy camino a takana. Tres salidas, y ninguna es técnica: qorpa · que viva en otra máquina
(summa ya lo hace) · o que muera.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
Antes: dos reconstrucciones daban `libKF6SyntaxHighlighting.so` distintos —
8.800.310 bytes diferentes desde el offset 41, y hasta el tamaño cambiaba
(10.345.888 contra 10.345.840). Ahora: REPRODUCE.
Hash: 4c1638a0… → 3db73c19… (arrastra 4 dependientes directos, 5 transitivos).
── Dónde NO estaba, que también cuenta ────────────────────────────────────────────────
No era el indexer: `katehighlightingindexer` arma el índice con `QVariantMap`, que es
QMap y va ordenado. No eran los generadores de Perl: ninguno de los cuatro itera un
hash. Mirarlo antes ahorró parchear lo que no era.
── Dónde estaba: `data/generators/generate_jinja.py`, con tres dependencias del azar ──
1. `to_do.pop()` sobre un `set` saca un elemento ARBITRARIO. En `--dry-run` el orden de
los `print(out_file)` es lo que CMake recoge en `out_xmls`, y eso acaba siendo **el
orden de las entradas del `.qrc`** ⇒ el recurso compilado cambiaba de disposición
entera. Se toma el menor: mismo conjunto, orden fijo.
2. `version = str(round(time.time()))` hornea la HORA DEL BUILD en el XML generado. Se
honra `SOURCE_DATE_EPOCH`, que es la convención de reproducible-builds y que el
sandbox de takana ya fija (=1).
3. `os.listdir()` sin ordenar. Sólo importa si dos ficheros declaran el mismo lenguaje,
pero quitar la dependencia del readdir no cuesta nada.
── Medido en los dos sentidos ANTES de tocar la receta ────────────────────────────────
Corriendo el generador a mano, sin builds de por medio:
· antes — tres PYTHONHASHSEED distintos ⇒ TRES md5 distintos, y el orden salta a la
vista: `jinja-json, jinja-yaml, jinja-toml…` contra
`jinja-qml, jinja-dockerfile, jinja-typescript…`
· después — las mismas tres semillas ⇒ el MISMO md5
· generando de verdad con semillas Y momentos distintos ⇒ los 35 XML IDÉNTICOS,
con `version="1"`
· control negativo — sin `SOURCE_DATE_EPOCH` sigue poniendo la hora actual
(comprobado: coincidía con `date +%s` al segundo) ⇒ fuera del sandbox no cambia nada
Primer aviso de esta medición: mi primera comparación dio «idéntico con las tres
semillas» y era MENTIRA — el script salía con «Destination folder does not exist» y yo
comparaba md5 de un mensaje de error. Comparar salidas sin mirar que la herramienta
hiciera algo es inventarse un control.
Con -vga none la captura ya no tiene punto ciego, asi que un ✗ significa
«la ventana no esta». Clasificado el ultimo cuadro de las 10: 2 con la
pagina pintada, 1 con la ventana en blanco y 7 con SOLO el escritorio.
Las dos salidas explicaban los ✗ inflados de las series VGA=1, no el
fenomeno.
El MOZ_LOG separa los dos regimenes: las que tienen ventana escriben
952-1505 lineas hasta el apagado; las 7 sin ventana se cortan a los ~40s
y quedan 6 minutos de silencio, sin crash (WebRender arranca). Quedan
como hipotesis NO medida los frame callbacks que el compositor no manda.
Ademas: tasa-primera-pintura.sh nombra el log por VGA (la serie nueva
habia sobrescrito los crudos de la anterior).
Medido dominio por dominio (DNS por DoH **y** HTTP contra la IP del origen) antes de tocar nada:
5 fósiles sin DNS (aura, api.aura, sigma, kosmofono, api.kosmofono) · 3 que ya viven en OTRA máquina
(summa, dev.summa, api.dev.summa → 154.197.1.2, así que sus bloques en gioser eran código muerto) ·
2 en 502 permanente (mail.sigma con :9000 caído, api.gioser.net con :8000 caído) · 5 mudados hoy ·
y **2 vivos de verdad**: `sergio.gioser.net` y `api.sergio.gioser.net`.
Dato que ordena: **ninguna de las raíces estáticas de los fósiles existe en disco**
(`/var/www/{aura_frontend,sigma,kosmofono,summa,summa-dev}`). El Caddyfile servía directorios
ausentes — la configuración sobrevivió a sus datos. De los backends sólo `:8770` escucha, y su
dominio ya apunta a otra parte.
Los 10 bloques muertos fuera (respaldo previo, `validate`, `reload`), con control: `sergio` y
`api.sergio` siguen en 200, y los mudados responden desde la caja.
⚠ El único fósil CON datos es `terapeuta.ec`: 279 M en `/var/www/terapeuta`, sin DNS y sin vhost. No
se borra acá; se anota para la decisión de borrado de la máquina.
Lo que queda por mudar es un frente acotado: un backend Python en :7378 y una API en :8771.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
ksvg, qqc2-desktop-style, kirigami-addons y libplasma, ya reconstruidos contra el
kirigami arreglado. REPRODUCEN 4 · DERIVA 0 · NO-DETERMINISMO 0.
No es adorno: los cuatro llevan QML, que es donde vivía la carrera del AOT. Que el
árbol reconstruido reproduzca es lo que cierra el arreglo — sellar de nuevo no
demuestra nada por sí solo.
El usuario avisó de que esa máquina está con arje desde hace meses. Tiene razón, y las dos cosas son
ciertas: PID 1 **es** `arje-zero`, la card `openrc-gitea` **no** llama a `rc-service` (ejecuta el
binario directo — el prefijo es herencia del nombre que le puso `arje-absorb` al traducir), y sin
embargo **`/run/openrc/started/` existe con servicios dentro** (NetworkManager, dbus, dhcpcd,
localmount…) y `rc-update show default` listaba gitea. OpenRC quedó como residuo ACTIVO, capaz de
arrancar por su cuenta: eso fue lo que revivió al gitea con ppid ≠ 1 después de que arje lo parara.
Regla para el resto de la mudanza: antes de dar un servicio por apagado, preguntar a los DOS —
`arjectl list-units` y `rc-update show default`. Un nombre que dice `openrc-` y no es OpenRC, al
lado de un OpenRC real que nadie esperaba que siguiera operando.
Y mudados `takana.gioser.net` y `hifas.gioser.net`: estáticos puros, 52 K, vhost en la caja, DNS de
CNAME a A, fuera del origen. 200 con TLS válido desde 2.29.29.217; `sergio.gioser.net` sigue en 200
y gioser baja de 16 a 14 vhosts.
Se repitió lo del ACME: el primer certificado se pide antes de que propague el DNS y falla contra el
origen. Conviene mover el DNS y RECIÉN ENTONCES añadir el vhost, o asumir un `restart` de más.
Los 14 que quedan tienen backend propio o son fósiles: no se mudan copiando un directorio.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
El arreglo del no-determinismo de kirigami movió su ArtifactHash (41eea38e… →
a72b1626…) y con él el de todo lo que cuelga: 37 dependientes directos, 39
transitivos (entran `frameworkintegration` y `plasma5support` por vía indirecta).
Reconstruidas las 39 en orden topológico y con UN solo `flock -o` para toda la
tanda. Comprobado aparte del log: para las 39 existe `store/<hash-de-hoy>-<nombre>`.
Las gordas: kwin 3027s, plasma-workspace 1958s, okular 810s, kirigami-addons 816s.
⚠ A mitad de tanda, `kirigami-addons` y `kdf` murieron con «No space left on
device» — y es otra vez la trampa de siempre: NO eran recetas rotas. El disco de
`/mnt/vvv` estaba al 100%. Las dos reconstruyen bien con sitio libre.
Dos cosas se arreglaron a raíz de eso:
· `poda-fuentes.sh` con su suelo de 24 h liberaba CERO, porque los 30 árboles
eran todos de hoy — la lección de `cache-ci-no-envejece` otra vez: un guardián
calibrado a una escala que el dato nunca alcanza no protege. Con `--horas 1`
y luego `--horas 0` se recuperaron 14 G.
· la tanda ahora poda el árbol de CADA receta al terminarla (sólo el suyo: las
deps son compartidas, borrarlas en vuelo es el ADR 0012). Con eso
`work/sources` se mantuvo en 54-71 M durante el resto de la cascada en vez de
crecer sin freno.
El `never: 1` que aparece en el grafo KDE es `minga`, una receta nueva de otro
agente, sin perfil y ajena a esta cascada.