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>
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>
`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>
`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>
Leyendo el perfil en cada captura, el sello (`toolkit.startup.last_success`) y la limpieza del
contador llegan al disco entre +100 s y +137 s DESDE EL LANZAMIENTO, no desde el primer cuadro. Y es
UN gancho y no dos: el mismo arranque que limpia escribe el sello, con su propia hora de arranque.
Las dos cotas salen de corridas independientes, que es lo que hace al intervalo creíble:
· a los +100 s NO había sellado — la corrida S1 vivió 100 s desde el lanzamiento (primer cuadro a
+97 s, fin del proceso tres segundos después, medido con los tiempos de sus propios ficheros);
· a los +137 s YA había sellado — la corrida con `--watch-prefs` lo ve aparecer en esa captura.
S1 parecía la excepción del modelo y resulta ser su cota inferior: si el reloj fuera el de la pintura
tendría que haber sellado, y no selló.
La consecuencia es contraintuitiva y es la que muerde: cuanto MÁS RÁPIDO pinta, más fácil es
envenenar el perfil, porque `--until-paint` corta antes. La serie de ayer no se rompió por ser larga
sino por ser rápida. Por eso la regla va en el arnés y no en un runbook: `PISO_SELLO = 180`, margen
sobre la cota alta, y `--until-paint` no corta antes de ese piso. El comentario del piso lleva los
dos números medidos al lado — un piso que se lee como elegido lo baja el próximo que lo vea.
Las corridas `cierre-1`/`cuanto-1`, el mando `--watch-prefs` y el piso los midió y escribió la otra
sesión del frente; acá van con la cota de S1 que los cierra por abajo.
El par aísla la variable —mismo pin, mismo perfil, misma imagen, y la única diferencia es cuánto vive
el navegador después del primer cuadro—:
S1 +97 s, muerta en el acto (`--until-paint`) ⇒ contador después: 1
cierre-1 +120 s, ~360 s de vida después de pintar ⇒ contador después: AUSENTE
Con eso queda contestada la pregunta que dos secciones atrás este documento daba por cerrada y no lo
estaba, y A deja de ser una anomalía: también siguió viva minutos después del primer cuadro.
Se dice además lo que la tabla NO prueba: si ese arranque además SELLÓ el éxito. El volcado del
«después» sólo grepeaba el contador; ahora `toolkit.startup.last_success` va en los DOS volcados y se
guarda en la medición (`last_success_antes` / `_despues`), que es lo que faltaba para no repetir la
corrida. Si el sello se mueve, es un gancho que sella y limpia a la vez; si no, son dos.
Y queda escrito que el 16 sigue sin explicación, ahora con una contradicción medida encima:
desapareció en una corrida diálogo + ATUQ-EXIT=0, y las fases k2/k3 del umbral fueron diálogo +
ATUQ-EXIT=0 y no limpiaron nada. La respuesta buena no tapa la sucia.
La corrida `cierre-1` y el mando `--watch-prefs` son de la otra sesión del frente.