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>
This commit is contained in:
@@ -3,31 +3,38 @@
|
||||
|
||||
python3 scripts/test-atuq-boveda-coherente.py
|
||||
python3 scripts/test-atuq-boveda-coherente.py --negative-control
|
||||
python3 scripts/test-atuq-boveda-coherente.py --negative-control-perfil
|
||||
|
||||
── QUÉ MIRA, Y POR QUÉ ESTE GUARDIÁN EXISTE APARTE ───────────────────────────────────────────
|
||||
Una extensión de `atuq` está enchufada en CINCO lugares distintos, y ninguno da error si falta:
|
||||
Una extensión de `atuq` está enchufada en SEIS lugares distintos, y ninguno da error si falta:
|
||||
|
||||
manifest.json el id que la extensión declara
|
||||
distribution/policies.json la política que la instala
|
||||
native-messaging/*.json el permiso para hablarle al host
|
||||
atuq.cfg las preferencias que la acompañan
|
||||
recipes/puriy-costura.toml el COMMIT del host, que decide si sus verbos existen
|
||||
docs/state/targets.toml quién DECLARA al dueño y al diálogo en las imágenes
|
||||
|
||||
Si falta la política, la extensión no se instala y el usuario ve un navegador sin la función. Si
|
||||
falta el permiso del host, la extensión se instala y **se conecta a nada** —`connectNative` falla
|
||||
en silencio y la insignia no aparece nunca—. Si faltan las preferencias, la bóveda y el gestor de
|
||||
Gecko se pelean por el mismo campo. Y si el commit pineado del host es ANTERIOR a los verbos, la
|
||||
extensión conecta, manda `vault.match` y recibe «verbo desconocido» —que `fondo.js` lee como «no hay
|
||||
bóveda» y se calla—. Ninguno de los cuatro se ve como un error: se ven como «no anda».
|
||||
bóveda» y se calla—. Y si `boveda` y `shuma-pregunta` no están declaradas en el perfil, la
|
||||
extensión se instala, conecta, manda `vault.match` y el host contesta `{"ok":true,"locked":true}`
|
||||
—«cerrada», que es una respuesta EXITOSA— porque del otro lado del socket no hay nadie: el dueño
|
||||
está sellado y en ninguna imagen. Ninguno de los cinco se ve como un error: se ven como «no anda».
|
||||
|
||||
Éste NO reemplaza al guardián de metal (servidor HTTP, navegador real, login real, el diálogo de
|
||||
consentimiento a la vista). Lo precede: mide lo que se puede medir sin construir nada, en un
|
||||
segundo, y ahorra descubrir en metal un renglón que faltaba en un JSON.
|
||||
|
||||
── LOS DOS CONTROLES NEGATIVOS, UNO POR AFIRMACIÓN ───────────────────────────────────────────
|
||||
── LOS TRES CONTROLES NEGATIVOS, UNO POR AFIRMACIÓN ──────────────────────────────────────────
|
||||
`--negative-control` saca el permiso del host de una copia en memoria y exige que esto lo detecte.
|
||||
`--negative-control-verbo` le manda al quinto chequeo un verbo inventado y exige lo mismo. Sin
|
||||
ellos, un guardián que siempre dice que sí se vería idéntico a uno que funciona.
|
||||
`--negative-control-verbo` le manda al quinto chequeo un verbo inventado y exige lo mismo.
|
||||
`--negative-control-perfil` saca a `boveda` de los cuatro perfiles de escritorio, también en
|
||||
memoria, y exige que el sexto lo vea. Sin ellos, un guardián que siempre dice que sí se vería
|
||||
idéntico a uno que funciona.
|
||||
|
||||
Y el quinto chequeo trae además un control POSITIVO —`sct.observe`, que el host pineado tiene que
|
||||
tener sí o sí—, porque es un `grep` que espera cero y un cero puede ser una ausencia o un sitio
|
||||
@@ -38,6 +45,7 @@ import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tomllib
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
ATUQ = os.path.join(ROOT, "recipes/atuq")
|
||||
@@ -151,6 +159,56 @@ def revisar_el_host(verbo_extra=None):
|
||||
mal(f"el host pineado ({commit[:9]}) NO atiende {v}: la extensión lo manda y recibe "
|
||||
f"«verbo desconocido», que fondo.js lee como «no hay bóveda» y se calla")
|
||||
|
||||
# ── 9. EL SEXTO LUGAR: ¿alguien DECLARA al dueño y al diálogo en las imágenes? ───────────────
|
||||
# El quinto lugar pregunta si el host SABE los verbos. Éste pregunta lo de una capa más abajo, que
|
||||
# es lo que costó tres semanas de no ver (SDD 26 §7.sexies): 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 Gecko muere con cada pestaña—, así que le habla a un DUEÑO; y el 2026-09-18 el dueño
|
||||
# estaba SELLADO y en `perfiles: []`, o sea en ninguna imagen. Sellado ≠ instalado.
|
||||
#
|
||||
# Se mira `targets.toml` —el manifiesto de objetivo— y no `build-state.json`, que es su derivado:
|
||||
# lo que decide qué va en la imagen es la declaración, y el estado se recalcula solo.
|
||||
PERFILES_ESCRITORIO = ["escritorio-kde", "escritorio-gnome", "escritorio-cosmic", "escritorio-sway"]
|
||||
# Las DOS o ninguna: media bóveda es una que niega todo en silencio. Sin el dueño, `vault.match` no
|
||||
# ofrece nada; sin el diálogo, `Command::new` falla y TODO `vault.fill` se deniega.
|
||||
LA_BOVEDA_EN_LA_IMAGEN = ["boveda", "shuma-pregunta"]
|
||||
# El control POSITIVO, por lo mismo que el del §quinto lugar: un `in` que espera encontrar puede
|
||||
# fallar porque la raíz falta o porque estoy leyendo el campo equivocado, y las dos se ven igual.
|
||||
# `atuq` TIENE que estar en los cuatro — si no está, este chequeo no está midiendo el fichero.
|
||||
RAIZ_CONTROL = "atuq"
|
||||
TARGETS = os.path.join(ROOT, "docs/state/targets.toml")
|
||||
|
||||
|
||||
def revisar_los_perfiles(sin_esta=None):
|
||||
try:
|
||||
with open(TARGETS, "rb") as f:
|
||||
perfiles = tomllib.load(f)["perfil"]
|
||||
except FileNotFoundError:
|
||||
mal(f"no existe {os.path.relpath(TARGETS, ROOT)}: el sexto lugar queda SIN COMPROBAR")
|
||||
return
|
||||
except Exception as e: # TOML roto es un fallo ruidoso, no un «está bien»
|
||||
mal(f"no se pudo leer {os.path.relpath(TARGETS, ROOT)} ({e})")
|
||||
return
|
||||
|
||||
for perfil in PERFILES_ESCRITORIO:
|
||||
if perfil not in perfiles:
|
||||
mal(f"{perfil} no existe en targets.toml: ¿se renombró un perfil de escritorio?")
|
||||
continue
|
||||
raices = list(perfiles[perfil].get("paquetes", []))
|
||||
if sin_esta:
|
||||
raices = [r for r in raices if r != sin_esta]
|
||||
if RAIZ_CONTROL not in raices:
|
||||
mal(f"CONTROL ROTO: {perfil} no declara {RAIZ_CONTROL}. O el navegador se cayó de la "
|
||||
f"imagen, o estoy leyendo el campo equivocado — y entonces lo de abajo no prueba nada")
|
||||
continue
|
||||
faltan = [r for r in LA_BOVEDA_EN_LA_IMAGEN if r not in raices]
|
||||
if faltan:
|
||||
mal(f"{perfil} NO declara {', '.join(faltan)}: la extensión se instala igual y la "
|
||||
f"bóveda contesta `locked:true` con `ok:true` — apagada, y sin un solo error")
|
||||
else:
|
||||
bien(f"{perfil} declara el dueño y el diálogo ({RAIZ_CONTROL} de control)")
|
||||
|
||||
|
||||
fallas = []
|
||||
|
||||
|
||||
@@ -168,7 +226,7 @@ def leer(p):
|
||||
return f.read()
|
||||
|
||||
|
||||
def revisar(permisos_host, verbo_extra=None):
|
||||
def revisar(permisos_host, verbo_extra=None, sin_perfil=None):
|
||||
# 1. La extensión existe y declara el id que todos los demás nombran.
|
||||
try:
|
||||
m = json.loads(leer("extensions/boveda/manifest.json"))
|
||||
@@ -232,10 +290,14 @@ def revisar(permisos_host, verbo_extra=None):
|
||||
# 8. Y el quinto lugar, que vive en otra receta y en otro repo.
|
||||
revisar_el_host(verbo_extra)
|
||||
|
||||
# 9. Y el sexto, que vive en el manifiesto de objetivo: quién la pone en la imagen.
|
||||
revisar_los_perfiles(sin_perfil)
|
||||
|
||||
|
||||
def main():
|
||||
control = "--negative-control" in sys.argv
|
||||
control_verbo = "--negative-control-verbo" in sys.argv
|
||||
control_perfil = "--negative-control-perfil" in sys.argv
|
||||
host = json.loads(leer("native-messaging/puriy_costura.json"))
|
||||
permisos = list(host.get("allowed_extensions", []))
|
||||
verbo_extra = None
|
||||
@@ -247,9 +309,15 @@ def main():
|
||||
# mirando el host sino contestando que sí.
|
||||
verbo_extra = "vault.este_verbo_no_existe"
|
||||
print(f"⚠ control negativo: se le agrega el verbo inventado {verbo_extra}")
|
||||
sin_perfil = None
|
||||
if control_perfil:
|
||||
# El dueño, sacado de una copia en memoria de los cuatro perfiles: si el sexto chequeo no
|
||||
# lo ve faltar, está contestando que sí en vez de mirar `targets.toml`.
|
||||
sin_perfil = "boveda"
|
||||
print(f"⚠ control negativo: se saca {sin_perfil} de los perfiles de escritorio")
|
||||
|
||||
print(f"── la bóveda en atuq ──")
|
||||
revisar(permisos, verbo_extra)
|
||||
revisar(permisos, verbo_extra, sin_perfil)
|
||||
|
||||
if control:
|
||||
if any("allowed_extensions" in f for f in fallas):
|
||||
@@ -263,6 +331,12 @@ def main():
|
||||
return 0
|
||||
print("\n✗ el control del verbo NO lo detectó: el quinto chequeo no mide nada")
|
||||
return 1
|
||||
if control_perfil:
|
||||
if any(sin_perfil in f and "NO declara" in f for f in fallas):
|
||||
print("\n✓ el control negativo del perfil lo detectó")
|
||||
return 0
|
||||
print("\n✗ el control del perfil NO lo detectó: el sexto chequeo no mide nada")
|
||||
return 1
|
||||
if fallas:
|
||||
print(f"\n✗ {len(fallas)} problema(s)")
|
||||
return 1
|
||||
|
||||
@@ -6,12 +6,15 @@
|
||||
python3 scripts/test-atuq-boveda-metal.py --list # qué afirma cada etapa, sin correr nada
|
||||
|
||||
── POR QUÉ ESTE GUARDIÁN, Y POR QUÉ NO ALCANZA CON EL DE COHERENCIA ──────────────────────────
|
||||
`test-atuq-boveda-coherente.py` mira los CINCO lugares donde una extensión se enchufa y tarda un
|
||||
`test-atuq-boveda-coherente.py` mira los SEIS lugares donde una extensión se enchufa y tarda un
|
||||
segundo. Es lo que hay que correr primero y no reemplaza a nada. Lo que no puede contestar es si del
|
||||
otro lado del cable hay alguien: el 2026-09-18 los cinco lugares estaban en orden —manifiesto,
|
||||
política, permiso, prefs y el commit del host con sus verbos— y la bóveda contestaba **cerrada** en
|
||||
las cuatro imágenes, porque el DUEÑO de la base y el DIÁLOGO de consentimiento no estaban en el
|
||||
corpus. Ningún guardián de ficheros podía verlo; éste empieza justamente por ahí.
|
||||
otro lado del cable hay alguien: el 2026-09-18 los cinco lugares que entonces se miraban estaban
|
||||
en orden —manifiesto, política, permiso, prefs y el commit del host con sus verbos— y la bóveda
|
||||
contestaba **cerrada** en las cuatro imágenes, porque el DUEÑO de la base y el DIÁLOGO de
|
||||
consentimiento no estaban en el corpus. Ningún guardián de FICHEROS podía verlo; éste empieza
|
||||
justamente por ahí. (El sexto lugar nació de eso: desde el 2026-09-21 aquél mira además quién
|
||||
DECLARA al dueño en la imagen, que es la mitad del §7.sexies que sí se puede ver sin construir
|
||||
nada — y la que volvió a morder el 2026-09-21, con las dos recetas selladas y en `perfiles: []`.)
|
||||
|
||||
── LAS SEIS ETAPAS, Y QUÉ AFIRMA CADA UNA ────────────────────────────────────────────────────
|
||||
A sin la app `boveda`, el host contesta `locked:true` ← el control, y es el bug del §7.sexies
|
||||
|
||||
@@ -77,7 +77,7 @@ done
|
||||
# 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 CINCO lugares (SDD-BOVEDA §8)"
|
||||
"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
|
||||
|
||||
Reference in New Issue
Block a user