SDD 26 §7.quinquies: el cable tiene dos puntas en dos repos, y hoy no coinciden

La bóveda se commiteó esta mañana con sus cuatro enchufes en orden y no funciona igual. El motivo no
está en ninguno de los cuatro: cada función de atuq es un VERBO del host, el host vive en tawasuyu, y
`recipes/puriy-costura.toml` lo pinea por commit. Escribir la extensión y subir el pin son dos
unidades distintas y la primera se commitea sin la segunda sin que nada proteste.

Queda escrito con las dos mediciones y sus controles: el binario SELLADO y vigente tiene «vault» 0
veces contra «cas» 5 —el hermano que tenía que dar positivo, sin el cual el cero no prueba nada— y
el pin es ANCESTRO del commit que agregó los verbos. Más la tabla de las diez extensiones: 13 verbos
sobre 8, y los únicos tres sin dueño son los de la bóveda; o sea que «cuándo se tocó la receta» no
contestaba esto.

También queda la trampa del instrumento, que costó más que el vigía: el extractor buscaba `verb: "…"`
y la extensión de IA arma el mensaje con el verbo en una VARIABLE, así que encontraba cero y la
declaraba sana. De ahí el control de cobertura.

Y por qué el pin no subió en el mismo turno, que es lo que hay que leer antes de intentarlo:
el `Cargo.lock` de tawasuyu no cierra para `puriy-costura` —11 deps viejas, sin `pacha-boveda`, y
`pacha-boveda-daemon` ausente del lock—. Reproducido en árbol limpio del commit: `cargo metadata
--locked` muere con «cannot update the lock file» sin nombrar al culpable, tal como la receta
avisaba; y `cargo metadata --offline` lo cierra con 37 líneas sin mover una versión de registry.

Pero el fichero está `MM` en el clon compartido —otra sesión lo tiene stageado Y modificado, y su
árbol YA trae la reparación sin commitear—, así que no se tocó. Con un repo de juguete quedó medido
por qué el `--` no alcanza ahí, que es lo contrario de lo que uno supone: con un fichero en MM,
`git commit -- <ruta>` commitea EL ÁRBOL, no lo stageado, y el índice ajeno de esa ruta desaparece.
El pathspec aísla de lo que el otro dejó en OTRAS rutas; en la ruta que uno nombra, no.

Y la unidad 12 entra al plan con lo que le falta dicho: el lock de allá, el pin, el rebuild y el
guardián de metal.
This commit is contained in:
Sergio
2026-09-15 19:06:34 +00:00
parent c30905e2b9
commit aa4fd151be
+114
View File
@@ -2699,6 +2699,119 @@ extensión va a poder leer el cuerpo de un script. Lo que NO va a poder es ver l
por esa vía —`filterResponseData` entrega el documento, no cada `<script>`—, y eso está bien para v1:
el ataque que `sct` nombra es la sustitución en el CDN, que es exactamente el caso `<script src>`.
### 7.quinquies El cable tiene DOS puntas en DOS repos — y hoy no coinciden (2026-09-15)
La bóveda se commiteó esta mañana (unidad 12, `6f0ba974`): la extensión, la política, el permiso del
host, las preferencias, y un guardián que mira los cuatro. Los cuatro estaban bien. **La bóveda no
funciona igual**, y el motivo no está en ninguno de esos cuatro sitios.
Cada función de `atuq` que no es CSS es un **verbo** del host nativo, y el host vive en OTRO REPO:
`recipes/puriy-costura.toml` lo pinea por commit de tawasuyu. O sea que el cable tiene dos puntas en
dos repos, y que `vault.match` sea un verbo o una cadena que nadie atiende lo decide un `commit =`
de un TOML que la extensión nunca menciona. Escribir la extensión y subir el pin son **dos unidades
de trabajo distintas**, y la primera se commitea sin la segunda sin que nada proteste.
**Cómo se ve el fallo, que es por qué merece vigía.** No falla nada. El manifiesto está, la política
instala, `connectNative` **conecta** —el host existe y contesta—, la extensión manda `vault.match` y
recibe:
{"ok": false, "error": "verbo desconocido: vault.match"}
`fondo.js` lee `r.ok !== true`, borra la insignia y se calla. El usuario ve un navegador sin bóveda;
un guardián de ficheros ve todo en orden. Es la misma familia que el §6.10 del subcomando sin driver:
sellado, con contenido, reproducible… y la función no está.
**La medición, con su control al lado.** El artefacto vigente (`hash --check` sobre la receta dice
`b3:1eb2b692 SELLADO`) contra su propio binario:
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 hermano que TENÍA que dar
positivo en el mismo binario. Y desde la fuente sale lo mismo por otro camino: la receta pinea
`e19bb0e5`, que `git merge-base --is-ancestor` confirma **ANCESTRO** de `bc6903f9e`, el commit que
agregó los verbos. El host sellado es anterior a la bóveda por construcción.
**Y no se podía deducir mirando la receta.** Las otras nueve extensiones conviven bien con ese mismo
pin viejo: 13 verbos sobre 8 extensiones, y los únicos tres sin dueño son los de la bóveda. «Cuándo
se tocó la receta por última vez» no contesta esta pregunta.
| extensión | verbos | ¿el pin los atiende? |
|---|---|---|
| `archivo` | `archive.add`, `archive.ask`, `archive.search` | ✓ |
| **`boveda`** | **`vault.match`, `vault.fill`, `vault.save`** | **✗ los tres** |
| `descargas` | `cas.ingest` | ✓ |
| `foco` | `focus.state` | ✓ |
| `ia` | `ai.ask`, `archive.ask` | ✓ |
| `medios` | `media.open` | ✓ |
| `sct` | `sct.observe` | ✓ |
| `torrent` | `torrent.add` | ✓ |
| `inicio`, `proxy` | — | no le hablan al host, a propósito |
Queda vigilado por `scripts/vigia-atuq-verbos.py`, que corre en un segundo sin construir nada y
pregunta `git grep '"<verbo>" =>' <commit> -- '*.rs'` **leyendo del objeto** —sin checkout: el árbol
de tawasuyu es compartido y siempre tiene ficheros en vuelo—. El mismo chequeo quedó además dentro
de `test-atuq-boveda-coherente.py`, que pasa a decir **cinco** lugares y no cuatro.
⚠ **Y lo que costó más que el vigía: el extractor de verbos no veía la mitad.** Buscaba `verb: "…"`,
que es como lo escribe la bóveda; pero la extensión de IA arma el mensaje con `postMessage({ id,
verb: verbo, … })` —el verbo llega por VARIABLE— así que ese patrón encontraba **cero verbos en
`ia`** y la declaraba sana sin haber mirado nada. Cero verbos encontrados y cero verbos faltando son
el mismo cero con dos causas. De ahí salió un tercer control que no es ni positivo ni negativo sino
de **cobertura**: una extensión de la que no se extrae ningún verbo se REPORTA, y las dos que de
verdad no le hablan al host están nombradas en el código para que no se confundan con el extractor
mudo.
#### Por qué el pin NO se subió en el mismo turno, y qué hace falta
El candidato es `be8710cff` —el más nuevo que toca `puriy-costura`, y trae además «la aplicación de
la bóveda y el navegador ya pueden convivir», que pinear `bc6903f9e` se saltearía—. **No se puede
todavía, y el muro está medido**, no supuesto: el `Cargo.lock` de tawasuyu no cierra para
`puriy-costura`. Su entrada en el lock de `main` todavía lista las **once** deps viejas —sin
`pacha-boveda`, sin `pacha-cifrador`— y `pacha-boveda-daemon` no está en el lock en absoluto.
Reproducido en un árbol LIMPIO del commit (`git archive <sha> | tar -x`, que es el procedimiento que
la propia receta dejó escrito y que evita que el lock describa «el escritorio de todos»):
cargo metadata --locked --offline
error: cannot update the lock file … because --locked was passed to prevent this
—y, como la receta avisaba, **no nombra al crate culpable**. La reparación es barata y quedó
comprobada en ese mismo árbol limpio: `cargo metadata --offline` cierra el lock con un diff de **37
líneas**, todas de contabilidad de deps por ruta, **sin mover una sola versión de registry**.
**Pero ese fichero no se commiteó, y la razón es la regla 2 de `CLAUDE.md` vista desde el otro lado.**
En el clon compartido, `git status` dice `MM Cargo.lock`: otra sesión lo tiene **stageado Y
modificado** ahora mismo. Las tres versiones, medidas:
| dónde | tamaño | deps de `puriy-costura` |
|---|---|---|
| `main` (`2c40330e4`) | 672 409 B | 11 — no cierra |
| el **índice** (stageado por otro) | 671 160 B | 11 — no cierra, y **no es el de `main`** |
| el **árbol** de esa sesión | 673 397 B | **18 — cierra** |
O sea que la reparación ya existe, sin commitear, en el árbol de otro agente. Tocarla es pisarle el
trabajo, y el `--` no protege de eso. **Comprobado en un repo de juguete, porque la intuición es la
contraria:**
```sh
# f.txt en estado MM: v2 en el índice (del otro), v3 en el árbol (mío)
git commit -m … -- f.txt
# ⇒ commitea v3 (EL ÁRBOL, no lo stageado)
# ⇒ y el índice queda en v3: lo que el otro tenía stageado ahí DESAPARECE
```
El `--` acota **qué rutas** entran al commit y con eso aísla de lo que el otro dejó en OTRAS rutas
—que es lo que la regla 2 dice y sigue siendo cierto—; para la ruta que uno nombra, se lleva el
árbol y **borra el índice ajeno**. En un repo compartido, un fichero en `MM` que uno no tocó no se
commitea ni con pathspec: se avisa.
⇒ **Pendiente, y no es de takana:** que tawasuyu publique el lock cerrado. Con eso, subir el pin a
`be8710cff`, reconstruir (2,4 G de vendoreo del workspace entero, ver la receta) y recién ahí escribir
el guardián de METAL de la bóveda —servidor, navegador real, login real, el diálogo de consentimiento
a la vista—, que es lo que el commit de la unidad 12 dejó anunciado.
## 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
@@ -2726,6 +2839,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.56.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 ✅ |
| 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. ⚠ **No funciona todavía**: los tres verbos existen en tawasuyu y la receta pinea un commit ANTERIOR (§7.quinquies), y el pin está bloqueado por un `Cargo.lock` que no cierra. **Falta**: el lock de allá, el pin, el rebuild, y el guardián de METAL | 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 | — |
Las unidades 2 y 4 son **paralelizables**: la toolchain no toca el chrome y el chrome no toca la