93 lines
5.5 KiB
Markdown
93 lines
5.5 KiB
Markdown
# Evaluador de decisiones (T05)
|
||
|
||
`PureDecisionEvaluator` implementa `DecisionEvaluator` sin Spring, I/O ni
|
||
persistencia. Es reutilizable entre workers; no guarda contexto ni resultados
|
||
entre llamadas. Devuelve `Selected(output, matchedRuleIds)` o `Failure(code)`.
|
||
`ConditionEvaluator` permite evaluar guardias: devuelve boolean o lanza
|
||
DomainException con EVALUATION_ERROR. No convierte errores en condiciones falsas.
|
||
|
||
## Semántica ejecutable
|
||
|
||
- EQ/NEQ comparan tipos JSON compatibles; números mediante BigDecimal.compareTo,
|
||
sin depender de la escala. No hay conversión de strings a números o fechas.
|
||
- Null es un valor presente. Solo EQ/NEQ lo comparan: null EQ null es true,
|
||
null EQ un valor no nulo es false. Una ruta ausente produce EVALUATION_ERROR
|
||
en cualquier comparación, incluso si el otro operando es null.
|
||
- EQ/NEQ admiten objetos y arrays estructurales, conservando el orden del array
|
||
e ignorando el orden de claves del objeto. Valores anidados con tipos
|
||
incompatibles producen error; formas/tamaños distintos producen desigualdad.
|
||
- GT/GTE/LT/LTE requieren dos números. No existe orden implícito de strings,
|
||
fechas, booleanos, objetos o null.
|
||
- IN requiere array homogéneo y un operando izquierdo compatible con sus elementos.
|
||
Revisa toda la lista antes de buscar: una coincidencia temprana no oculta tipos
|
||
mezclados. Null no participa en IN. Una lista vacía retorna false para un valor
|
||
no nulo. La igualdad numérica tampoco depende de escala dentro de IN.
|
||
- EXISTS retorna false solo para un path sin valor; un null explícito sí existe.
|
||
AND/OR cortocircuitan en orden; NOT invierte el resultado y propaga errores.
|
||
- UNIQUE examina reglas hasta detectar una segunda coincidencia, que retorna
|
||
AMBIGUOUS_DECISION incluso si ambas salidas son iguales. Si ninguna coincide,
|
||
usa defaultOutput. Un error previo a decidir el resultado no usa el default.
|
||
- FIRST se habilita únicamente con hitPolicy=FIRST y selecciona la primera regla
|
||
coincidente, sin evaluar los datos de reglas posteriores. La comprobación
|
||
estructural y de límites sí cubre la definición completa previamente.
|
||
- Selected conserva el ID de la regla elegida; lista vacía identifica el default.
|
||
La persistencia de esa evidencia en auditoría pertenece a las tareas posteriores.
|
||
|
||
## JSON Pointer y contexto
|
||
|
||
El resolver solo admite las raíces tipadas /request/data, /event/data, /results y
|
||
/actor. Desescapa ~1 y ~0 una sola vez y admite claves vacías y caracteres Unicode.
|
||
En arrays acepta índices decimales canónicos sin ceros iniciales; índices fuera de
|
||
rango, '-' y acceso a un hijo de un escalar no resuelven valor. No ejecuta expresiones.
|
||
|
||
Actor expone subject, businessScope y roles provenientes del snapshot confiable;
|
||
roles se ordenan para que su representación sea determinista. Los campos del evento
|
||
no sustituyen esa identidad. Resolver raíz /request/data devuelve únicamente data,
|
||
no identidad, estado, revisión ni ACL de la solicitud.
|
||
|
||
## Límites
|
||
|
||
EvaluationLimits permite reducir límites hasta los techos operativos: profundidad
|
||
20 y 1000 nodos. Se configura al construir el evaluador; el wiring del motor vendrá
|
||
con los servicios que lo consumen. No es configuración editable del flujo.
|
||
|
||
La raíz de cada condición tiene profundidad 1. Cada condición y cada expresión
|
||
path/literal cuenta como nodo; una comparación tiene tres nodos y profundidad 2.
|
||
Los literales son hojas del AST. Se suman todas las reglas y ocurrencias, aunque
|
||
compartan el mismo objeto Java. Los IDs duplicados son error. El preflight usa una
|
||
pila explícita y rechaza también ramas que un cortocircuito habría omitido.
|
||
|
||
Para acotar comparaciones de datos, IN admite hasta maxNodes elementos y la
|
||
igualdad estructural hasta maxNodes pares visitados por comparación. Exceder el
|
||
presupuesto devuelve EVALUATION_ERROR. Esto no sustituye límites de bytes al
|
||
recibir/deserializar: definición 1 MiB y datos 256 KiB siguen pendientes de T06/T09.
|
||
|
||
## Solapamientos estáticos
|
||
|
||
IntervalOverlapAnalyzer reconoce EQ/GT/GTE/LT/LTE numéricos de path frente a literal,
|
||
operandos invertidos y conjunciones AND del mismo path. Intersecta extremos abiertos
|
||
y cerrados con BigDecimal y descarta intervalos vacíos. Devuelve parejas de IDs y
|
||
path con solapamiento demostrado, además de IDs de reglas fuera del subconjunto.
|
||
|
||
No analiza OR/NOT/EXISTS/IN/NEQ ni compara intervalos sobre paths diferentes.
|
||
La ausencia de solapamientos encontrados no certifica disjunción general. T06
|
||
consumirá estos diagnósticos al publicar; FIRST puede tener precedencia intencional.
|
||
UNIQUE mantiene obligatoriamente detección de ambigüedad en runtime.
|
||
|
||
## Evidencia y alcance
|
||
|
||
DecisionEvaluatorTest usa el flujo scoring.json contractual para 71/70/61/60 y
|
||
fracciones de precisión alta. Las fixtures missing-score/string-score se rechazan
|
||
por el schema BureauResult y, si llegan al evaluador, producen EVALUATION_ERROR,
|
||
nunca una salida de scoring bajo. No es todavía una prueba de adapter de buró.
|
||
|
||
Las suites incluyen los once operadores, null/ausencia, IN heterogéneo, condiciones
|
||
anidadas, cortocircuito, FIRST/UNIQUE, límites exactos, 50000 niveles de entrada,
|
||
uso concurrente, JSON Pointer y extremos de intervalos. La prueba de arquitectura
|
||
incluye el evaluador de application y lo compila con únicamente java.base.
|
||
|
||
No hay nuevos endpoints, llamadas externas, cambios SQL ni escritura de solicitudes.
|
||
El mapeo JSON a DSL usado por la prueba scoring es exclusivamente un fixture de
|
||
pruebas; el parser/validador completo de publicación corresponde a T06. Los criterios
|
||
A04–A06 se verifican al nivel de decisiones/contrato, no como flujo REST completo.
|