Files
sergio 550c98f275 refactor(monorepo): reorganización lógica + renames + SDDs + split CHANGELOG
Reorganización física de crates/:
- core/ (mezclaba 6 propósitos) se divide en protocol/, init/, runtime/, compat/
- shared/ (3 crates) se redistribuye en protocol/ e init/
- lapaloma (sub-módulo de ui_engine) se promueve a modules/pineal/

Renames de proyectos:
- shipote → shuma (runtime de sandboxes)
- nouser → akasha (explorador de Mónadas)
- yahweh → nahual (motor GPUI, antes ui_engine/)
- lapaloma → pineal (data-viz agnóstica)

Fraccionamiento UI → core agnóstico:
- vista-core (DeckState + snap, 175 LOC, 5 tests verdes)
- barra-core (Task + render_html + sanitize, 90 LOC, 5 tests verdes)
- vista-web y barra-web ahora son thin DOM bindings

Documentación nueva:
- 16 SDDs por subdirectorio (≤80 LOC c/u): protocol/init/runtime/compat
  + 10 módulos + apps/
- docs/STATUS.md con cifras reales por proyecto
- docs/ROADMAP.md con plan a finalización (6 hitos, ~6-8 semanas)
- CHANGELOG.md particionado en docs/changelog/<proyecto>.md (7 buckets)

Automatización:
- scripts/reorg.py — script idempotente que: git mv directorios, renombra
  package names, recomputa path = refs, reescribe imports rust, actualiza
  workspace Cargo.toml. Soporta --dry-run.
- scripts/split-changelog.py — particiona CHANGELOG por componente.

Validación:
- cargo check --workspace pasa (124 crates + 2 nuevos cores).
- 10 tests adicionales (5 en vista-core + 5 en barra-core) verdes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 14:48:34 +00:00

7.3 KiB

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:

  • Escucha $XDG_RUNTIME_DIR/shipote.sock (fallback /run/user/$UID/shipote.sock).
  • Restaura snapshot de $XDG_STATE_HOME/shipote/state.json (fallback $HOME/.local/state/shipote/state.json).
  • Relanza pipelines live (con restart_on_failure=true) automáticamente.
  • Reaper cada 500 ms (cosecha zombies + drena pending restarts + chequea quota breaches).
  • SIGTERM/SIGINT → snapshot + stop_with_grace(1s) de todos los workspaces + exit.

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:

Crate Tests
ente-incarnate 16 (clone+ns, stdio, pre_exec, caps detect, cgroup paths)
nouser-core 27 (pre-existentes — discerner integrado sin regresiones)
shipote-card 8 (roundtrip TOML/JSON, compile-to-card, intersect_soma)
shipote-core 26 (workspaces, pipeline fan-in/out, flow_channel replay, stats history, restart, quota enforce, snapshot dirty-skip, ...)
shipote-discern 5 (MagicBytes, JsonProbe, CardProbe, TomlProbe, Utf8Probe)
yahweh-provider-fs 3 (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.