6.3 KiB
ETAPA 4C — Motor de resolución de flujo (módulo puro, cliente)
1. Objetivo
Construir el motor que interpreta el esquema declarativo del formulario y resuelve
la secuencia de pantallas según el estado de respuestas. Es un módulo puro y aislado
en lib/, sin dependencias de React ni del DOM — entrada→salida determinista,
testeable con Node. El componente (Etapa 4D) lo consume; el motor no conoce al componente.
2. Contexto previo
- ADR-005: la lógica de flujo vive en el esquema (datos). El motor la interpreta.
- El esquema v3 está en la DB: questions con
type,conditional_rules,instance_generator,instance_of,hint, más filastype='section'. - Decisión confirmada: el motor corre en el CLIENTE (interpretación de flujo, no validación de seguridad — esa va server-side en 4G).
- Decisión confirmada: las secciones (
type='section') son PANTALLAS propias en el grafo. - La lógica de v2 (
lib/conditional.ts,survey-form.tsx) es INCOMPATIBLE y se reemplaza:- v2 evalúa AND (
rules.every); v3 necesita OR entre condiciones de ocultamiento. - v2 solo conoce
eq/eq_anyy acciónshow; v3 necesitacontains,eq_sole,not_in, acciónhide. - v2 infiere secciones por regex de prefijo; v3 las tiene como datos.
- v2 evalúa AND (
- El comportamiento esperado está validado en el mockup
wizard_formulario_mapeo_v3.html(funciónbuildVisibley navegación) — usar como referencia de comportamiento, NO de arquitectura.
3. DECISIONES YA TOMADAS — no consultar de nuevo
- Motor puro en
lib/(proponé el nombre: ej.lib/form-engine.ts), sin React/DOM. - Vocabulario de operadores:
eq,eq_any,not_in(escalares),contains,eq_sole(array). - Acciones:
show,hide. - Combinación: múltiples reglas en el array de una pregunta se evalúan en OR.
(Una pregunta se oculta si CUALQUIER regla
hideaplica; se muestra si CUALQUIER reglashowaplica. Definí la semántica precisa de show+hide combinados y documentala.) - Secciones = pantallas propias en el grafo.
- Instancias: 4.1 (
instance_generator=true) genera N instancias; las preguntas coninstance_of='4.1'se repiten una vez por instancia activa, en orden por familiar (familiar1: 4.2→4.3, familiar2: 4.2→4.3, ...) como en el mockup. - Estado de respuestas con clave compuesta
question_code:instance_id(instancias) oquestion_codeconinstance_id='default'(normales).
4. Tareas
4.1 Tipos del motor (lib/types.ts ampliado o nuevo)
Definir/ampliar:
ConditionalRule: operadores y acciones completos del vocabulario v3.FormSchema: la representación del formulario que el motor consume (secciones, preguntas, reglas, instanciación) — derivada de las filas dequestions.WizardState: respuestas (con instancias), instancia activa, pantalla actual.Screen: una pantalla resoluble (sección-intro | pregunta | pregunta-de-instancia | fin).
4.2 Evaluador de reglas
Reescribir la evaluación (reemplaza lib/conditional.ts):
- Implementar los 5 operadores y 2 acciones.
contains/eq_soleoperan sobre respuestas array (multiple_choice).- Semántica OR documentada y correcta para el caso
r_hide_ning_sn. - Función pura:
(rule, answers) => booleany(question, answers) => 'show'|'hide'.
4.3 Resolución del grafo de pantallas
Función pura que dado el esquema + estado devuelve la lista ordenada de pantallas visibles:
- Expande instancias (4.2/4.3 por cada familiar activo declarado en 4.1).
- Aplica visibilidad (oculta secciones/preguntas según reglas).
- Incluye las pantallas de sección.
- Equivale conceptualmente al
buildVisible()del mockup, pero como módulo puro.
4.4 Navegación
Funciones puras next(state, schema) y back(state, schema) que devuelven el nuevo
estado (pantalla actual actualizada), resolviendo saltos. Identificar la pantalla actual
por ID estable, no por índice (lección del mockup: el índice se desincroniza cuando
cambian las instancias).
4.5 Carga del esquema
Actualizar la query (app/page.tsx) para traer las 3 columnas nuevas
(hint, instance_generator, instance_of). Transformar las filas de questions
en el FormSchema que consume el motor.
4.6 Tests del motor (Node, sin navegador)
Tests puros que verifiquen:
- Recorrido completo (todos los vínculos) genera las pantallas esperadas.
- "Solo niño sin discapacidad" (eq_sole) → recorrido liviano correcto (5.3, 8.4, 9.1, 9.4).
- "Ninguna de las anteriores" (contains) → salta a sección 10.
- 3.1='No' oculta 3.2-3.5.
- 3 familiares → 6 pantallas de instancia en orden por familiar.
- Navegación next/back coherente cuando cambian las instancias.
5. Entregables (DoD)
- Motor puro en
lib/sin dependencias de React/DOM. - Los 5 operadores y 2 acciones implementados y testeados.
- Resolución de grafo con instancias y secciones-pantalla.
- Navegación por ID estable, no por índice.
- Query actualizada con las 3 columnas nuevas.
- Tests Node que cubren los recorridos del punto 4.6, todos en verde.
- NO se toca el componente todavía (es 4D) — el motor se entrega standalone + tests.
6. Qué reportar
Verificado:
- Motor en [archivo], puro (sin React/DOM) ✓
- Operadores implementados: eq, eq_any, not_in, contains, eq_sole ✓
- Acciones: show, hide ✓ — semántica de combinación: [descripción]
- Tests: N/N en verde
- recorrido completo ✓
- solo niño (eq_sole) → 5.3/8.4/9.1/9.4 ✓
- ninguna (contains) → salta S10 ✓
- 3.1=No oculta 3.2-3.5 ✓
- 3 familiares → 6 pantallas en orden ✓
- next/back coherente ✓
Asumido:
- [supuestos de diseño del motor]
7. Qué NO hacer
- ❌ No poner lógica de flujo en un componente React (el motor es puro, lib/).
- ❌ No tocar el componente de formulario todavía (es 4D).
- ❌ No implementar validación de seguridad acá (es 4G, server-side).
- ❌ No usar índices numéricos para la pantalla actual — usar ID estable.
- ❌ No tocar v2.1.0-stable ni el seed.
8. Versionado
Commit sugerido:
feat(engine): motor de resolución de flujo declarativo [4C]
Módulo puro que interpreta el esquema v3 y resuelve pantallas.
5 operadores (eq, eq_any, not_in, contains, eq_sole), acciones show/hide.
Instancias de vínculo y secciones-pantalla. Navegación por ID estable.
Tests Node cubren los 3 recorridos. Reemplaza lib/conditional.ts de v2.