orquestador/specs/DECISION_EVALUATOR.md

93 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.