diff --git a/docs/26-atuq-envoltorio-gecko.md b/docs/26-atuq-envoltorio-gecko.md new file mode 100644 index 00000000..a876b485 --- /dev/null +++ b/docs/26-atuq-envoltorio-gecko.md @@ -0,0 +1,237 @@ +# SDD 26 — `atuq`: el envoltorio Gecko de la distro + +Escrito 2026-09-05, a partir de la pregunta del usuario: *«ya habiendo compilado firefox y waterfox, +qué tan complicado vs provechoso suena crear nuestro propio envoltorio, en vez de zen?»*, y de su +aclaración de por qué la pregunta existe: **`puriy` quedó muy verde y es difícil sacarlo de ahí**. + +`atuq` es *zorro* en quechua. El nombre estaba libre —verificado con `grep -ri atuq` sobre +`/mnt/vvv/hammer` y `/mnt/vvv/tawasuyu`, cero coincidencias— y dice exactamente lo que la cosa es: +otro fox, con marca propia y sin usar la de Mozilla (ver el §branding de `recipes/firefox.toml`). + +**Este documento no reemplaza a `puriy` ni lo cancela.** `puriy` sigue siendo el motor soberano; el +§9 explica por qué `atuq` es su andamio y no su desvío. + +--- + +## 1. La corrección que ordena todo: no hay envoltorio fuera del chrome + +La intuición natural —una carcasa Llimphi con nuestros widgets, y Gecko adentro pintando la página— +**no es posible**. Gecko no tiene API de embebido en escritorio desde que murió XULRunner; GeckoView +existe y es de Android. No hay forma soportada de meter el motor en una ventana de `mirada`. + +⇒ un envoltorio de Gecko es, necesariamente, **chrome-level**: JS/CSS/XHTML *dentro* del propio +Firefox, más extensiones, más procesos externos que hablen con él. + +Y eso es exactamente lo que Zen es. Zen no toca el motor: su diferencia entera —workspaces, split +view, glance, compact mode— vive en el chrome, más una herramienta (`surfer`) que reaplica sus +parches sobre el árbol de Firefox y recompila. **Su costo no es el motor: es la cinta de correr del +rebase cada cuatro semanas.** Copiar su método sería heredar su costo sin heredar su equipo. + +## 2. La decisión de arquitectura: artefacto DERIVADO, no fork de fuente + +Si `atuq` parchea el árbol, **cada iteración de UI cuesta un build de Gecko de cuatro horas**. Eso +mata el proyecto en la primera semana de diseño, porque el diseño de chrome es iterativo por +naturaleza. + +Pero nosotros no distribuimos un binario: sellamos artefactos. Entonces `atuq` es una receta cuyo +`[deps]` incluye `firefox`, y cuyas fases copian el árbol instalado e inyectan encima: + +| Qué se inyecta | Mecanismo de Firefox | Sin recompilar | +|---|---|---| +| Marca, iconos, nombre | `distribution/`, `application.ini` | ✅ | +| Prefs de fábrica | `defaults/pref/*.js` + autoconfig (`.cfg`) | ✅ | +| Política de empresa | `distribution/policies.json` | ✅ | +| Chrome propio (dientes, layout) | `userChrome.css` + re-empaque de `omni.ja` | ✅ | +| Extensiones nuestras | `distribution/extensions/` | ✅ | + +**Ventajas que esto tiene sobre el método de Zen, y que son estructurales:** + +1. **Iteración en segundos, no en horas.** El chrome se toca sin volver a compilar C++. +2. **No mueve el `ArtifactHash` de `firefox`.** El corpus no se invalida; `waterfox` y cualquier otro + fork siguen compartiendo el mismo artefacto base. +3. **Las CVE se heredan gratis.** Un fork de fuente te vuelve dueño del reloj de seguridad del + binario más atacado de la máquina — es lo que hundió a casi todos los forks de Firefox, y el + reproche histórico a Waterfox. Un derivado se reconstruye solo cuando sube `firefox`. + +**Los dos gotchas reales del camino, que son trabajo pero chico:** + +- **`omni.ja` es un zip ⇒ hay que re-empacarlo determinista** (mtimes fijos, orden estable) o el + artefacto deja de reproducir bit a bit. Es la misma disciplina que ya exige la imagen del lab. +- **Hay que invalidar el startup cache** tras tocarlo (fichero `.purgecaches` junto al binario, o + bump del BuildID). Si no, los cambios no se ven y **parece que el overlay no agarró**: un falso + negativo de los caros, de la misma familia que el cache-hit que congela regresiones. + +### 2.bis Cuándo SÍ hay que parchear el árbol + +Cuando algo necesite tocar C++ del motor. Hoy conocemos un caso: `sct` en su forma fuerte (§6.1). +La regla es: **nada baja al árbol antes de que exista la toolchain del §3**, porque hasta entonces +cada intento cuesta cuatro horas. Y cuando baje, el vigía de parches (`scripts/vigia-parches.py`, +commit `aa200a4`) es lo que convierte esas cuatro horas en un minuto para saber si el parche agarra. + +## 3. La puerta de las optimizaciones: no es un flag, es una toolchain + +El usuario decidió habilitar las optimizaciones. Lo que hay que saber antes de intentarlo: + +`recipes/firefox.toml` va con `compiler = "gcc"` por el **muro 3** (zig enlaza `libc++` estática para +musl y el `configure` de Mozilla exige encontrar un `NEEDED …libc++`; es negativa de upstream, no una +perilla). El problema es que **PGO, LTO y BOLT son cadena de clang en Gecko**: + +- `--enable-lto=cross` quiere clang + lld. El LTO de GCC sobre Gecko no está soportado upstream. +- `--enable-profile-use` espera `-fprofile-instr-use` (clang), no `-fprofile-use` (gcc). +- BOLT necesita `llvm-bolt`. + +Y **el corpus no tiene clang usable como compilador**. Verificado en las recetas, no supuesto: + +- `recipes/clang18.toml` compila `ninja -C build libclang.so clang-resource-headers` y su fase + `install` copia **sólo** `build/lib/libclang.so*` y las cabeceras `clang-c`. Está ahí porque + `bindgen` carga `libclang.so` en runtime. **No hay driver `clang`, ni `lld`, ni `libc++`.** +- `llvm18` se selló con `-DLLVM_ENABLE_PROJECTS=""` — LLVM a secas. + +⇒ **la unidad de trabajo real es una receta `llvm-toolchain` con clang + lld + `libc++` compartida +para musl.** Es la misma pieza que resuelve el muro 3, así que destraba de una sola vez: LTO, PGO, +BOLT, y el regreso de Firefox a una toolchain más cercana a la del resto del corpus. **Es la mayor +palanca por unidad de trabajo que hay en este frente**, y por eso encabeza el plan del §8. + +**Riesgos de PGO, escritos antes de empezar:** + +- El PGO de Mozilla **corre el navegador** para juntar el perfil (`profileserver.py`, headless + + marionette). Dentro de un sandbox hermético, sin red y sin X11, eso hay que hacerlo andar. + Headless no necesita display, pero sí necesita que el árbol de perfil se genere adentro. +- **El perfil resultante es un input del artefacto.** O entra en `hash_inputs`, o `atuq` deja de ser + determinista y no lo vamos a notar: sería otra forma del lab que no está en `hash_inputs`. +- Ganancia esperable, para calibrar expectativas: PGO+LTO en Gecko son del orden de 10-25% en carga + de página y JS. **Hoy estamos ATRÁS de Zen en este eje, no adelante** — Zen hereda la + configuración de Mozilla tal cual. Esto no es una ventaja nuestra: es una deuda que se salda. + +## 4. Lo que `atuq` NO promete + +Esta sección existe antes que la lista de features a propósito, con el mismo criterio que el modelo +de adversario de `qullqa`: **lo que no se promete se escribe primero, porque una promesa falsa de +privacidad es peor que no ofrecer nada.** + +**`atuq` no es Tor Browser y no va a tener «modo Tor».** Tor Browser no es «Firefox + SOCKS»: su +valor son las contramedidas de huella (RFP, letterboxing, normalización de fuentes/canvas/timers) y +sobre todo **un conjunto de anonimato donde todos se ven idénticos**. `atuq` es, por construcción, un +binario único en el mundo: musl, Wayland-only, branding propio, extensiones propias. Alguien saliendo +por Tor desde `atuq` es **más** identificable, no menos, y su conjunto de anonimato son diez +personas. Para anonimato: Tor Browser, y lo decimos nosotros primero. + +Lo que sí se ofrece, y es honesto porque es otra cosa: **proxy por contenedor** (§6.8) — separación +de tráfico, no anonimato. + +**`atuq` tampoco promete** anti-fingerprinting propio (es un programa de investigación con equipo +full-time) ni bloqueo de anuncios propio (se shipea uBO y listo). + +## 5. Contexto verificado al escribir (2026-09-05) + +De `docs/state/build-state.json`, no de memoria: + +| Dato | Valor | +|---|---| +| Recetas / nodos | 838 / 840 | +| Selladas | 837 | +| `firefox` 154.0 | **sealed**, cola `corpus` | +| `waterfox` 6.7.1.1 | **never** — primer build en curso | +| Plataforma compartida | `gtk3`, `atk`, `nodejs`, `clang18`, `cbindgen`: todas sealed | + +**`atuq` no arranca hasta que `waterfox` selle.** Waterfox es la prueba de la tesis del reúso —«las +diferencias reales con `firefox.toml` son TRES: la fuente, el branding y la versión»—. Si esa tesis +falla, el precio de todo este documento cambia y hay que releerlo. + +## 6. Los diferenciadores, priorizados + +La columna «quién más lo tiene» es lo que evita que nos contemos un cuento. + +| # | Qué | Quién más lo tiene | Pieza que ya existe | Costo | +|---|---|---|---|---| +| 6.1 | **`sct` — transparencia de scripts** | **nadie** | `puriy-sct`, `puriy-sct-testigo` | medio | +| 6.2 | **Descargas direccionadas por contenido** | nadie | store CAS de hammer, `tejido` | bajo | +| 6.3 | **Archivo personal + RAG local** | Rewind/Recall (nube, Windows); SingleFile (guarda, no busca) | `khipu`, `rag-motor`, `willay-rag` | medio | +| 6.4 | **Historial y perfil sobre `qullqa`** | nadie | `qullqa-core`, `qullqa-pozo` | medio | +| 6.5 | **Foco por `cortafuegos`, no por extensión** | nadie (nadie es dueño del navegador *y* del sistema) | `cortafuegos`, `pacha` | bajo | +| 6.6 | **Medios por fuera del navegador** | extensiones sueltas; de fábrica no | `foreign-ytdlp`, `-platform`, `-dlna` | bajo | +| 6.7 | **IA local en la barra lateral** | Chrome/Edge son nube; Zen no tiene | `rimay`, `iniy` | bajo | +| 6.8 | **Proxy por contenedor** | nadie de fábrica | — (API de Firefox) | bajo | +| 6.9 | **Torrent adentro** | **Vivaldi lo trae; Brave tuvo WebTorrent** | `shared/foreign-torrent` (SDD propio, sobre librqbit) | bajo | + +### 6.1 `sct` es la joya + +BLAKE3 a todo lo que se ejecuta, y **negarse a correr código que ningún testigo vio nunca**. Es lo +más cerca que hay de «Certificate Transparency, pero para el JavaScript que te corre en la cara», y +no lo tiene nadie: ni Zen, ni Brave, ni Tor Browser. + +En tawasuyu ya está escrito y —dice su README— la lógica es **agnóstica del transporte** y está +certificada sin red; `puriy-sct-testigo` es sólo el cable HTTP. + +- **v1, sin tocar C++:** extensión con `webRequest` bloqueante que hashea cada respuesta de script y + consulta al testigo antes de dejarla pasar. +- **v2, forma fuerte:** gancho en el script loader de Gecko. Eso sí es parche de árbol ⇒ §2.bis ⇒ + después de la toolchain del §3. + +### 6.2 Una descarga con identidad + +Lo bajado no es un archivo en `~/Downloads`: es un objeto BLAKE3 en el store — deduplicado, +verificable, y re-compartible por `tejido`. El torrent (6.9) alimenta lo mismo. **Ningún navegador +trata una descarga como algo con identidad**; para todos es un blob con nombre, y por eso lo bajás +dos veces y no lo sabés. + +Ésa, y no «tener torrent», es la razón por la que 6.9 vale: Vivaldi ya tiene torrent, pero termina en +una carpeta. + +### 6.3 El archivo personal es la razón por la que alguien usaría `atuq` + +Cada página visitada se congela en el CAS y entra al DAG de `khipu`; después le preguntás a tu +propio historial en lenguaje natural, **todo local**. Es la feature que más justifica el proyecto +entero, y sale de piezas que ya están escritas. + +### 6.4 `qullqa` con su advertencia puesta + +Almacenamiento con negación plausible y modelo de adversario **escrito** — ningún navegador tiene +eso; el modo incógnito es teatro. ⚠ Con la advertencia que el propio SDD de `qullqa` ya anotó y que +**hay que repetir acá, no esconder**: en una máquina con swap sin cifrar, el documento no aplica. +Se promete lo que se puede probar. + +## 7. La costura: un host de native messaging en Rust + +Todo lo del §6 que no es CSS pasa por **un solo mecanismo**: un proceso Rust que habla native +messaging con la extensión de `atuq` y, del otro lado, con la suite (`agora` para identidad Ed25519, +`khipu`, el store, `foreign-*`, `cortafuegos`). + +Que sea **uno** y no siete es la decisión: cada feature del §6 pasa a ser un verbo de ese host, no un +proyecto nuevo. El binario vive en tawasuyu (es suite, no build system); `atuq` sólo lo declara como +dep y le deja el manifiesto de native messaging en su sitio. **El nombre del crate se decide en +tawasuyu y con su regla 10 puesta** — acá no se bautiza nada de allá. + +## 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 +siguiente. + +| # | Unidad | Puerta que abre | Bloqueada por | +|---|---|---|---| +| 1 | `waterfox` sella | valida la tesis del reúso | build en curso | +| 2 | **`llvm-toolchain`** (clang+lld+libc++ musl) | LTO, PGO, BOLT **y** el muro 3 | — | +| 3 | `firefox` con LTO+PGO (perfil en `hash_inputs`) | el eje de velocidad | 2 | +| 4 | **`atuq`: receta derivada + overlay de chrome** | el andamio de todo lo demás | 1 | +| 5 | Host de native messaging (tawasuyu) | los verbos del §6 | 4 | +| 6 | `sct` v1 (extensión + testigo) | el diferenciador que nadie tiene | 5 | +| 7 | Descargas al CAS | 6.2, y alimenta 6.9 | 5 | +| 8 | Archivo + RAG | 6.3 | 5, 7 | +| 9 | Proxy por contenedor, torrent, medios, foco | 6.5–6.9 | 5 | + +Las unidades 2 y 4 son **paralelizables**: la toolchain no toca el chrome y el chrome no toca la +toolchain. Si hay dos frentes, van juntas. + +## 9. Por qué esto no abandona a `puriy` + +`puriy` es el motor DOM/CSS propio con JS real (QuickJS-NG sobre `wasmi`) cuyo límite declarado no es +el lenguaje sino **el wiring nativo**: DOM bindings completos, red, render. Eso no se acelera +escribiendo otro navegador; se acelera con tiempo. + +`atuq` no le compite porque no comparte una sola línea con él, y **le sirve** porque todo lo del §6 +vive del lado Rust: el host del §7, el testigo de `sct`, las descargas al CAS, el archivo con RAG. +Son **agnósticos del motor**. Cuando `puriy` madure, se enchufan del mismo lado sin reescribirse. + +Dicho al revés, que es como conviene recordarlo: **`atuq` es el navegador que se puede usar mientras +`puriy` crece, y el andamio de las features que `puriy` va a heredar.** Si dentro de dos años `atuq` +se apaga, lo que se tira es una receta derivada y una hoja de CSS; todo lo demás sobrevive. diff --git a/docs/README.md b/docs/README.md index 9c758a24..9790df7a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,6 +21,7 @@ discrepancia, o se corrige el código o se actualiza el SDD con un commit que ex | 11 | [Bootstrap from-scratch](11-bootstrap.md) | Track posterior: Stage 0/1/2, auto-alojamiento, semilla pinned | | 12 | [`arje` como init real del Stage 1](12-init-real.md) | Contrato de runtime: seed card, hammerd supervisado, `CRASHED` real | | 16 | [harkaq: la jaula de hammer](16-harkaq-jaula.md) | Landlock+seccomp sobre el bwrap actual; política = clausura; evidencia negativa de hermeticidad | +| 26 | [`atuq`: el envoltorio Gecko](26-atuq-envoltorio-gecko.md) | Navegador propio como artefacto DERIVADO de `firefox` (no fork de fuente); la toolchain clang como puerta de PGO/LTO; qué se promete y qué no | ### Runbooks (operativos)