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>
162 lines
11 KiB
Bash
Executable File
162 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# test-atuq-suite.sh — corre TODOS los guardianes de `atuq`, en orden de coste, y da un cuadro.
|
|
#
|
|
# ══ POR QUÉ EXISTE ════════════════════════════════════════════════════════════════════════════
|
|
# Los guardianes de atuq son VEINTE y ninguno corre solo. Ya pasó lo que tenía que pasar: el de
|
|
# descargas estuvo ROJO dos días y nadie lo corrió (commit `29831e62`), y el 2026-09-15 el artefacto
|
|
# vigente estuvo SIN SELLAR desde el commit de la bóveda hasta que alguien miró — durante esas horas
|
|
# ningún guardián podía medir nada y el repo se veía igual de sano. Un guardián que nadie corre es
|
|
# documentación, no una medición.
|
|
#
|
|
# ══ LO PRIMERO QUE MIRA ES EL SELLO, Y NO ES UN DETALLE ═══════════════════════════════════════
|
|
# Todo `recipes/atuq/` es `source.dir` ⇒ tocar una extensión, `atuq.cfg`, la política o el README
|
|
# cambia el ArtifactHash, y los guardianes se NIEGAN a medir un artefacto que no sea el vigente. El
|
|
# ciclo es **editar todo → resellar UNA vez → medir**; al revés se pagan 340 M de store por edición.
|
|
# Si falta el sello, esto NO corre nada: dice cómo construirlo y sale.
|
|
#
|
|
# ══ EL CONTROL DE ESTA CORRIDA ════════════════════════════════════════════════════════════════
|
|
# Hoy (2026-09-18) el resultado CORRECTO es **20 en verde**. El vigésimo entró ese día: primero
|
|
# truncado —sólo su etapa A, porque las otras cinco chocaban con un muro ajeno (§7.septies)— y desde
|
|
# esa misma tarde ENTERO, con sus seis etapas. Lo fue «19 en verde» desde el 2026-09-16. Lo fue «17 y dos rojos» hasta esta
|
|
# tarde: los dos eran los verbos de la bóveda, y se apagaron al subir el pin de `puriy-costura`
|
|
# (SDD 26 §7.quinquies.bis). Si mañana hay un rojo, cambió algo que hay que ir a ver.
|
|
#
|
|
# ⚠ **Un cuadro entero en verde puede ser un producto sano o un runner que no corre nada, y se ven
|
|
# igual.** Mientras hubo un rojo conocido, el número lo distinguía solo. Ahora no, así que lo que
|
|
# sostiene la corrida son otras dos cosas, las dos comprobadas:
|
|
#
|
|
# · **la puerta del sello** — contra un store sin el artefacto, esto NO corre nada y devuelve 1
|
|
# (verificado a propósito con un store vacío);
|
|
# · **el control de cada guardián** — todos traen el suyo (una rotura que TIENE que matarlos, o un
|
|
# positivo que TIENE que aparecer). El runner no los reemplaza: los junta.
|
|
#
|
|
# ⚠ Y la advertencia que este fichero se aplicó a sí mismo dos veces: la cabecera anunció «un rojo»
|
|
# y eran dos, y después «dos» cuando ya no quedaba ninguno. **Un número escrito como predicción
|
|
# envejece callado.** Si el cuadro no coincide con esto, el sospechoso es esta cabecera.
|
|
#
|
|
# ══ LO QUE CUESTA ═════════════════════════════════════════════════════════════════════════════
|
|
# **~38 min** en gioser, en serie (32,1 min medidos el 2026-09-16 sobre 19; el vigésimo suma 6,
|
|
# medidos en dos corridas seguidas — levanta cuatro compositores y dos navegadores). Los cuatro primeros salen en 10 s y no tocan
|
|
# el navegador: para «¿rompí algo del cruce política↔XPI?» alcanza con `--only` y no hace falta la
|
|
# media hora. Los caros son `sct` (241 s, seis cargas), `archivo-semantico` (227 s, embeddings),
|
|
# `instalacion` (180 s, tres sesiones) y `ia` (180 s, levanta `llama-server`).
|
|
#
|
|
# ══ QUÉ NO ESTÁ ACÁ ═══════════════════════════════════════════════════════════════════════════
|
|
# Nada, hoy. El de notificaciones (`scripts/wlr/dunst-headless.sh --via-atuq`) vive en el arnés de
|
|
# sway y por eso se había quedado afuera; entra igual, porque una lista con un hueco nombrado en la
|
|
# cabecera se lee como cobertura al tercer día. Si mañana alguien saca uno, que lo nombre acá.
|
|
#
|
|
# NO CONSTRUYE NADA y NO TOMA EL LOCK de la granja: sólo lee artefactos ya sellados, así que se puede
|
|
# correr con la granja a pleno. Va en SERIE a propósito — cada guardián levanta un navegador y esta
|
|
# máquina tiene cuatro núcleos sin swap; dos a la vez es un OOM. Y cada uno escribe en SU fichero:
|
|
# dos corridas sobre el mismo log se MEZCLAN y el resultado parece un pase.
|
|
#
|
|
# scripts/test-atuq-suite.sh # los diecinueve, en orden de coste
|
|
# scripts/test-atuq-suite.sh --list # qué afirma cada uno, sin correr nada
|
|
# scripts/test-atuq-suite.sh --only sct # sólo los que contengan «sct» en el nombre
|
|
# scripts/test-atuq-suite.sh --store DIR --logs DIR
|
|
set -u
|
|
|
|
STORE="./store"
|
|
LOGS="work/atuq-suite"
|
|
SOLO=""
|
|
LISTAR=0
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--store) STORE="$2"; shift 2 ;;
|
|
--logs) LOGS="$2"; shift 2 ;;
|
|
--only) SOLO="$2"; shift 2 ;;
|
|
--list) LISTAR=1; shift ;;
|
|
-h|--help) sed -n '2,40p' "$0"; exit 0 ;;
|
|
*) printf 'no entiendo «%s» — ver --help\n' "$1" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
# etiqueta|comando|qué AFIRMA. El orden es de barato a caro: lo que se rompe gratis
|
|
# se descubre en el primer minuto y no después de media hora de navegadores.
|
|
GUARDIANES=(
|
|
"vigia-atuq-verbos|python3 scripts/vigia-atuq-verbos.py|el host PINEADO atiende los verbos que mandan las diez extensiones (§7)"
|
|
"test-atuq-boveda-coherente|python3 scripts/test-atuq-boveda-coherente.py|la bóveda está enchufada en los SEIS lugares (SDD-BOVEDA §8); el sexto es quién la DECLARA en la imagen (SDD 26 §7.decies)"
|
|
# Corría truncado (`--hasta A`) mientras el muro del §7.septies tapaba las otras cinco etapas.
|
|
# Desde el 2026-09-18 corre ENTERO: seis etapas, ~6 min, con el navegador de verdad, el diálogo de
|
|
# consentimiento a la vista y el control de decir que NO. Es el único de la suite que mide la
|
|
# cadena hasta el CAMPO del formulario y no hasta la respuesta del host.
|
|
"test-atuq-boveda-metal|python3 scripts/test-atuq-boveda-metal.py|la bóveda entrega la contraseña, y SÓLO con el sí de una persona (§7.novies)"
|
|
"test-atuq-politica|python3 scripts/test-atuq-politica.py|el cruce XPI empaquetado ↔ política, con cinco roturas a propósito"
|
|
"test-atuq-rootfs|python3 scripts/test-atuq-rootfs.py|el rootfs resuelve todos los NEEDED y nada se cae al LAB"
|
|
"test-atuq-inicio|python3 scripts/test-atuq-inicio.py|la página de inicio y la pestaña nueva son las NUESTRAS (§4.e)"
|
|
"test-atuq-chrome|python3 scripts/test-atuq-chrome.py|el JS de atuq.cfg llega al gBrowser, y la vista dividida (§4.g)"
|
|
"test-atuq-nativo|python3 scripts/test-atuq-nativo.py|una extensión habla con un proceso NATIVO y le vuelve la respuesta (§7)"
|
|
"test-atuq-foco|python3 scripts/test-atuq-foco.py|el navegador MUESTRA el foco del sistema y no lo apaga (§6.5)"
|
|
"test-atuq-instalacion|python3 scripts/test-atuq-instalacion.py|quién instala de verdad las extensiones: el ESCANEO, no la política"
|
|
"test-atuq-ruteo|python3 scripts/test-atuq-ruteo.py|el contenedor sale por SU proxy — saludo SOCKS5 (§6.8)"
|
|
"test-atuq-archivo|python3 scripts/test-atuq-archivo.py|congelar lo leído al CAS y buscarlo; nunca lo privado (§6.3)"
|
|
"test-atuq-descargas|python3 scripts/test-atuq-descargas.py|la descarga entra al CAS con su BLAKE3 y el fichero no se toca (§6.2)"
|
|
"test-atuq-medios|python3 scripts/test-atuq-medios.py|el medio lo abre mpv, no una pestaña (§6.6)"
|
|
"test-atuq-torrent|python3 scripts/test-atuq-torrent.py|magnet → daemon propio que sobrevive al navegador (§6.9)"
|
|
"test-atuq-sct|python3 scripts/test-atuq-sct.py|la cadena de sct entera: seis cargas y un servidor HTTP real (§6.1)"
|
|
"test-atuq-codecs|bash scripts/test-atuq-codecs.sh|H.264+AAC · VP9+Opus · AV1 · MP3 · FLAC REPRODUCEN (§4.f)"
|
|
"test-atuq-ia|python3 scripts/test-atuq-ia.py|la barra lateral le pregunta a un modelo de ESTA máquina (§6.7)"
|
|
"test-atuq-archivo-semantico|python3 scripts/test-atuq-archivo-semantico.py|el archivo contesta por PARECIDO, no por palabra exacta (§6.3)"
|
|
"dunst-via-atuq|sh scripts/wlr/dunst-headless.sh --via-atuq|una PÁGINA WEB notifica y la notificación se DIBUJA (§6.10)"
|
|
)
|
|
|
|
if [ "$LISTAR" = 1 ]; then
|
|
printf '── los guardianes de atuq, de barato a caro ──\n'
|
|
for g in "${GUARDIANES[@]}"; do
|
|
IFS='|' read -r etq cmd afirma <<<"$g"
|
|
printf ' %-30s %s\n %s\n' "$etq" "$afirma" "$cmd"
|
|
done
|
|
exit 0
|
|
fi
|
|
|
|
# ── el sello, antes que nada ──────────────────────────────────────────────────────────────────
|
|
H=$(./target/release/takana --store "$STORE" hash recipes/atuq.toml --check 2>/dev/null | tail -1)
|
|
case "$H" in
|
|
*SELLADO*) : ;;
|
|
*) printf 'no pude preguntar el hash de atuq (¿sin `target/release/takana`?)\n'; exit 2 ;;
|
|
esac
|
|
if [ "${H#* }" != "SELLADO" ]; then
|
|
printf '✗ el `atuq` VIGENTE no está sellado: %s\n' "${H%% *}"
|
|
printf ' Ningún guardián puede medir — se niegan, y con razón. Construilo UNA vez y volvé:\n\n'
|
|
printf ' flock -o work/.farm-build.lock ./target/release/takana --store %s build recipes/atuq.toml\n\n' "$STORE"
|
|
exit 1
|
|
fi
|
|
printf '── los guardianes de atuq sobre %s ──\n' "${H%% *}"
|
|
mkdir -p "$LOGS"
|
|
|
|
verdes=0; rojos=0; saltados=0
|
|
RESUMEN=()
|
|
for g in "${GUARDIANES[@]}"; do
|
|
IFS='|' read -r nombre cmd afirma <<<"$g"
|
|
case "$nombre" in *"$SOLO"*) : ;; *) continue ;; esac
|
|
log="$LOGS/$nombre.txt"
|
|
printf ' %-30s ' "$nombre"
|
|
t0=$(date +%s)
|
|
# Cada guardián a SU fichero: dos corridas sobre el mismo log se MEZCLAN y el resultado parece un
|
|
# pase — ya pasó (se leyó «✓ SALIDA=0» de la corrida vieja con las cargas de la nueva).
|
|
$cmd >"$log" 2>&1
|
|
rc=$?
|
|
t=$(( $(date +%s) - t0 ))
|
|
# 77 es «no están las condiciones» (falta un rootfs, falta un modelo), no un fallo del producto.
|
|
case "$rc" in
|
|
0) veredicto="✓ verde "; verdes=$((verdes+1)) ;;
|
|
77) veredicto="— saltado"; saltados=$((saltados+1)) ;;
|
|
*) veredicto="✗ ROJO "; rojos=$((rojos+1)) ;;
|
|
esac
|
|
printf '%s %4ds %s\n' "$veredicto" "$t" "$afirma"
|
|
RESUMEN+=("$veredicto|$nombre|$t|$log")
|
|
done
|
|
|
|
printf '\n'
|
|
if [ "$rojos" -gt 0 ]; then
|
|
printf 'los ROJOS, con su salida entera:\n'
|
|
for r in "${RESUMEN[@]}"; do
|
|
case "$r" in "✗"*) printf ' %s → %s\n' "$(echo "$r" | cut -d'|' -f2)" "$(echo "$r" | cut -d'|' -f4)" ;; esac
|
|
done
|
|
printf '\n'
|
|
fi
|
|
printf '%d verde(s) · %d rojo(s) · %d saltado(s) — salidas en %s/\n' "$verdes" "$rojos" "$saltados" "$LOGS"
|
|
[ "$rojos" -eq 0 ]
|