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>
This commit is contained in:
sergio
2026-05-19 14:48:34 +00:00
parent 86fb6ae20b
commit 550c98f275
375 changed files with 8512 additions and 7155 deletions
@@ -0,0 +1,168 @@
//! Readers V1: tres formatos JSON ya existentes en el monorepo.
//!
//! Cada reader implementa:
//! - `can_read`: heurística estructural para decidir si el JSON es
//! suyo. No requiere flag explícito en el input — los inputs legacy
//! no los tienen.
//! - `read`: deserializa el JSON al tipo del crate origen (sin tocarlo)
//! y lo envuelve en [`Card`] derivando los campos del wrapper.
//!
//! Convenciones para derivar el wrapper:
//! - `id`: del campo `id` del input (cada formato lo expone). Si es
//! ULID se serializa a string canónico.
//! - `label`: del campo `label`.
//! - `lineage`: del campo `lineage` cuando existe (Ente/Monad).
//! - `extensions`: campos JSON desconocidos respecto a la struct del
//! crate origen. Hoy lo mantenemos vacío (los crates origen ya
//! tienen sus propios `extensions` internos via `#[serde(flatten)]`)
//! — no duplicamos. Si en el futuro queremos mover el "extras" del
//! crate origen al wrapper, esta es la palanca.
use serde_json::Value;
use crate::{Card, CardBody, CardLoadError, CardReader, EnteCard, MonadManifest, UiModuleSpec, CARD_SCHEMA_VERSION};
// ============================================================================
// Ente (brahman-card)
// ============================================================================
/// Reader para el shape JSON de [`brahman_card::Card`].
///
/// Heurística de detección: el input tiene `payload` Y `supervision`
/// — son los campos requeridos del schema Ente que ningún otro
/// formato del monorepo tiene.
pub struct EnteJsonReader;
impl CardReader for EnteJsonReader {
fn name(&self) -> &'static str {
"ente-json"
}
fn can_read(&self, input: &Value) -> bool {
let obj = match input.as_object() {
Some(o) => o,
None => return false,
};
obj.contains_key("payload") && obj.contains_key("supervision")
}
fn read(&self, input: Value) -> Result<Card, CardLoadError> {
let id = pull_string(&input, "id").unwrap_or_default();
let label = pull_string(&input, "label").unwrap_or_default();
let lineage = pull_string(&input, "lineage");
let ente: EnteCard =
serde_json::from_value(input).map_err(|e| CardLoadError::ReaderFailed {
reader: "ente-json",
message: e.to_string(),
})?;
Ok(Card {
id,
schema_version: CARD_SCHEMA_VERSION,
lineage,
label,
extensions: Default::default(),
body: CardBody::Ente(ente),
})
}
}
// ============================================================================
// Monad (akasha-card)
// ============================================================================
/// Reader para el shape JSON de [`akasha_card::MonadManifest`].
///
/// Heurística: tiene `members` (BTreeSet<FileId>) Y `cardinality`
/// (u32). La combinación es exclusiva del MonadManifest.
pub struct MonadJsonReader;
impl CardReader for MonadJsonReader {
fn name(&self) -> &'static str {
"monad-json"
}
fn can_read(&self, input: &Value) -> bool {
let obj = match input.as_object() {
Some(o) => o,
None => return false,
};
obj.contains_key("members") && obj.contains_key("cardinality")
}
fn read(&self, input: Value) -> Result<Card, CardLoadError> {
let id = pull_string(&input, "id").unwrap_or_default();
let label = pull_string(&input, "label").unwrap_or_default();
let lineage = pull_string(&input, "lineage");
let monad: MonadManifest =
serde_json::from_value(input).map_err(|e| CardLoadError::ReaderFailed {
reader: "monad-json",
message: e.to_string(),
})?;
Ok(Card {
id,
schema_version: CARD_SCHEMA_VERSION,
lineage,
label,
extensions: Default::default(),
body: CardBody::Monad(monad),
})
}
}
// ============================================================================
// UiModule (nahual-meta-schema)
// ============================================================================
/// Reader para el shape JSON de los `module.json` de la metainterfaz
/// ([`nahual_meta_schema::Module`]).
///
/// Heurística: tiene `entities` Y `views` Y `menu`. Es el shape más
/// específico del repo, así que va primero en el orden default — si
/// matchea, ningún otro reader debería intentar.
pub struct UiModuleJsonReader;
impl CardReader for UiModuleJsonReader {
fn name(&self) -> &'static str {
"ui-module-json"
}
fn can_read(&self, input: &Value) -> bool {
let obj = match input.as_object() {
Some(o) => o,
None => return false,
};
obj.contains_key("entities") && obj.contains_key("views") && obj.contains_key("menu")
}
fn read(&self, input: Value) -> Result<Card, CardLoadError> {
let id = pull_string(&input, "id").unwrap_or_default();
let label = pull_string(&input, "label").unwrap_or_default();
// UiModule no tiene lineage en su schema, queda None.
let module: UiModuleSpec =
serde_json::from_value(input).map_err(|e| CardLoadError::ReaderFailed {
reader: "ui-module-json",
message: e.to_string(),
})?;
Ok(Card {
id,
schema_version: CARD_SCHEMA_VERSION,
lineage: None,
label,
extensions: Default::default(),
body: CardBody::UiModule(module),
})
}
}
// ============================================================================
// Helpers
// ============================================================================
fn pull_string(v: &Value, key: &str) -> Option<String> {
v.get(key)?.as_str().map(|s| s.to_string())
}