refactor(yahweh): Fase 2c — widget render extraído a yahweh-widget-meta-form

Cierra el refactor de UI. El widget render (forms, lists, modal de
delete, EntityRef selector, sidebar, key handlers) deja de vivir en
nakui-ui y pasa a un crate yahweh nuevo, genérico sobre MetaBackend.

crates/modules/ui_engine/widgets/meta-form/ (yahweh-widget-meta-form):
- pub MetaApp<B: MetaBackend> con todo el state UI + impl Render
  + handlers + render_*. El bound `B: MetaBackend` se propaga.
- pub fn new(modules, backend, initial_toast, initial_error, cx):
  constructor sin bootstrap. Caller pre-construye todo.
- Helpers locales del widget: lookup_field, append_compact_msg,
  format_seed_toast.
- Cero deps a nakui o brahman-cards. Reusable por cualquier app.
- 3 tests funcionales puros (lookup_field, append_compact_msg,
  format_seed_toast).

nakui-ui (shell):
- main.rs: 1959 → 424 líneas (78% reducción). Sólo bootstrap:
  load_ui_modules + load executors + NakuiBackend::open +
  cx.open_window con MetaApp::<NakuiBackend>::new como root view.
- Dep nueva yahweh-widget-meta-form.
- Tests E2E quedan: event_log_replay, morphism_pipeline real
  sales, load_ui_modules x3 (4 shell). NakuiBackend tests siguen
  en backend.rs (8). Widget tests en su crate.

Distribución total tests refactor yahweh:
- yahweh-meta-schema: 8
- yahweh-meta-runtime: 42
- yahweh-widget-meta-form: 3
- brahman-cards: 26
- nakui-ui: 12 (4 shell + 8 backend)
Total: 91 tests cubriendo el área.

Cada crate compila individualmente. Fase 3 (shell mínimo) era
implícita en F2c — el shell ya quedó en 424 líneas.

Pendientes restantes: KCL → Nickel, eliminar card.k.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-05-10 02:00:34 +00:00
parent 2462aca444
commit b3a99f38dc
7 changed files with 1463 additions and 1680 deletions
+83
View File
@@ -6,6 +6,89 @@ ratio/diff ver `git show <sha>`.
## 2026-05-10
### refactor(yahweh): Fase 2c — extracción del widget al crate `yahweh-widget-meta-form`
Cierra el refactor de UI: el widget render (forms, lists, modal de
delete, EntityRef selector, sidebar, key handlers) deja de vivir en
el binario nakui-ui y pasa a un crate yahweh nuevo, genérico sobre
`MetaBackend`. nakui-ui queda como un shell de bootstrap de 424
líneas.
Crate nuevo: `crates/modules/ui_engine/widgets/meta-form/`
(`yahweh-widget-meta-form`):
- **Deps**: gpui, yahweh-meta-schema, yahweh-meta-runtime, yahweh-theme,
yahweh-widget-text-input, serde_json, uuid. **Cero deps a nakui** o
brahman-cards — reusable por cualquier app.
- **`MetaApp<B: MetaBackend>`** público: estructura genérica con
`modules`, `backend: B`, `active`, `form_inputs`, `editing`,
`pending_delete`, `toast`, `load_error`. El bound `B: MetaBackend`
se propaga a todos los `impl MetaApp<B>` y al `impl Render for
MetaApp<B>`.
- **`MetaApp::new(modules, backend, initial_toast, initial_error, cx)`**:
constructor sin lógica de bootstrap. El caller pre-construye
modules + backend + cualquier mensaje inicial. La active view
default es la primera entry del menú del primer módulo.
- **Methods preservados** del original (rename simbólico): select_view,
open_edit, commit_seed, commit_morphism, commit_delete, apply_action,
list_rows, render_*, tick interno via WriteOutcome.post_status.
- **Helpers locales del widget**: `lookup_field` (path walker JSON
por la lista renderer), `append_compact_msg` (concatenador del
toast), `format_seed_toast` (decide "creado/actualizado/sin cambios"
según `WriteOutcome`).
- **3 tests funcionales puros**: `lookup_field`, `append_compact_msg`,
`format_seed_toast`. Tests con GPUI cx no son posibles sin un
TestAppContext setup; quedan implícitos vía type-check del trait
bound.
Cambios en `nakui-ui` (shell):
- **main.rs**: 1959 → **424** líneas (78% reducción). Ahora sólo:
1. Carga modules via `brahman_cards::load_cards_from_dir` +
`load_ui_modules` (filtra UiModule body, valida, dedup).
2. Carga executors para módulos con `nakui_module_dir`.
3. `NakuiBackend::open(...)` para inicializar el backend.
4. `cx.open_window(...)` con `MetaApp::<NakuiBackend>::new(...)`
como root view.
- **`use yahweh_widget_meta_form::MetaApp`** + dep nueva en
Cargo.toml. Los imports de yahweh-meta-runtime/schema desaparecen
de main (los consume el widget internamente).
- **Tests del shell**: 4 tests E2E que tocan nakui-core directamente
(event_log_replay, morphism_pipeline_real_sales_vender,
load_ui_modules x3). Los tests del NakuiBackend impl quedan en
`backend.rs` (8 tests). Los tests del widget viven en su propio
crate.
- **`backend.rs`**: sin cambios (NakuiBackend ya estaba aislado en
Fase 2b).
Distribución final del refactor yahweh:
- `yahweh-meta-schema`: 8 tests (data puro).
- `yahweh-meta-runtime`: 42 tests (helpers + trait MetaBackend).
- `yahweh-widget-meta-form`: 3 tests (widget genérico).
- `brahman-cards`: 26 tests (loader unificado).
- `nakui-ui`: 12 tests (4 shell + 8 backend impl).
- **Total: 91 tests** cubriendo el área.
Cada crate compila individualmente. El widget consume el trait sin
saber qué backend hay debajo; `nakui-ui` provee el trait wireado a
nakui-core; cualquier futuro shell (mock para tests, otro stack de
storage) puede reusar el widget sin cambio.
Lo que NO hace Fase 2c:
- No mueve `format_seed_toast`/`append_compact_msg`/`lookup_field`
a `yahweh-meta-runtime`. Son lo bastante widget-flavored
(`SharedString` de gpui, decisiones de UX del toast, etc.) que
preferí dejarlos al lado del render.
- No introduce un `MetaApp::with_status` builder pattern. La
signature de `new` con 5 args es manejable; si crece, se refactor
después.
- No expone configuración del widget (theme override, layout
custom, etc.). Cuando emerja una segunda app que use el widget
con preferencias distintas, se agregan opts.
**Pendientes**:
1. **KCL → Nickel**: kcl_wrapper en nakui-core reemplazado por
evaluación de Nickel contracts. Migrar los 3 schemas .k de
sales/inventory/treasury a .ncl.
2. **`card.k` eliminado** (REFERENCE ONLY documentado en su header).
### 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:
Generated
+14
View File
@@ -6402,6 +6402,7 @@ dependencies = [
"yahweh-meta-runtime",
"yahweh-meta-schema",
"yahweh-theme",
"yahweh-widget-meta-form",
"yahweh-widget-text-input",
]
@@ -12926,6 +12927,19 @@ dependencies = [
"yahweh-core",
]
[[package]]
name = "yahweh-widget-meta-form"
version = "0.1.0"
dependencies = [
"gpui",
"serde_json",
"uuid",
"yahweh-meta-runtime",
"yahweh-meta-schema",
"yahweh-theme",
"yahweh-widget-text-input",
]
[[package]]
name = "yahweh-widget-splitter"
version = "0.1.0"
+1
View File
@@ -62,6 +62,7 @@ members = [
"crates/modules/ui_engine/widgets/tabs",
"crates/modules/ui_engine/widgets/tiled",
"crates/modules/ui_engine/widgets/text_input",
"crates/modules/ui_engine/widgets/meta-form",
# ============================================================
# modules/nakui/ — ERP matemático (nakui absorbido)
+1
View File
@@ -11,6 +11,7 @@ yahweh-meta-schema = { path = "../../modules/ui_engine/libs/meta-schema" }
yahweh-meta-runtime = { path = "../../modules/ui_engine/libs/meta-runtime" }
brahman-cards = { path = "../../core/brahman-cards" }
yahweh-widget-text-input = { path = "../../modules/ui_engine/widgets/text_input" }
yahweh-widget-meta-form = { path = "../../modules/ui_engine/widgets/meta-form" }
yahweh-theme = { path = "../../modules/ui_engine/libs/theme" }
gpui = { workspace = true }
serde_json = { workspace = true }
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,15 @@
[package]
name = "yahweh-widget-meta-form"
version.workspace = true
edition.workspace = true
license.workspace = true
description = "Yahweh — widget metainterfaz: lista, formulario, modal de delete y selector EntityRef que renderean cualquier `yahweh-meta-schema::Module` contra cualquier `yahweh_meta_runtime::MetaBackend`. App-agnostic."
[dependencies]
gpui = { workspace = true }
serde_json = { workspace = true }
uuid = { workspace = true, features = ["serde"] }
yahweh-meta-runtime = { path = "../../libs/meta-runtime" }
yahweh-meta-schema = { path = "../../libs/meta-schema" }
yahweh-theme = { path = "../../libs/theme" }
yahweh-widget-text-input = { path = "../text_input" }
File diff suppressed because it is too large Load Diff