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:
@@ -3317,6 +3317,107 @@ llimphi de escritorio podía pintar sin Vulkan (§7.septies), y que el dueño at
|
|||||||
(§7.octies). Las tres se veían igual desde el navegador: una bóveda que no ofrece nada, sin un solo
|
(§7.octies). Las tres se veían igual desde el navegador: una bóveda que no ofrece nada, sin un solo
|
||||||
error. Es el argumento entero a favor de medir en metal y no leer ficheros.
|
error. Es el argumento entero a favor de medir en metal y no leer ficheros.
|
||||||
|
|
||||||
|
#### 7.decies La bóveda estaba SELLADA y en ninguna imagen — el sexto lugar donde una extensión se enchufa (2026-09-21)
|
||||||
|
|
||||||
|
El §7.novies cerró la función: las seis etapas en verde, el diálogo a la vista, el control de decir
|
||||||
|
que no. Lo que quedaba abierto era la **decisión 1 del §7.sexies** —«en qué imágenes se declaran»—
|
||||||
|
con su respuesta escrita como **NO**, y con el motivo: mientras ninguna app llimphi pudiera pintar
|
||||||
|
(§7.septies), declararlas era instalar 43 M de binarios que niegan todo sin un error.
|
||||||
|
|
||||||
|
Ese motivo se cayó el 2026-09-18. La respuesta de hoy es **SÍ, en las cuatro**, y antes de tomarla
|
||||||
|
la pregunta se volvió a medir en vez de darla por sabida:
|
||||||
|
|
||||||
|
```
|
||||||
|
atuq sealed perfiles=['escritorio-cosmic','escritorio-gnome','escritorio-kde','escritorio-sway']
|
||||||
|
puriy-costura sealed perfiles=['escritorio-cosmic','escritorio-gnome','escritorio-kde','escritorio-sway']
|
||||||
|
boveda sealed perfiles=[]
|
||||||
|
shuma-pregunta sealed perfiles=[]
|
||||||
|
```
|
||||||
|
|
||||||
|
**`sealed` con `perfiles: []` es la lección de `foot` otra vez** —y no por falta de haberla
|
||||||
|
escrito: `targets.toml` la repetía **quince veces** antes de hoy—: una receta sellada que ningún
|
||||||
|
perfil declara NO ESTÁ EN NINGUNA IMAGEN, y la métrica de clausura no lo puede ver porque mide lo
|
||||||
|
declarado. Las dos entran a los cuatro perfiles de escritorio de
|
||||||
|
`docs/state/targets.toml`, **las dos o ninguna**: sin el dueño `vault.match` no ofrece nada, y sin
|
||||||
|
el diálogo `Command::new` falla y TODO `vault.fill` se deniega — media bóveda es una que niega todo
|
||||||
|
en silencio. Cuestan **~43 M por imagen** (22 M + 21 M medidos sobre los artefactos sellados), contra
|
||||||
|
los ~1,25 GiB que ya lleva el §6.7.
|
||||||
|
|
||||||
|
##### El hueco que apareció al declararlas: estar en la imagen no es poder abrirla
|
||||||
|
|
||||||
|
Con las dos raíces puestas, la app viaja en las cuatro imágenes y **sigue sin existir para quien la
|
||||||
|
usa**: `recipes/boveda.toml` instalaba `/usr/bin/boveda` y nada más, y los lanzadores de los cuatro
|
||||||
|
escritorios leen `/usr/share/applications`. A un binario que nadie lista sólo se llega escribiendo
|
||||||
|
`boveda` en una terminal. Es **la misma forma de fallo, una capa más arriba**: la función instalada,
|
||||||
|
apagada y sin un error — que es lo único que este capítulo entero viene persiguiendo.
|
||||||
|
|
||||||
|
Entra `boveda.desktop` en la fase `install` de la receta. Tres cosas se midieron antes de escribirlo:
|
||||||
|
|
||||||
|
- **el icono existe.** `Icon=dialog-password` es nombre del icon naming spec, y está en los tres
|
||||||
|
temas que los perfiles declaran: `breeze-icons` (6 ficheros), `adwaita-icon-theme` (1),
|
||||||
|
`cosmic-icons` (2). El cuarto perfil (sway) lleva sólo `hicolor`, que por diseño no trae iconos:
|
||||||
|
ahí cae al genérico, que es degradarse y no romperse;
|
||||||
|
- **el fichero lo acepta el validador de verdad** —el `desktop-file-validate` del artefacto
|
||||||
|
`desktop-file-utils`, con `atuq.desktop` de control, que pasa sin una observación—. Deja un hint
|
||||||
|
sobre `Categories=Utility;Security;`: que `Security` se empareja con `Settings` o `System`. **Las
|
||||||
|
dos formas que callan ese hint lo cambian por uno peor** —medido: `Utility;Security;System;` y
|
||||||
|
`Utility;Security;Settings;` traen dos categorías principales ⇒ «application might appear more
|
||||||
|
than once in the application menu»—. Se queda como está, que es además lo que usa KeePassXC;
|
||||||
|
- **⚠ y la ventana NO se va a poder emparejar con el lanzador, y no es de acá.** `llimphi_ui::run`
|
||||||
|
no llama nunca a `with_name`, y winit 0.30.13 sólo manda `set_app_id` `if let Some(name) =
|
||||||
|
attributes.platform_specific.name` ⇒ **la ventana sale sin `app_id`**, y con el título `"llimphi"`,
|
||||||
|
que es el default de `App::title` y `BovedaApp` no sobrescribe. Por eso el `.desktop` no lleva
|
||||||
|
`StartupWMClass`: no habría contra qué emparejarlo. Vale para **toda** app llimphi, no para ésta:
|
||||||
|
el dock las ve a todas iguales y sin nombre. Es de llimphi —como el muro del §7.septies— y se
|
||||||
|
arregla allá.
|
||||||
|
|
||||||
|
El `.desktop` mueve el hash de la receta: `b3:b0c6adc4` ⇒ `b3:3f1072cc`, reconstruida en el worker
|
||||||
|
con la guarda del §7.quinquies puesta (`### receta verificada 3f1072cc…` antes de compilar nada,
|
||||||
|
porque el latido revierte la receta del worker cada media hora y un acierto de caché sobre la receta
|
||||||
|
vieja imprime `SELLADA` en cero segundos). Y el artefacto se miró por dentro, que es la regla 3:
|
||||||
|
|
||||||
|
```
|
||||||
|
/.hammer/recipe.toml
|
||||||
|
/usr/bin/boveda
|
||||||
|
/usr/share/applications/boveda.desktop ← 22 M, y el validador del store lo acepta
|
||||||
|
```
|
||||||
|
|
||||||
|
##### El SEXTO lugar, y su guardián
|
||||||
|
|
||||||
|
`test-atuq-boveda-coherente.py` decía —y este documento con él— que una extensión de `atuq` está
|
||||||
|
enchufada en **cinco** lugares. Son **seis**, y el sexto es el que faltaba:
|
||||||
|
|
||||||
|
| lugar | qué decide | cómo se ve cuando falta |
|
||||||
|
|---|---|---|
|
||||||
|
| `manifest.json` | el id que la extensión declara | — |
|
||||||
|
| `distribution/policies.json` | la política que la instala | navegador sin la función |
|
||||||
|
| `native-messaging/*.json` | el permiso para hablarle al host | `connectNative` falla en silencio |
|
||||||
|
| `atuq.cfg` | las preferencias que la acompañan | el gestor de Gecko se pelea por el campo |
|
||||||
|
| `recipes/puriy-costura.toml` | el COMMIT del host: si sus verbos existen | «verbo desconocido» ⇒ se calla |
|
||||||
|
| **`docs/state/targets.toml`** | **quién DECLARA al dueño y al diálogo en la imagen** | **`ok:true, locked:true`** |
|
||||||
|
|
||||||
|
El sexto chequeo mira `targets.toml` —el manifiesto de objetivo, no `build-state.json`, que es su
|
||||||
|
derivado— y exige las dos raíces en los cuatro perfiles, con **control positivo**: `atuq` tiene que
|
||||||
|
estar ahí, porque un `in` que no encuentra puede ser una raíz ausente o un campo equivocado y las dos
|
||||||
|
se ven igual. El tercer control negativo (`--negative-control-perfil`) saca a `boveda` de una copia
|
||||||
|
en memoria y exige que esto lo vea; sin él, un chequeo que siempre dice que sí se vería idéntico a
|
||||||
|
uno que funciona. Probado en los dos sentidos: los cuatro perfiles en verde, y el control en rojo.
|
||||||
|
|
||||||
|
##### Lo que queda abierto, dicho como lo que es
|
||||||
|
|
||||||
|
1. **quién levanta la app.** Hoy: la persona, desde el lanzador. Mientras no esté abierta, la bóveda
|
||||||
|
del navegador contesta `locked:true` —correcto, y es lo que hace cualquier gestor de contraseñas—,
|
||||||
|
pero nadie decidió todavía si debe autoarrancar con la sesión. No se decide de paso: autoarrancar
|
||||||
|
la ata a que la identidad del llavero esté desbloqueada en el login (la decisión 2 del §7.sexies,
|
||||||
|
que sigue abierta);
|
||||||
|
2. **el único proveedor de GL de las cuatro imágenes es `iris` (Intel).** `mesa-llvmpipe` no está en
|
||||||
|
ningún perfil y `mesa-swrast` sólo en `escritorio-mirada` — y softpipe no le alcanza a wgpu, que
|
||||||
|
pide compute (§7.septies). O sea que en metal sin GPU Intel el diálogo no pinta… igual que no
|
||||||
|
pintaría el escritorio entero, que también es cliente de GL: **la bóveda no agrega un hueco, lo
|
||||||
|
hereda**. Lo que taparía el caso de la VM es un proveedor por software en el perfil, y eso es una
|
||||||
|
decisión de tamaño con dos candidatos (`mesa-llvmpipe`, o lavapipe como receta nueva), no un
|
||||||
|
arreglo de paso.
|
||||||
|
|
||||||
## 8. Plan, por unidades de trabajo
|
## 8. Plan, por unidades de trabajo
|
||||||
|
|
||||||
Cada una cierra sola, se commitea y se pushea. El orden no es preferencia: cada una destraba a la
|
Cada una cierra sola, se commitea y se pushea. El orden no es preferencia: cada una destraba a la
|
||||||
@@ -3344,7 +3445,7 @@ siguiente.
|
|||||||
| 9 | **Medios (6.6) ✅ y torrent (6.9) ✅ — 2026-09-10.** El medio lo abre `mpv`; el torrent lo toma `puriy-costura-torrent`, un daemon **propio, configurable y perezoso** que sobrevive al navegador y cosecha al CAS. Medido antes de decidir: la pila de librqbit compila para musl (226 crates), así que la decisión fue «no ahí» y no «no se puede». **Faltan** el foco (6.5) y la IA local (6.7), ésta bloqueada porque el corpus no tiene modelo ni embeddings | 6.5–6.7, 6.9 | 5 ✅ |
|
| 9 | **Medios (6.6) ✅ y torrent (6.9) ✅ — 2026-09-10.** El medio lo abre `mpv`; el torrent lo toma `puriy-costura-torrent`, un daemon **propio, configurable y perezoso** que sobrevive al navegador y cosecha al CAS. Medido antes de decidir: la pila de librqbit compila para musl (226 crates), así que la decisión fue «no ahí» y no «no se puede». **Faltan** el foco (6.5) y la IA local (6.7), ésta bloqueada porque el corpus no tiene modelo ni embeddings | 6.5–6.7, 6.9 | 5 ✅ |
|
||||||
| 10 | **Foco (6.5) — 2026-09-10.** Entra al corpus la cadena `nftables` (libmnl + libnftnl + nft 1.1.6), que el grafo pedía y nadie había puesto, con dos arreglos de fábrica: el sello de tiempo que rompía la reproducción y un bashismo. Medido con root: el cgroup en foco no sale y el de al lado sí. Y del lado del navegador, la extensión `foco` MUESTRA el estado y **no tiene verbo para apagarlo**. **Falta** quién pone a `atuq` en un cgroup (delegación, decisión de arje) y quién aplica la política (root) | 6.5 | 6 ✅ |
|
| 10 | **Foco (6.5) — 2026-09-10.** Entra al corpus la cadena `nftables` (libmnl + libnftnl + nft 1.1.6), que el grafo pedía y nadie había puesto, con dos arreglos de fábrica: el sello de tiempo que rompía la reproducción y un bashismo. Medido con root: el cgroup en foco no sale y el de al lado sí. Y del lado del navegador, la extensión `foco` MUESTRA el estado y **no tiene verbo para apagarlo**. **Falta** quién pone a `atuq` en un cgroup (delegación, decisión de arje) y quién aplica la política (root) | 6.5 | 6 ✅ |
|
||||||
| 11 | **Motor de inferencia local (6.7) — 2026-09-11.** Entra `recipes/llama-cpp.toml` (b10901, estática, 199 M, **REPRODUCE**), que resulta ser **un solo muro para dos pendientes**: el §6.7 y la mitad semántica del §6.3 no eran dos problemas, era que el corpus no tenía con qué correr un modelo (`pluma-llm` sólo tiene backends de nube; `rimay-verbo-fastembed` DESCARGA onnxruntime glibc + el modelo). ⚠ Y dejó medido lo que no se podía deducir: **`SOURCE_DATE_EPOCH` —la variable que nos da reproducibilidad— apagaba las SEIS perillas de ISA de ggml**, y el artefacto sellaba y corría con 0 `%ymm`. Ahora van declaradas y el `install` las comprueba. Guardián `scripts/test-llama-cpp.py` con control negativo vivo. **Faltan** el modelo (fuente pineada, no receta), los verbos del host y quién levanta el servidor | 6.7, y la mitad semántica de 6.3 | 5 ✅ |
|
| 11 | **Motor de inferencia local (6.7) — 2026-09-11.** Entra `recipes/llama-cpp.toml` (b10901, estática, 199 M, **REPRODUCE**), que resulta ser **un solo muro para dos pendientes**: el §6.7 y la mitad semántica del §6.3 no eran dos problemas, era que el corpus no tenía con qué correr un modelo (`pluma-llm` sólo tiene backends de nube; `rimay-verbo-fastembed` DESCARGA onnxruntime glibc + el modelo). ⚠ Y dejó medido lo que no se podía deducir: **`SOURCE_DATE_EPOCH` —la variable que nos da reproducibilidad— apagaba las SEIS perillas de ISA de ggml**, y el artefacto sellaba y corría con 0 `%ymm`. Ahora van declaradas y el `install` las comprueba. Guardián `scripts/test-llama-cpp.py` con control negativo vivo. **Faltan** el modelo (fuente pineada, no receta), los verbos del host y quién levanta el servidor | 6.7, y la mitad semántica de 6.3 | 5 ✅ |
|
||||||
| 12 | **La bóveda (SDD-BOVEDA §8) — a medias, 2026-09-15.** La décima extensión: ofrece la credencial del sitio abierto y no puede sacar una contraseña por su cuenta —`vault.match` contesta títulos y usuarios; la contraseña sale por `vault.fill`, que **pregunta en el escritorio**—. La dirección la pone el chrome, nunca la página. El gestor de Gecko se aparta como VALOR DE ARRANQUE y no como política. **Destrabada el 2026-09-16** (§7.quinquies.bis): el `Cargo.lock` de tawasuyu publicado —y resultó ser byte a byte el que la otra sesión ya tenía sin commitear—, el pin subido a `23a292863` ⇒ `b3:7d63655a`, construido en el worker (el vendoreo son 2,4 G y el hub estaba al 99%) y medido con el mismo `strings` que había diagnosticado el hueco: `vault` de **0 a 10**, con `cas`/`sct` de control. **Falta**, y no era lo que este renglón decía (§7.sexies, 2026-09-18): el host sellado contesta `vault.status → locked:true` porque **el dueño de la bóveda y el diálogo de consentimiento no estaban en el corpus** — la función está apagada de fábrica en las cuatro imágenes. Entran `recipes/boveda.toml` y `recipes/shuma-pregunta.toml`, **las dos SELLADAS el 2026-09-18** (`b3:59ffd74b` y `b3:99763eca`, construidas en el worker). ⚠ Y con eso apareció el muro de verdad, que no es de la bóveda: **ninguna app llimphi de escritorio abre ventana en esta distro** porque no hay Vulkan en ninguna imagen y el camino GL de llimphi arma la instancia sin display handle (§7.septies). **CERRADA el 2026-09-18** (§7.novies): el guardián de metal —`scripts/test-atuq-boveda-metal.py`— pasa sus **seis etapas**, con el navegador de verdad, el diálogo a la vista y el control de decir que NO. Para llegar hubo que arreglar **tres piezas ajenas al navegador**: el dueño y el diálogo no estaban en el corpus (§7.sexies), ninguna ventana llimphi podía pintar sin Vulkan (§7.septies, arreglado en llimphi) y el dueño atendía de a UN cliente, lo que con el navegador abierto dejaba la bóveda muda (§7.octies, arreglado en pacha con su test de regresión) | el gestor de contraseñas de la suite dentro del navegador | 5 ✅ |
|
| 12 | **La bóveda (SDD-BOVEDA §8) — a medias, 2026-09-15.** La décima extensión: ofrece la credencial del sitio abierto y no puede sacar una contraseña por su cuenta —`vault.match` contesta títulos y usuarios; la contraseña sale por `vault.fill`, que **pregunta en el escritorio**—. La dirección la pone el chrome, nunca la página. El gestor de Gecko se aparta como VALOR DE ARRANQUE y no como política. **Destrabada el 2026-09-16** (§7.quinquies.bis): el `Cargo.lock` de tawasuyu publicado —y resultó ser byte a byte el que la otra sesión ya tenía sin commitear—, el pin subido a `23a292863` ⇒ `b3:7d63655a`, construido en el worker (el vendoreo son 2,4 G y el hub estaba al 99%) y medido con el mismo `strings` que había diagnosticado el hueco: `vault` de **0 a 10**, con `cas`/`sct` de control. **Falta**, y no era lo que este renglón decía (§7.sexies, 2026-09-18): el host sellado contesta `vault.status → locked:true` porque **el dueño de la bóveda y el diálogo de consentimiento no estaban en el corpus** — la función está apagada de fábrica en las cuatro imágenes. Entran `recipes/boveda.toml` y `recipes/shuma-pregunta.toml`, **las dos SELLADAS el 2026-09-18** (`b3:59ffd74b` y `b3:99763eca`, construidas en el worker). ⚠ Y con eso apareció el muro de verdad, que no es de la bóveda: **ninguna app llimphi de escritorio abre ventana en esta distro** porque no hay Vulkan en ninguna imagen y el camino GL de llimphi arma la instancia sin display handle (§7.septies). **CERRADA el 2026-09-18** (§7.novies): el guardián de metal —`scripts/test-atuq-boveda-metal.py`— pasa sus **seis etapas**, con el navegador de verdad, el diálogo a la vista y el control de decir que NO. Para llegar hubo que arreglar **tres piezas ajenas al navegador**: el dueño y el diálogo no estaban en el corpus (§7.sexies), ninguna ventana llimphi podía pintar sin Vulkan (§7.septies, arreglado en llimphi) y el dueño atendía de a UN cliente, lo que con el navegador abierto dejaba la bóveda muda (§7.octies, arreglado en pacha con su test de regresión). **Y ENTRA A LAS IMÁGENES el 2026-09-21** (§7.decies): hasta ese día las dos estaban `sealed` con `perfiles: []` —o sea selladas y en ninguna imagen, la lección de `foot` que ese mismo fichero repetía quince veces—, así que la función seguía apagada de fábrica aunque anduviera. Se declaran en los cuatro perfiles de escritorio (~43 M por imagen) y la receta aprende a instalar `boveda.desktop`, porque estar en la imagen no es poder abrirla: sin entrada en `/usr/share/applications` a la app sólo se llega escribiendo su nombre en una terminal. El guardián de coherencia pasa de CINCO lugares a SEIS —el sexto es `targets.toml`— con su tercer control negativo. **Abierto**: quién la levanta con la sesión, y de dónde sale la raíz de las claves (decisión 2 del §7.sexies) | el gestor de contraseñas de la suite dentro del navegador | 5 ✅ |
|
||||||
| 9.a | **Proxy por contenedor ✅ v0.5** — contenedores por política + extensión con `proxy.onRequest` | 6.8, y NO dependía de 5: es API de Firefox | — |
|
| 9.a | **Proxy por contenedor ✅ v0.5** — contenedores por política + extensión con `proxy.onRequest` | 6.8, y NO dependía de 5: es API de Firefox | — |
|
||||||
|
|
||||||
Las unidades 2 y 4 son **paralelizables**: la toolchain no toca el chrome y el chrome no toca la
|
Las unidades 2 y 4 son **paralelizables**: la toolchain no toca el chrome y el chrome no toca la
|
||||||
|
|||||||
@@ -328,6 +328,30 @@ paquetes = [
|
|||||||
# trampa, porque el panel está en todas. Bajarlo de acá es bajarlo de la imagen, no de la receta.
|
# trampa, porque el panel está en todas. Bajarlo de acá es bajarlo de la imagen, no de la receta.
|
||||||
"llama-cpp",
|
"llama-cpp",
|
||||||
"ia-modelo-chat",
|
"ia-modelo-chat",
|
||||||
|
# ── LA BÓVEDA DEL NAVEGADOR (SDD 26 §7.sexies, decisión 1 — 2026-09-21) ──────────────────────
|
||||||
|
# `atuq` trae la décima extensión desde el 2026-09-15 y el host pineado atiende `vault.*` desde
|
||||||
|
# el 2026-09-16; aun así la función venía **APAGADA DE FÁBRICA en las cuatro imágenes**, sin un
|
||||||
|
# solo error: `vault.status` contesta `{"ok":true,"locked":true}` porque el host NUNCA abre la
|
||||||
|
# base (sled toma lock exclusivo y el proceso que lanza Gecko muere y revive con cada pestaña);
|
||||||
|
# le habla a un DUEÑO por un socket, y el dueño no estaba declarado en ningún perfil. Las dos
|
||||||
|
# recetas estaban selladas desde el 2026-09-18 con `perfiles: []` — sellado ≠ instalado, que es
|
||||||
|
# la lección de `foot`, escrita QUINCE veces en este fichero antes de hoy (`grep 'lección de
|
||||||
|
# .foot.'`) y aun así vuelta a pasar. Y «cerrada» es una respuesta EXITOSA:
|
||||||
|
# ni un log, ni un reintento, ni la insignia la distinguen de un usuario que no desbloqueó la suya.
|
||||||
|
# `boveda` la app DUEÑA de la base: la abre para su ventana y levanta el socket del
|
||||||
|
# navegador en un hilo. Sin ella, `vault.match` no ofrece nada, nunca.
|
||||||
|
# `shuma-pregunta` el diálogo de consentimiento que `PorDialogo` lanza por PATH. Sin él,
|
||||||
|
# `Command::new` falla ⇒ TODO `vault.fill` se deniega, indistinguible de que
|
||||||
|
# la persona haya dicho que no.
|
||||||
|
# **Las dos o ninguna**: media bóveda es una que niega todo en silencio. Cuestan ~43 M por imagen
|
||||||
|
# (22 M + 21 M medidos sobre los artefactos sellados), contra los ~1,25 GiB del §6.7 de acá arriba.
|
||||||
|
# ⚠ La respuesta fue NO hasta el 2026-09-18, y no por el tamaño: ninguna app llimphi de escritorio
|
||||||
|
# podía abrir ventana sin Vulkan (§7.septies), así que declararlas habría sido instalar una bóveda
|
||||||
|
# que niega todo. Eso se arregló en llimphi y se MIDIÓ en metal: las seis etapas de
|
||||||
|
# `scripts/test-atuq-boveda-metal.py` en verde —con el navegador de verdad, el diálogo a la vista
|
||||||
|
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
||||||
|
"boveda",
|
||||||
|
"shuma-pregunta",
|
||||||
# ── CAPTURA Y STREAMING ──────────────────────────────────────────────────────────────────────
|
# ── CAPTURA Y STREAMING ──────────────────────────────────────────────────────────────────────
|
||||||
# `obs-studio` (2026-09-04). A diferencia de mpv, ésta vive en ESTA COLA y no en el corpus, y no
|
# `obs-studio` (2026-09-04). A diferencia de mpv, ésta vive en ESTA COLA y no en el corpus, y no
|
||||||
# es preferencia: su frontend es Qt6 y las 13 recetas Qt viven sólo en `incoming-kde`. Un qtbase
|
# es preferencia: su frontend es Qt6 y las 13 recetas Qt viven sólo en `incoming-kde`. Un qtbase
|
||||||
@@ -566,6 +590,30 @@ paquetes = [
|
|||||||
# trampa, porque el panel está en todas. Bajarlo de acá es bajarlo de la imagen, no de la receta.
|
# trampa, porque el panel está en todas. Bajarlo de acá es bajarlo de la imagen, no de la receta.
|
||||||
"llama-cpp",
|
"llama-cpp",
|
||||||
"ia-modelo-chat",
|
"ia-modelo-chat",
|
||||||
|
# ── LA BÓVEDA DEL NAVEGADOR (SDD 26 §7.sexies, decisión 1 — 2026-09-21) ──────────────────────
|
||||||
|
# `atuq` trae la décima extensión desde el 2026-09-15 y el host pineado atiende `vault.*` desde
|
||||||
|
# el 2026-09-16; aun así la función venía **APAGADA DE FÁBRICA en las cuatro imágenes**, sin un
|
||||||
|
# solo error: `vault.status` contesta `{"ok":true,"locked":true}` porque el host NUNCA abre la
|
||||||
|
# base (sled toma lock exclusivo y el proceso que lanza Gecko muere y revive con cada pestaña);
|
||||||
|
# le habla a un DUEÑO por un socket, y el dueño no estaba declarado en ningún perfil. Las dos
|
||||||
|
# recetas estaban selladas desde el 2026-09-18 con `perfiles: []` — sellado ≠ instalado, que es
|
||||||
|
# la lección de `foot`, escrita QUINCE veces en este fichero antes de hoy (`grep 'lección de
|
||||||
|
# .foot.'`) y aun así vuelta a pasar. Y «cerrada» es una respuesta EXITOSA:
|
||||||
|
# ni un log, ni un reintento, ni la insignia la distinguen de un usuario que no desbloqueó la suya.
|
||||||
|
# `boveda` la app DUEÑA de la base: la abre para su ventana y levanta el socket del
|
||||||
|
# navegador en un hilo. Sin ella, `vault.match` no ofrece nada, nunca.
|
||||||
|
# `shuma-pregunta` el diálogo de consentimiento que `PorDialogo` lanza por PATH. Sin él,
|
||||||
|
# `Command::new` falla ⇒ TODO `vault.fill` se deniega, indistinguible de que
|
||||||
|
# la persona haya dicho que no.
|
||||||
|
# **Las dos o ninguna**: media bóveda es una que niega todo en silencio. Cuestan ~43 M por imagen
|
||||||
|
# (22 M + 21 M medidos sobre los artefactos sellados), contra los ~1,25 GiB del §6.7 de acá arriba.
|
||||||
|
# ⚠ La respuesta fue NO hasta el 2026-09-18, y no por el tamaño: ninguna app llimphi de escritorio
|
||||||
|
# podía abrir ventana sin Vulkan (§7.septies), así que declararlas habría sido instalar una bóveda
|
||||||
|
# que niega todo. Eso se arregló en llimphi y se MIDIÓ en metal: las seis etapas de
|
||||||
|
# `scripts/test-atuq-boveda-metal.py` en verde —con el navegador de verdad, el diálogo a la vista
|
||||||
|
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
||||||
|
"boveda",
|
||||||
|
"shuma-pregunta",
|
||||||
# ── VISOR DE IMÁGENES, TAMBIÉN EN LAS CUATRO ─────────────────────────────────────────────────
|
# ── VISOR DE IMÁGENES, TAMBIÉN EN LAS CUATRO ─────────────────────────────────────────────────
|
||||||
# `swayimg` y no `imv`, que era lo que proponía `docs/plan-apps-usuario-final.md`: imv dibuja con
|
# `swayimg` y no `imv`, que era lo que proponía `docs/plan-apps-usuario-final.md`: imv dibuja con
|
||||||
# OpenGL de función fija (`glBegin`/`glOrtho`) y esta distro NO tiene proveedor de GL de
|
# OpenGL de función fija (`glBegin`/`glOrtho`) y esta distro NO tiene proveedor de GL de
|
||||||
@@ -941,6 +989,30 @@ paquetes = [
|
|||||||
# trampa, porque el panel está en todas. Bajarlo de acá es bajarlo de la imagen, no de la receta.
|
# trampa, porque el panel está en todas. Bajarlo de acá es bajarlo de la imagen, no de la receta.
|
||||||
"llama-cpp",
|
"llama-cpp",
|
||||||
"ia-modelo-chat",
|
"ia-modelo-chat",
|
||||||
|
# ── LA BÓVEDA DEL NAVEGADOR (SDD 26 §7.sexies, decisión 1 — 2026-09-21) ──────────────────────
|
||||||
|
# `atuq` trae la décima extensión desde el 2026-09-15 y el host pineado atiende `vault.*` desde
|
||||||
|
# el 2026-09-16; aun así la función venía **APAGADA DE FÁBRICA en las cuatro imágenes**, sin un
|
||||||
|
# solo error: `vault.status` contesta `{"ok":true,"locked":true}` porque el host NUNCA abre la
|
||||||
|
# base (sled toma lock exclusivo y el proceso que lanza Gecko muere y revive con cada pestaña);
|
||||||
|
# le habla a un DUEÑO por un socket, y el dueño no estaba declarado en ningún perfil. Las dos
|
||||||
|
# recetas estaban selladas desde el 2026-09-18 con `perfiles: []` — sellado ≠ instalado, que es
|
||||||
|
# la lección de `foot`, escrita QUINCE veces en este fichero antes de hoy (`grep 'lección de
|
||||||
|
# .foot.'`) y aun así vuelta a pasar. Y «cerrada» es una respuesta EXITOSA:
|
||||||
|
# ni un log, ni un reintento, ni la insignia la distinguen de un usuario que no desbloqueó la suya.
|
||||||
|
# `boveda` la app DUEÑA de la base: la abre para su ventana y levanta el socket del
|
||||||
|
# navegador en un hilo. Sin ella, `vault.match` no ofrece nada, nunca.
|
||||||
|
# `shuma-pregunta` el diálogo de consentimiento que `PorDialogo` lanza por PATH. Sin él,
|
||||||
|
# `Command::new` falla ⇒ TODO `vault.fill` se deniega, indistinguible de que
|
||||||
|
# la persona haya dicho que no.
|
||||||
|
# **Las dos o ninguna**: media bóveda es una que niega todo en silencio. Cuestan ~43 M por imagen
|
||||||
|
# (22 M + 21 M medidos sobre los artefactos sellados), contra los ~1,25 GiB del §6.7 de acá arriba.
|
||||||
|
# ⚠ La respuesta fue NO hasta el 2026-09-18, y no por el tamaño: ninguna app llimphi de escritorio
|
||||||
|
# podía abrir ventana sin Vulkan (§7.septies), así que declararlas habría sido instalar una bóveda
|
||||||
|
# que niega todo. Eso se arregló en llimphi y se MIDIÓ en metal: las seis etapas de
|
||||||
|
# `scripts/test-atuq-boveda-metal.py` en verde —con el navegador de verdad, el diálogo a la vista
|
||||||
|
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
||||||
|
"boveda",
|
||||||
|
"shuma-pregunta",
|
||||||
# ── VISOR DE IMÁGENES, TAMBIÉN EN LAS CUATRO ─────────────────────────────────────────────────
|
# ── VISOR DE IMÁGENES, TAMBIÉN EN LAS CUATRO ─────────────────────────────────────────────────
|
||||||
# `swayimg` y no `imv`, que era lo que proponía `docs/plan-apps-usuario-final.md`: imv dibuja con
|
# `swayimg` y no `imv`, que era lo que proponía `docs/plan-apps-usuario-final.md`: imv dibuja con
|
||||||
# OpenGL de función fija (`glBegin`/`glOrtho`) y esta distro NO tiene proveedor de GL de
|
# OpenGL de función fija (`glBegin`/`glOrtho`) y esta distro NO tiene proveedor de GL de
|
||||||
@@ -1179,6 +1251,30 @@ paquetes = [
|
|||||||
# trampa, porque el panel está en todas. Bajarlo de acá es bajarlo de la imagen, no de la receta.
|
# trampa, porque el panel está en todas. Bajarlo de acá es bajarlo de la imagen, no de la receta.
|
||||||
"llama-cpp",
|
"llama-cpp",
|
||||||
"ia-modelo-chat",
|
"ia-modelo-chat",
|
||||||
|
# ── LA BÓVEDA DEL NAVEGADOR (SDD 26 §7.sexies, decisión 1 — 2026-09-21) ──────────────────────
|
||||||
|
# `atuq` trae la décima extensión desde el 2026-09-15 y el host pineado atiende `vault.*` desde
|
||||||
|
# el 2026-09-16; aun así la función venía **APAGADA DE FÁBRICA en las cuatro imágenes**, sin un
|
||||||
|
# solo error: `vault.status` contesta `{"ok":true,"locked":true}` porque el host NUNCA abre la
|
||||||
|
# base (sled toma lock exclusivo y el proceso que lanza Gecko muere y revive con cada pestaña);
|
||||||
|
# le habla a un DUEÑO por un socket, y el dueño no estaba declarado en ningún perfil. Las dos
|
||||||
|
# recetas estaban selladas desde el 2026-09-18 con `perfiles: []` — sellado ≠ instalado, que es
|
||||||
|
# la lección de `foot`, escrita QUINCE veces en este fichero antes de hoy (`grep 'lección de
|
||||||
|
# .foot.'`) y aun así vuelta a pasar. Y «cerrada» es una respuesta EXITOSA:
|
||||||
|
# ni un log, ni un reintento, ni la insignia la distinguen de un usuario que no desbloqueó la suya.
|
||||||
|
# `boveda` la app DUEÑA de la base: la abre para su ventana y levanta el socket del
|
||||||
|
# navegador en un hilo. Sin ella, `vault.match` no ofrece nada, nunca.
|
||||||
|
# `shuma-pregunta` el diálogo de consentimiento que `PorDialogo` lanza por PATH. Sin él,
|
||||||
|
# `Command::new` falla ⇒ TODO `vault.fill` se deniega, indistinguible de que
|
||||||
|
# la persona haya dicho que no.
|
||||||
|
# **Las dos o ninguna**: media bóveda es una que niega todo en silencio. Cuestan ~43 M por imagen
|
||||||
|
# (22 M + 21 M medidos sobre los artefactos sellados), contra los ~1,25 GiB del §6.7 de acá arriba.
|
||||||
|
# ⚠ La respuesta fue NO hasta el 2026-09-18, y no por el tamaño: ninguna app llimphi de escritorio
|
||||||
|
# podía abrir ventana sin Vulkan (§7.septies), así que declararlas habría sido instalar una bóveda
|
||||||
|
# que niega todo. Eso se arregló en llimphi y se MIDIÓ en metal: las seis etapas de
|
||||||
|
# `scripts/test-atuq-boveda-metal.py` en verde —con el navegador de verdad, el diálogo a la vista
|
||||||
|
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
||||||
|
"boveda",
|
||||||
|
"shuma-pregunta",
|
||||||
# `dunst` es LA OTRA MITAD, y sólo hace falta acá: KDE la atiende con plasma-workspace, GNOME con
|
# `dunst` es LA OTRA MITAD, y sólo hace falta acá: KDE la atiende con plasma-workspace, GNOME con
|
||||||
# gnome-shell y COSMIC con cosmic-notifications; sway no tenía a NADIE escuchando
|
# gnome-shell y COSMIC con cosmic-notifications; sway no tenía a NADIE escuchando
|
||||||
# `org.freedesktop.Notifications`, así que una página que pedía notificar mandaba el mensaje al bus
|
# `org.freedesktop.Notifications`, así que una página que pedía notificar mandaba el mensaje al bus
|
||||||
|
|||||||
@@ -92,6 +92,44 @@ install = '''
|
|||||||
set -e
|
set -e
|
||||||
test -x target/release/boveda || { echo "no hay target/release/boveda — ¿cambió el nombre del bin en pacha-boveda-llimphi?" >&2; exit 1; }
|
test -x target/release/boveda || { echo "no hay target/release/boveda — ¿cambió el nombre del bin en pacha-boveda-llimphi?" >&2; exit 1; }
|
||||||
install -Dm755 target/release/boveda /out/usr/bin/boveda
|
install -Dm755 target/release/boveda /out/usr/bin/boveda
|
||||||
|
|
||||||
|
# ── EL LANZADOR, Y POR QUÉ ES PARTE DE LA FUNCIÓN Y NO UN ADORNO (2026-09-21) ─────────────────
|
||||||
|
# Sin esta entrada la app viaja en la imagen y **no existe para quien la usa**: los lanzadores de
|
||||||
|
# los cuatro escritorios leen `/usr/share/applications`, y a un binario que nadie lista sólo se
|
||||||
|
# llega escribiendo `boveda` en una terminal. Sería exactamente la forma de fallo que esta receta
|
||||||
|
# existe para cerrar —la función instalada, apagada y en silencio (SDD 26 §7.sexies)— una capa más
|
||||||
|
# arriba: la bóveda declarada en el perfil, la insignia del navegador vacía, y nada que falle.
|
||||||
|
#
|
||||||
|
# `Icon=dialog-password` es nombre del icon naming spec y está MEDIDO en los tres temas que los
|
||||||
|
# perfiles declaran, no supuesto: `breeze-icons` 6 ficheros, `adwaita-icon-theme` 1, `cosmic-icons`
|
||||||
|
# 2. El cuarto perfil (sway) lleva sólo `hicolor`, que por diseño no trae iconos: ahí el lanzador
|
||||||
|
# cae al genérico, que es degradarse, no romperse.
|
||||||
|
#
|
||||||
|
# ⚠ Lo que esta entrada NO puede hacer, y conviene saberlo antes de buscarlo acá: emparejar la
|
||||||
|
# VENTANA con el lanzador. `llimphi_ui::run` no llama nunca a `with_name`, así que winit 0.30.13
|
||||||
|
# sólo manda `set_app_id` `if let Some(name) = attributes.platform_specific.name` ⇒ la ventana sale
|
||||||
|
# **sin app_id**, y con el título `"llimphi"`, que es el default de `App::title` y `BovedaApp` no
|
||||||
|
# sobrescribe. Por eso acá no hay `StartupWMClass`: no habría contra qué emparejarlo. Es de llimphi
|
||||||
|
# —como el muro del §7.septies— y se arregla allá, no acá.
|
||||||
|
mkdir -p /out/usr/share/applications
|
||||||
|
cat > /out/usr/share/applications/boveda.desktop <<'DESKTOP'
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=Bóveda
|
||||||
|
Name[en]=Vault
|
||||||
|
GenericName=Gestor de contraseñas
|
||||||
|
GenericName[en]=Password Manager
|
||||||
|
Comment=Tus contraseñas, y quien las pide tiene que preguntarte
|
||||||
|
Comment[en]=Your passwords, and whoever asks has to ask you
|
||||||
|
Exec=boveda
|
||||||
|
Icon=dialog-password
|
||||||
|
Terminal=false
|
||||||
|
Categories=Utility;Security;
|
||||||
|
Keywords=contraseñas;claves;bóveda;passwords;
|
||||||
|
StartupNotify=true
|
||||||
|
DESKTOP
|
||||||
|
chmod 0644 /out/usr/share/applications/boveda.desktop
|
||||||
|
test -s /out/usr/share/applications/boveda.desktop || { echo "boveda.desktop quedó vacío" >&2; exit 1; }
|
||||||
'''
|
'''
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|||||||
@@ -3,31 +3,38 @@
|
|||||||
|
|
||||||
python3 scripts/test-atuq-boveda-coherente.py
|
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
|
||||||
|
python3 scripts/test-atuq-boveda-coherente.py --negative-control-perfil
|
||||||
|
|
||||||
── QUÉ MIRA, Y POR QUÉ ESTE GUARDIÁN EXISTE APARTE ───────────────────────────────────────────
|
── 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
|
manifest.json el id que la extensión declara
|
||||||
distribution/policies.json la política que la instala
|
distribution/policies.json la política que la instala
|
||||||
native-messaging/*.json el permiso para hablarle al host
|
native-messaging/*.json el permiso para hablarle al host
|
||||||
atuq.cfg las preferencias que la acompañan
|
atuq.cfg las preferencias que la acompañan
|
||||||
recipes/puriy-costura.toml el COMMIT del host, que decide si sus verbos existen
|
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
|
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
|
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
|
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
|
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
|
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
|
É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
|
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.
|
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` 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
|
`--negative-control-verbo` le manda al quinto chequeo un verbo inventado y exige lo mismo.
|
||||||
ellos, un guardián que siempre dice que sí se vería idéntico a uno que funciona.
|
`--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
|
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
|
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 re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import tomllib
|
||||||
|
|
||||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
ATUQ = os.path.join(ROOT, "recipes/atuq")
|
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 "
|
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")
|
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 = []
|
fallas = []
|
||||||
|
|
||||||
|
|
||||||
@@ -168,7 +226,7 @@ def leer(p):
|
|||||||
return f.read()
|
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.
|
# 1. La extensión existe y declara el id que todos los demás nombran.
|
||||||
try:
|
try:
|
||||||
m = json.loads(leer("extensions/boveda/manifest.json"))
|
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.
|
# 8. Y el quinto lugar, que vive en otra receta y en otro repo.
|
||||||
revisar_el_host(verbo_extra)
|
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():
|
def main():
|
||||||
control = "--negative-control" in sys.argv
|
control = "--negative-control" in sys.argv
|
||||||
control_verbo = "--negative-control-verbo" 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"))
|
host = json.loads(leer("native-messaging/puriy_costura.json"))
|
||||||
permisos = list(host.get("allowed_extensions", []))
|
permisos = list(host.get("allowed_extensions", []))
|
||||||
verbo_extra = None
|
verbo_extra = None
|
||||||
@@ -247,9 +309,15 @@ def main():
|
|||||||
# mirando el host sino contestando que sí.
|
# mirando el host sino contestando que sí.
|
||||||
verbo_extra = "vault.este_verbo_no_existe"
|
verbo_extra = "vault.este_verbo_no_existe"
|
||||||
print(f"⚠ control negativo: se le agrega el verbo inventado {verbo_extra}")
|
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 ──")
|
print(f"── la bóveda en atuq ──")
|
||||||
revisar(permisos, verbo_extra)
|
revisar(permisos, verbo_extra, sin_perfil)
|
||||||
|
|
||||||
if control:
|
if control:
|
||||||
if any("allowed_extensions" in f for f in fallas):
|
if any("allowed_extensions" in f for f in fallas):
|
||||||
@@ -263,6 +331,12 @@ def main():
|
|||||||
return 0
|
return 0
|
||||||
print("\n✗ el control del verbo NO lo detectó: el quinto chequeo no mide nada")
|
print("\n✗ el control del verbo NO lo detectó: el quinto chequeo no mide nada")
|
||||||
return 1
|
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:
|
if fallas:
|
||||||
print(f"\n✗ {len(fallas)} problema(s)")
|
print(f"\n✗ {len(fallas)} problema(s)")
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -6,12 +6,15 @@
|
|||||||
python3 scripts/test-atuq-boveda-metal.py --list # qué afirma cada etapa, sin correr nada
|
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 ──────────────────────────
|
── 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
|
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,
|
otro lado del cable hay alguien: el 2026-09-18 los cinco lugares que entonces se miraban estaban
|
||||||
política, permiso, prefs y el commit del host con sus verbos— y la bóveda contestaba **cerrada** en
|
en orden —manifiesto, política, permiso, prefs y el commit del host con sus verbos— y la bóveda
|
||||||
las cuatro imágenes, porque el DUEÑO de la base y el DIÁLOGO de consentimiento no estaban en el
|
contestaba **cerrada** en las cuatro imágenes, porque el DUEÑO de la base y el DIÁLOGO de
|
||||||
corpus. Ningún guardián de ficheros podía verlo; éste empieza justamente por ahí.
|
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 ────────────────────────────────────────────────────
|
── 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
|
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.
|
# se descubre en el primer minuto y no después de media hora de navegadores.
|
||||||
GUARDIANES=(
|
GUARDIANES=(
|
||||||
"vigia-atuq-verbos|python3 scripts/vigia-atuq-verbos.py|el host PINEADO atiende los verbos que mandan las diez extensiones (§7)"
|
"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.
|
# 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
|
# 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
|
# 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