# Changelog Registro cronológico de cambios sustantivos en el monorepo Brahman. Cada entrada lista las acciones concretas tras un commit; para detalles de ratio/diff ver `git show `. ## 2026-05-08 ### feat: Phase B-1 — unificación ontológica de Cards (Ente ↔ Data) La Card es **el** protocolo de presentación del ecosistema, no sólo de los procesos. Una Mónada Nouser y un Ente Brahman son ambos "entidades que se presentan"; el consumidor (UI, broker, admin) discrimina por `kind` cuando importa, pero todos hablan el mismo idioma. Cambios: - `brahman-card`: - `CardKind { Ente (default), Data }`. Conserva back-compat: Cards existentes son `Ente` por default. - `DataFacet { summary, keywords, centroid, member_count, dispersion, presentation_hint }`. Liviano para el wire — listas grandes (members, embeddings completos) se consultan al daemon dueño bajo demanda. - `Card.kind` y `Card.data: Option` agregados. WireCard espeja, conversiones `From` propagan. - Default impl actualizado. - `brahman-broker::BrokeredCard`: propaga `kind` y `data` desde la Card registrada. No afecta el matching (sigue siendo por TypeRef + priority + pin_to); permite a observadores discriminar sin re-query. - `nouser-card`: depende ahora de `brahman-card`. Nuevo método `MonadManifest::to_brahman_card()` que proyecta: - id, label, lineage → directos. - payload Virtual, supervision Delegate, lifecycle Daemon (placeholder semántico — la Mónada no se ejecuta). - kind = Data. - data = Some(DataFacet) con summary, keywords, centroide, member_count, entropy → dispersion, y un `presentation_hint` derivado del `Lens` (`Code` → `"code"`, `Gallery` → `"gallery"`, etc.). - Test nuevo: `projects_to_brahman_card`. - `brahman-status`: cada sesión muestra ahora `[ente]` o `[data]` como prefijo. Para sesiones `data`, render adicional con summary, members + dispersion, keywords y lens hint. Resultado: la UI (yahweh, brahman-status, futuro explorer) ve una sola lista uniforme. No tiene que saber si está mirando un proceso o un cúmulo de datos — sólo lee el Card y se adapta por `kind`. Tests acumulados: 59 (card 11, broker 15, handshake codec+transport 2 + integ 7, card-wit 4, admin 0, nouser-card 7, nouser-core 13). cargo check --workspace: 0 errores, 0 warnings. Próximo: **Phase B-2** — bin `nouser daemon ` que sidecarea cada Mónada como una sesión brahman, publicándola al broker. Brahman-status las verá junto a los entes. ### feat(nouser): Phase A — mecanismo determinista de Mónadas Primer trozo del módulo Nouser (Kairos): explorador de Mónadas como "imanes semánticos" sobre el filesystem. Phase A cubre el 90% de los casos sin tocar IA — sólo metadatos y heurísticas. Crates nuevos: - `crates/modules/nouser/card`: `MonadManifest` (la Tarjeta de Presentación de una Mónada — espejo conceptual de `brahman::Card` pero para datos, no para procesos runtime). Campos: id (Ulid), label, summary, centroid (vacío en Phase A), keywords, cardinality, entropy [0,1], dominant_lens, pins, members, timestamps, extensions (forward-compat). 6 tests de validación + JSON roundtrip. - `crates/modules/nouser/core`: pipeline determinista. - `scanner`: walkdir → `Vec` con metadatos (path, size, mtime, extension). Skipea hidden por default. Configurable max depth y follow_links. - `cluster::by_directory`: agrupa por parent dir, mínimo 3 archivos para promover a Mónada (configurable). Calcula keywords (top-N extensiones por frecuencia + alfabético), elige `Lens` dominante (Code/Gallery/Markdown/Database/Grid) según extensión más frecuente, computa entropía de Shannon normalizada [0,1]. - `db`: `MonadDb` en memoria con índices BTreeMap files/monads y `resolve_members(monad_id)` que filtra IDs huérfanos. Phase B traerá persistencia. - bin `nouser`: subcomandos `scan `, `show `, `json `. Env var `NOUSER_MIN_FILES` para tunear el threshold. - 13 tests (4 scanner + 6 cluster + 3 db). Demo end-to-end: $ nouser scan crates scan: 255 archivos en crates, 19 mónadas (min_files=3) [01KR4C13] src card=12 ent=0.00 lens=Code keywords: rs [01KR4C13] tests card=14 ent=0.00 lens=Code keywords: rs [01KR4C13] fixtures card=5 ent=0.00 lens=Grid keywords: rhai ... $ nouser show crates 01KR4C Monad 01KR4C1370DVF6NMTW6SECNXAF label: src summary: 4 archivos en crates/modules/nouser/core/src (ext: rs) cardinality: 4 entropy: 0.0000 lens: Code members (4): 4132 bytes crates/modules/nouser/core/src/db.rs ... Pendientes para próximas fases (anotados, no urgentes): - **Phase B**: bin `nouser daemon` que sidecarea a brahman-init declarando flows (`scan-request:json` → `monad-update:json`). - **Phase C**: pseudo-embeddings deterministas (hash de path/ext/size a 32-d) + atracción por centroide via cosine similarity. Implementa el "imán" sin LLM. - **Phase D**: módulo `nouser-nous` aparte para el LLM real (Llama/ONNX). En `priority_contexts.test` el Init pinea a `mock-nous` (embeddings determinísticos); en `prod` a `real-nous`. - **Polish**: labels de Mónada incluir 2-3 componentes del path para desambiguar `src/` repetidos en monorepo. Workspace: 0 errores, 0 warnings. Tests acumulados: 58 (card 11, broker 15, handshake codec+transport 2 + integ 7, card-wit 4, admin 0, nouser-card 6, nouser-core 13). ### feat(broker): priority contexts — biases per-contexto operativo - `brahman-card::ContextBias { pin_to: Option, priority_offset: i8 }` declara un override per-contexto. - `Card.priority_contexts: BTreeMap` y mismo en `WireCard` (cruza el wire). Las conversiones `From` lo propagan. - `BrokerConfig.current_context: Option`. Cuando el broker corre bajo un contexto y una Card declara biases para ese nombre, se aplican: - Como **consumidor**: `pin_to` sobreescribe el `Flow.pin_to` estático. - Como **productor**: `priority_offset` se suma a la priority base (clamp en `[Low=0, Critical=3]`) para el ranking. - `BrokeredCard` propaga `priority_contexts`. `find_producer_for` usa `effective_priority(card)` y `effective_pin(card, input)` antes de los tiebreaks. - `brahman-admin::AdminConfig.current_context` + `StatusSnapshot.current_context` espejan el contexto activo. `brahman-status` lo imprime como `Context: ` justo debajo de `Init: ...`. - `ente-zero` lee `BRAHMAN_BROKER_CONTEXT` env var y la propaga al broker y al admin. Sin var, biases per-contexto inactivos. - 4 tests nuevos en brahman-broker: `context_priority_offset_lifts_producer_above_alphabetic_winner`, `context_pin_to_overrides_static_pin`, `unknown_context_no_op`, `priority_offset_clamps_to_critical`. - Validación end-to-end: `BRAHMAN_BROKER_CONTEXT=test ente-zero` → `brahman-status` muestra `Context: test`. ### feat(card): WireCard + extensions — forward-compat sin romper postcard - `Card.extensions: BTreeMap` restaurado con `#[serde(flatten, default, skip_serializing_if = is_empty)]`. Los campos JSON/TOML desconocidos sobreviven el roundtrip de archivos. - Nuevo `WireCard`: proyección postcard-friendly (sin `extensions`, `genesis: Vec` recursivo). Conversiones `From` y `From` con descarte/recreación de extensions. - `brahman-handshake::Hello.card` pasa de `Card` a `WireCard`. Client hace `card.into()` antes de enviar; Server hace `hello.card.into()` para volver a Card antes de validar/registrar. - 3 tests nuevos en brahman-card: `extensions_preserved_in_json_roundtrip`, `wire_card_roundtrip_strips_extensions`, `wire_card_postcard_friendly` (postcard encode/decode efectivo). - brahman-card gana `postcard` como dev-dep para el último test. - Contrato documentado: extensions = anotaciones locales que NO cruzan al Init; sólo viven en archivos. ### `9420eae` chore: limpia warnings dead-code en arje (commit del usuario) - `ente-zero/src/events.rs`: `#![allow(dead_code)]` a nivel módulo — es vocabulario de eventos con variantes/campos reservados para flujos no cableados aún (CapabilityRequested, ShutdownReason::Signal, CapabilityGrant::{Granted, Denied, QuotaExceeded}, ExitStatus fields). - `ente-zero/src/graph/mod.rs`: comentado el re-export ahora innecesario de `SHUTDOWN_GRACE`. `DEFAULT_GRANT_TTL` con `#[allow(dead_code)]` + nota "reservado para capability granting". - `ente-zero/src/graph/capabilities.rs`: `renew_grant` con `#[allow(dead_code)]` (capability renewal pendiente). - `ente-kernel/src/surface.rs`: drop de `use anyhow::Context` (no se usaba). - `ente-hostnamed-compat/src/main.rs`: drop de `Connection` (no se usaba). - `ente-polkit-compat/src/main.rs`: `PolicyDecision.source` con `#[allow(dead_code)]` (sólo aparece en `Debug` para logging). - `cargo check --workspace`: 17 warnings → 0. ### feat(sidecar): WIT al sidecar — módulos conscientes vivos - `brahman-card::WitInterface` deriva `Serialize`, `Deserialize`, `PartialEq`, `Eq` para cruzar el wire postcard. - `brahman-handshake::Hello` lleva `wit: Option`. Server usa `ResolvedCard::from_conscious` cuando viene presente, `from_agnostic` cuando no. - `brahman-handshake::Client::connect` queda como wrapper agnóstico de `connect_with(path, card, wit: Option)`. - `brahman-broker::Broker::register` ahora toma `Option` como tercer arg. `BrokeredCard` guarda el wit. 25 sitios de tests actualizados con `, None`. - `brahman-sidecar::SidecarConfig` con campo `wit`. Helpers nuevos: `SidecarConfig::new(card).with_wit(wit)` y `spawn_conscious(card, wit)`. El log `attached` reporta `conscious=true|false`. - `brahman-status` muestra marker 🧠 + sección `wit:` (package/world, imports, exports) por sesión consciente. - Example nuevo `crates/shared/brahman-sidecar/examples/presence-conscious.rs`: toma label + path .wit (default `shared_wit/protocol.wit`), parsea con brahman-card-wit, spawna sidecar consciente. - Validado end-to-end: ``` $ 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 ``` ### feat(core): brahman-card-wit — extractor opcional de contratos WIT - Crate nuevo `crates/core/brahman-card-wit` con `wit-parser = "0.230"`. - API: `parse_wit(source)` y `parse_wit_file(path)` devuelven `Vec` (uno por `world` declarado). - Interfaces importadas/exportadas (no sólo funciones) se resuelven por nombre via `resolve.interfaces[id].name`. - Example `crates/core/brahman-card-wit/examples/brahman-wit-info.rs` CLI: `brahman-wit-info shared_wit/protocol.wit` → lista paquete, worlds, imports y exports. - 4 tests: inline, archivo real (`shared_wit/protocol.wit`), parse error, world vacío. - Validado contra `protocol.wit`: detecta worlds `module` y `admin-host` con sus imports/exports correctos. ### `7b589b8` chore: agrega CHANGELOG.md retroactivo - `CHANGELOG.md` en la raíz con los 11 commits previos documentados acción por acción. A partir de este punto, cada cambio sustantivo actualiza también este archivo en el mismo commit. ### `8a83a26` feat(handshake): notificación push de matches - Frame `MatchEvent { kind: Available | Lost, ... }` añadido al protocolo. - `Session::run_post_handshake` usa `tokio::select!` para multiplexar reads del cliente y un canal `mpsc` push del server. - Server: `SessionTxTable` (Arc>>>) y `LastMatches` para diff por sesión. `broadcast_match_diffs` corre tras cada `register` y `unregister`, emite sólo los cambios. - Capacity del canal push: 32 (ephemeral, `try_send` non-blocking). - Client: `VecDeque` interno, `take_event()` (non-blocking) y `await_event(timeout)`. `ping()` ahora drena MatchEvents intermedios hasta encontrar el Pong. - Example `crates/core/brahman-handshake/examples/subscriber.rs`. - Test `match_event_pushed_on_producer_arrival` (handshake integ 6→7). ### `70a7a0d` feat: segundo módulo (nakui) + admin API + brahman-status - Crate nuevo `crates/shared/brahman-sidecar` (DRY del thread + tokio + ping loop). API: `spawn(card)` / `spawn_with_handle(config)`. - `nakui` cmd_run llama `brahman_sidecar::spawn` antes de `run_server`. Card: lifecycle Daemon, supervision Restart, flow `command` (json) / `report` (json). - Crate nuevo `crates/core/brahman-admin` con `StatusSnapshot` JSON line-delim, `AdminServer` y `client::query`. - ente-zero levanta también el AdminServer en `primordial_loop`. - Example `crates/shared/brahman-sidecar/examples/presence.rs` (módulo dummy long-lived parametrizable por label). - Example `crates/core/brahman-admin/examples/brahman-status.rs` (CLI que pretty-printa el snapshot). - `brahman-broker`: `BrokeredCard` ahora incluye `lifecycle`. `Endpoint` y `Match` derivan `Serialize`/`Deserialize`. Nuevo `Broker::cards()` iterador. - `brahman-card`: `pub use ::ulid` para que módulos no dependan de ulid. - yahweh-shell migrado al sidecar compartido (96→53 LOC). ### `595f68e` feat(yahweh-shell): primer módulo brahman vivo - yahweh-shell spawnea sidecar antes de `Application::new()`. - Card declarada: label `brahman.ui_engine`, lifecycle Widget, supervision Delegate, payload Virtual, flow input `render-data` (json) / output `user-intent` (json). - Sidecar en thread aparte con tokio current_thread runtime, desacoplado del runtime GPUI. ### `df9d10c` feat(ente-zero): enchufa el handshake server al Init real - ente-zero levanta `brahman_handshake::server::Server::bind` en `primordial_loop` después del ente-bus, con degradación grácil si bind falla (mismo patrón que uevents). - Nuevo módulo `brahman-handshake/src/transport.rs`: helper `default_socket_path()` con resolución `BRAHMAN_INIT_SOCKET` → `XDG_RUNTIME_DIR` → `TMPDIR`. - Example `crates/core/brahman-handshake/examples/probe.rs`. - Validación end-to-end manual: probe contra ente-zero vivo imprime `HelloAck: session=... init_attached=true`. ### `07d77a3` feat(handshake): integra el broker con el ciclo de sesiones - `ServerConfig` acepta `Option>>`. - `register_session` indexa la Card en el broker y la `SessionRegistry` antes de emitir HelloAck. - `Session::handle` refactor a `do_handshake → run_post_handshake → cleanup` con cleanup unificado (broker + sessions). - Tests integ nuevos: `broker_registers_and_unregisters_with_session` y `broker_matches_two_live_modules`. - Fix colateral: `brahman-card::TypeRef` pasa de internally-tagged (`#[serde(tag = "kind")]`) a externally-tagged. Postcard no soporta internally-tagged en formatos no self-describing. JSON cambia de `{"kind":"primitive","name":"x"}` a `{"primitive":{"name":"x"}}`. ### `5091106` feat(core): brahman-broker — matching híbrido - Crate nuevo `crates/core/brahman-broker`. - 3 estrategias de matching: `Exact`, `Structural`, `ExactThenStructural` (default). Devuelven `Match::via` con la estrategia que ganó. - Override `pin_to`: el consumer pide un productor por label; si la pista no resuelve, cae en type-search. - Tiebreak por `Card.priority` desc, luego `label` asc (estable y determinista). - API: `register`, `unregister`, `find_producer_for`, `all_matches`, `cards`, `sessions`, `len`, `is_empty`. - 11 tests (matching, pin_to, priority, no-self-loops, all-matches). ### `814390f` feat(core): brahman-handshake — protocolo runtime - Crate nuevo `crates/core/brahman-handshake` con server y client Rust↔Rust sobre Unix socket. - Frames length-prefixed (4 bytes LE) + cuerpo postcard. - Mensajes: `Hello`, `HelloAck`, `Ping`, `Pong`, `Farewell`, `Error`. - `MAX_FRAME_BYTES = 4 MiB` para evitar reservas absurdas. - Tradeoff: drop `extensions`/`extra` de Card por incompat postcard ↔ `serde_json::Value`. Forward-compat queda en `schema_version` + `protocol_version` negotiation. - 4 tests integ + 1 unit en codec. ### `ed0e973` refactor(arje): migra ente-card a re-export de brahman-card - `ente-card/src/lib.rs` reescrito como crate-shim de re-export (327 LOC → 25 LOC). - `EntityCard` ≡ `brahman_card::Card` por type alias. - `ente-card/Cargo.toml`: deps reducidas a `brahman-card`. - `Card` impl `Default` (Ulid::nil(), label vacío) para que `..Default::default()` funcione en struct-literals. - 4 sitios en `ente-zero/src/seed.rs` actualizados con `..Default::default()` para los campos aditivos. - Los 21 consumidores arje compilan sin tocar fuente. ### `0feba74` feat(core): brahman-card — Tarjeta canónica híbrida - Crate nuevo `crates/core/brahman-card`. - Hereda de arje: `id: Ulid`, `lineage`, `Capability` tipado, `Payload::{Wasm, Native, Virtual, Legacy}`, `SomaSpec` (namespaces, cgroups, rlimits, cpu_affinity), `Supervision` (Restart con backoff, OneShot, Delegate), `genesis` recursivo. - Aditivo brahman: `Permissions` enumerados (`NetworkingPolicy`, `FsPolicy`, `IpcPolicy`), `Lifecycle` ortogonal a Supervision, `Priority` de scheduling, `Flows` con `TypeRef` discriminado (Primitive | Wit), `pin_to` opcional. - `TrustLevel` derivado de `Permissions` (no declarado). - `ResolvedCard { card, wit: Option, trust }`. - Soporta JSON (canónico) + TOML (auto-detectado por extensión). - 8 tests incluido `arje_seed_format_compatible` que valida que el JSON de arje sigue parseando con defaults para los aditivos. ### `4d50bfc` chore: absorbe nakui (ERP matemático) en modules/nakui - `~/nakui` → `crates/modules/nakui/{core,modules}`. - `core/`: el crate `nakui-core` con 4 bins (nakui, demo, inventory_demo, sales_demo) y tests. - `modules/{inventory,sales,treasury}/`: data declarativa (`nsmc.json`, `schema.k`, `morphisms/`) que el crate consume. No son crates Cargo. - Deps directas (no `workspace = true`): thiserror v1, surrealdb, rhai, petgraph. No conflicto con el resto del workspace. ### `53dbdf0` chore: monorepo inicial con arje + minga + yahweh absorbidos - 45 crates absorbidos en 4 ejes: - `crates/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 `*-compat`). - `crates/modules/semantic_dht/`: 5 crates de minga (`minga-core` con AST/CAS/MST, `minga-p2p` con libp2p Kad, `minga-store`, `minga-vfs`, `minga-cli`). - `crates/modules/ui_engine/`: 11 crates de yahweh (libs/{core, theme, bus, providers}, widgets/{tree, splitter, tabs, tiled, container_core, text_input}). - `crates/apps/`: 5 crates de yahweh (file_explorer, database_explorer, text_viewer, image_viewer, yahweh-shell). - `shared_wit/protocol.wit` con handshake/lifecycle inicial. - `Cargo.toml` unificado: thiserror bumped a 2 (transparente para arje), tokio "full", paths intra-workspace de yahweh redirigidos. - `cargo check --workspace`: 0 errores (sólo dead-code warnings preexistentes en ente-zero).