refactor(yahweh): Fase 2b — MetaBackend trait + NakuiBackend + MetaUi consume el backend

3 steps en un commit:

A) yahweh-meta-runtime/backend.rs: trait MetaBackend con 6 métodos
   (list_records, load_record, seed, update, delete, morphism) +
   WriteOutcome { id, changed, post_status }. 9 tests con MemBackend.

B) nakui-ui/backend.rs: NakuiBackend struct con store/log/executors/
   compaction. NakuiBackend::open() compone log+snapshot+replay+tick;
   impl MetaBackend mapea cada método al pipeline nakui-core.
   snapshot_path_for / maybe_compact_log se mueven acá. 7 tests del
   impl.

C) MetaUi consume el backend:
   - 6 fields colapsan en `backend: NakuiBackend`.
   - MetaUi::new pasa de ~150 líneas a ~10 (delega a NakuiBackend::open).
   - commit_seed / commit_morphism / commit_delete delegan al trait;
     CommitOutcome enum eliminado, reemplazado por WriteOutcome.
   - tick_runtime_compact eliminado (interno al backend; el msg sale
     por WriteOutcome.post_status).
   - validate_entity_refs callsite usa cierre sobre backend.load_record.
   - Imports nakui_core::delta y event_log salen de main.rs (sólo
     quedan en tests E2E).

Tests: 33→42 yahweh-meta-runtime (+9 trait), 14→21 nakui-ui (+7
backend impl). 97 totales en el área. Cada crate compila individualmente.

Pendiente Fase 2c: extraer widget render (form/list/modal/EntityRef)
al crate yahweh — ahora trivial porque el render solo consume
&self.modules + self.backend (via trait).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-05-10 01:48:49 +00:00
parent 6104484498
commit 2462aca444
5 changed files with 1187 additions and 561 deletions
+99
View File
@@ -6,6 +6,105 @@ ratio/diff ver `git show <sha>`.
## 2026-05-10
### refactor(yahweh): Fase 2b — `MetaBackend` trait + `NakuiBackend` + MetaUi consume el backend
Materialización del trait que diseñamos en charla. Tres pasos
combinados en un solo commit:
**Step A** — trait + WriteOutcome en `yahweh-meta-runtime`:
- Nuevo módulo `backend.rs` con:
- `pub trait MetaBackend: 'static` con 6 métodos:
`list_records`, `load_record`, `seed`, `update`, `delete`,
`morphism`. Convención de ids como `Uuid` canónico (los
backends que internamente usan otros tipos mapean), `set+clear`
pre-computados por el caller (no double-roundtrip al store),
threshold `'static` sin Send/Sync (suficiente para handlers
GPUI single-threaded).
- `pub struct WriteOutcome { id, changed, post_status }` con
constructor `no_change(id)`. La UI usa `changed = 0` para
"sin cambios", `post_status` para concatenar mensajes
auto-emitidos por el backend (compact, etc.).
- 9 tests con un `MemBackend` mínimo (HashMap por
`(entity, uuid)`): seed/load round-trip, list/filter/order,
update set/clear/no-op, delete/missing, object-safety check.
**Step B**`NakuiBackend` en `nakui-ui/src/backend.rs`:
- Estructura que ownea `Arc<Mutex<MemoryStore>>`,
`Option<Arc<Mutex<EventLog>>>`, `BTreeMap<id, Arc<Executor>>`,
`snap_path`, `snapshot_threshold`, `writes_since_compact`.
- `NakuiBackend::open(log_path, threshold, executors) -> (Self, OpenStatus)`:
abre log, carga snapshot, replay, auto-compact si threshold
cruzado; devuelve `OpenStatus { init_toast, load_error }` para
que el caller agregue al banner.
- `tick_compact()` privado que cada write public method invoca
tras éxito; devuelve `Option<String>` que se mete en
`WriteOutcome.post_status`.
- `impl MetaBackend for NakuiBackend`:
- `seed`: WAL order (log first, store after), `tick_compact`,
devuelve `WriteOutcome { id: Some(uuid), changed: 1, post_status }`.
- `update`: si `set+clear` vacíos devuelve `WriteOutcome::no_change`;
si no construye `FieldOp::Set`+`FieldOp::Clear`, log Morphism
`ui.edit_record` con `params.fields/cleared`, store.apply, tick.
- `delete`: `FieldOp::Delete`, log Morphism `ui.delete_record`,
store.apply, tick.
- `morphism`: locks log + store, `execute_and_log_with_recovery`,
tick. `WriteOutcome { id: None, changed: ops.len(), post_status }`.
- Funciones `snapshot_path_for` y `maybe_compact_log` movidas acá
desde main.rs (ahora son detalle del backend).
- 7 tests del impl: round-trip via trait, set+clear, no-op edit
no escribe, delete/load, list_records, morphism sin executor da
error claro, threshold dispara snapshot.
**Step C**`MetaUi` consume el backend:
- Reemplaza fields `store` / `event_log` / `executors` /
`snap_path` / `snapshot_threshold` / `writes_since_compact`
por un único `backend: NakuiBackend`.
- `MetaUi::new` colapsa el wiring de persistencia en
`NakuiBackend::open(...)` — pasó de ~150 líneas a ~10 líneas.
- `commit_seed` ya no construye `LogEntry`/`FieldOp` directos:
- SEED → `self.backend.seed(entity, obj)`.
- EDIT → `self.backend.load_record + compute_field_delta +
compute_clear_fields → self.backend.update(set, clear)`.
- Devuelve `WriteOutcome` (reemplaza el viejo enum `CommitOutcome`).
- `commit_morphism` parsea inputs/params del form y delega a
`self.backend.morphism(...)`.
- `commit_delete` es one-liner: `self.backend.delete(entity, id)`.
- `tick_runtime_compact` eliminado (ahora interno al backend; el
msg viaja en `WriteOutcome.post_status`).
- `list_rows` queda como proxy `self.backend.list_records(entity)`.
- `validate_entity_refs` callsite usa cierre sobre
`backend.load_record` (en vez de `&Store`).
- Nuevo helper `format_seed_toast(entity, was_editing, &outcome)`
reemplaza el match sobre `CommitOutcome`.
- Imports limpiados: no más `nakui_core::delta::FieldOp`/`FieldPath`,
no más `nakui_core::event_log::*` en main.rs (sólo en tests E2E).
No más `Arc/Mutex` (vive en backend).
Distribución de tests post-refactor:
- `yahweh-meta-runtime`: 33 → **42** (+9 trait tests con MemBackend).
- `nakui-ui`: 14 → **21** (+7 tests del NakuiBackend impl).
- `yahweh-meta-schema`: 8 (sin cambio).
- `brahman-cards`: 26 (sin cambio).
- Total: **97**.
Build: cada crate compila individualmente.
Nota sobre Fase 2b/c estado:
- ✅ Backend trait + impl + MetaUi usa backend.
- ⏭ Falta extraer los **widgets render** (form/list/modal/EntityRef
selector) de nakui-ui a un crate yahweh nuevo
(sugerencia: `yahweh-widget-meta-form`). Esa extracción ahora es
trivial: el render code ya consume sólo `&self.modules` +
`self.backend` (vía trait). Lo dejo para próximo commit.
**Pendientes**:
1. **Fase 2c**: extraer widget render al crate yahweh
(`yahweh-widget-meta-form` o similar) — `MetaApp<B: MetaBackend>`
genérico, `nakui-ui` queda como ~50 líneas de shell con
`MetaApp::<NakuiBackend>::new(...)`.
2. **KCL → Nickel**: kcl_wrapper reemplazado por evaluación de
Nickel contracts.
3. **`card.k` eliminado** (REFERENCE ONLY).
### refactor(yahweh): Fase 2 — extraer helpers puros a `yahweh-meta-runtime`
Sigue de la Fase 1 (lift del schema a yahweh). Ahora extraemos los
**helpers puros** que cualquier widget renderer o backend ejecutor