feat(ente-zero): enchufa el handshake server al Init real

ente-zero (PID 1 del fractal arje) ahora levanta el server de
brahman-handshake junto al ente-bus existente, escuchando en
\$BRAHMAN_INIT_SOCKET (default \$XDG_RUNTIME_DIR/brahman-init.sock).
Es un canal paralelo dedicado a módulos brahman-conscientes que se
presentan con una Card y declaran flujos tipados.

Cambios:

- crates/core/brahman-handshake/src/transport.rs: helper nuevo con
  resolución XDG_RUNTIME_DIR → TMPDIR, override por var de entorno
  BRAHMAN_INIT_SOCKET. Test unitario para el override.
- crates/core/brahman-handshake/Cargo.toml: example "probe" + dev-dep
  anyhow. Probe sirve como herramienta de diagnóstico para conectar
  contra cualquier server vivo.
- crates/core/brahman-handshake/examples/probe.rs: cliente mínimo que
  hace Hello → Ping → Farewell e imprime el HelloAck recibido.
- crates/core/ente-zero/Cargo.toml: dependencias brahman-handshake
  + brahman-broker.
- crates/core/ente-zero/src/main.rs: en primordial_loop, tras spawn
  del ente-bus, crea Arc<Mutex<Broker>> compartido y llama
  Server::bind. Si el bind falla (FS no escribible, socket en uso),
  loggea y degrada a "modo bus-only" — la doctrina PID 1 no rompe por
  subsistemas opcionales (mismo patrón que uevents).

Validación end-to-end manual:
  $ BRAHMAN_INIT_SOCKET=/tmp/e2e.sock ./target/debug/ente-zero &
  $ BRAHMAN_INIT_SOCKET=/tmp/e2e.sock cargo run --example probe
    HelloAck: session=01KR41Q8... server=0.1.0 protocol=0.1.0 init_attached=true
    Pong: ts=1778252489714ms
    Farewell OK

Tests: 27/27 (broker 11 + card 8 + handshake codec+transport 2 + integ 6).
cargo check --workspace: 0 errores.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-05-08 15:02:29 +00:00
parent 07d77a335f
commit df9d10cc52
7 changed files with 147 additions and 0 deletions
@@ -0,0 +1,52 @@
//! Convenciones de transporte: dónde vive el socket del Init.
//!
//! Resolución del path canónico:
//! 1. Variable de entorno [`SOCKET_ENV`] si está definida (override
//! explícito, prioridad máxima).
//! 2. `$XDG_RUNTIME_DIR/brahman-init.sock` (sesión usuario).
//! 3. `$TMPDIR/brahman-init.sock` (fallback portable).
use std::path::PathBuf;
/// Variable de entorno que sobreescribe la ruta del socket del Init.
pub const SOCKET_ENV: &str = "BRAHMAN_INIT_SOCKET";
/// Nombre del socket dentro del runtime dir.
pub const SOCKET_NAME: &str = "brahman-init.sock";
/// Ruta canónica al socket del Init brahman.
pub fn default_socket_path() -> PathBuf {
if let Ok(p) = std::env::var(SOCKET_ENV) {
return PathBuf::from(p);
}
let base = std::env::var_os("XDG_RUNTIME_DIR")
.map(PathBuf::from)
.unwrap_or_else(std::env::temp_dir);
base.join(SOCKET_NAME)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn env_override_wins() {
// Nota: estos tests modifican entorno del proceso. `cargo test`
// los corre paralelos por defecto pero usamos un nombre de var
// único y restablecemos al final.
let key = "BRAHMAN_INIT_SOCKET_TEST_OVERRIDE";
// SAFETY: sólo escribimos una variable local al test; sin
// contaminar SOCKET_ENV.
std::env::set_var(key, "/tmp/explicit.sock");
let saved = std::env::var(SOCKET_ENV).ok();
std::env::set_var(SOCKET_ENV, "/tmp/explicit.sock");
let p = default_socket_path();
assert_eq!(p, PathBuf::from("/tmp/explicit.sock"));
// Restaurar
match saved {
Some(v) => std::env::set_var(SOCKET_ENV, v),
None => std::env::remove_var(SOCKET_ENV),
}
std::env::remove_var(key);
}
}