8ede06f8c4fb668a877e5864d655bf877cf00550
14 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4c9e4c3962 |
feat(card): Card::new(label) — alternativa segura a Default::default()
Cierra la trap documentada de Card::default() que devuelve id =
Ulid::nil(). Usar Card::default() viva colisionaba con cualquier otra
Card default-construida bajo el mismo id 00000...
La fix no es romper Default (sigue siendo determinista, requerido por
callers que lo usan como template para deserializacion y patterns de
busqueda) sino agregar un constructor explicito Card::new(label) que
asigna id = Ulid::new() + label provisto, manteniendo defaults seguros
en todo lo demas.
Pensado para struct-literals con override parcial:
let card = Card {
kind: CardKind::Data,
payload: Payload::Embedded(json),
..Card::new("mi-modulo.algo")
};
Refactor de call sites en codigo de produccion:
- brahman_sidecar::discovery::build_consumer_card
- nouser daemon::build_engine_card
Default queda con docstring expandida que apunta a Card::new para uso
"vivo". to_brahman_card en nouser-card NO se modifica porque asigna
el id estable de la Monada, no uno fresco.
Tests: 3 unitarios nuevos en brahman-card. 15 tests verdes (era 12).
|
||
|
|
b3feaf667c |
feat: Crossreferencia — Card.references como grafo del fractal
Las Cards ahora declaran sus relaciones con otras Cards. El Engine
posee Mónadas; las Mónadas declaran que son poseídas por el Engine.
- brahman-card:
- RelationshipKind { Owns, OwnedBy, Processes, ProcessedBy, Sibling }
- CardReference { kind, target_id: Ulid, target_label: String }.
target_label es cache para que la UI renderee sin resolver.
- Card.references: Vec<CardReference> + espejo en WireCard.
Conversiones From propagan.
- brahman-broker::BrokeredCard propaga references.
- brahman-status imprime "ref OwnedBy → label (id)" por sesión.
- nouser daemon: cada Mónada publicada añade OwnedBy apuntando al
engine. Declaración unilateral — el engine no necesita conocer
Mónada IDs de antemano.
Validación end-to-end:
$ ente-zero & nouser daemon crates/core
$ brahman-status
Sessions (6):
[ente] brahman.nouser_engine
[data] brahman-handshake/src
ref OwnedBy → brahman.nouser_engine (01K...)
[data] ente-brain/src
ref OwnedBy → brahman.nouser_engine (01K...)
...
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
5edc912ed8 |
feat: Phase D-3 + D-4 — service_socket en Card, providers coexisten
Cierra el ciclo del swap automático Nous mock↔real:
- brahman-card: Card.service_socket: Option<PathBuf> y espejo en
WireCard. Path del data plane (distinto al Init). Cualquier
consumer que matchee con esta Card conecta directo, sin discovery
extra.
- brahman-broker: BrokeredCard propaga service_socket. Sin
participación en matching — sólo metadata.
- brahman-handshake::MatchEvent: nuevo campo
producer_service_socket. Server lo busca en BrokeredCard al emitir
Available.
- nouser-nous::transport: provider_socket_path(provider: &str)
devuelve nouser-nous-{provider}.sock por default. Mock y real
coexisten en sockets distintos (Phase D-4). default_socket_path()
conserva el comportamiento single-provider.
- Mock declara nouser-nous-mock.sock; real declara
nouser-nous-real.sock. La Card se construye DESPUÉS del bind.
- brahman-status imprime "socket:" por sesión cuando está presente.
Validación end-to-end:
$ ente-zero & nouser-nous-mock & nouser-nous-real &
$ ls /run/user/1001/nouser-nous-*.sock
nouser-nous-mock.sock
nouser-nous-real.sock
$ brahman-status
Sessions (2):
[ente] nouser.nous_real
socket: /run/user/1001/nouser-nous-real.sock
[ente] nouser.nous_mock
socket: /run/user/1001/nouser-nous-mock.sock
Pendiente (no crítico): nouser-core attract --remote usa todavía
NOUSER_NOUS_SOCKET hardcoded. Siguiente paso: subscribirse al
MatchEvent del broker y usar producer_service_socket directo, así
BRAHMAN_BROKER_CONTEXT=test/prod swapea provider sin tocar al
consumer.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
b3c3c00cf2 |
feat(nouser): Phase D — proveedor Nous mock + cliente remoto
Cierra el patrón "Nous como módulo aparte intercambiable": el contrato
del proveedor de embeddings vive en su crate, el mock determinístico
implementa ese contrato sirviéndolo por Unix socket, y nouser-core
sabe consumirlo remotamente. El switch mock↔real (futuro) será vía
priority_contexts en el broker.
Crates nuevos:
- crates/modules/nouser/nous: contrato compartido.
- EmbedRequest { kind: { EmbedFile | EmbedText | Ping }, payload }.
- EmbedFilePayload (path, ext, size, mtime), EmbedTextPayload.
- EmbedResponse (embedding, model, elapsed_ms), PingResponse,
ErrorResponse.
- Wire: line-delimited JSON sobre Unix socket, single-shot.
- Constants FLOW_EMBED_REQUEST, FLOW_EMBED_RESULT, FLOW_TYPE_NAME.
- transport::default_socket_path con env NOUSER_NOUS_SOCKET.
- crates/modules/nouser/nous-mock: bin nouser-nous-mock.
- Sidecarea a brahman-init con Card kind=Ente declarando los flows
embed-request/embed-result + priority_contexts.test = +1.
- Bind del socket Nous + accept loop tokio.
- EmbedFile delega a nouser_core::embed::embed (Phase C).
- Modelo: "mock-pseudo-32d".
Cambios:
- nouser-core: dep nueva nouser-nous. Subcomando attract --remote
abre un UnixStream blocking, envía EmbedRequest, lee response.
Imprime "embed: local|remote" para ver cuál ruta corrió.
Bug encontrado y corregido:
- ContextBias tenía #[serde(skip_serializing_if = ...)] en sus campos.
Postcard NO soporta skip-condicional en formatos no self-describing:
el serializer omitía bytes que el deserializer esperaba, rompiendo
la wire de cualquier Card con priority_contexts poblada.
Síntoma: "postcard decode: Hit the end of buffer" en el server,
"early eof" en el cliente.
- Fix: removidos los skip_serializing_if de ContextBias. JSON pretty
ahora emite {"pin_to": null, "priority_offset": 0} pero el wire
funciona. Trade-off aceptado.
- Test wirecard_postcard_with_priority_contexts en brahman-card que
ejercita el roundtrip postcard con biases poblados.
Validación end-to-end:
$ ente-zero & nouser-nous-mock & nouser daemon crates/core
$ brahman-status
Sessions (7):
[ente] nouser.nous_mock flows: embed-request, embed-result
[ente] brahman.nouser_engine
[data] src summary: 6 archivos en crates/core/brahman-handshake/src
[data] graph summary: 7 archivos en crates/core/ente-zero/src/graph
...
$ nouser attract --remote crates/core <archivo>.rs
embed: remote
🧲 0.9058 src ...
(mock log: embed_file path=...)
Tests: 75. cargo check --workspace: 0 errores, 0 warnings.
Próximo natural: Phase D-2 — real-nous con ONNX/Llama text-embedding.
Declara la misma Card con priority_contexts.prod = +1 y el swap es
transparente para el consumer.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
b85700c538 |
feat: Phase B-1 — unificación ontológica de Cards (Ente ↔ Data)
La Card pasa a ser EL protocolo de presentación del ecosistema. 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.
brahman-card:
- CardKind { Ente (default), Data }. Backward-compat: Cards existentes
quedan Ente.
- DataFacet { summary, keywords, centroid, member_count, dispersion,
presentation_hint } — vista liviana para el wire. Listas grandes
(members reales, embeddings completos) se consultan al daemon dueño
bajo demanda.
- Card.kind y Card.data agregados. WireCard espeja, conversiones From
propagan ambos campos.
- Default impl actualizado.
brahman-broker:
- BrokeredCard propaga kind y data desde la Card registrada. No afecta
el matching (sigue por TypeRef + priority + pin_to); permite a
observadores discriminar sin re-query.
nouser-card:
- Depende ahora de brahman-card.
- MonadManifest::to_brahman_card() proyecta una Mónada a Card brahman:
- id, label, lineage directos.
- payload Virtual, supervision Delegate, lifecycle Daemon
(placeholder — la Mónada no se ejecuta).
- kind = Data.
- data = Some(DataFacet { summary, keywords, centroide,
member_count, entropy → dispersion, presentation_hint del Lens }).
- Test nuevo projects_to_brahman_card.
brahman-status:
- Prefijo [ente] o [data] por sesión.
- Sesiones data renderean también summary, members + dispersion,
keywords y lens hint.
Resultado: la UI ve una sola lista uniforme — no necesita saber si
mira procesos o cúmulos de datos, sólo lee el Card y se adapta por
kind. La función de presentarse es la misma para todos.
Tests: 59 (card 11, broker 15, handshake codec+tr 2 + integ 7,
card-wit 4, admin 0, nouser-card 7 +1, nouser-core 13).
cargo check --workspace: 0 errores, 0 warnings.
Próximo: Phase B-2 — bin nouser daemon que sidecarea cada Mónada como
sesión brahman, mezclándolas con los entes en brahman-status.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
bbb9a9d2f5 |
feat(broker): priority contexts — biases per-contexto operativo
Cierra el último pendiente de feature: el broker ahora puede operar
bajo un contexto (test/prod/foreground/secure/etc) que activa biases
declarados en las Cards.
Schema (brahman-card):
- ContextBias { pin_to: Option<String>, priority_offset: i8 }.
- Card.priority_contexts: BTreeMap<String, ContextBias>, también en
WireCard. Las conversiones From propagan el campo.
Comportamiento (brahman-broker):
- BrokerConfig.current_context: Option<String>. Cuando es Some(ctx) y
una Card tiene priority_contexts.get(ctx), el bias aplica:
- Consumer-side: bias.pin_to sobreescribe Flow.pin_to estático.
- Producer-side: bias.priority_offset se suma a la priority base
(clamp en [Low=0, Critical=3]).
- BrokeredCard propaga priority_contexts. find_producer_for usa
effective_priority y context_bias en lugar de comparar Priority
directo.
Observabilidad:
- AdminConfig.current_context + StatusSnapshot.current_context.
- brahman-status imprime "Context: <nombre>" si está activo.
Wiring:
- ente-zero lee BRAHMAN_BROKER_CONTEXT del entorno y la propaga al
broker y al admin. Sin var, biases inactivos (back-compat total).
Tests nuevos (brahman-broker, +4):
- context_priority_offset_lifts_producer_above_alphabetic_winner:
sin contexto a-prod gana por alfabético; con context "test" b-prod
gana por offset +1.
- context_pin_to_overrides_static_pin: static pin "real-dht", test
override "mock-dht" → mock gana en context "test".
- unknown_context_no_op: biases declarados para "test" no aplican
cuando broker está en "prod".
- priority_offset_clamps_to_critical: offset enorme se clampa a 3.
Validación end-to-end manual:
$ BRAHMAN_BROKER_CONTEXT=test ente-zero &
$ brahman-status
Init: server=0.1.0 protocol=0.1.0 attached=true
Context: test
Tests acumulados: 39 (card 11, broker 15, handshake codec+transport 2 +
integ 7, card-wit 4, admin 0). cargo check --workspace: 0 errores, 0
warnings.
Con esto cierran TODOS los pendientes técnicos abiertos. El único
"pendiente" que queda es el caso real para extender (priority
contexts per-deployment, scheduling biases dinámicos, etc.).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
f19ca723b6 |
feat(card): WireCard + extensions — forward-compat sin romper postcard
Restaura el campo extensions de Card que había caído al adoptar postcard (serde_json::Value usa secuencias/maps de longitud dinámica). La solución es separar dos formas: - Card (la rica): para JSON/TOML. Tiene extensions: BTreeMap<String, serde_json::Value> con #[serde(flatten, skip_serializing_if = is_empty)]. Los campos desconocidos del archivo sobreviven el roundtrip. - WireCard (la slim): para postcard. Mismo schema sin extensions y con genesis: Vec<WireCard> recursivo. Postcard-friendly por construcción. Conversiones From<Card> for WireCard (descarta extensions) y From<WireCard> for Card (extensiones quedan vacías post-wire). El contrato es explícito: extensions son anotaciones locales que sobreviven file I/O pero NO cruzan al Init. brahman-handshake::Hello.card cambia de Card a WireCard. Client hace card.into() al enviar; Server hace hello.card.into() para volver a Card antes de validar/registrar. Tests: - 3 nuevos en brahman-card: extensions_preserved_in_json_roundtrip, wire_card_roundtrip_strips_extensions, wire_card_postcard_friendly (verifica que postcard::to_allocvec(&wire) NO falla — caso que rompía con Card.extensions populadas). - 1 ajuste en handshake/tests/handshake.rs (struct-literal de Hello ahora con card: sample_card(...).into()). - brahman-card: postcard como dev-dep. Tests acumulados: 35 (card 11, broker 11, handshake codec+transport 2 + integ 7, card-wit 4, admin 0). 0 errores, 0 warnings (vienen del commit anterior |
||
|
|
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> |
||
|
|
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>
|
||
|
|
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> |