feat(yahweh-meta-runtime): promover short_hash y preview_value desde nakui-explorer

Continúa la integración de apps nakui al stack yahweh. Los
helpers visuales que nakui-explorer tenía locales y son reusables
suben a yahweh-meta-runtime/format.

yahweh-meta-runtime:
- short_hash(h: &[u8; 32]) -> String: hex de los primeros 4 bytes.
- preview_value(v: &Value, max: usize) -> String: JSON one-liner
  truncado con "..." (edge case max < 3 sin panic).
- 5 tests nuevos.

nakui-explorer:
- Nueva dep yahweh-meta-runtime.
- Borrado helpers locales (short_uuid + short_hash + preview_value)
  + 4 tests duplicados.
- Imports desde yahweh-meta-runtime.

Tests: 42→47 yahweh-meta-runtime, 7→3 nakui-explorer (los 3 que
quedan son específicos del explorer: load_log, breakdown,
missing_file). Resto intacto.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-05-10 09:38:50 +00:00
parent df089f0585
commit d5ef7144b5
5 changed files with 121 additions and 60 deletions
+40
View File
@@ -6,6 +6,46 @@ ratio/diff ver `git show <sha>`.
## 2026-05-10 ## 2026-05-10
### feat(yahweh-meta-runtime): promover `short_hash` y `preview_value` desde nakui-explorer
Continúa la integración de las apps nakui al stack yahweh. Los
helpers visuales que `nakui-explorer` tenía locales y son reusables
suben a `yahweh-meta-runtime/format` para que cualquier app pueda
consumirlos sin duplicar.
Cambios en `yahweh-meta-runtime`:
- **`pub fn short_hash(h: &[u8; 32]) -> String`**: hex de los
primeros 4 bytes (8 chars). Útil para mostrar bundle/schema
hashes en UI sin quemar pantalla.
- **`pub fn preview_value(v: &Value, max: usize) -> String`**:
JSON one-liner truncado con `...` al final si excede `max`
chars. Edge case: `max < 3` devuelve los primeros `max` chars
sin sufijo.
- Re-exports en lib.
- 5 tests nuevos: 4 tests + 1 sanity para el caso `max < ellipsis`.
Migración de `nakui-explorer`:
- Nueva dep `yahweh-meta-runtime` en Cargo.toml.
- Borrado helpers locales `short_uuid`, `short_hash`,
`preview_value` (~30 líneas).
- `use yahweh_meta_runtime::{preview_value, short_hash, short_uuid}`.
- Borrados 4 tests duplicados (los runtime los testea).
Tests:
- `yahweh-meta-runtime`: 42 → **47** (+5 helpers nuevos).
- `nakui-explorer`: 7 → **3** (4 duplicados; quedan los 3
específicos: load_log, breakdown, missing_file).
- Resto del workspace intacto.
Beneficio operativo: 3 helpers visuales centralizados. Cualquier
app nueva que muestre UUIDs/hashes/JSON-previews los importa sin
re-implementar la heurística de truncamiento.
Pendiente arquitectural: el render del card timeline en
`nakui-explorer` (border-l-4 colored + flex_col + texto en niveles)
es un pattern reusable que también aparece en `yahweh-widget-meta-form`
(render_list filas). Cuando aparezca un tercer consumer de ese
pattern se extrae a un widget yahweh.
### feat(brahman-cards): templates Nickel canónicos para cada body kind ### feat(brahman-cards): templates Nickel canónicos para cada body kind
Materializa el patrón "import + override" del brazo: hasta ahora Materializa el patrón "import + override" del brazo: hasta ahora
`BRAHMAN_CARDS_TEMPLATES_DIR` existía como mecanismo pero el repo `BRAHMAN_CARDS_TEMPLATES_DIR` existía como mecanismo pero el repo
+1
View File
@@ -7,6 +7,7 @@ description = "Explorador GPUI del event log de Nakui: timeline de seeds + morph
[dependencies] [dependencies]
nakui-core = { path = "../../modules/nakui/core" } nakui-core = { path = "../../modules/nakui/core" }
yahweh-meta-runtime = { path = "../../modules/ui_engine/libs/meta-runtime" }
gpui = { workspace = true } gpui = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
uuid = { workspace = true, features = ["serde"] } uuid = { workspace = true, features = ["serde"] }
+7 -59
View File
@@ -30,6 +30,7 @@ use gpui::{
SharedString, Window, WindowBounds, WindowOptions, SharedString, Window, WindowBounds, WindowOptions,
}; };
use nakui_core::event_log::{EventLog, LogEntry}; use nakui_core::event_log::{EventLog, LogEntry};
use yahweh_meta_runtime::{preview_value, short_hash, short_uuid};
const REFRESH_INTERVAL: Duration = Duration::from_secs(2); const REFRESH_INTERVAL: Duration = Duration::from_secs(2);
@@ -378,35 +379,8 @@ impl Render for Explorer {
} }
} }
fn short_uuid(id: &uuid::Uuid) -> String { // Helpers `short_uuid`, `short_hash`, `preview_value` viven en
let s = id.to_string(); // `yahweh_meta_runtime::format`. Se usan acá via el `use` de arriba.
if s.len() > 8 {
s[..8].to_string()
} else {
s
}
}
fn short_hash(h: &[u8; 32]) -> String {
let mut s = String::with_capacity(8);
for b in h.iter().take(4) {
use std::fmt::Write;
let _ = write!(s, "{:02x}", b);
}
s
}
/// Renderiza un `serde_json::Value` en una sola línea limitada a `max`
/// caracteres (para preview en la timeline, no para edición).
fn preview_value(v: &serde_json::Value, max: usize) -> String {
let s = v.to_string();
if s.chars().count() <= max {
s
} else {
let truncated: String = s.chars().take(max - 3).collect();
format!("{truncated}...")
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@@ -472,34 +446,8 @@ mod tests {
assert!(result.is_empty()); assert!(result.is_empty());
} }
#[test] // Tests de `short_uuid` / `short_hash` / `preview_value` viven
fn preview_value_truncates_long_strings() { // en `yahweh-meta-runtime::format` tras la migración. Si esos se
let v = serde_json::json!({"a": "x".repeat(200)}); // vuelven a romper, los tests específicos del crate runtime los
let p = preview_value(&v, 30); // capturan; acá no duplicamos.
assert!(p.len() <= 30);
assert!(p.ends_with("..."));
}
#[test]
fn preview_value_keeps_short_strings_intact() {
let v = serde_json::json!({"a": 1});
let p = preview_value(&v, 30);
assert_eq!(p, "{\"a\":1}");
}
#[test]
fn short_uuid_takes_first_8_chars() {
let id = uuid::Uuid::parse_str("a1b2c3d4-e5f6-7890-abcd-ef1234567890").unwrap();
assert_eq!(short_uuid(&id), "a1b2c3d4");
}
#[test]
fn short_hash_takes_first_4_bytes_hex() {
let mut h = [0u8; 32];
h[0] = 0xaa;
h[1] = 0xbb;
h[2] = 0xcc;
h[3] = 0xdd;
assert_eq!(short_hash(&h), "aabbccdd");
}
} }
@@ -52,6 +52,36 @@ pub fn short_uuid(id: &Uuid) -> String {
id.to_string().chars().take(8).collect() id.to_string().chars().take(8).collect()
} }
/// Hex string de los primeros 4 bytes de un hash SHA-256 (8
/// caracteres). Útil para mostrar bundle/schema hashes en UI sin
/// quemar pantalla con los 64 chars completos.
pub fn short_hash(h: &[u8; 32]) -> String {
use std::fmt::Write;
let mut s = String::with_capacity(8);
for b in h.iter().take(4) {
let _ = write!(s, "{:02x}", b);
}
s
}
/// Renderea un `serde_json::Value` en una sola línea, truncado a
/// `max` caracteres con `...` al final si excede. Para preview en
/// timelines/cards/listas — NO para edición.
///
/// `max` es un upper-bound aproximado: el resultado nunca excede
/// `max` chars, pero puede ser más corto si el value es chico.
pub fn preview_value(v: &Value, max: usize) -> String {
let s = v.to_string();
if s.chars().count() <= max {
s
} else if max < 3 {
s.chars().take(max).collect()
} else {
let truncated: String = s.chars().take(max - 3).collect();
format!("{truncated}...")
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -105,6 +135,45 @@ mod tests {
assert_eq!(value_to_input_text(&json!(42)), "42"); assert_eq!(value_to_input_text(&json!(42)), "42");
} }
#[test]
fn short_hash_takes_first_4_bytes_hex() {
let mut h = [0u8; 32];
h[0] = 0xaa;
h[1] = 0xbb;
h[2] = 0xcc;
h[3] = 0xdd;
assert_eq!(short_hash(&h), "aabbccdd");
}
#[test]
fn short_hash_zeros() {
let h = [0u8; 32];
assert_eq!(short_hash(&h), "00000000");
}
#[test]
fn preview_value_keeps_short_strings_intact() {
let v = json!({"a": 1});
assert_eq!(preview_value(&v, 30), "{\"a\":1}");
}
#[test]
fn preview_value_truncates_long_strings_with_ellipsis() {
let v = json!({"a": "x".repeat(200)});
let p = preview_value(&v, 30);
assert!(p.chars().count() <= 30);
assert!(p.ends_with("..."));
}
#[test]
fn preview_value_handles_max_smaller_than_ellipsis() {
// Edge case: max < 3 (no espacio para "..."). Devuelve
// los primeros `max` chars sin sufijo, sin panic.
let v = json!("xxxxxxxxxxxxxxxx");
let p = preview_value(&v, 2);
assert!(p.chars().count() <= 2);
}
#[test] #[test]
fn short_uuid_returns_first_8_chars() { fn short_uuid_returns_first_8_chars() {
let id = Uuid::parse_str("01ARZ3ND-EKTS-V4RR-FFQ6-9G5FAV000000").ok(); let id = Uuid::parse_str("01ARZ3ND-EKTS-V4RR-FFQ6-9G5FAV000000").ok();
@@ -30,6 +30,9 @@ pub mod refs;
pub use backend::{MetaBackend, WriteOutcome}; pub use backend::{MetaBackend, WriteOutcome};
pub use delta::{compute_clear_fields, compute_field_delta}; pub use delta::{compute_clear_fields, compute_field_delta};
pub use format::{human_label_for_record, render_value, short_uuid, value_to_input_text}; pub use format::{
human_label_for_record, preview_value, render_value, short_hash, short_uuid,
value_to_input_text,
};
pub use parse::{infer_param_value, parse_field_value, resolve_param_value}; pub use parse::{infer_param_value, parse_field_value, resolve_param_value};
pub use refs::validate_entity_refs; pub use refs::validate_entity_refs;