> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…
atuq: la bóveda le habla a un host que no sabe sus verbos — y eran CINCO lugares, no cuatro
Este guardián nació esta mañana diciendo que una extensión está enchufada en CUATRO sitios y que
ninguno da error si falta. Los cuatro estaban bien. El quinto no, y es el que hoy está roto.
El quinto lugar vive en otra receta y en otro repo: `recipes/puriy-costura.toml` pinea un commit de
tawasuyu, y es ESE commit el que decide si `vault.match` es un verbo o una cadena que nadie atiende.
Medido, con su control al lado, sobre el artefacto SELLADO y vigente (`hash --check` dice SELLADO
para `b3:1eb2b692`):
strings del binario sellado → «vault» 0 veces · «cas» 5 veces ⇐ EL CONTROL
El cero solo no probaba nada —un grep que devuelve cero puede ser una ausencia o un sitio
equivocado, y las dos se ven igual—; lo que lo convierte en evidencia es el «cas» que TENÍA que dar
positivo en el mismo binario. Y del lado de la fuente sale lo mismo: la receta pinea `e19bb0e5`, que
es ANCESTRO de `bc6903f9e` —el commit que agregó los verbos—, así que el host sellado es anterior a
la bóveda por construcción.
Cómo se ve ese fallo desde la silla del usuario, que es por qué esto merece guardián: el manifiesto
está, el permiso está, la política instala, `connectNative` CONECTA, la extensión manda
`vault.match` y el host contesta `verbo desconocido`. `fondo.js` lee `r.ok !== true`, borra la
insignia y se calla. Un navegador sin bóveda, y todos los ficheros en orden.
El chequeo pregunta `git grep '"<verbo>" =>' <commit> -- '*.rs'` sobre el clon, sin checkout: el
árbol de tawasuyu es compartido y siempre tiene ficheros en vuelo de otras sesiones. Los verbos los
saca de `fondo.js` y no de una lista escrita acá, que se desincronizaría justo en el único sitio
donde eso no se ve.
Tres controles, porque el chequeo es un grep que espera cero:
- POSITIVO: `sct.observe` tiene que aparecer en el commit pineado. Si no aparece, lo roto es el
guardián y lo dice así, en vez de acusar a la receta;
- `--negative-control-verbo`: le agrega un verbo inventado y exige que lo detecte;
- y si el clon no está, «no se pudo comprobar» NO es «está bien»: falla ruidosamente.
Lo que este commit NO hace: subir el pin. Eso es su propia unidad y tiene un muro medido delante —el
`Cargo.lock` de tawasuyu en `main` todavía describe a `puriy-costura` con sus once deps viejas, sin
`pacha-boveda` ni `pacha-cifrador`, y `pacha-boveda-daemon` no está en el lock en absoluto. Con eso,
`cargo vendor --locked` muere sin nombrar al culpable, que es exactamente la trampa que la propia
receta dejó escrita.
diff --git a/scripts/test-atuq-boveda-coherente.py b/scripts/test-atuq-boveda-coherente.py
index 94780aca..eead8d62 100755
--- a/scripts/test-atuq-boveda-coherente.py
+++ b/scripts/test-atuq-boveda-coherente.py
@@ -5,28 +5,38 @@
python3 scripts/test-atuq-boveda-coherente.py --negative-control
── QUÉ MIRA, Y POR QUÉ ESTE GUARDIÁN EXISTE APARTE ───────────────────────────────────────────
-Una extensión de `atuq` está enchufada en CUATRO lugares distintos, y ninguno da error si falta:
+Una extensión de `atuq` está enchufada en CINCO 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
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. Ninguno de los tres se ve como un error: se ven como «no anda».
+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».
É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 ───────────────────────────────────────────
`--negative-control` saca el permiso del host de una copia en memoria y exige que esto lo detecte.
-Sin él, 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. 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
+equivocado: las dos se ven igual, y sólo las separa un patrón hermano que TENGA que dar positivo.
"""
import json
import os
import re
+import subprocess
import sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -36,6 +46,98 @@ ID = "boveda@atuq.tawasuyu"
# Las preferencias de D7: de fábrica manda la bóveda, pero el usuario puede volver atrás.
PREFS = ["signon.rememberSignons", "signon.autofillForms"]
+# ── 8. EL QUINTO LUGAR: ¿el host que la RECETA PINEA sabe los verbos que ella manda? ──────────
+# Los siete de arriba miran `recipes/atuq/`, que es el lado del navegador. Pero una extensión no
+# está enchufada en cuatro lugares sino en CINCO, y el quinto vive en otra receta y en otro repo:
+# `recipes/puriy-costura.toml` pinea un commit de tawasuyu, y es ESE commit el que decide si
+# `vault.match` es un verbo o una cadena que nadie atiende.
+#
+# Falla igual de callado que los otros —peor, incluso—: el manifiesto está, el permiso está, la
+# política instala, `connectNative` CONECTA, la extensión manda `vault.match` y el host contesta
+# `{"ok": false, "error": "verbo desconocido: vault.match"}`. `fondo.js` lee `r.ok !== true`, borra
+# la insignia y se calla. Lo que el usuario ve es un navegador sin bóveda; lo que un guardián de
+# ficheros ve es todo en orden.
+#
+# Y no es hipotético: así estaba el 2026-09-15 al escribir esto. La extensión se commiteó con los
+# verbos ya escritos en tawasuyu (`bc6903f9e`) y la receta seguía pineada en `e19bb0e5`, que es su
+# ANCESTRO. El artefacto sellado lo confirma desde el otro lado, con su control puesto:
+# strings del binario sellado → «vault» 0 veces · «cas» 5 veces
+#
+# ── EL CONTROL POSITIVO NO ES DECORACIÓN ──────────────────────────────────────────────────────
+# Este chequeo es un `grep` que espera CERO, y un cero puede ser una ausencia o un sitio
+# equivocado: las dos se ven igual. Por eso se pregunta también por `sct.observe`, un verbo que el
+# commit pineado TIENE que tener —`sct` es la unidad 6, sellada y medida en metal—. Si el control
+# sale cero, lo que está roto es el guardián y se dice así, en vez de acusar a la receta.
+VERBOS_CONTROL = "sct.observe"
+TAWASUYU = os.environ.get("TAWASUYU", "/mnt/vvv/tawasuyu")
+RECETA_HOST = os.path.join(ROOT, "recipes/puriy-costura.toml")
+
+
+def verbos_que_manda_la_extension():
+ """Los verbos salen del propio `fondo.js`, no de una lista escrita a mano acá.
+
+ Una lista paralela se desincroniza el día que alguien agrega un verbo y no toca este
+ fichero — y lo haría en el único sitio donde eso no puede verse."""
+ fondo = leer("extensions/boveda/fondo.js")
+ return sorted(set(re.findall(r'verb:\s*"([a-z]+\.[a-z_]+)"', fondo)))
+
+
+def commit_pineado():
+ with open(RECETA_HOST, encoding="utf-8") as f:
+ m = re.search(r'^commit\s*=\s*"([0-9a-f]{7,40})"', f.read(), re.M)
+ return m.group(1) if m else None
+
+
+def atiende(commit, verbo):
+ """¿Hay un brazo de `match` para este verbo en el commit pineado?
+
+ `git grep <commit>` lee del objeto, así que no hace falta hacer checkout ni tocar el árbol
+ compartido de tawasuyu, que siempre tiene ficheros en vuelo de otras sesiones."""
+ r = subprocess.run(
+ ["git", "-C", TAWASUYU, "grep", "-qF", f'"{verbo}" =>', commit, "--", "*.rs"],
+ capture_output=True,
+ )
+ return r.returncode == 0
+
+
+def revisar_el_host(verbo_extra=None):
+ verbos = verbos_que_manda_la_extension()
+ if not verbos:
+ mal("no se pudo leer ningún `verb:` de fondo.js: este chequeo no está midiendo nada")
+ return
+ if verbo_extra:
+ verbos = verbos + [verbo_extra]
+
+ commit = commit_pineado()
+ if not commit:
+ mal(f"{os.path.relpath(RECETA_HOST, ROOT)} no pinea ningún commit")
+ return
+ if not os.path.isdir(os.path.join(TAWASUYU, ".git")):
+ # Un ausente falla RUIDOSAMENTE: si el clon no está, esto no se puede comprobar, y
+ # «no se pudo comprobar» no es «está bien».
+ mal(f"no hay clon de tawasuyu en {TAWASUYU}: el quinto lugar queda SIN COMPROBAR "
+ f"(se cambia con TAWASUYU=/ruta)")
+ return
+ if subprocess.run(["git", "-C", TAWASUYU, "cat-file", "-e", f"{commit}^{{commit}}"],
+ capture_output=True).returncode != 0:
+ mal(f"el clon de tawasuyu no conoce el commit pineado {commit[:9]}: "
+ f"hace falta un `git fetch` antes de creerle a este guardián")
+ return
+
+ # El control primero: si éste falla, ningún cero de abajo significa nada.
+ if not atiende(commit, VERBOS_CONTROL):
+ mal(f"CONTROL ROTO: {VERBOS_CONTROL} tampoco aparece en {commit[:9]}. El grep está mirando "
+ f"el sitio equivocado y los ceros de abajo no prueban ninguna ausencia")
+ return
+ bien(f"control: {VERBOS_CONTROL} SÍ está en el host pineado ({commit[:9]}) ⇒ el grep mide")
+
+ for v in verbos:
+ if atiende(commit, v):
+ bien(f"el host pineado atiende {v}")
+ else:
+ 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")
+
fallas = []
@@ -53,7 +155,7 @@ def leer(p):
return f.read()
-def revisar(permisos_host):
+def revisar(permisos_host, verbo_extra=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"))
@@ -114,17 +216,27 @@ def revisar(permisos_host):
else:
bien("la dirección la pone el navegador, no la página")
+ # 8. Y el quinto lugar, que vive en otra receta y en otro repo.
+ revisar_el_host(verbo_extra)
+
def main():
control = "--negative-control" in sys.argv
+ control_verbo = "--negative-control-verbo" in sys.argv
host = json.loads(leer("native-messaging/puriy_costura.json"))
permisos = list(host.get("allowed_extensions", []))
+ verbo_extra = None
if control:
print("⚠ control negativo: se le saca el permiso del host")
permisos = [x for x in permisos if x != ID]
+ if control_verbo:
+ # Un verbo que ningún commit puede atender: si el quinto chequeo no lo ve faltar, no está
+ # 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}")
print(f"── la bóveda en atuq ──")
- revisar(permisos)
+ revisar(permisos, verbo_extra)
if control:
if any("allowed_extensions" in f for f in fallas):
@@ -132,6 +244,12 @@ def main():
return 0
print("\n✗ el control negativo NO lo detectó: este guardián no mide nada")
return 1
+ if control_verbo:
+ if any(verbo_extra in f for f in fallas):
+ print("\n✓ el control negativo del verbo lo detectó")
+ return 0
+ print("\n✗ el control del verbo NO lo detectó: el quinto chequeo no mide nada")
+ return 1
if fallas:
print(f"\n✗ {len(fallas)} problema(s)")
return 1