tawasuyu

tawasuyu/brahman

Rust 328TOML 124JSON 17Markdown 144636 Sutichaykuna

⎇ main crates/modules/shuma/docs/DEVELOPMENT.md Markdown · 244 siq'ikuna · 7.3 KB Ñawpa willay ch'uya

refactor(monorepo): reorganización lógica + renames + SDDs + split CHANGELOG 550c98f27 · sergio ·

1# Development guide — shipote
2
3Cómo compilar, correr, testear y debuggear shipote desde la raíz del monorepo (`/home/sergio/brahman`).
4
5## Compilar
6
7Todos los crates de shipote y su soporte:
8```sh
9cargo build -p shipote-daemon -p shipote-cli -p shipote-shell
10```
11
12Sólo lo esencial (daemon + cli, sin GUI):
13```sh
14cargo build -p shipote-daemon -p shipote-cli
15```
16
17Workspace completo:
18```sh
19cargo check --workspace
20```
21
22## Correr el daemon
23
24```sh
25SHIPOTE_LOG=info ./target/debug/shipote-daemon
26```
27
28Filtros útiles:
29```sh
30SHIPOTE_LOG=warn,shipote_core=info ./target/debug/shipote-daemon          # menos ruido
31SHIPOTE_LOG=warn,audit=info ./target/debug/shipote-daemon                 # sólo audit
32SHIPOTE_LOG=info,shipote_core::pipeline=debug ./target/debug/shipote-daemon # debug del pipeline
33```
34
35El daemon:
36- Escucha `$XDG_RUNTIME_DIR/shipote.sock` (fallback `/run/user/$UID/shipote.sock`).
37- Restaura snapshot de `$XDG_STATE_HOME/shipote/state.json` (fallback `$HOME/.local/state/shipote/state.json`).
38- Relanza pipelines `live` (con `restart_on_failure=true`) automáticamente.
39- Reaper cada 500 ms (cosecha zombies + drena pending restarts + chequea quota breaches).
40- SIGTERM/SIGINT → snapshot + `stop_with_grace(1s)` de todos los workspaces + exit.
41
42## Correr el shell (GUI)
43
44```sh
45cargo run -p shipote-shell
46```
47
48Polling cada 2 s al daemon. Si el daemon no está corriendo, muestra "Daemon DOWN" banner rojo. Sparkline de RSS por workspace. Cards: Estado, Capabilities, Workspaces, Comandos, Saved pipelines, Flow channels, Quota breaches, Live tail.
49
50Requiere DISPLAY (X11/Wayland) — no corre en sandbox sin gráfico.
51
52## Correr el CLI
53
54```sh
55./target/debug/shipote ping
56./target/debug/shipote health
57./target/debug/shipote workspace create demo.toml
58```
59
60Ver [CLI.md](CLI.md) para referencia completa.
61
62## Tests
63
64Suite completa (85 tests al cierre de Fase R):
65```sh
66cargo test -p ente-incarnate \
67           -p shipote-card \
68           -p shipote-protocol \
69           -p shipote-discern \
70           -p shipote-core \
71           -p yahweh-provider-fs \
72           -p nouser-core \
73           --no-fail-fast
74```
75
76Breakdown:
77| Crate | Tests |
78|---|---|
79| `ente-incarnate` | 16 (clone+ns, stdio, pre_exec, caps detect, cgroup paths) |
80| `nouser-core` | 27 (pre-existentes — discerner integrado sin regresiones) |
81| `shipote-card` | 8 (roundtrip TOML/JSON, compile-to-card, intersect_soma) |
82| `shipote-core` | 26 (workspaces, pipeline fan-in/out, flow_channel replay, stats history, restart, quota enforce, snapshot dirty-skip, ...) |
83| `shipote-discern` | 5 (MagicBytes, JsonProbe, CardProbe, TomlProbe, Utf8Probe) |
84| `yahweh-provider-fs` | 3 (discern_head + integración) |
85
86Tests específicos útiles:
87```sh
88# Fan-in (merger):
89cargo test -p shipote-core --lib pipeline_fanin -- --nocapture
90
91# Replay buffer:
92cargo test -p shipote-core --lib replay -- --nocapture
93
94# Quota enforcement:
95cargo test -p shipote-core --lib quota_enforce -- --nocapture
96
97# Snapshot incremental:
98cargo test -p shipote-core --lib save_snapshot_skips
99```
100
101> Algunos tests del pipeline (fan-in/fan-out) son tokio-async y necesitan `--test-threads=1` cuando todos los tests corren juntos. La suite por crate ya funciona bien.
102
103## Smoke E2E manual
104
105Demo end-to-end de los features principales:
106
107```sh
108# 1. Limpiar estado previo
109rm -f $HOME/.local/state/shipote/state.json
110pkill -f shipote-daemon
111
112# 2. Arrancar daemon (en background o terminal aparte)
113SHIPOTE_LOG=info ./target/debug/shipote-daemon &
114sleep 0.3
115
116# 3. Crear workspace
117cat > /tmp/ws.toml <<'EOF'
118label = "demo"
119on_exit = "reap"
120EOF
121WS=$(./target/debug/shipote workspace create /tmp/ws.toml)
122echo "workspace: $WS"
123
124# 4. Health check
125./target/debug/shipote health
126
127# 5. Run comando con log capture
128./target/debug/shipote run -w $WS /bin/echo -- "hello shipote"
129sleep 0.3
130CMD=$(./target/debug/shipote commands $WS | head -1 | awk '{print $1}')
131./target/debug/shipote logs $WS $CMD
132
133# 6. Pipeline con tap (data plane real)
134cat > /tmp/pipe.toml <<EOF
135label = "demo-pipe"
136workspace = "$WS"
137discern = { sample_bytes = 4096, enrich_producer = true }
138
139[[nodes]]
140label = "p1"
141payload.Native = { exec = "/bin/echo", argv = ['{"hello": 1}'], envp = [] }
142
143[[nodes]]
144label = "p2"
145payload.Native = { exec = "/bin/cat", argv = [], envp = [] }
146
147[[edges]]
148from = 0
149from_output = "stdout"
150to = 1
151to_input = "stdin"
152EOF
153./target/debug/shipote pipeline run /tmp/pipe.toml --tap
154
155# 7. Flow throughput
156./target/debug/shipote flow throughput
157
158# 8. Stats con CPU%
159./target/debug/shipote workspace stats $WS
160
161# 9. SIGTERM (drain + snapshot)
162pkill -TERM -f shipote-daemon
163```
164
165## Debug del daemon
166
167### Logs del daemon en archivo
168```sh
169SHIPOTE_LOG=info ./target/debug/shipote-daemon 2>&1 | tee /tmp/shipote-daemon.log
170```
171
172### Filtrar audit log
173```sh
174SHIPOTE_LOG=warn,audit=info ./target/debug/shipote-daemon 2>&1 | grep audit
175```
176
177### Verificar caps runtime
178```sh
179shipote caps
180```
181Te dice si `user_ns` está bloqueado por sysctl/LSM y si tu cgroup está delegado.
182
183### Inspeccionar el snapshot
184```sh
185cat $HOME/.local/state/shipote/state.json | jq .
186```
187
188JSON con: version, timestamp_ms, workspaces, saved_pipelines, live_pipelines, stats_history persistida.
189
190### Debugging FDs
191```sh
192ls -la /proc/$(pgrep -x shipote-daemon)/fd | head -20
193```
194Si ves muchos `pipe:[N]` o `socket:[N]` huérfanos, hay leak en algún spawn.
195
196## Arquitectura del repositorio
197
198```
199crates/
200├── apps/
201│   ├── shipote-daemon/     ← binario long-running
202│   ├── shipote-cli/        ← binario `shipote`
203│   └── shipote-shell/      ← GUI GPUI
204├── modules/shipote/
205│   ├── shipote-card/       ← tipos WorkspaceSpec/PipelineSpec/...
206│   ├── shipote-protocol/   ← wire postcard
207│   ├── shipote-discern/    ← MagicBytes/Json/Toml/Card/Utf8
208│   ├── shipote-core/       ← WorkspaceManager + pipeline + flow_channel + ...
209│   ├── README.md           ← entry point (este archivo es vecino)
210│   └── docs/
211│       ├── ARCHITECTURE.md
212│       ├── CLI.md
213│       ├── RECIPES.md
214│       └── DEVELOPMENT.md  ← estás acá
215└── shared/
216    └── ente-incarnate/     ← extraído de ente-soma; reusable por shipote y otros
217```
218
219## Memoria del proyecto
220
221Toda la historia de fases (F a R) está documentada en:
222```
223/home/sergio/.claude/projects/-home-sergio-brahman/memory/project_shipote.md
224```
225
226Esa memoria persiste entre conversaciones con Claude Code. Si arrancás una sesión nueva, Claude la consulta automáticamente.
227
228## Issues conocidos
229
230### El remote `origin` está mal configurado
231`https:/sergio:...` con un solo `/`. Para subir los 10 commits locales:
232```sh
233git remote set-url origin https://sergio:<password>@gitea.gioser.net/sergio/brahman
234git push origin main
235```
236
237### El daemon no se conecta al broker
238Si el Init (`brahman-init.sock`) no está corriendo, el sidecar loguea `no conectado` y el daemon sigue standalone. Esto es **diseñado** (graceful degradation), no un bug. Los announcements de edge-card al broker tampoco llegan en este modo.
239
240### Pipeline restart pierde ULIDs
241Cada relaunch genera un pipeline_id nuevo. Trackers externos que dependen del ULID se rompen. Workaround: usar el `label` del pipeline (estable entre restarts).
242
243### `tokio::test` + `waitpid` síncrono
244Algunos tests del pipeline necesitan `--test-threads=1` porque el waitpid síncrono dentro de un `current_thread` runtime bloquea el reactor antes de que las tareas spawneadas corran.

DEVELOPMENT.md

Development guide — shipote

Cómo compilar, correr, testear y debuggear shipote desde la raíz del monorepo (/home/sergio/brahman).

Compilar

Todos los crates de shipote y su soporte:

cargo build -p shipote-daemon -p shipote-cli -p shipote-shell

Sólo lo esencial (daemon + cli, sin GUI):

cargo build -p shipote-daemon -p shipote-cli

Workspace completo:

cargo check --workspace

Correr el daemon

SHIPOTE_LOG=info ./target/debug/shipote-daemon

Filtros útiles:

SHIPOTE_LOG=warn,shipote_core=info ./target/debug/shipote-daemon          # menos ruido
SHIPOTE_LOG=warn,audit=info ./target/debug/shipote-daemon                 # sólo audit
SHIPOTE_LOG=info,shipote_core::pipeline=debug ./target/debug/shipote-daemon # debug del pipeline

El daemon:

Correr el shell (GUI)

cargo run -p shipote-shell

Polling cada 2 s al daemon. Si el daemon no está corriendo, muestra "Daemon DOWN" banner rojo. Sparkline de RSS por workspace. Cards: Estado, Capabilities, Workspaces, Comandos, Saved pipelines, Flow channels, Quota breaches, Live tail.

Requiere DISPLAY (X11/Wayland) — no corre en sandbox sin gráfico.

Correr el CLI

./target/debug/shipote ping
./target/debug/shipote health
./target/debug/shipote workspace create demo.toml

Ver CLI.md para referencia completa.

Tests

Suite completa (85 tests al cierre de Fase R):

cargo test -p ente-incarnate \
           -p shipote-card \
           -p shipote-protocol \
           -p shipote-discern \
           -p shipote-core \
           -p yahweh-provider-fs \
           -p nouser-core \
           --no-fail-fast

Breakdown:

CrateTests
ente-incarnate16 (clone+ns, stdio, pre_exec, caps detect, cgroup paths)
nouser-core27 (pre-existentes — discerner integrado sin regresiones)
shipote-card8 (roundtrip TOML/JSON, compile-to-card, intersect_soma)
shipote-core26 (workspaces, pipeline fan-in/out, flow_channel replay, stats history, restart, quota enforce, snapshot dirty-skip, ...)
shipote-discern5 (MagicBytes, JsonProbe, CardProbe, TomlProbe, Utf8Probe)
yahweh-provider-fs3 (discern_head + integración)

Tests específicos útiles:

# Fan-in (merger):
cargo test -p shipote-core --lib pipeline_fanin -- --nocapture

# Replay buffer:
cargo test -p shipote-core --lib replay -- --nocapture

# Quota enforcement:
cargo test -p shipote-core --lib quota_enforce -- --nocapture

# Snapshot incremental:
cargo test -p shipote-core --lib save_snapshot_skips

Algunos tests del pipeline (fan-in/fan-out) son tokio-async y necesitan --test-threads=1 cuando todos los tests corren juntos. La suite por crate ya funciona bien.

Smoke E2E manual

Demo end-to-end de los features principales:

# 1. Limpiar estado previo
rm -f $HOME/.local/state/shipote/state.json
pkill -f shipote-daemon

# 2. Arrancar daemon (en background o terminal aparte)
SHIPOTE_LOG=info ./target/debug/shipote-daemon &
sleep 0.3

# 3. Crear workspace
cat > /tmp/ws.toml <<'EOF'
label = "demo"
on_exit = "reap"
EOF
WS=$(./target/debug/shipote workspace create /tmp/ws.toml)
echo "workspace: $WS"

# 4. Health check
./target/debug/shipote health

# 5. Run comando con log capture
./target/debug/shipote run -w $WS /bin/echo -- "hello shipote"
sleep 0.3
CMD=$(./target/debug/shipote commands $WS | head -1 | awk '{print $1}')
./target/debug/shipote logs $WS $CMD

# 6. Pipeline con tap (data plane real)
cat > /tmp/pipe.toml <<EOF
label = "demo-pipe"
workspace = "$WS"
discern = { sample_bytes = 4096, enrich_producer = true }

[[nodes]]
label = "p1"
payload.Native = { exec = "/bin/echo", argv = ['{"hello": 1}'], envp = [] }

[[nodes]]
label = "p2"
payload.Native = { exec = "/bin/cat", argv = [], envp = [] }

[[edges]]
from = 0
from_output = "stdout"
to = 1
to_input = "stdin"
EOF
./target/debug/shipote pipeline run /tmp/pipe.toml --tap

# 7. Flow throughput
./target/debug/shipote flow throughput

# 8. Stats con CPU%
./target/debug/shipote workspace stats $WS

# 9. SIGTERM (drain + snapshot)
pkill -TERM -f shipote-daemon

Debug del daemon

Logs del daemon en archivo

SHIPOTE_LOG=info ./target/debug/shipote-daemon 2>&1 | tee /tmp/shipote-daemon.log

Filtrar audit log

SHIPOTE_LOG=warn,audit=info ./target/debug/shipote-daemon 2>&1 | grep audit

Verificar caps runtime

shipote caps

Te dice si user_ns está bloqueado por sysctl/LSM y si tu cgroup está delegado.

Inspeccionar el snapshot

cat $HOME/.local/state/shipote/state.json | jq .

JSON con: version, timestamp_ms, workspaces, saved_pipelines, live_pipelines, stats_history persistida.

Debugging FDs

ls -la /proc/$(pgrep -x shipote-daemon)/fd | head -20

Si ves muchos pipe:[N] o socket:[N] huérfanos, hay leak en algún spawn.

Arquitectura del repositorio

crates/
├── apps/
│   ├── shipote-daemon/     ← binario long-running
│   ├── shipote-cli/        ← binario `shipote`
│   └── shipote-shell/      ← GUI GPUI
├── modules/shipote/
│   ├── shipote-card/       ← tipos WorkspaceSpec/PipelineSpec/...
│   ├── shipote-protocol/   ← wire postcard
│   ├── shipote-discern/    ← MagicBytes/Json/Toml/Card/Utf8
│   ├── shipote-core/       ← WorkspaceManager + pipeline + flow_channel + ...
│   ├── README.md           ← entry point (este archivo es vecino)
│   └── docs/
│       ├── ARCHITECTURE.md
│       ├── CLI.md
│       ├── RECIPES.md
│       └── DEVELOPMENT.md  ← estás acá
└── shared/
    └── ente-incarnate/     ← extraído de ente-soma; reusable por shipote y otros

Memoria del proyecto

Toda la historia de fases (F a R) está documentada en:

/home/sergio/.claude/projects/-home-sergio-brahman/memory/project_shipote.md

Esa memoria persiste entre conversaciones con Claude Code. Si arrancás una sesión nueva, Claude la consulta automáticamente.

Issues conocidos

El remote origin está mal configurado

https:/sergio:... con un solo /. Para subir los 10 commits locales:

git remote set-url origin https://sergio:<password>@gitea.gioser.net/sergio/brahman
git push origin main

El daemon no se conecta al broker

Si el Init (brahman-init.sock) no está corriendo, el sidecar loguea no conectado y el daemon sigue standalone. Esto es diseñado (graceful degradation), no un bug. Los announcements de edge-card al broker tampoco llegan en este modo.

Pipeline restart pierde ULIDs

Cada relaunch genera un pipeline_id nuevo. Trackers externos que dependen del ULID se rompen. Workaround: usar el label del pipeline (estable entre restarts).

tokio::test + waitpid síncrono

Algunos tests del pipeline necesitan --test-threads=1 porque el waitpid síncrono dentro de un current_thread runtime bloquea el reactor antes de que las tareas spawneadas corran.