feat(brahman-cards): Nickel reader + templates con merge nativo (V2)
El brazo ahora acepta `.ncl`: evalúa via nickel-lang 2.0, exporta a JSON, dispatcha por los readers JSON estándar. Templates funcionan con import + & merge nativos de Nickel — el brazo no inventa mecánica paralela. - Dep nickel-lang = "2.0.0" (interfaz estable). - Nuevo módulo nickel_eval con eval_nickel_file(path) -> Value y errores tipados (Io/Eval/Export/JsonReparse). Mensaje de Nickel como texto plano sin ANSI. - load_card_with añade arm "ncl" simétrico al "json". - CardLoadError::Nickel propaga el error limpio. - Imports resueltos: parent dir del input + env BRAHMAN_CARDS_TEMPLATES_DIR (registry global, opcional). - Convención obligatoria documentada: fields override-ables del template usan `| default` (sin eso Nickel rechaza el merge). 9 tests nuevos: eval directo, dispatch a UiModule/Ente, template merge con id+label override, registry via env, error wrapping, contract violation en eval-time (`id | String = 42`), shape desconocida. 22 tests totales en brahman-cards (13 JSON V1 + 9 Nickel V2). Workspace build verde. NO hace: migrar consumers, set canonical de templates, KCL→Nickel — todos para commits siguientes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,101 @@ ratio/diff ver `git show <sha>`.
|
||||
|
||||
## 2026-05-09
|
||||
|
||||
### feat(brahman-cards): Nickel reader + templates con merge nativo (V2)
|
||||
Sigue al V1 (readers JSON). Ahora el brazo acepta inputs `.ncl`:
|
||||
los evalúa via `nickel-lang` 2.0, exporta a JSON, y dispatcha por
|
||||
los mismos readers JSON estándar. Un `.ncl` puede producir
|
||||
cualquier `CardBody` siempre que su shape sea reconocida. Los
|
||||
templates funcionan con los `import` + `&` merge nativos de
|
||||
Nickel — el brazo no inventa una mecánica paralela.
|
||||
|
||||
Cambios:
|
||||
- **Dep `nickel-lang = "2.0.0"`** (interfaz estable, no
|
||||
`nickel-lang-core` que es internal/inestable). Compila clean
|
||||
pero suma ~1 min al build cold del crate.
|
||||
- **Nuevo módulo `nickel_eval.rs`** con `eval_nickel_file(path) ->
|
||||
Result<Value, NickelEvalError>`. Errores tipados:
|
||||
`Io`, `Eval`, `Export`, `JsonReparse` — el mensaje de Nickel se
|
||||
formatea como texto plano (sin ANSI) para que sea legible en
|
||||
logs y toasts.
|
||||
- **`load_card_with` añade `"ncl"`**: lee archivo → eval Nickel →
|
||||
exporta a JSON → parsea de vuelta a Value → dispatch a los
|
||||
readers JSON. Pipeline simétrico a `"json"`.
|
||||
- **`CardLoadError::Nickel(NickelEvalError)`**: el error de
|
||||
Nickel se propaga limpio al error público del brazo.
|
||||
- **Resolución de imports**:
|
||||
- El parent dir del input se agrega como import path → `import
|
||||
"./template.ncl"` resuelve sin config.
|
||||
- El env `BRAHMAN_CARDS_TEMPLATES_DIR` (constante exportada
|
||||
`BRAHMAN_CARDS_TEMPLATES_ENV`) agrega un registry global →
|
||||
`import "ui_module_minimal.ncl"` desde cualquier ubicación.
|
||||
- No hay magic resolución por kind. El autor del Card decide
|
||||
qué template importa.
|
||||
|
||||
**Convención obligatoria de templates** (documentada en
|
||||
`nickel_eval.rs`): las fields que el usuario va a sobrescribir
|
||||
deben marcarse `| default` (o `| optional`). Sin ese marker
|
||||
Nickel rechaza el merge de strings/numbers no-iguales con la
|
||||
misma prioridad. Patrón canónico:
|
||||
|
||||
```nickel
|
||||
# template ui_module_basic.ncl
|
||||
{
|
||||
id | String | default = "TEMPLATE_ID",
|
||||
label | String | default = "TEMPLATE_LABEL",
|
||||
...
|
||||
}
|
||||
|
||||
# uso concreto
|
||||
let base = import "ui_module_basic.ncl" in
|
||||
base & { id = "my_id", label = "Mi Label" }
|
||||
```
|
||||
|
||||
9 tests nuevos en `tests/nickel.rs`:
|
||||
- `eval_nickel_file_returns_value_for_valid_input` — happy path.
|
||||
- `eval_nickel_file_surfaces_evaluation_error` — variant `Eval`
|
||||
con path + message.
|
||||
- `load_card_dispatches_ncl_to_ui_module_variant` — pipeline
|
||||
e2e a UiModule.
|
||||
- `load_card_dispatches_ncl_to_ente_variant` — pipeline e2e a
|
||||
Ente.
|
||||
- `template_merge_overrides_id_and_label_only` — el caso del
|
||||
user: template + override de id+label, resto del template
|
||||
intacto.
|
||||
- `template_resolves_via_env_registry` — uso del env como
|
||||
registry global.
|
||||
- `load_card_wraps_nickel_error_in_card_load_error` — wrap
|
||||
limpio del error.
|
||||
- `nickel_contract_violation_caught_at_eval_time` — value-add
|
||||
concreto: `id | String = 42` falla en eval, no en deserialize
|
||||
ni aguas abajo.
|
||||
- `ncl_evaluating_to_unknown_shape_returns_no_matching_reader`
|
||||
— sanity de coherencia con dispatcher JSON.
|
||||
|
||||
22 tests en total en `brahman-cards` (13 JSON V1 + 9 Nickel V2).
|
||||
Workspace build verde tras la dep nueva.
|
||||
|
||||
**Lo que NO hace V2** (sigue pendiente):
|
||||
- No migra consumers — `nakui-ui` sigue cargando con
|
||||
`nakui_ui_schema::load_modules_from_dir`. La migración a
|
||||
`brahman_cards::load_card` queda para después.
|
||||
- No define un set canonical de templates en el repo (algo
|
||||
como `templates/ente_basic.ncl`, `templates/ui_module_minimal.ncl`).
|
||||
Eso emerge cuando aparezcan los primeros casos de uso reales
|
||||
donde dos cards comparten estructura.
|
||||
- No hace cross-validation entre template + override (ej:
|
||||
detectar que un override saca un campo required del template).
|
||||
Nickel ya lo hace via contracts si el template tiene un schema.
|
||||
- No expone una API streaming (load N cards en paralelo). El
|
||||
use case actual es one-shot al boot.
|
||||
|
||||
**Pendientes para próximos commits** (orden):
|
||||
1. Migrar consumers (`nakui-ui` consume `brahman_cards::load_card`).
|
||||
2. Yahweh refactor: lift del MetaUi runtime a `crates/modules/ui_engine/`.
|
||||
3. KCL → Nickel: kcl_wrapper reemplazado por evaluación de Nickel
|
||||
contracts; los 3 schemas .k de nakui modules pasan a .ncl.
|
||||
4. card.k eliminado (es REFERENCE ONLY documentado).
|
||||
|
||||
### feat(brahman-cards): brazo unificado V1 — readers JSON + estructura canónica
|
||||
**Pivote arquitectónico** decidido en charla: Brahman maneja varios
|
||||
formatos legítimos de "Card" (cada formato vive en su crate origen y
|
||||
|
||||
Reference in New Issue
Block a user