cuatro daemons propios corriendo en la caja — y la máquina se llamaba «(none)»

Sellaron `matilda`, `pacha`, `pacha-secretos` y `sandokan-watch`; las cuatro promovidas a canónicas
(hash idéntico antes y después de moverlas) y las tres primeras ya supervisadas por arje.
`matilda` archivó 78 ficheros leyendo el access log de caddy; `pacha` corre con SUS reglas y no con
las de fábrica; `pacha-secretos` vuelve a existir como binario — en gioser era un inodo borrado.

TRES CORREN COMO ROOT, declarado en vez de heredado. No es descuido: `matilda` lee
`/var/log/caddy/requests.json`, que caddy crea `-rw------- root root` y recrea igual en cada
rotación; y los tres del trío escriben en el MISMO `/var/lib/tupu`, cuyos 322 ficheros en gioser son
root:root — bajar a uno solo deja mezcla de dueños en un árbol compartido. O los tres, o ninguno. La
salida limpia (caddy con `mode 640` + cuenta propia del árbol) queda anotada en la receta. `pacha` y
`pacha-secretos` sí bajan a cuenta propia: en gioser tampoco corrían como root.

🕳️ LA CAJA NO TENÍA HOSTNAME. `hostname` decía `(none)` y `/etc/hostname` no existía — NINGUNA caja
takana lo fija: ni netup, ni el product-rootfs. Nunca importó porque nada archivaba por nombre,
hasta que llegó matilda: sus primeros 72 ficheros fueron a `/var/lib/tupu/none/`, y dos máquinas
distintas archivarían en la misma carpeta sin que nada falle. Puesto `/etc/hostname` + una Card
OneShot en el genesis para que sobreviva al reinicio. Lo correcto es que lo haga `netup`.

🛡️ Y `sandokan-watch` quedaba VERDE SIN VIGILAR: en takana no hay `auth.log` ni journalctl, así que
arrancaba, decía «sin fuente de accesos: no se guarda nada» y se quedaba «corriendo · 0 reinicios».
Su Card ahora sale 78 nombrando el problema y NO entra al genesis: un vigía que no vigila es peor
que uno caído, porque el caído se ve.

De paso, dos veredictos FALSOS en una tarde por probar con algo que la caja no tiene: `/dev/tcp` no
existe en busybox ash (dio «cerrado» para los cinco puertos de gioser, incluidos :80 y :443, que
sirven) y la expansión de llaves tampoco (dijo que los artefactos no habían llegado; habían
llegado). Misma familia que el §6.23.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-09-16 20:25:05 +00:00
co-authored by Claude Opus 5
parent 7be069cc5a
commit 98cd672a10
9 changed files with 281 additions and 80 deletions
+73
View File
@@ -2220,6 +2220,79 @@ la máquina exista. Lo que ya no existe es la dependencia: **ningún dominio res
`shuma-askpass` («sudo/ssh pedirán la clave por el TTY»). Es otro crate del mismo workspace y es
otra receta — no bloquea la consola.
### 6.38 🧩 Los primeros cuatro daemons propios, corriendo en la caja *(2026-09-16)*
De las diez recetas encoladas, cuatro sellaron y ya corren supervisadas por arje:
| | cuenta | qué hace, comprobado |
|---|---|---|
| `matilda` | **root** | lee el access log de caddy y archivó **78 ficheros** en `/var/lib/tupu/takana/` |
| `pacha` | `pacha` (965) | vivo, 0 reinicios, con SUS reglas (`reglas.ron`), no las de fábrica |
| `pacha-secretos` | `pacha` | vivo, 0 reinicios — y su binario en gioser era un **inodo borrado** |
| `sandokan-watch` | root | **frenado a propósito**: no puede trabajar acá (ver abajo) |
#### ⚠ Tres corren como ROOT, y está declarado en vez de heredado
Lo natural sería una cuenta sin privilegio por servicio, como `shuma` o `gitea`. Con el trío de la
telemetría **no se puede**, y las dos razones son medidas:
1. `matilda` lee `/var/log/caddy/requests.json`, que caddy crea **`-rw------- root root`** y recrea
igual en cada rotación: un grupo con permiso de lectura se pierde en la próxima.
2. `tupu`, `matilda` y `sandokan-watch` escriben en el MISMO `/var/lib/tupu`, y en gioser sus 322
ficheros son `root:root`. Bajar uno solo deja **mezcla de dueños en un árbol compartido**: escribe
el primero y los otros fallan al modificar.
⇒ o los tres como root, o ninguno. La salida limpia está anotada en la receta para el día que se
quiera: que caddy escriba con `mode 640` y que el árbol sea de una cuenta propia. `pacha` y
`pacha-secretos` sí bajan a una cuenta propia, porque en gioser tampoco corrían como root.
#### 🕳️ La caja se llamaba «(none)» — y eso se archivaba
`matilda` archiva POR MÁQUINA, y sus primeros 72 ficheros fueron a `/var/lib/tupu/**none**/`:
```
$ hostname → (none)
$ cat /etc/hostname → no existe
```
**Ninguna caja takana fija su hostname**: no lo hace `netup`, no está en el product-rootfs, no hay
`/etc/hostname`. Nunca importó porque nada archivaba por nombre — hasta que llegó algo que sí. Y no
falla: archiva bajo `none`, y dos máquinas distintas archivarían en la misma carpeta.
Puesto `/etc/hostname` + una Card **OneShot** `hostname` en el genesis, para que sobreviva al
reinicio sin depender de que alguien se acuerde. Con el nombre puesto, matilda re-archiva en
`/var/lib/tupu/takana/`. Quedan 72 ficheros huérfanos bajo `none/`: son los 20 minutos anteriores.
⇒ **lo correcto es que lo haga `netup`**, que es quien configura la identidad de red de la máquina;
la Card es la mitigación de hoy, y está dicho en su propia guarda.
#### 🛡️ Un vigía que no vigila es PEOR que uno caído, porque el caído se ve
`sandokan-watch` arrancó, quedó «corriendo · 0 reinicios»… y no guardaba una línea. Lo dice él mismo
si uno lo corre a mano:
```
sandokan-watch · sin fuente de accesos (ni /var/log/auth.log ni journalctl): no se guarda nada
```
En gioser lee el `auth.log` de un syslog que **en takana no existe** — no hay systemd ni syslog. Su
Card ahora lleva una guarda que sale **78** nombrando el problema, así que el servicio no queda
verde mintiendo; y **no entra al `genesis`**, sólo a `cards.d`, porque no tiene sentido que arranque
al boot para fallar. Destrabarlo es darle el diario de arje como fuente, y eso es trabajo de su repo.
#### Dos herramientas que no existen donde se prueba
Dos veredictos falsos en una tarde, los dos por probar con algo que la caja no tiene:
- **`/dev/tcp/host/puerto` no existe en busybox `ash`** ⇒ un barrido de puertos contra gioser dio
«cerrado» para los cinco, incluidos `:80` y `:443`, que sirven. Con `curl telnet://` el resultado
es el contrario: `:2345` y `:443` **abiertos**, `:22` cerrado.
- **La expansión de llaves (`{a,b}`) tampoco** ⇒ un `ls /store/*-{matilda,pacha}` dijo que los
artefactos no habían llegado. Habían llegado.
Es la misma lección del §6.23 (`ps` y `dig` ausentes) y merece repetirse: *una prueba que no puede
pasar se ve igual que una que todavía no pasó*.
## 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:
-28
View File
@@ -1,28 +0,0 @@
# matilda — grabador: `matilda record --interval 60 --root /var/lib/tupu --access-log …`.
#
# ⚠ Lee el ACCESS LOG de caddy (`/var/log/caddy/requests.json`). En la caja nueva ese fichero
# existe sólo si el Caddyfile importa el snippet `acceso` — que sí lo hace. Si algún día deja
# de hacerlo, matilda no falla: graba vacío.
# El crate vive en `02_ruway/shuma/baremetal/matilda-app` y su paquete se llama `matilda`.
#
# Receta Cargo contra el monorepo de tawasuyu, pinneada al MISMO commit que `shuma-*` y
# `puriy-costura`: el árbol de fuentes se comparte por `<dep>-<sha>`, así que un pin distinto es otro
# vendoreo de 2,4 G. Estática musl con zig-cc — la caja la arranca el init y no puede depender de
# encontrar un cargador, que es justo lo que le falta al binario glibc de gioser.
name = "matilda"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[source]
repo = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git"
commit = "23a292863f53b355c5c02d6185904f2c33d8ab42"
# tawasuyu COMMITEA su propio `vendor/` (smithay parcheado, enchufado por `[patch.crates-io]` POR
# RUTA); el `cargo vendor` de takana lo pisaría y el error habla de `taffy`, no de esto.
cargo_vendor_dir = ".hammer-cargo-vendor"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = ["-p", "matilda", "--bin", "matilda"]
-26
View File
@@ -1,26 +0,0 @@
# pacha — `pacha daemon`, corriendo en gioser sin que nadie lo declare.
#
# El paquete es `pacha-cli` y el binario `pacha`. Sus reglas viven en `~/.config/pacha/reglas*.ron`:
# son DECISIONES del usuario, no defaults, y no las genera nada.
#
# Receta Cargo contra el monorepo de tawasuyu, pinneada al MISMO commit que `shuma-*` y
# `puriy-costura`: el árbol de fuentes se comparte por `<dep>-<sha>`, así que un pin distinto es otro
# vendoreo de 2,4 G. Estática musl con zig-cc — la caja la arranca el init y no puede depender de
# encontrar un cargador, que es justo lo que le falta al binario glibc de gioser.
name = "pacha"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[source]
repo = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git"
commit = "23a292863f53b355c5c02d6185904f2c33d8ab42"
# tawasuyu COMMITEA su propio `vendor/` (smithay parcheado, enchufado por `[patch.crates-io]` POR
# RUTA); el `cargo vendor` de takana lo pisaría y el error habla de `taffy`, no de esto.
cargo_vendor_dir = ".hammer-cargo-vendor"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = ["-p", "pacha-cli", "--bin", "pacha"]
-26
View File
@@ -1,26 +0,0 @@
# sandokan-watch — vigía: `--every 60 --state /var/lib/sandokan-watch.json --record --root /var/lib/tupu`.
#
# El paquete es `sandokan-seguridad-core` y el binario `sandokan-watch`.
# ⚠ Escribe en `/var/lib/tupu`, el mismo directorio que `tupu` y `matilda` (ver esa receta).
#
# Receta Cargo contra el monorepo de tawasuyu, pinneada al MISMO commit que `shuma-*` y
# `puriy-costura`: el árbol de fuentes se comparte por `<dep>-<sha>`, así que un pin distinto es otro
# vendoreo de 2,4 G. Estática musl con zig-cc — la caja la arranca el init y no puede depender de
# encontrar un cargador, que es justo lo que le falta al binario glibc de gioser.
name = "sandokan-watch"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[source]
repo = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git"
commit = "23a292863f53b355c5c02d6185904f2c33d8ab42"
# tawasuyu COMMITEA su propio `vendor/` (smithay parcheado, enchufado por `[patch.crates-io]` POR
# RUTA); el `cargo vendor` de takana lo pisaría y el error habla de `taffy`, no de esto.
cargo_vendor_dir = ".hammer-cargo-vendor"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = ["-p", "sandokan-seguridad-core", "--bin", "sandokan-watch"]
+26
View File
@@ -26,3 +26,29 @@ compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = ["-p", "tupu-cli", "--bin", "tupu"]
# ── EL SERVICIO (SDD 30) ────────────────────────────────────────────────────────────────────────
# Fuera de `hash_inputs`: declararlo no re-hashea.
#
# ⚠ **CORRE COMO ROOT, Y NO ES UN DESCUIDO — ES UNA RESTRICCIÓN MEDIDA.** Lo natural sería una
# cuenta propia sin privilegio, como `shuma` o `gitea`. Acá no se puede, por dos hechos:
#
# 1. `matilda` lee `/var/log/caddy/requests.json`, que caddy crea **`-rw------- root root`** y
# recrea igual en cada rotación. Un grupo con lectura se pierde en la próxima rotación.
# 2. Los tres —`tupu`, `matilda`, `sandokan-watch`— escriben en el MISMO `/var/lib/tupu`, y en
# gioser sus 322 ficheros son `root:root`. Bajar a uno solo deja mezcla de dueños en un árbol
# compartido, que es la trampa de siempre: escribe el primero y los otros fallan al modificar.
#
# ⇒ o los tres como root, o ninguno. La salida limpia existe y está anotada para el día que se
# quiera: que caddy escriba su log con lectura de grupo (`output file … { mode 640 }`) y que el
# árbol sea de una cuenta `tupu`. Mientras tanto, esto es lo que HACE la máquina vieja, declarado
# en vez de heredado.
[[service]]
label = "tupu"
id = "01M2EKDA00TVPV000000000001"
exec = "/bin/busybox"
argv = ["sh", "-c", "test -d /var/lib/tupu || mkdir -p /var/lib/tupu || exit 78; exec /usr/bin/tupu collect --interval 10 --root /var/lib/tupu"]
envp = [["PATH", "/usr/bin:/bin"], ["HOME", "/root"]]
networking = "full"
cgroup = "arje.slice/tupu"
restart = { initial_ms = 1000, max_ms = 30000 }
+54
View File
@@ -0,0 +1,54 @@
# matilda — grabador: `matilda record --interval 60 --root /var/lib/tupu --access-log …`.
#
# ⚠ Lee el ACCESS LOG de caddy (`/var/log/caddy/requests.json`). En la caja nueva ese fichero
# existe sólo si el Caddyfile importa el snippet `acceso` — que sí lo hace. Si algún día deja
# de hacerlo, matilda no falla: graba vacío.
# El crate vive en `02_ruway/shuma/baremetal/matilda-app` y su paquete se llama `matilda`.
#
# Receta Cargo contra el monorepo de tawasuyu, pinneada al MISMO commit que `shuma-*` y
# `puriy-costura`: el árbol de fuentes se comparte por `<dep>-<sha>`, así que un pin distinto es otro
# vendoreo de 2,4 G. Estática musl con zig-cc — la caja la arranca el init y no puede depender de
# encontrar un cargador, que es justo lo que le falta al binario glibc de gioser.
name = "matilda"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[source]
repo = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git"
commit = "23a292863f53b355c5c02d6185904f2c33d8ab42"
# tawasuyu COMMITEA su propio `vendor/` (smithay parcheado, enchufado por `[patch.crates-io]` POR
# RUTA); el `cargo vendor` de takana lo pisaría y el error habla de `taffy`, no de esto.
cargo_vendor_dir = ".hammer-cargo-vendor"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = ["-p", "matilda", "--bin", "matilda"]
# ── EL SERVICIO (SDD 30) ────────────────────────────────────────────────────────────────────────
# Fuera de `hash_inputs`: declararlo no re-hashea.
#
# ⚠ **CORRE COMO ROOT, Y NO ES UN DESCUIDO — ES UNA RESTRICCIÓN MEDIDA.** Lo natural sería una
# cuenta propia sin privilegio, como `shuma` o `gitea`. Acá no se puede, por dos hechos:
#
# 1. `matilda` lee `/var/log/caddy/requests.json`, que caddy crea **`-rw------- root root`** y
# recrea igual en cada rotación. Un grupo con lectura se pierde en la próxima rotación.
# 2. Los tres —`tupu`, `matilda`, `sandokan-watch`— escriben en el MISMO `/var/lib/tupu`, y en
# gioser sus 322 ficheros son `root:root`. Bajar a uno solo deja mezcla de dueños en un árbol
# compartido, que es la trampa de siempre: escribe el primero y los otros fallan al modificar.
#
# ⇒ o los tres como root, o ninguno. La salida limpia existe y está anotada para el día que se
# quiera: que caddy escriba su log con lectura de grupo (`output file … { mode 640 }`) y que el
# árbol sea de una cuenta `tupu`. Mientras tanto, esto es lo que HACE la máquina vieja, declarado
# en vez de heredado.
[[service]]
label = "matilda"
id = "01M2EKDA00MAT1DA0GRABA0001"
exec = "/bin/busybox"
argv = ["sh", "-c", "test -d /var/lib/tupu || mkdir -p /var/lib/tupu || exit 78; test -r /var/log/caddy/requests.json || { echo 'matilda: no puedo leer /var/log/caddy/requests.json — sin el access log de caddy graba VACÍO y nadie lo nota' >&2; exit 78; }; exec /usr/bin/matilda record --interval 60 --root /var/lib/tupu --access-log /var/log/caddy/requests.json"]
envp = [["PATH", "/usr/bin:/bin"], ["HOME", "/root"]]
networking = "full"
cgroup = "arje.slice/matilda"
restart = { initial_ms = 1000, max_ms = 30000 }
@@ -26,3 +26,19 @@ compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = ["-p", "pacha-secretos", "--bin", "pacha-secretos"]
# ── EL SERVICIO (SDD 30) ────────────────────────────────────────────────────────────────────────
# La cuenta la declara `recipes/incoming/pacha.toml` — es la misma, y dos recetas declarando la
# misma cuenta con distinto uid abortan la imagen a propósito (`takana users --merge`).
#
# Su base de datos es EFÍMERA por diseño (en gioser: `/tmp/pacha-secretos-efimero-<pid>/db`), así
# que no hay estado que mudar: lo que sí viaja es el log de estado en `~/.local/state/tawasuyu/`.
[[service]]
label = "pacha-secretos"
id = "01M2EKDA00PACHA5ECRET05X12"
exec = "/bin/busybox"
argv = ["sh", "-c", "/bin/grep -q '^pacha:' /etc/passwd || { echo 'pacha-secretos: falta el usuario `pacha` — lo declara recipes/pacha.toml' >&2; exit 78; }; cd /var/lib/pacha || exit 78; exec /usr/bin/setuidgid pacha /usr/bin/pacha-secretos"]
envp = [["PATH", "/usr/bin:/bin"], ["HOME", "/var/lib/pacha"], ["USER", "pacha"], ["XDG_RUNTIME_DIR", "/run/pacha"]]
networking = "full"
cgroup = "arje.slice/pacha-secretos"
restart = { initial_ms = 1000, max_ms = 30000 }
+50
View File
@@ -0,0 +1,50 @@
# pacha — `pacha daemon`, corriendo en gioser sin que nadie lo declare.
#
# El paquete es `pacha-cli` y el binario `pacha`. Sus reglas viven en `~/.config/pacha/reglas*.ron`:
# son DECISIONES del usuario, no defaults, y no las genera nada.
#
# Receta Cargo contra el monorepo de tawasuyu, pinneada al MISMO commit que `shuma-*` y
# `puriy-costura`: el árbol de fuentes se comparte por `<dep>-<sha>`, así que un pin distinto es otro
# vendoreo de 2,4 G. Estática musl con zig-cc — la caja la arranca el init y no puede depender de
# encontrar un cargador, que es justo lo que le falta al binario glibc de gioser.
name = "pacha"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[source]
repo = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git"
commit = "23a292863f53b355c5c02d6185904f2c33d8ab42"
# tawasuyu COMMITEA su propio `vendor/` (smithay parcheado, enchufado por `[patch.crates-io]` POR
# RUTA); el `cargo vendor` de takana lo pisaría y el error habla de `taffy`, no de esto.
cargo_vendor_dir = ".hammer-cargo-vendor"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = ["-p", "pacha-cli", "--bin", "pacha"]
# ── LA CUENTA (SDD 30) ──────────────────────────────────────────────────────────────────────────
# Fuera de `hash_inputs`. En gioser corre como `sergio` —nunca como root—, así que acá es una cuenta
# propia y sin privilegio. La comparte con `pacha-secretos`: son la misma familia y el mismo estado
# (`~/.local/state/tawasuyu/pacha-secretos/`), y separarlos obligaría a un grupo intermedio para que
# uno lea lo que el otro escribe.
[[user]]
name = "pacha"
uid = 965
home = "/var/lib/pacha"
# ── EL SERVICIO ─────────────────────────────────────────────────────────────────────────────────
# ⚠ La guarda EXIGE `reglas.ron`. No es celo: son **decisiones del usuario, no defaults** — sin
# ellas pacha no falla, arranca con otra política, y eso no se ve en ningún log. Mismo criterio que
# el `gateway-token` de shuma: lo que no se puede regenerar se exige, no se inventa.
[[service]]
label = "pacha"
id = "01M2EKDA00PACHADAEM0N00110"
exec = "/bin/busybox"
argv = ["sh", "-c", "/bin/grep -q '^pacha:' /etc/passwd || { echo 'pacha: falta el usuario `pacha` en /etc/passwd — lo declara esta receta con [[user]]' >&2; exit 78; }; test -s /var/lib/pacha/.config/pacha/reglas.ron || { echo 'pacha: falta /var/lib/pacha/.config/pacha/reglas.ron — son las REGLAS del usuario, no un default; vienen de ~/.config/pacha/ del origen' >&2; exit 78; }; mkdir -p /run/pacha && chown pacha:pacha /run/pacha; cd /var/lib/pacha || exit 78; exec /usr/bin/setuidgid pacha /usr/bin/pacha daemon"]
envp = [["PATH", "/usr/bin:/bin"], ["HOME", "/var/lib/pacha"], ["USER", "pacha"], ["XDG_RUNTIME_DIR", "/run/pacha"]]
networking = "full"
cgroup = "arje.slice/pacha"
restart = { initial_ms = 1000, max_ms = 30000 }
+62
View File
@@ -0,0 +1,62 @@
# sandokan-watch — vigía: `--every 60 --state /var/lib/sandokan-watch.json --record --root /var/lib/tupu`.
#
# El paquete es `sandokan-seguridad-core` y el binario `sandokan-watch`.
# ⚠ Escribe en `/var/lib/tupu`, el mismo directorio que `tupu` y `matilda` (ver esa receta).
#
# Receta Cargo contra el monorepo de tawasuyu, pinneada al MISMO commit que `shuma-*` y
# `puriy-costura`: el árbol de fuentes se comparte por `<dep>-<sha>`, así que un pin distinto es otro
# vendoreo de 2,4 G. Estática musl con zig-cc — la caja la arranca el init y no puede depender de
# encontrar un cargador, que es justo lo que le falta al binario glibc de gioser.
name = "sandokan-watch"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[source]
repo = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git"
commit = "23a292863f53b355c5c02d6185904f2c33d8ab42"
# tawasuyu COMMITEA su propio `vendor/` (smithay parcheado, enchufado por `[patch.crates-io]` POR
# RUTA); el `cargo vendor` de takana lo pisaría y el error habla de `taffy`, no de esto.
cargo_vendor_dir = ".hammer-cargo-vendor"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = ["-p", "sandokan-seguridad-core", "--bin", "sandokan-watch"]
# ── EL SERVICIO (SDD 30) ────────────────────────────────────────────────────────────────────────
# Fuera de `hash_inputs`: declararlo no re-hashea.
#
# ⚠ **CORRE COMO ROOT, Y NO ES UN DESCUIDO — ES UNA RESTRICCIÓN MEDIDA.** Lo natural sería una
# cuenta propia sin privilegio, como `shuma` o `gitea`. Acá no se puede, por dos hechos:
#
# 1. `matilda` lee `/var/log/caddy/requests.json`, que caddy crea **`-rw------- root root`** y
# recrea igual en cada rotación. Un grupo con lectura se pierde en la próxima rotación.
# 2. Los tres —`tupu`, `matilda`, `sandokan-watch`— escriben en el MISMO `/var/lib/tupu`, y en
# gioser sus 322 ficheros son `root:root`. Bajar a uno solo deja mezcla de dueños en un árbol
# compartido, que es la trampa de siempre: escribe el primero y los otros fallan al modificar.
#
# ⇒ o los tres como root, o ninguno. La salida limpia existe y está anotada para el día que se
# quiera: que caddy escriba su log con lectura de grupo (`output file … { mode 640 }`) y que el
# árbol sea de una cuenta `tupu`. Mientras tanto, esto es lo que HACE la máquina vieja, declarado
# en vez de heredado.
[[service]]
label = "sandokan-watch"
id = "01M2EKDA005AND0KANWATCH001"
exec = "/bin/busybox"
argv = ["sh", "-c", "test -d /var/lib/tupu || mkdir -p /var/lib/tupu || exit 78; test -r /var/log/auth.log || command -v journalctl >/dev/null || { echo 'sandokan-watch: no hay FUENTE DE ACCESOS en esta máquina (ni /var/log/auth.log ni journalctl). El binario arranca igual y NO GUARDA NADA: un vigía verde que no vigila. En takana hace falta darle el diario de arje o una fuente equivalente.' >&2; exit 78; }; exec /usr/bin/sandokan-watch --every 60 --state /var/lib/sandokan-watch.json --record --root /var/lib/tupu"]
envp = [["PATH", "/usr/bin:/bin"], ["HOME", "/root"]]
networking = "full"
cgroup = "arje.slice/sandokan-watch"
restart = { initial_ms = 1000, max_ms = 30000 }
# ⚠ MEDIDO EN LA CAJA (2026-09-16): acá NO PUEDE TRABAJAR, y lo dice él mismo:
#
# sandokan-watch · sin fuente de accesos (ni /var/log/auth.log ni journalctl): no se guarda nada
#
# En gioser lee el `auth.log` de un syslog que en takana no existe —no hay systemd ni syslog— así
# que el servicio arrancaba, quedaba «corriendo · 0 reinicios» y no guardaba una línea. Por eso la
# guarda de arriba sale 78 en vez de dejarlo verde: **un vigía que no vigila es peor que uno caído,
# porque el caído se ve**. Destrabarlo es darle el diario de arje como fuente, y eso es trabajo de
# su propio repo, no de esta receta.