Commit Graph
1226 Commits
Author SHA1 Message Date
SergioandClaude Opus 5 0d0ab79092 el tar de busybox no sirve para un rootfs ajeno — y takana ya no dibuja un pingüino
`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
2026-09-14 21:46:08 +00:00
SergioandClaude Opus 5 93362fc21b el TLS arreglado en la caja, la distro con nombre, y el ENOSPC que no era de la raíz
**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
2026-09-14 21:40:45 +00:00
SergioandClaude Opus 5 64d48e743e minga abierto a P2P (la ventana oficial), fastfetch al corpus, y el rehash por su ruta
**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
2026-09-14 21:34:42 +00:00
Sergio 2d8a0a72e9 estado: cosecha granja 2026-09-14T21:33:25Z — avance del árbol KDE 2026-09-14 21:33:25 +00:00
Sergio 981709d241 syntax-highlighting: arreglado el no-determinismo — era el generador de Jinja
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.
2026-09-14 21:15:00 +00:00
Sergio 21381b598f atuq: la serie con UNA sola tarjeta — 2 de 10, y el hueco resulta real
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).
2026-09-14 21:11:18 +00:00
Sergio 42325dd1ca estado: cosecha granja 2026-09-14T21:02:09Z — avance del árbol KDE 2026-09-14 21:02:09 +00:00
Sergio 8b9cf35026 estado: 4 dependientes de la cascada verificados — reproducen al hash nuevo
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.
2026-09-14 20:54:03 +00:00
Sergio c719fe211a estado: cascada de kirigami reconstruida — 39/39 al hash nuevo, cero fallos
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.
2026-09-14 20:41:34 +00:00
Sergio 5257726d64 estado: cosecha granja 2026-09-14T20:32:59Z — avance del árbol KDE 2026-09-14 20:33:00 +00:00
Sergio 920d276b45 estado: cosecha granja 2026-09-14T20:03:29Z — avance del árbol KDE 2026-09-14 20:03:29 +00:00
SergioandClaude Opus 5 69526768b7 CUTOVER: el gitea sirve desde la caja nueva — TLS válido, HTTPS y SSH, supervisado por arje
`git.gioser.net` y `git.tawasuyu.net` responden **200 con TLS válido desde 2.29.29.217**, `git clone`
funciona por HTTPS **y** por SSH:2345, y `gitea` + `caddy` corren supervisados por `arje-zero`. El
gitea de gioser está parado. Es el primer servicio real que deja la máquina que se va a borrar.

Mudanza INCREMENTAL: los DNS de gioser son casi todos `CNAME → www`, así que mover `www` habría
mudado quince dominios cuyos backends siguen allá. Se convirtió sólo `git` (las dos zonas) de CNAME
a A propio con TTL 60 — reversible en un minuto.

Cinco cosas que sólo se aprenden haciéndolo:

· **Parar el origen no es `rc-service gitea stop`**: dice «already stopped» con el proceso vivo, y
  matarlo no alcanza — lo revive arje-zero, que lo tiene como card `openrc-gitea` con Restart y
  **9001 reinicios** en el contador. Se paró con `arjectl stop openrc-gitea` (el arjectl que
  construimos hoy, hablando con el arje de gioser), y para eso hubo que extraer su card del genesis
  y escribirla en `cards.d` — que es justo el hueco del §6.12.
· **El token de `hcloud` también gestiona el DNS** (Cloud API unificada, `/v1/zones`); la API vieja
  `dns.hetzner.com/api/v1` redirige a la consola web. Y un `PUT` sobre el rrset no puede cambiar el
  TIPO: hay que DELETE del CNAME y POST del A.
· **ACME falló primero contra gioser** (502) porque el challenge salió antes de que propagara el
  DNS. Con el DNS al día, `arjectl restart caddy` → certificate obtained successfully.
· **La identidad SSH se muda con el servicio**: `REMOTE HOST IDENTIFICATION HAS CHANGED` hasta que
  se copiaron las claves de host de gioser a la caja. Así los clones existentes no notan nada; el
  precio es limpiar el known_hosts propio del `:22` de administración.
· El `sshd` del producto escucha sólo en `:22` ⇒ el git por SSH necesitó `Port 2345` y que el
  usuario `gitea` tenga shell real (su authorized_keys fuerza `command="gitea serv …"`).

`caddy` gana su `[[service]]` (con guarda del Caddyfile, HOME propio para los certificados de ACME
—o cada reinicio pediría certificados nuevos y se comería el límite de emisión— y la nota de por qué
corre como root) y el perfil lo arranca.

Consecuencia para la granja: las 23 recetas que clonan por `https://git.tawasuyu.net/…` **ya apuntan
a la caja**. Comprobado: el worker resuelve 2.29.29.217 y `git ls-remote` responde.

Revertir, si hiciera falta: `arjectl start openrc-gitea` en gioser y los dos `git` de vuelta a CNAME.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
2026-09-14 19:53:09 +00:00
Sergio e5fefa35d2 estado: cosecha granja 2026-09-14T19:33:51Z — avance del árbol KDE 2026-09-14 19:33:51 +00:00
Sergio 2238913a4e estado: cosecha granja 2026-09-14T19:03:35Z — avance del árbol KDE 2026-09-14 19:03:35 +00:00
Sergio 5b98d1b2bf atuq: no era el perfil — son DOS SALIDAS, y el «3 de 13» medía la cámara
Dos cosas antes de la medición: el MOZ_LOG de las que pintan y las que no termina IDÉNTICO (las dos
commitean WaylandBufferSHM de 1280x696), y el cruce de las 15 corridas está confundido — las 13 de
«perfil del usuario» salieron todas con VGA=1.

`screendump` de QMP fotografía UN dispositivo. Con VGA=1 hay dos, y hasta ahora se miraba uno. Con
`id=` en cada uno y capturando los dos en cada toma, en la misma corrida y el mismo instante:

    +312s  ██ PRIMERA PINTURA — 704456 px EN vga0
           gpu0 = 962675 px de fondo + panel y dock (el escritorio, SIN navegador)
           vga0 = 703766 px magenta                 (la ventana, con la página)

⇒ cosmic-comp maneja las DOS salidas y la ventana cae en una u otra. «Pinta 3 de 13» era cuántas
veces cayó en la pantalla que yo fotografiaba: una tasa de mi cámara, no del producto. El §6.10.ter
tiene la misma explicación (aquel arranque también traía `drm: card0 card1`).

Queda en pie, ya sin confundido: el navegador arranca, mapea y commitea SIEMPRE; cuando la ventana
está en la pantalla que se mira, se ve entre +184 y +312 s; el perfil no era la causa y cosmic-comp
nesteado tampoco.

⚠ Tercera vez en el día con la misma forma: un ✗ de una captura de UNA pantalla no dice «la ventana
no está», dice «no está en ESA» — igual que `mapped 1` no probaba que se viera. El estado anota ahora
en qué pantalla apareció y cuántas se fotografiaron, y el vigía NO cuenta las ciegas: las nombra.
2026-09-14 18:57:00 +00:00
Sergio 26dd2233dc estado: cosecha granja 2026-09-14T18:33:41Z — avance del árbol KDE 2026-09-14 18:33:41 +00:00
Sergio 49b2842ddb atuq: la TASA — pinta 3 de 13 con el perfil del usuario, y cuando pinta siempre a ~200 s
Diez corridas idénticas con `scripts/cosmic/tasa-primera-pintura.sh` (--as-user, VGA=1, ventana 480 s,
captura cada 30 s), más las cinco anteriores, todas anotadas en docs/state/primera-pintura.json:

    perfil del usuario     3 de 13 pintaron   184, 199, 204 s
    perfil nuevo en tmpfs  2 de 2             197, 197 s

Dos cosas que la tasa dice y una anécdota no podía: cuando pinta, pinta SIEMPRE en la misma ventana
(184…204 s) y nunca a los 300, 400 ni 900 ⇒ no es una cola larga, son DOS REGÍMENES —o sale a los
~200 s o no sale—; y con el perfil del usuario falla ~3 de cada 4, mientras que con perfil nuevo en
tmpfs no falló (2 de 2, pocas corridas para afirmar que nunca, suficientes para saber dónde mirar:
qué hace el primer arranque del perfil que el perfil ya hecho no hace).

⚠ Condición de la medida, parte del número: las diez salieron con el anfitrión a load ~10 (tanda de
KDE de otro agente + una VM de otra sesión, en 4 cores). El número es un PISO, no una constante.

⚠ Y una trampa del arnés medida en las corridas 8–10: con esa carga el guest tarda más de 420 s en
llegar al shell y los `esperar` vencen. No las invalida —se verificó una por una que el navegador se
lanzó y dejó su MOZ_LOG de 1200–5000 líneas— pero una corrida abortada de verdad se ve casi igual:
por eso el guion cuenta las abortadas APARTE en vez de sumarlas a los fallos.
2026-09-14 18:27:29 +00:00
Sergio 4456b65829 estado: cosecha granja 2026-09-14T18:04:26Z — avance del árbol KDE 2026-09-14 18:04:26 +00:00
SergioandClaude Opus 5 fd09ca77b0 arjectl en la imagen: relanzar en caliente — y el genesis NO alcanzaba para eso
El servicio que falla y agota su backoff sólo se podía recuperar reiniciando la máquina entera.
Ya no. Y no hubo que escribir nada: **el cliente existía en tawasuyu y el crate se llama `arje-ctl`**
(el binario, `arjectl`). Buscarlo por `arjectl` no lo encontraba, y de ahí salió mi conclusión falsa
de que había que implementarlo — el protocolo ya traía ListEntes, SpawnCardFromDisk,
StopCardFromDisk, KillEnte y EnteStatus.

`recipes/arjectl.toml` lo construye del MISMO commit que `arje-zero` (98db584f), y no por comodidad:
el bus es un protocolo entre dos binarios y un cliente de otro árbol puede conectar sin entenderse
con el init. Publica sólo `arjectl`; el crate también produce un `systemctl` de camuflaje que acá no
se instala — en una distro sin systemd, ese nombre en el PATH invita a escribir runbooks con el
verbo ajeno.

⚠ EL HUECO QUE SÓLO SE VE USÁNDOLO: el genesis de la seed dice qué arranca AL BOOT, pero
`start`/`restart` usan `SpawnCardFromDisk`, que lee `/etc/arje/cards.d/<label>.json` — y el armado
no lo escribía:

    $ arjectl start gitea
    Error: arje-zero rechazó: card gitea: No such file or directory
           (buscada en /etc/arje/cards.d/gitea.json)

Son dos preguntas distintas —qué arranca solo, y qué se puede encarnar a pedido— y arje las responde
desde sitios distintos. `inyectar-cards.py` escribe ahora los dos árboles, y en `cards.d` escribe
TODAS las cards, no sólo las nuevas: `sshd` viene del product-rootfs y tampoco era relanzable.

Medido con la VM arrancada UNA sola vez: la imagen trae `cards.d/{gitea,sshd}.json` · `list-units`
da PID/CPU/MEM/HILOS/reinicios · poner el `app.ini` + `arjectl start gitea` ⇒ **GET / 200 sin
reiniciar** (uptime 6 min) · `arjectl restart gitea` cambia el PID (118 → 192) y sigue en 200.

⚠ Y un aviso que costó un HTTP intermitente: **`arjectl start` sobre un Ente YA VIVO lo DUPLICA** —
`SpawnCardFromDisk` no deduplica por label y arje le da un ULID nuevo. En gitea el síntoma fue
`unable to lock level db … resource temporarily unavailable` y un `[F]`: dos servidores peleando por
el mismo estado. Para relanzar se usa `restart`, o se mira `list-units` antes. Un `start` idempotente
es trabajo de arje, no de esta imagen.

⚠ Deuda anotada, no barrida: `arjectl` va en `perfil.servidor` porque este frente es el que lo pagó.
TODA imagen de takana corre arje-zero como PID 1 y ninguna se puede operar sin él ⇒ el argumento
para subirlo a `base` es fuerte, y es una línea. Se deja como decisión.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
2026-09-14 17:59:11 +00:00
Sergio 8054119429 estado: cosecha granja 2026-09-14T17:34:29Z — avance del árbol KDE 2026-09-14 17:34:30 +00:00
Sergio 446c209fd2 estado: cosecha granja 2026-09-14T17:04:07Z — avance del árbol KDE 2026-09-14 17:04:08 +00:00
Sergio 44b3624de6 kirigami: arreglado el no-determinismo — eran DOS causas, y ahora reproduce bit a bit
Antes: dos reconstrucciones con las mismas entradas y el mismo lab daban artefactos
distintos. Ahora: `why-differs` da 464 entradas idénticas · 0 divergen.

Hash: 41eea38e… → a72b1626… (arrastra 37 dependientes directos, 39 transitivos).

── CAUSA 1: el AOT de QML compilaba un conjunto DISTINTO de funciones cada vez ─────────
`libKirigamiTemplates.so` cambiaba de tamaño (5.737.344 vs 5.795.072) y difería en 177
símbolos locales, todos `QmlCacheGeneratedCode…__invoke` y concentrados en CUATRO ficheros:
InlineMessage, LinkButton, NavigationTabBar y Badge.

Y esos cuatro son justo los que importan módulos QML HERMANOS del propio proyecto
(`org.kde.kirigami.platform`, `.primitives`, `.controls`). `qmlcachegen` sólo compila a AOT
lo que puede resolver de tipos, y los tipos del hermano salen de su `.qmltypes`, que produce
otro objetivo del mismo build. `src/templates/CMakeLists.txt` no declara `DEPENDENCIES`
ninguna ⇒ con ninja en paralelo es una CARRERA.

Control que sostiene el diagnóstico: `Chip` y `Heading`, del mismo directorio, no divergen —
y `kirigami-addons` y `kquickcharts`, que también llevan QML, reproducen. No es «QML es
no-determinista».

Arreglo: `-j1` en el compile. Orden topológico fijo ⇒ el cachegen ve siempre lo mismo.
NO es throttling (eso va por nice/taskset justamente para no re-hashear): es corrección, y
el re-hash es el precio que se paga a propósito.

Descartadas, con motivo: `-DQT_QML_NO_CACHEGEN=ON` apaga también el bytecode precompilado
(coste de arranque en el escritorio); `--only-bytecode` sería lo quirúrgico pero
`QT_QMLCACHEGEN_ARGUMENTS` es propiedad de objetivo y NO es INHERITED, así que no hay forma
de ponerla desde la línea de órdenes.

── CAUSA 2: el .tar.bz2 de plantillas se armaba sin orden ──────────────────────────────
`kde_package_app_templates` de ECM tiene camino reproducible —`--sort=name --mtime=@
SOURCE_DATE_EPOCH --numeric-owner --owner=0 --group=0`— pero detrás de `if(GNU_TAR_FOUND)`,
que exige que `tar --version` diga «GNU tar». El rootfs del lab es Alpine: `tar` es BUSYBOX
⇒ caía al respaldo `cmake -E tar cvfj`, que ni ordena ni normaliza. El orden lo ponía readdir.

Arreglo: `tar` (GNU tar 1.35, ya en el corpus) entra en `[deps] build`.

Comprobado mirando el artefacto, no deducido:

    drwxr-xr-x 0/0  1970-01-01 00:00 ./
    -rw-r--r-- 0/0  1970-01-01 00:00 ./CMakeLists.txt
    -rw-r--r-- 0/0  1970-01-01 00:00 ./LICENSES/BSD-3-Clause.txt

owner 0/0, mtime al epoch (SOURCE_DATE_EPOCH=1 lo fija el sandbox) y la lista ORDENADA.
2026-09-14 16:40:35 +00:00
Sergio 45f7bdda45 estado: cosecha granja 2026-09-14T16:33:58Z — avance del árbol KDE 2026-09-14 16:33:58 +00:00
Sergio 9ceed7bbbe estado: cosecha granja 2026-09-14T16:03:24Z — avance del árbol KDE 2026-09-14 16:03:24 +00:00
Sergio c14db82263 atuq: el tiempo de primera pintura, en el vigía de la imagen — y es 3 de 5, no un número
`scripts/cosmic/atuq-en-imagen.py` ya no contesta «pinta / no pinta» sino CUÁNTO TARDA: mide cada
captura, imprime `+Ns ██ PRIMERA PINTURA`, acepta `--budget` (def. 420 s) y `--until-paint`, y sale
≠0 si no pintó o si se pasó del presupuesto. El magenta se cuenta CON TOLERANCIA porque `cosmic-idle`
atenúa la pantalla al 46 % a los ~+590 s y un contador por color exacto lo lee como «desapareció».

El número se publica en `docs/state/primera-pintura.json` y `scripts/vigia-imagen.py` lo informa como
sexto dato, marcado como «no lo mide este vigía» (arrancar la imagen son ~15 min sin KVM). Se ACUMULA
una entrada por corrida, no se pisa, y el vigía informa la tasa:

    ⚠ pintaron 3 de 5 corridas · primera pintura +197…+204s

⚠ Y eso corrige lo que publiqué hace una hora. Con cinco corridas sobre la MISMA imagen: pintó en
tres (+197, +197, +204 s) y NO pintó en dos —una con 900 s de observación—, siendo la 4 y la 5 el
mismo comando. El fallo es INTERMITENTE: ni «nunca pinta» ni «sólo tardaba».

El argumento que me llevó a «tarda» era el MOZ_LOG (`mapped 1` + «has buffer» + WaylandBufferSHM
commiteado). La corrida 5 lo refutó: commiteaba cuadros desde ≤+377 s con la pantalla vacía a los
900 s. Que el cliente se crea visible NO es evidencia de que se vea; la evidencia es el píxel. Queda
escrito en el vigía, al lado de la tasa, para que no se vuelva a usar como prueba.

De paso, las flags nuevas nacen en inglés (CLAUDE.md §4): --as-user, --wait, --budget, --until-paint,
--only-cosmic; los mensajes siguen en castellano.
2026-09-14 16:02:27 +00:00
Sergio 1b3af538d3 estado: cosecha granja 2026-09-14T15:34:25Z — avance del árbol KDE 2026-09-14 15:34:25 +00:00
Sergio 426e5d1b1d estado: KF6 tanda 5 — 11/11 reproducen
kio kcolorscheme kdeclarative krunner kwayland layer-shell-qt kquickimageeditor
kcharselect kruler kdf kfind.

  REPRODUCEN: 11 · DERIVA: 0 · NO-DETERMINISMO: 0 · no construyeron: 0

`kio` entra acá y es de las gordas del árbol KDE: reproduce bit a bit.
2026-09-14 15:24:47 +00:00
SergioandClaude Opus 5 de7c3faa9c gitea arranca: su [[service]], probado con el entorno de verdad — y dos fallos que sólo salen ahí
La receta ya declara su servicio (SDD 30) y `perfil.servidor` lo habilita. El ArtifactHash NO se
mueve (`b3:391a613e…` antes y después): `[[service]]` está fuera de `hash_inputs`.

⚠ Primero, una corrección del commit anterior: declaraba `gitea` en `perfil.servidor` con SEIS
LÍNEAS DE COMENTARIO y sin la línea `"gitea",`. El perfil cargó igual, el grafo no dijo nada y el
paquete simplemente no estaba. Lo cazó `targets.py --services` al resolver el label: «lo declara
gitea, que NO pertenece al perfil». Un comentario que explica una entrada que no existe se lee como
la entrada.

La card no encarna el binario directo: **gitea se niega a correr como root** (`[F] Gitea is not
supposed to be run as root`), así que va por `setuidgid`. Y comprueba dos cosas del SITIO antes de
arrancar, saliendo 78 con un mensaje que las nombra: `/etc/gitea/app.ini` y el usuario `gitea`. Un
gitea sin config no falla — arranca y ofrece el asistente de «crear administrador» a quien pase.

Probado en el worker con el argv exacto y `env -i`, que es lo que arje hace de verdad. Tres fallos
que con una shell normal no se ven NUNCA:

· `exec setuidgid …` a secas ⇒ `sh: exec: line 0: setuidgid: not found`. El `sh` de busybox de la
  imagen no trae `FEATURE_SH_STANDALONE`: no despacha sus applets, los busca en `PATH`, y PID 1 no
  garantiza ninguno. Todo con ruta absoluta (`/bin/grep`, `/usr/bin/setuidgid`).
· sin `PATH` en el `envp` ⇒ `git not found: executable file not found in $PATH`. **gitea lanza
  `git` como subproceso**, y el mensaje se lee como «falta git» con git instalado y raíz de `base`.
  Un envp vacío no es «limpio»: es sin PATH.
· sin `cd` ⇒ `fatal: error reading '/root/.git'`. El cwd se hereda y gitea corre `git config` en él.
  `Service` no tiene campo `cwd`, así que va en el argv, a la vista.

Con eso: escucha, `GET /` responde **200** y el proceso corre como `gitea`. Las dos guardas
verificadas por separado (78 y su mensaje cada una). El worker quedó limpio y censado: sin usuario,
sin /etc/gitea, sin /var/lib/gitea, sin symlinks y sin procesos.

Y `/etc/gitea` entra en las rutas de la mudanza: el `app.ini` guarda los SECRETOS generados (gitea
los escribe en el propio fichero, que por eso tiene que ser suyo, `gitea:gitea 0660`).

⚠ Lo que queda abierto y está anotado en la receta: **el usuario `gitea` no existe en el producto**.
`/etc/passwd` de la imagen es la constante `takana_bootstrap::PRODUCT_PASSWD` y sólo trae `root` y
`sshd`. El SDD 30 sacó las Cards de una constante de Rust y las puso en la receta; los USUARIOS
siguen donde estaban las Cards. Hasta que se declaren, el usuario llega con los datos del sitio.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
2026-09-14 15:16:21 +00:00
Sergio f2aafb1b39 estado: KF6 tanda 4 + 15 del worker — dos no-determinismos REALES en la imagen de KDE
Hub, KF6 tanda 4: REPRODUCEN 9 · DERIVA 1 · NO-DETERMINISMO 2 · no construyeron 0
Worker, Rust: REPRODUCEN 13 · DERIVA 2 · NO-DETERMINISMO 0

El libro pasa de 104 a 207 entradas en la jornada.

── Los dos que divergen, y por qué importan ──────────────────────────────────────────

`kirigami` — está en `escritorio-kde` y tiene **37 dependientes**. Dos sitios:
  · libKirigamiTemplates.so: los símbolos del AOT de QML llevan un contador por fichero
    que cambia de corrida a corrida (`…LinkButton_qml3$_28/_38/_58` en A contra
    `…Badge_qml3$_88/_98/_108` en B) ⇒ el orden en que se compilan los .qml no está fijado.
  · kdevappwizard/templates/kirigami6.tar.bz2: difiere desde el byte 0xa, o sea desde el
    primer bloque comprimido — un tar armado sin orden estable.

`syntax-highlighting` — también en `escritorio-kde`. libKF6SyntaxHighlighting.so difiere
en 8.800.310 bytes desde el offset 41 y hasta **el tamaño cambia** (10.345.888 contra
10.345.840). Las cadenas que difieren son datos comprimidos ⇒ es el recurso generado con
las definiciones de sintaxis, otra vez orden de entrada.

Los tres de hoy (con `gocryptfs`) son la MISMA clase: **recurso generado cuyo orden de
entrada nadie fija**. No es el compilador ni el lab: es que la receta deja que el orden lo
decida un `readdir` o el planificador.

── Lo que NO se hace acá, y por qué ──────────────────────────────────────────────────
Arreglarlo toca la receta ⇒ re-hash ⇒ reconstruir kirigami y sus 37 dependientes. Eso es
una decisión de campaña con su coste, no algo que se mete de paso en una verificación.
Los cuatro ejemplares quedan en `store/.divergen/` para poder mirarlos.

── Control que sostiene el hallazgo ──────────────────────────────────────────────────
`kirigami-addons` y `kquickcharts` TAMBIÉN llevan QML y reproducen. O sea que no es «QML
es no-determinista»: es algo propio de esas dos recetas.
2026-09-14 15:09:32 +00:00
Sergio 703e81d6a8 estado: cosecha granja 2026-09-14T15:04:16Z — avance del árbol KDE 2026-09-14 15:04:16 +00:00
Sergio 9d6c79a749 estado: cosecha granja 2026-09-14T14:33:32Z — avance del árbol KDE 2026-09-14 14:33:32 +00:00
Sergio cb101fd70b estado: KF6 tanda 3 (12/12) + 17 del worker, con el primer NO-DETERMINISMO real del frente Go
Hub, KDE Frameworks tanda 3: kglobalaccel kpackage kconfigwidgets kiconthemes
ktextwidgets kxmlgui kparts kcmutils knotifications kdeclarative ksvg kwallet.
  REPRODUCEN: 12 · DERIVA: 0 · NO-DETERMINISMO: 0 · no construyeron: 0

Worker (ya con `go` arreglado), familia Go:
  REPRODUCEN: 15 · DERIVA: 1 · NO-DETERMINISMO: 1 · no construyeron: 0

  · `checkmake` — la que antes «no construía» — REPRODUCE. Cierra el arreglo del enlace
    de `go`: no estaba rota, faltaba el binario en el PATH del host.
  · `cilium-cli` DERIVA: el artefacto guardado era viejo; las dos reconstrucciones
    coinciden entre sí ⇒ se movió el mundo, no la receta. No es un fallo.
  · `gocryptfs` NO-DETERMINISMO, y es el primero de verdad del frente Go.

La causa de gocryptfs, con los dos ejemplares guardados en `store/.divergen/`:

    usr/bin/gocryptfs  ELF, difieren [.text .rodata .data .debug_*]
      · .debug_str sólo en A: …/.gotmp/go-build3432240771/b141
      · .debug_str sólo en B: …/.gotmp/go-build2186295412/b141

El directorio temporal `go-build<aleatorio>` queda horneado en el DWARF. Hipótesis a
comprobar, no conclusión: sólo pasa con `cgo = true`, porque cgo genera fuentes C en ese
temporal y su ruta real entra en la info de depuración; con CGO off no hay fuentes
generadas y las 15 restantes reproducen. En el corpus hay exactamente cuatro recetas Go
con cgo: gitea, gocryptfs, sq y usql — ninguna verificada todavía. Se miden antes de
afirmar nada.
2026-09-14 14:23:38 +00:00
SergioandClaude Opus 5 74151a2b0c gitea 1.27.0 con sqlite y bindata: el binario sellado no podía abrir la base de datos
La mudanza de gioser pasa por levantar su gitea del otro lado — 28 repos, 26 sin copia fuera. El
corpus ya tenía `gitea` sellado (1.26.4, `b3:35bb4f04…`) y NO sirve, medido contra el artefacto:

    $ gitea --config app.ini migrate
    Error: sqlite3 requires: -tags sqlite,sqlite_unlock_notify
    this Gitea binary was not built with SQLite3 support

Construía, reproducía y no podía abrir la sqlite en la que gioser guarda TODO (`DB_TYPE = sqlite3`).
Y `gitea --version` decía `version development`. Es subcomando-sin-driver un piso más abajo.

Tres cambios, y el tercero es el que no se ve venir:

· Pin 1.27.0 (gioser corre 1.27.0). No es cosmético: gitea migra el esquema hacia adelante y se
  planta si la DB trae migraciones más nuevas que el binario, así que el pin va por delante del
  origen, nunca por detrás.
· Tags `sqlite,sqlite_unlock_notify` (⇒ `cgo = true`, el driver de mattn es C) y `bindata`, que
  embebe `public/` y `templates/`: sin él la receta publica sólo el ejecutable y el servidor
  arrancaría sin UI.
· La fuente pasa de `repo`+`commit` al TARBALL DE RELEASE. El clon no alcanza: la UI se compila
  con Node y las deps Go no están vendoreadas en git. El `gitea-src-1.27.0.tar.gz` trae las dos
  cosas hechas — medido: `public/assets/` 764, `vendor/` 11246, `templates/` 663 — así que
  construye con el lab tal cual, sin Node y sin red. La URL es locator (ADR 0013); ancla el sha256.

Nuevo hash: `b3:391a613e…`. Declarado en `perfil.servidor` como paquete y NO en `servicios`:
arrancarlo necesita el [[service]] del SDD 30 con su app.ini, y declarar un arranque que no existe
sería la mentira que ese campo existe para no tener.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
2026-09-14 14:17:52 +00:00
Sergio 0a75414da0 estado: 12 KF6 más verificadas + 10 rescatadas del libro del worker
Tanda 2 de la familia KDE Frameworks (hub): kbookmarks kcolorscheme kcompletion
kdnssd kholidays kunitconversion kauth kpty solid sonnet prison kservice.

  REPRODUCEN: 12 · DERIVA: 0 · NO-DETERMINISMO: 0 · no construyeron: 0

Y aparte: el worker tenía su propio libro (`work/repro-worker.tsv`, fuera de la siembra)
con 13 verificaciones del 2026-09-05 que nunca volvieron al hub. Cobertura medida y
perdida. Importadas 10.

Las otras 3 NO se importan, y el motivo es el que justifica que la clave del libro sea
(receta, ArtifactHash) y no la receta sola: su hash cambió desde entonces, así que la
medición ya no habla del artefacto de hoy.
  · atuq, bzip2  — reproducían, pero a un hash superado
  · aichat       — decía NO-DETERMINISMO a `c40a15bd…`; el hash vigente es `7a515b0a…`
                   y a ÉSE el propio worker le midió «reproduce». Importar por nombre
                   habría arrastrado un no-determinismo que ya no existe.
2026-09-14 14:13:14 +00:00
Sergio 6c1c316671 estado: cosecha granja 2026-09-14T14:03:05Z — avance del árbol KDE 2026-09-14 14:03:05 +00:00
Sergio bb83a4f973 estado: 12 frameworks KF6 tier 1 verificados — reproducen los 12
Barrido por FAMILIA (KDE Frameworks tier 1, todos CMake), que es lo que hace
legible el censo: si el fallo fuera del toolchain se concentraría acá y saltaría
a la vista. karchive kcodecs kconfig kdbusaddons kguiaddons ki18n kidletime
kitemmodels kplotting kwidgetsaddons kwindowsystem kcrash.

  REPRODUCEN: 12 · DERIVA: 0 · NO-DETERMINISMO: 0 · no construyeron: 0

Los 12 además CONSTRUYEN hoy, que es el otro hallazgo del verificador: `sealed`
sólo dice que alguien los construyó alguna vez con algún lab, y el lab rueda.
2026-09-14 14:01:38 +00:00
Sergio 5cb6e568d6 catálogo: wl-clipboard sube al corpus — cerraba el único orphan_dep de cuatro grafos
Estaba sólo en `recipes/incoming-wlr/`, o sea inalcanzable desde las otras
cuatro colas. `cliphist` vive en el CORPUS y la pide en `[deps] run`, así que
corpus, gnome, kde y cosmic la reportaban como `orphan_deps: ["wl-clipboard"]`.

No era cosmético: `escritorio-cosmic` declara `cliphist` de raíz, y la imagen
se habría armado con el demonio de historial y SIN `wl-copy`/`wl-paste` — el
modo de fallo silencioso que la propia receta de cliphist advierte (el binario
corre y no hace nada). La clausura no lo podía ver: decía `falta=0` en los
cinco perfiles, porque una dep que no resuelve no se cuenta, desaparece.

Solución = la que el catálogo ya usó con `mpv` y `atuq`: subirla al corpus, de
donde las colas la alcanzan (sibling-first y después el catálogo padre).

Medido antes de mover: ninguna de sus 9 deps tenía variante hermana en
`incoming-wlr`, así que el ArtifactHash no podía cambiar — y no cambió
(`b3:fc2ab7b7…` a los dos lados, comprobado con `takana hash`). Cero re-sellos.

Tras regenerar los cinco grafos: `orphan_deps: []` en los cinco, y la clausura
de `escritorio-cosmic` pasa de 273 a 274, sellada.
2026-09-14 13:54:28 +00:00
Sergio d2187fda11 estado: 11 recetas KDE más verificadas reproducibles (SDD 23) 2026-09-14 13:48:34 +00:00
Sergio 98df75a8cb estado: cosecha granja 2026-09-14T13:32:34Z — avance del árbol KDE 2026-09-14 13:32:34 +00:00
Sergio 5614d8c855 estado: cosecha granja 2026-09-14T13:02:49Z — avance del árbol KDE 2026-09-14 13:02:49 +00:00
Sergio edfdda2d4d estado: cosecha granja 2026-09-14T12:32:23Z — avance del árbol KDE 2026-09-14 12:32:23 +00:00
Sergio a26780cbd8 estado: cosecha granja 2026-09-14T12:03:00Z — avance del árbol KDE 2026-09-14 12:03:00 +00:00
Sergio 658eecb9cd estado: cosecha granja 2026-09-14T11:32:56Z — avance del árbol KDE 2026-09-14 11:32:56 +00:00
Sergio 0eee35a041 estado: cosecha granja 2026-09-14T11:03:49Z — avance del árbol KDE 2026-09-14 11:03:49 +00:00
Sergio 6c45f438b0 estado: cosecha granja 2026-09-14T10:32:23Z — avance del árbol KDE 2026-09-14 10:32:23 +00:00
Sergio af2469107f estado: cosecha granja 2026-09-14T10:02:17Z — avance del árbol KDE 2026-09-14 10:02:17 +00:00
Sergio d21d69ff8f estado: cosecha granja 2026-09-14T09:32:17Z — avance del árbol KDE 2026-09-14 09:32:17 +00:00
Sergio d16018bab7 estado: cosecha granja 2026-09-14T09:01:54Z — avance del árbol KDE 2026-09-14 09:01:54 +00:00
Sergio 97a04a145b estado: cosecha granja 2026-09-14T08:31:57Z — avance del árbol KDE 2026-09-14 08:31:57 +00:00
Sergio 192b9ab652 estado: cosecha granja 2026-09-14T08:02:17Z — avance del árbol KDE 2026-09-14 08:02:17 +00:00