gioser

sergio/takana

> 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.

e7369efe824aed48bb1b0752bd128d37c9b7b791 · por Sergio · (hace 1 mes) · padre 98c9e4daa · ver el árbol en este commit

Delta semántico · 6

scripts/test-atuq-boveda-coherente.py

1 archivos · +123 −5

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