eba629a806c7f861dd00a37c20b0f9e9d1ef3a52
313 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
354f992c63 |
feat(sidecar): WIT al sidecar — módulos conscientes vivos
Cierra el ciclo brahman-card-wit ↔ runtime: un módulo que tenga su .wit lo parsea, lo manda en Hello, y aparece como "consciente" en el broker y en brahman-status. Cambios coordinados (un solo commit por la cadena de tipos): - brahman-card::WitInterface deriva Serialize/Deserialize/Eq. - brahman-handshake::Hello lleva wit: Option<WitInterface> (#[serde(default)] para tolerar Hellos antiguos en formato JSON aunque postcard exige presencia explícita). - Server's register_session enruta a ResolvedCard::from_conscious cuando viene wit; from_agnostic cuando no. - Client::connect queda como wrapper de connect_with(path, card, wit: Option<WitInterface>) — backward-compatible. - Broker::register acepta Option<WitInterface> como tercer arg; BrokeredCard guarda el wit. 25 sitios de tests actualizados con `, None` (vía perl). - brahman-sidecar::SidecarConfig.wit + helpers SidecarConfig::with_wit y spawn_conscious(card, wit). Log attached reporta conscious=true|false. - brahman-status pretty-print con 🧠 + sección wit (package/world + imports + exports) por sesión consciente. - Example nuevo presence-conscious: parsea protocol.wit y se presenta consciente. Validación end-to-end manual: $ ente-zero & $ presence-conscious demo.conscious shared_wit/protocol.wit & $ brahman-status Sessions (1): 01K... demo.conscious 🧠 lifecycle=Daemon wit: brahman:protocol@0.1.0 / module imports: types, handshake, lifecycle exports: run Tests: 32/32 (broker 11 + card 8 + handshake codec+transport 2 + integ 7 + admin 0 + card-wit 4). Workspace: 0 errores. CHANGELOG.md actualizado. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
f4dc019004 |
feat(core): brahman-card-wit — extractor opcional de contratos WIT
Crate nuevo crates/core/brahman-card-wit que parsea texto WIT con
wit-parser y devuelve un Vec<WitInterface> (de brahman-card),
listo para acoplarse a una ResolvedCard::from_conscious(card, wit).
Ámbito intencional: sólo parsing texto, no toca wasm-tools ni
wit-component. Es opt-in: brahman-card no depende de éste.
API pública:
- parse_wit(source: &str) -> Result<Vec<WitInterface>, WitError>
- parse_wit_file(path: impl AsRef<Path>) -> Result<...>
Cada WitInterface incluye: package, world, imports, exports.
Las interfaces importadas/exportadas (no sólo funciones) se
resuelven por nombre via resolve.interfaces[id].name; las
funciones inline aparecen como WorldKey::Name directo.
Example CLI: brahman-wit-info <ruta.wit> imprime los worlds.
$ brahman-wit-info shared_wit/protocol.wit
2 world(s):
package: brahman:protocol@0.1.0
world: module
imports: types, handshake, lifecycle
exports: run
...
Tests: 4/4 (inline + archivo real + parse error + world vacío).
Workspace: 0 errores.
CHANGELOG.md actualizado con la entrada nueva y la del commit
anterior (
|
||
|
|
8a83a26de0 |
feat(handshake): notificación push de matches del broker al cliente
El servidor empuja MatchEvent (Available | Lost) a los consumers cuando
sus inputs cambian de match — sea porque un productor llegó, porque
otro mejor lo desplazó, o porque desapareció.
Mecánica:
- Frame::MatchEvent con MatchEventKind { Available, Lost } y los datos
del match (consumer_flow, producer_session/label/flow, ty, via, pinned).
- Server: SessionTxTable (Arc<Mutex<HashMap<SessionId, mpsc::Sender>>>)
+ LastMatches (último match conocido por consumer/input). En cada
register/unregister, broadcast_match_diffs recomputa con el broker
y emite SOLO los diffs respecto al estado anterior.
- Session::run_post_handshake usa tokio::select! para multiplexar
read_frame del cliente y rx.recv() de su tx push.
- Cleanup ahora también limpia push_table y last_matches y dispara un
broadcast (para notificar a quienes pierden el match).
- Client: VecDeque<MatchEvent> bufferea eventos que llegan mezclados
con respuestas a Ping. API:
- take_event() — non-blocking, drena buffer
- await_event(timeout) — bloquea hasta evento o timeout
- ping() ahora drena MatchEvents intermedios hasta encontrar el Pong.
Capacity del canal push por sesión: 32 frames (try_send no-blocking;
si se llena, los eventos extra se descartan — se documenta como
ephemeral, el cliente puede re-consultar via brahman-status).
Test nuevo en brahman-handshake/tests/handshake.rs:
- match_event_pushed_on_producer_arrival: consumer espera, no recibe
evento → llega productor → recibe Available → productor se va →
recibe Lost.
Example nuevo: brahman-handshake/examples/subscriber.rs — cliente que
loguea cada MatchEvent en tiempo real. Útil para ver la dinámica del
broker. Pings cada 25s para keepalive.
Demo end-to-end verificada (4 eventos, 3 ya cubren el ciclo completo):
T+0.3 alpha llega → Available ← demo.alpha.out
T+0.8 beta llega → (sin evento: alpha gana por orden alfabético)
T+1.3 alpha killed → Available ← demo.beta.out (re-evaluación)
T+1.8 beta killed → Lost ← <none>
El broker emite diff: ningún evento cuando un nuevo productor llega
sin desplazar al ganador actual.
Tests: 28/28 (handshake integ 6→7). cargo check --workspace: 0 errores.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
70a7a0d46d |
feat: segundo módulo (nakui) + admin API + brahman-status
Dos cosas en una sesión, en el orden discutido:
(1) Segundo módulo brahman vivo: nakui-core
- crates/modules/nakui/core/Cargo.toml: deps brahman-card,
brahman-sidecar, ulid.
- crates/modules/nakui/core/src/bin/nakui.rs: brahman_card_for_nakui()
construye una Card como Lifecycle::Daemon, Supervision::Restart,
flow.input "command" (json) + flow.output "report" (json). El
cmd_run llama brahman_sidecar::spawn antes de levantar el server
de nakui.
(2) crates/shared/brahman-sidecar (estrena crates/shared/)
Boilerplate del sidecar extraído (DRY): el thread con tokio current
thread runtime, conexión vía Client::connect, ping loop. Yahweh y
nakui ahora consumen este crate. API:
- spawn(card) fire-and-forget
- spawn_with_handle(config) con JoinHandle
Example "presence" útil para demos: módulo dummy con label tomado
del primer arg que se queda vivo hasta SIGTERM.
(3) crates/core/brahman-admin: observabilidad del broker
Socket Unix paralelo en \$BRAHMAN_ADMIN_SOCKET (default
\$XDG_RUNTIME_DIR/brahman-admin.sock). Cada conexión recibe un
StatusSnapshot JSON line-delimited y se cierra. Compatible con nc/socat.
- StatusSnapshot { server, protocol, init_attached, sessions, matches }
- server::AdminServer
- client::query(path)
- example "brahman-status" CLI
(4) Wiring de ente-zero
En primordial_loop, junto al handshake server, ahora también levanta
AdminServer con misma política de degradación grácil.
(5) brahman-broker: BrokeredCard ahora incluye lifecycle. Endpoint y
Match derivan Serialize/Deserialize. Nuevo método cards() expone
iterador de BrokeredCard para que el admin pueda construir snapshots.
(6) brahman-card: re-export pub use ulid::* para que módulos no
necesiten depender de ulid directamente.
(7) yahweh-shell migrado al sidecar compartido. Su brahman_client.rs
pasa de 96 a 53 líneas: sólo declara la Card, delega el spawn.
Demo end-to-end:
$ ente-zero &
$ presence demo.producer &
$ presence demo.consumer &
$ brahman-status
Init: server=0.1.0 protocol=0.1.0 attached=true
Sessions (2):
01KR42TY1J... demo.producer lifecycle=Daemon priority=Normal
01KR42TY1K... demo.consumer lifecycle=Daemon priority=Normal
Matches (2):
demo.producer.in ← demo.consumer.out via Exact
demo.consumer.in ← demo.producer.out via Exact
El broker matchea bidireccional por tipo. El admin lo expone.
Tests: 27/27. cargo check --workspace: 0 errores.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
595f68e252 |
feat(yahweh-shell): primer módulo brahman vivo
yahweh-shell se presenta al Init brahman como módulo Widget mediante un sidecar en thread aparte. La GUI GPUI levanta normalmente; el sidecar mantiene la sesión brahman en paralelo, desacoplado. Cambios: - crates/apps/yahweh-shell/Cargo.toml: deps brahman-card, brahman-handshake, ulid. - crates/apps/yahweh-shell/src/brahman_client.rs: thread con tokio current_thread runtime que arma una Card, llama Client::connect, y loop de pings cada 30s. Si el Init no está disponible, loggea y termina — yahweh sigue funcionando standalone. - crates/apps/yahweh-shell/src/main.rs: brahman_client::spawn() antes de Application::new(). El spawn no bloquea. Card declarada por yahweh: - label: "brahman.ui_engine" - lifecycle: Widget - payload: Virtual (yahweh no se inicia desde el Init, se presenta) - supervision: Delegate - permissions: filesystem read-write (persiste layout.json), IPC wit-v1 - flow.input: render-data (json) - flow.output: user-intent (json) Validación end-to-end: $ ente-zero & $ probe → session=...8G, init_attached=true $ yahweh → [brahman] attached: session=...Y7 Ambos clientes (probe + yahweh sidecar) se registran en el broker del Init en sesiones distintas. yahweh es el primer módulo "real" — no un tester — que vive como nodo del fractal mientras corre. Tests: 27/27 verdes. cargo check --workspace: 0 errores. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
df9d10cc52 |
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>
|
||
|
|
07d77a335f |
feat(handshake): integra el broker con el ciclo de sesiones
ServerConfig acepta un Option<Arc<Mutex<Broker>>> compartido. Cuando está
presente, el servidor lo mantiene en sincronía con las sesiones:
- Tras un Hello aceptado, register_session indexa la Card en el broker
ANTES de insertar en el SessionRegistry y de emitir HelloAck.
- Al cerrar la sesión (Farewell, EOF, o error en run_post_handshake), un
cleanup() unificado llama unregister en el broker y remove en el
SessionRegistry. Garantizado por refactor de Session::handle a
do_handshake → run_post_handshake → cleanup.
Tests nuevos en handshake.rs:
- broker_registers_and_unregisters_with_session: confirma el ciclo
register → farewell → unregister.
- broker_matches_two_live_modules: dos clientes (productor + consumidor)
conectados; el broker resuelve find_producer_for(consumer.session, "in")
→ producer "dht". Tras farewell del productor, el match desaparece.
Fix colateral: brahman-card::TypeRef pasa de internally-tagged
(#[serde(tag = "kind")]) a externally-tagged (default). Postcard no
soporta internally-tagged en formatos no self-describing — sin este
cambio el wire de Hello con Cards que tengan flujos no codificaba.
JSON cambia de {"kind":"primitive","name":"x"} a
{"primitive":{"name":"x"}}. Documentado en el doc-comment de TypeRef.
26/26 tests verdes (broker 11 + card 8 + handshake codec 1 + integ 6).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
5091106c21 |
feat(core): brahman-broker — matching híbrido productor↔consumidor
Crate nuevo en crates/core/brahman-broker que indexa Cards por SessionId
y empareja flow.input de un consumidor con flow.output del productor más
adecuado.
Tres ejes de matching:
1. Estrategia (MatchStrategy):
- Exact: igualdad estricta de TypeRef.
- Structural: misma forma — para Wit, mismo package + name (ignora
interface); para Primitive, mismo name.
- ExactThenStructural (default): prefiere Exact; cae en Structural si
no hay. Reporta cuál ganó en Match.via.
2. Override pin_to: si el consumidor declara pin_to = "label", el broker
prefiere productores con ese label (siempre que el tipo matchee).
Si la pista falla, cae en type-search general. Match.pinned indica
qué camino se siguió.
3. Prioridad: empate de tipo se resuelve por Card.priority (Critical >
High > Normal > Low). Empate de prioridad se resuelve lexicográfica-
mente por label (estable y determinista).
API mínima:
- Broker::new(config)
- register(session, &Card) / unregister(session)
- find_producer_for(consumer_session, input_name) -> Option<Match>
- all_matches() -> Vec<Match> (introspección)
El broker es stateless w.r.t. routes: cada query se computa bajo demanda.
Sólo persiste el índice de BrokeredCard (vista mínima: label, priority,
inputs, outputs).
Cambio aditivo en brahman-card: Priority deriva PartialOrd/Ord/Hash para
ser usable como tiebreaker.
Tests: 11/11.
- exact_match_same_typeref
- structural_ignores_interface
- exact_strategy_rejects_interface_mismatch
- exact_then_structural_prefers_exact
- pin_to_overrides_type_search
- pin_to_unresolvable_falls_back_to_type_match
- priority_breaks_ties
- label_alpha_breaks_priority_ties
- unregister_removes_producer
- no_self_loops
- all_matches_lists_pairs
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
814390feec |
feat(core): brahman-handshake — protocolo runtime Init↔módulo
Crate nuevo en crates/core/brahman-handshake que implementa el handshake real del shared_wit/protocol.wit como wire format Rust↔Rust sobre Unix socket con frames length-prefixed + cuerpo postcard. Componentes: - src/messages.rs: Hello, HelloAck, Ping, Pong, Farewell, HandshakeError y Frame (enum-suma). HandshakeError ya implementa thiserror::Error y cruza el wire. - src/codec.rs: write_frame / read_frame asíncronos con MAX_FRAME_BYTES de 4 MiB. Test interno de roundtrip. - src/server.rs: Server::bind crea el listener en Unix socket; emite ResolvedCard tras validar la Card y devuelve ULID como SessionId. ServerConfig.init_attached se reporta en HelloAck. - src/client.rs: Client::connect hace pre-validación local de la Card (fail fast), envía Hello, parsea HelloAck. ping() y farewell() expuestos. - tests/handshake.rs: 4 tests de integración: * full_handshake_roundtrip — happy path con 3 pings + farewell * rejects_invalid_card_client_side — label vacío rechazado pre-envío * server_rejects_protocol_mismatch — protocol_version 999.0.0 → Error * ping_before_hello_rejected — Ping sin Hello previo → Rejected Limitación conocida: postcard no serializa serde_json::Value (variantes Array/Object con length dinámico). Se removieron por eso los campos `extensions` (Card) y `extra` (Permissions). Forward-compat queda cubierta por schema_version + protocol_version negotiation; si más adelante necesitamos preservar campos JSON desconocidos, irá en un WireCard separado o un envelope. 13/13 tests verdes (brahman-card 8 + brahman-handshake codec 1 + integ 4). cargo check --workspace: 0 errores. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ed0e973c81 |
refactor(arje): migra ente-card a re-export de brahman-card
ente-card pasa a ser un crate-shim que re-exporta los tipos de brahman-card bajo sus nombres legacy: - EntityCard ≡ brahman_card::Card (alias) - Capability, Payload, SomaSpec, Supervision, etc. — pub use directo Cambios concretos: - crates/core/brahman-card/src/lib.rs: añade impl Default for Card. Permite usar `..Default::default()` en struct-literals para los campos aditivos (permissions, lifecycle, priority, flow, extensions). - crates/core/ente-card/src/lib.rs: reescrito como shim de re-export (~25 líneas). Las definiciones, validaciones y tests viven en brahman-card. - crates/core/ente-card/Cargo.toml: deps reducidas a brahman-card; se eliminan serde/serde_json/ulid (vienen transitivos vía re-export). - crates/core/ente-zero/src/seed.rs: 4 struct-literals de EntityCard ahora terminan con `..Default::default()` para cubrir los nuevos campos del schema híbrido. Los 21 consumidores de ente-card (ente-zero, ente-bus, ente-brain, ente-soma, ente-cas, los 12 *-compat, etc.) compilan sin cambios — sus `use ente_card::EntityCard` y demás imports siguen resolviendo, ahora a tipos de brahman-card. cargo test -p brahman-card: 8/8. cargo build -p ente-zero: OK. cargo check --workspace: 0 errores. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
0feba74503 |
feat(core): brahman-card — Tarjeta de Presentación canónica híbrida
Crate nuevo en crates/core/brahman-card que unifica el modelo de arje y el de brahman/core_protocol original: De arje (ente-card): - Identidad ULID + lineage opcional - Capability tipado (Spawn, Journal, Endpoint, Device, Netlink, ...) - Payload discriminado (Wasm | Native | Virtual | Legacy) - SomaSpec (namespaces, cgroups, rlimits, cpu_affinity) - Supervision (Restart con backoff, OneShot, Delegate) - genesis: Vec<Card> recursivo - Validación exhaustiva (label, self-dep, payload, rlimits, cgroup) Aditivo brahman: - flow: Flows con TypeRef discriminado (Primitive | Wit) - pin_to opcional como pista para el broker - Permissions enumerados (NetworkingPolicy, FsPolicy, IpcPolicy) - Lifecycle ortogonal (Daemon | Oneshot | Widget) - Priority de scheduling - TrustLevel derivado de Permissions (no declarado) - ResolvedCard con WitInterface opcional - extensions: HashMap para forward-compat Formatos: JSON canónico + TOML, auto-detectados por extensión de archivo. Tests: 8/8 incluyendo arje_seed_format_compatible que valida que el formato JSON existente de arje sigue parseando con defaults para los campos nuevos. ente-card original sigue intacto; los consumidores (ente-zero, etc.) migrarán en una pasada posterior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
4d50bfc587 |
chore: absorbe nakui (ERP matemático) en modules/nakui
- crates/modules/nakui/core/: el crate nakui-core (4 bins, tests).
Deps directas (serde, rhai, surrealdb, petgraph, sha2, uuid, tokio,
thiserror v1) — no convertidas a workspace = true en esta pasada.
- crates/modules/nakui/modules/{inventory,sales,treasury}/: datos
declarativos del dominio (nsmc.json, schema.k, morphisms/) que el
crate consume — no son crates.
cargo check -p nakui-core: 0 errores.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
53dbdf0f1d |
chore: monorepo inicial con arje + minga + yahweh absorbidos
Workspace en 4 ejes (core/modules/apps/shared):
- core/: 24 crates de arje (Init systemd-compatible: ente-card, ente-zero,
ente-kernel, ente-bus, ente-cas, ente-soma, ente-wasm, ente-snapshot,
ente-brain, ente-echo, ente-policy-provider, + 12 crates *-compat)
- modules/semantic_dht/: 5 crates de minga (minga-core con AST/CAS/MST,
minga-p2p con libp2p Kad, minga-store, minga-vfs, minga-cli)
- modules/ui_engine/: 11 crates de yahweh (libs/{core,theme,bus,providers},
widgets/{tree,splitter,tabs,tiled,container_core,text_input})
- apps/: 5 crates de yahweh (file_explorer, database_explorer, text_viewer,
image_viewer, yahweh-shell)
- shared_wit/protocol.wit: handshake/lifecycle inicial
Cargo.toml unificado: thiserror bumped a 2 (transparente para arje), tokio
"full", paths intra-workspace de yahweh redirigidos a su nueva ubicación.
cargo check --workspace: 0 errores, 17 warnings (dead code preexistente).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|