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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user