feat(nakui-ui): EntityRef validation en parse_field_value (UUID al submit)

Antes: parse_field_value(EntityRef, raw) devolvía Ok(json!(raw))
blindly. Garbage entraba al log/store si el field se usaba como
seed o param (sólo el path de morphism inputs validaba UUID).

Ahora: Uuid::parse_str(raw.trim()) → error claro si falla, value
trimmed si pasa. El selector clickable garantiza happy path; este
check es defensivo contra paste manual o garbage tipeado.

5 tests nuevos: happy path, trim de whitespace, rechazo de garbage,
rechazo de empty, propagación de error a resolve_param_value con
label del FieldSpec en el mensaje.

35 tests verdes. E2E del morphism real intacto (sus inputs van por
path dedicado, no por parse_field_value).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-05-09 21:39:31 +00:00
parent 7e2be96a57
commit bcccf3b953
2 changed files with 104 additions and 9 deletions
+46
View File
@@ -6,6 +6,52 @@ ratio/diff ver `git show <sha>`.
## 2026-05-09
### feat(nakui-ui): EntityRef validation en parse_field_value (UUID al submit)
Cierra otro pendiente: `parse_field_value(FieldKind::EntityRef, raw)`
devolvía `Ok(json!(raw))` blindly — el value entraba al log/store
incluso si era basura. La validación de UUID sólo ocurría cuando el
field se usaba como **input** del morphism (línea ~540 de
`commit_morphism`); como **seed field** o como **param**, garbage
pasaba silenciosamente.
Cambios:
- **`parse_field_value(EntityRef, raw)`** ahora hace
`Uuid::parse_str(raw.trim())` y devuelve error claro si falla:
`"'<raw>' no es UUID válido (usá el selector de records)"`. En
caso de éxito, devuelve el UUID **trimmed** como string —
protege contra paste manual con whitespace.
- **Doble cobertura**: este path cubre seed fields (commit_seed via
obj.insert) y morphism params (resolve_param_value lo invoca por
cada FieldSpec con kind=EntityRef). El path de morphism inputs
ya validaba antes con `Uuid::parse_str` directo — sigue intacto,
no hay double-validation.
- **Selector clickable es happy path**: el dropdown setea valores
bien-formados, así que el usuario nunca debería ver el error en
uso normal. Sólo dispara con paste manual o si el usuario escribe
garbage en el input — defensivo.
5 tests nuevos (reemplazan al obsoleto `parse_field_entity_ref_returns_string`):
- `parse_field_entity_ref_accepts_valid_uuid` — happy path.
- `parse_field_entity_ref_trims_whitespace``" uuid\n"``"uuid"`.
- `parse_field_entity_ref_rejects_non_uuid``"abc-123"` → error
con el value y la palabra "UUID" en el mensaje.
- `parse_field_entity_ref_rejects_empty_string``""` → rebota.
- `resolve_param_strict_entity_ref_propagates_error` — sanity de
que el wireup en resolve_param_value hereda el strict checking,
con label del FieldSpec en el mensaje.
35 tests verdes (+4 net). El E2E del morphism real
`morphism_pipeline_executes_real_sales_vender` sigue verde — sus
inputs van por el path dedicado, no por parse_field_value.
Pendientes restantes:
- **Atajo Esc para Cancelar** del modal de delete.
- **`FieldOp::Clear`** — para soportar borrar un value vía form.
- **Snapshot durante runtime** (cada N writes, no sólo al startup).
- **Validación cross-field** (ej: el UUID del EntityRef existe en
la entity referida) — hoy sólo validamos forma; un UUID válido
pero inexistente sí pasa.
### feat(nakui-ui): snapshot/compaction automático del event log al startup
Cierra el último gran pendiente del round: el replay full cada
startup escala lineal en el log. Con 60+ entries el costo de boot