refactor(nakui-core): KCL → Nickel — kcl_wrapper reemplazado por evaluación in-process
Cierra el plan original. El motor de validación de entities deja de shellear el binario externo `kcl` y pasa a evaluar Nickel contracts in-process via la dep nickel-lang (la misma que usa el brazo de cards). Los 3 schemas de sales/inventory/treasury migran de .k a .ncl. nakui-core: - Nueva dep nickel-lang = "2.0.0". - Borrado kcl_wrapper.rs. - Nuevo nickel_validator.rs con vet(schema_path, state, entity) que evalúa `let bundle = (import "<schema>") in (std.deserialize 'Json m%%"<json>"%%) | bundle.<entity>`. - executor.rs: KclError → NickelError, KclPre/Post/PostCreate → SchemaPre/Post/PostCreate, kcl_check → validate_entity. build_schema_bundle ahora emite `(import "X") & (import "Y") & ...` en lugar de concatenar bytes (cada .ncl es expresión completa). - manifest.rs: default schema "schema.ncl", extract_schema_names reescrito para sintaxis Nickel record (CapitalCase keys con 2-space indent). Schemas migrados: - sales/schema.ncl: Venta con std.contract.Sequence [record, from_predicate] para combinar shape + invariante cross-field (total == cantidad * precio_unitario). El patrón directo `record | from_predicate` rebota con "missing definition" porque el predicate evalúa antes de que el value populate el record; documentado en cada schema. - inventory/schema.ncl, treasury/schema.ncl: idem. - 3 schema.k viejos borrados; sales/nsmc.json paths actualizados. Tests: refs Kcl* renombradas; paths .k → .ncl; tests inline que escribían schema.k cambian a schema.ncl con sintaxis Nickel. 84 tests verdes en nakui-core. Doc-only borrados: - crates/core/ente-card/schema/card.k (REFERENCE ONLY). - crates/core/ente-brain/schema/rule.k (REFERENCE ONLY). Beneficios: sin dep externa al binario `kcl` (build CI limpio), errores Nickel en línea con caret pointing al field, mismo motor que cards (una dep para todo el repo), sin tempfile JSON intermedio. Cierra el plan original yahweh + KCL + card.k. Pendientes salen de nuevo trabajo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+111
@@ -6,6 +6,117 @@ ratio/diff ver `git show <sha>`.
|
||||
|
||||
## 2026-05-10
|
||||
|
||||
### refactor(nakui-core): KCL → Nickel — `kcl_wrapper` reemplazado por evaluación in-process
|
||||
Cierra el ciclo: el motor de validación de entities deja de
|
||||
shellear el binario externo `kcl` y pasa a evaluar **Nickel
|
||||
contracts** in-process via la dep `nickel-lang` (la misma que ya
|
||||
usa `brahman-cards` para sus templates). Los 3 schemas de los
|
||||
módulos sales/inventory/treasury migran de `.k` a `.ncl`.
|
||||
Además se borran los 2 archivos `.k` doc-only del repo
|
||||
(`ente-card/schema/card.k`, `ente-brain/schema/rule.k` — ambos
|
||||
estaban marcados "REFERENCE ONLY. NOT LOADED").
|
||||
|
||||
Cambios en **nakui-core**:
|
||||
- **Nueva dep**: `nickel-lang = "2.0.0"` (interfaz estable).
|
||||
- **Borrado** `kcl_wrapper.rs` (43 líneas) — shellear el binario
|
||||
desaparece.
|
||||
- **Nuevo** `nickel_validator.rs`:
|
||||
- `pub fn vet(schema_path, state, schema_name) -> Result<(), NickelError>`
|
||||
evalúa `let bundle = (import "<schema>") in
|
||||
(std.deserialize 'Json m%%"<json>"%%) | bundle.<entity>`.
|
||||
- El state JSON va dentro de un raw string Nickel
|
||||
(`m%%"..."%%`) y se deserialize via `std.deserialize 'Json`.
|
||||
No embebemos el state como record literal Nickel directo
|
||||
porque la sintaxis JSON usa `:` (Nickel records usan `=`).
|
||||
- 5 tests propios cubriendo happy path + 4 fallure modes
|
||||
(field missing, predicate fails, cross-field invariant
|
||||
fails, optional field present/absent).
|
||||
- **`executor.rs`**:
|
||||
- `kcl_wrapper::vet` → `nickel_validator::vet`.
|
||||
- `KclError` → `NickelError`.
|
||||
- `ExecError::KclPre/KclPost/KclPostCreate` → `SchemaPre/Post/PostCreate`
|
||||
(más neutro, ya no menciona KCL).
|
||||
- `kcl_check` (privado) → `validate_entity`.
|
||||
- `build_schema_bundle` ahora emite un archivo Nickel con
|
||||
`(import "X") & (import "Y") & ...` en lugar de concatenar
|
||||
bytes (cada `.ncl` es una expresión record completa, no
|
||||
juntable como texto plano).
|
||||
- **`manifest.rs`**:
|
||||
- `effective_schemas` default `"schema.k"` → `"schema.ncl"`.
|
||||
- `extract_schema_names` reescrito: ahora detecta keys
|
||||
CapitalCase con 2 spaces de indent (convención de los
|
||||
`schema.ncl`), no más patrón `schema X:` de KCL.
|
||||
- Tests del extractor actualizados (1 test reemplazado por 2:
|
||||
`_handles_nickel_record_top_level` + `_skips_let_bindings_and_lowercase`).
|
||||
|
||||
Cambios en **schemas de módulos**:
|
||||
- **`sales/schema.ncl`**: contracts Nickel para `Venta`. Usa
|
||||
`std.contract.Sequence [record_contract, from_predicate]`
|
||||
para combinar shape + invariante cross-field
|
||||
(`total == cantidad * precio_unitario`). El patrón directo
|
||||
`record | from_predicate` rebota con "missing definition" porque
|
||||
el predicate evalúa el contract antes de que el value lo
|
||||
populate; documentado en el comment.
|
||||
- **`inventory/schema.ncl`**: `Stock`, `MovimientoStock`,
|
||||
`TransferenciaStock` (esta última con cross-field
|
||||
`source != dest` via Sequence).
|
||||
- **`treasury/schema.ncl`**: `Caja`, `Movimiento`,
|
||||
`Transferencia` (con cross-field via Sequence).
|
||||
- Helpers locales en cada archivo: `positive_int`,
|
||||
`non_negative_int`, `currency_iso`, etc. via
|
||||
`std.contract.from_predicate`.
|
||||
- Los 3 `schema.k` viejos **borrados**.
|
||||
- `sales/nsmc.json` actualizado: paths `schema.k` →
|
||||
`schema.ncl`.
|
||||
|
||||
Cambios en **tests**:
|
||||
- `sales.rs`, `inventory.rs`: `KclPost` → `SchemaPost`.
|
||||
- `kernel_guards.rs`: `KclPostCreate` → `SchemaPostCreate`,
|
||||
path del schema directo `treasury/schema.k` →
|
||||
`treasury/schema.ncl`.
|
||||
- `graph.rs`, `manifest_validation.rs`: tests que escriben
|
||||
`schema.k` inline cambian a `schema.ncl` con sintaxis Nickel.
|
||||
- `schema_versioning.rs`: refs `schema.k` → `schema.ncl`.
|
||||
|
||||
Cambios documentales:
|
||||
- **Borrado** `crates/core/ente-card/schema/card.k` (1 archivo,
|
||||
REFERENCE ONLY documentado en su header).
|
||||
- **Borrado** `crates/core/ente-brain/schema/rule.k` (REFERENCE
|
||||
ONLY documentado en su header).
|
||||
|
||||
Tests:
|
||||
- **nakui-core**: 84 tests verdes (41 unit + 43 integration en
|
||||
graph/event_log/manifest_validation/schema_versioning/
|
||||
inventory/sales/kernel_guards). Suite full pasa.
|
||||
- **nakui-ui**, **brahman-cards**, **yahweh-***: sin cambios,
|
||||
todos verdes.
|
||||
- Total cubriendo el área: 174 tests.
|
||||
|
||||
Beneficios:
|
||||
- **Sin dep externa**: el binario `kcl` ya no es requisito de
|
||||
runtime ni de tests. Build limpio en CI sin instalar KCL.
|
||||
- **Errores en línea**: Nickel reporta contract violations con
|
||||
caret pointing al field exacto del schema y el value que
|
||||
falló. KCL daba mensajes textuales menos navegables.
|
||||
- **Mismo motor que el brazo de cards**: una sola dependencia
|
||||
Nickel para todo el repo (validación + templates de cards).
|
||||
- **Sin tempfile JSON intermedio**: el state se evalúa
|
||||
directamente en memoria; no hay `std::fs::write` por cada
|
||||
validate.
|
||||
|
||||
Limitaciones / decisiones:
|
||||
- El comentario "REFERENCE ONLY" de los `.k` borrados ya estaba
|
||||
marcado en sus headers; eran sólo notas de diseño para humanos.
|
||||
La autoridad real (Rust validate methods) sigue intacta.
|
||||
- La sintaxis Nickel `record_contract | from_predicate` no
|
||||
funciona — hay que envolver en `std.contract.Sequence [record,
|
||||
from_predicate]`. Documentado en cada schema y en el doc del
|
||||
validator.
|
||||
|
||||
**Pendientes restantes**: ninguno del refactor original. Los
|
||||
yahweh + KCL + card.k cierran. Próximos pendientes salen de
|
||||
nuevo trabajo (no del plan que arrastrábamos).
|
||||
|
||||
### 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
|
||||
|
||||
Reference in New Issue
Block a user