SDD 28 §6.25: api.sergio.gioser.net sirve desde la caja, dentro de una jaula qorpa

El primer servicio AJENO que corre sobre takana. 200 con TLS publico desde 2.29.29.217 y
`/api/chat/` contestando con Gemini de verdad, con el backend en una instancia `qorpa` sobre el
rootfs de Arch pineado por sha256, supervisado por arje-zero como el ente `sergioh-api`.

Es el que §6.21 llamo «lo que decide la fecha de borrado de gioser»: su venv trae extensiones
`cpython-314-...-linux-gnu.so`, o sea glibc, y no tiene camino a musl. La coincidencia que lo hizo
barato: el Arch pineado trae python 3.14.7 y el venv de gioser es 3.14.6 — misma serie, asi que el
venv se REHACE adentro con pip en vez de copiarse.

La seccion trae ademas el muro (la jaula no viajaba en ninguna imagen — commit anterior), los tres
tropiezos del camino (el uid 1001 del rsync que cae fuera del userns; una instancia admite UN solo
`run`; `ps` que no ve procesos y `dig` que no existe, dos ausencias que se leen como diagnostico) y
lo que quedo declarado: `instance.toml` con un unico dir concedido, las 84 deps pineadas en
`requirements.lock`, y la tarjeta en cards.d Y en el genesis.

Y una correccion de rumbo en §9: la lista «lo que falta para el cutover» era del 11-09 y sus pasos
1-5 ya estan hechos. Lo que sigue vivo en gioser son TRES vhosts, no quince.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-09-15 17:31:00 +00:00
co-authored by Claude Opus 5
parent 1e0e249d44
commit 486bf7bb22
+81
View File
@@ -1442,6 +1442,81 @@ generación guarda una copia del árbol aplicado — el nuestro son **272 MB**
guarda un árbol entero por generación, y el síntoma (`ENOSPC` con la raíz medio vacía) apunta al
sitio equivocado.
### 6.25 ✅ CUTOVER DE `api.sergio.gioser.net` — el primer servicio AJENO que sirve takana *(2026-09-15)*
**`https://api.sergio.gioser.net` responde 200 con certificado público válido desde `2.29.29.217`**,
y su `/api/chat/` contesta con Gemini de verdad. El backend corre **dentro de una jaula `qorpa`**
(rootfs de Arch pineado por sha256), supervisado por `arje-zero` como el ente `sergioh-api`.
Es el servicio que §6.21 declaró sin camino a musl —su venv trae extensiones
`cpython-314-x86_64-linux-**gnu**.so`— y por eso «lo que decide la fecha de borrado de gioser». El
camino elegido era `qorpa` (ADR 0015) y ahora está recorrido de punta a punta.
**La coincidencia que lo hizo barato:** el Arch bootstrap pineado trae **python 3.14.7** y el venv de
gioser es **3.14.6**. Misma serie ⇒ las extensiones compiladas no son un problema: el venv se rehace
adentro con `pip`, no se copia.
#### 🧨 EL MURO: la jaula no viajaba en NINGUNA imagen
`takana qorpa provision` abortó con un mensaje correcto y una instrucción imposible:
Error: no encuentro harkaq-exec en /root/.cache/harkaq/harkaq-exec
construilo: gcc -O1 -Wall -static -o … scripts/harkaq/harkaq-exec.c
**En una caja instalada no hay `gcc`, ni `scripts/`, ni árbol de desarrollo.** El binario sólo existía
como un `gcc` a mano en la caché de `$HOME` del hub — o sea que la jaula del ADR 0015 funcionaba
**únicamente en la máquina donde alguien la había compilado**. Y su compañero estaba igual, medido en
`build-state.json`: **`bwrap` sellado desde hace meses con `"perfiles": []`**, CERO perfiles. Los dos
se invocan por PATH, y no sólo desde `qorpa`: `takana-build/src/sandbox.rs` llama a `bwrap` en cada
build. ⇒ **ninguna imagen de takana podía enjaular nada, ni construir**. Es
[[subcomando-sin-driver]] un piso más abajo: el CLI que los llama viaja en todas las imágenes y sus
herramientas en ninguna.
Arreglado en la misma unidad de trabajo: `recipes/harkaq-exec.toml` (nueva, estática musl,
`b3:cd34954f…`, 269 K), `bwrap` + `harkaq-exec` declarados en **`perfil.base`**, y `qorpa.rs`
buscando el binario también en `/usr/bin` —el orden es `HARKAQ_BIN` → árbol de desarrollo → paquete,
para que un cambio en la jaula se pruebe sin instalar nada—. ⚠ El pin de la receta va **al commit que
tocó la fuente** (`1d9ddcee`, del 2026-09-03) y no a HEAD: el repo commitea cada media hora por el
cron de la cosecha, y pinear HEAD re-hashearía la receta cada media hora sin que su fuente se moviera.
#### Los tres tropiezos del camino, todos de la misma familia
1. **`chown`**: el `rsync` preservó el uid 1001 de gioser, y dentro del userns ese uid queda FUERA del
rango mapeado ⇒ ni siendo root adentro se puede escribir. `python -m venv` fallaba con
`Permission denied` en el directorio concedido mientras andaba perfecto en `/tmp`. El árbol del
sitio va a `root:root` del anfitrión, que es lo que el mapa de la jaula sí alcanza.
2. **Una instancia, un `run`**: el segundo `qorpa run` sobre la misma instancia es rechazado por el
kernel («dos overlays con el mismo `upper` corromperían la capa mutable»). Correcto y hay que
saberlo: con el servicio arriba **no se entra a la instancia a hacer mantenimiento**.
3. **`ps` de la caja no ve los procesos y `dig` no existe en el hub**. Dos herramientas ausentes que
se leen como diagnóstico: el primero dice «no hay nada corriendo» y el segundo dejó un `until` de
espera de DNS girando cinco minutos contra una condición que **nunca podía cumplirse**. Un
guardián que no puede pasar nunca se ve igual que uno que todavía no pasó.
#### Lo que quedó declarado, y lo que no
- `instance.toml` es la verdad: `packages = ["python","python-pip"]`, `network = true` (pacman, pip y
la propia API de Gemini la necesitan) y **un solo dir concedido** (`/work/sergioh``/srv/sergioh`,
rw). Ni sockets, ni dispositivos, ni nada más.
- El código y el venv viven **fuera** de la instancia, en el anfitrión: el `upper` es caché (D3) y se
tira. Y las 84 dependencias quedaron pineadas en `requirements.lock` — el `requirements.txt` del
sitio no pinea nada, así que sin el lock un `recreate` traería otras versiones.
- La tarjeta `sergioh-api` va en `/etc/arje/cards.d/` **y** en el `genesis` de `/ente/seed.card.json`
(son dos preguntas distintas: qué arranca solo y qué se puede encarnar a pedido, §6.12), con dos
guardas que salen 78 nombrando el arreglo si falta la instancia o el venv.
-**Todavía invoca con `HARKAQ_BIN=/usr/bin`** en la tarjeta: el `takana` de la caja es el del
`commit` pineado en `recipes/takana.toml` y no trae aún la búsqueda en `/usr/bin`. Sale solo cuando
se suba ese pin.
#### El estado de la mudanza tras esto
| | |
|---|---|
| **mudado hoy** | `api.sergio.gioser.net` (DNS: CNAME→`www` **borrado**, A→`2.29.29.217` TTL 60) |
| **pendiente inmediato** | apagar el `sergioh_backend` de gioser **cuando propague** (OpenRC *y* arje: `rc-update del` + `rc-service stop` + `arjectl stop openrc-…`, §6.17). Hasta entonces sirve a los resolutores que aún tengan el CNAME cacheado |
| **lo que falta de `sergio.gioser.net`** | el frontend ya está copiado en `/work/www/sergioh`; falta `/shuma/*``shuma-gateway` (:7378), que es glibc dinámico y **cabe en esta misma jaula** (el binario está rescatado en `/work/rescate-binarios/`) pero cuelga de `shuma-daemon`, que es un sistema entero, no un binario |
| **y los otros dos vivos** | `gioser.net`/`www` (estáticos + `/hooks/*` en :8770 + `/reencuentro` con php-fpm) y `tawasuyu.net` (estático, raíz en `/mnt/vvv/tawasuyu`) |
## 7. Reusar los scripts que ya existen, y no escribir de nuevo
Pedido explícito del usuario. El inventario de lo que ya hace el trabajo:
@@ -1517,6 +1592,12 @@ receta usa uno.
### Lo que falta para el cutover, en este orden
**La lista de abajo es del 2026-09-11 y los pasos 1-5 YA ESTÁN** (gitea mudado y sirviendo, §6.14;
estáticos mudados, §6.18; fósiles barridos, §6.19; `api.sergio` mudado, §6.25). El estado vigente de
la mudanza está en la tabla del final de §6.25; lo que sigue vivo en gioser son **tres vhosts**
(`sergio` con su `/shuma`, `gioser.net`/`www`, `tawasuyu.net`) y los servicios del censo.
1. **Actualizar la caja a la imagen nueva** (gitea + `arjectl` + las cuentas de `[[user]]`).
`takana upgrade` está probado (§6.13 del SDD 27 y §5.4 acá); el `dd` es para provisionar, no para
actualizar — sobrescribe el disco local y re-etiqueta la partición.