Resumen

  • JMAP Enhanced Result References permite seleccionar datos de una respuesta anterior mediante JSON Pointer o JSON Path e insertarlos en propiedades, parches y filtros posteriores.
  • Las reglas de cardinalidad evitan elecciones implícitas: un destino escalar acepta un nodo, no varios. Resolver la ambigüedad escogiendo “el primero” inventaría una preferencia que la evidencia no contiene.

El cliente buscaba el identificador de un buzón dentro de una respuesta anterior. El autor de la expresión esperaba una coincidencia, pero utilizó descenso recursivo. La respuesta contenía el mismo nombre de propiedad en cuatro ramas. JSON Path hizo exactamente lo solicitado y construyó una lista de cuatro nodos.

El destino esperaba una cadena. Según el proyecto, más de un nodo para una propiedad primitiva debe producir invalidResultReference. Un desarrollador propuso la reparación habitual: tomar la primera coincidencia. La solicitud volvería a ser verde y la cola de trabajo seguiría avanzando.

Pero el orden de una lista de nodos no demuestra prioridad. Puede reflejar el orden del documento, la estructura de serialización o el recorrido del evaluador. Convertir la primera posición en una decisión de negocio habría añadido una regla que ningún actor autorizado había formulado.

La revisión 02 de JMAP Enhanced Result References está fechada el 21 de junio de 2026 y expira el 23 de diciembre de 2026. En el corte de investigación era un Internet-Draft activo del grupo JMAP en la vía Standards Track. No es una RFC final ni prueba de implementación o adopción.

El documento amplía el modelo de RFC 8620. Una petición JMAP puede contener llamadas ejecutadas secuencialmente. Una llamada posterior identifica la respuesta anterior mediante resultOf y name, y path selecciona datos de sus argumentos. La novedad permite usar esas referencias dentro de propiedades de /set, valores de PatchObject y FilterCondition de /query; además incorpora JSON Path de forma opcional junto a JSON Pointer.

La mejora reduce viajes de ida y vuelta y permite componer operaciones expresivas. También convierte la cardinalidad en parte explícita del contrato.

Uno no significa “cualquiera de ellos”

JSON Path produce una lista de nodos. Para un destino primitivo o de objeto único, exactamente un nodo se convierte en valor; cero se convierte en null; más de uno se rechaza. Para un destino de matriz, cero produce [] y uno o varios producen una matriz en el orden definido por RFC 9535. Para un mapa, cero produce {} y solo un objeto conforme puede ocupar el destino.

Las reglas son útiles porque impiden que cada servidor improvise. También conservan una afirmación negativa: cuando hay cuatro coincidencias y el destino admite una, el sistema no sabe cuál corresponde. El error no dice que los cuatro datos sean falsos. Dice que la evidencia disponible no satisface la singularidad exigida por la acción.

Tomar el primer nodo, el último o uno al azar eliminaría esa señal. Ordenar por una fecha tampoco resolvería el problema salvo que una política autorizada declare que “el más reciente” es el criterio. La selección técnica no puede crear por sí sola una jerarquía institucional.

Esta diferencia se vuelve crítica cuando el valor gobierna una operación irreversible: elegir una identidad, una carpeta, un destinatario, una clave o un ámbito de consulta. La aplicación puede pedir una lista y presentar opciones a un responsable. Puede afinar la expresión con un predicado respaldado por una regla. Lo que no debería hacer es fingir que la posición en el JSON equivale a mandato.

Cero también obliga a decidir

La ausencia tiene su propia cardinalidad. En un destino escalar, una selección JSON Path vacía se resuelve como null. En una matriz se convierte en []; en un mapa, en {}. Son resultados bien definidos, no decisiones universales.

Para una propiedad, null puede significar borrar el valor existente. En un filtro, una lista vacía puede hacer que ninguna entidad coincida o que una condición se interprete de manera especial. Un mapa vacío puede borrar excepciones o simplemente no aportar ninguna. La misma forma JSON puede tener efectos opuestos según el método.

JSON Pointer añade una distinción. Si un puntero exacto no encuentra la ruta y no contiene wildcard, falla. Una selección con wildcard que no encuentra nada puede producir el vacío tipado. Cambiar de una forma de ruta a otra para evitar errores puede cambiar la semántica de ausencia.

Por eso cada destino importante necesita una política explícita para cero coincidencias: rechazar, conservar el valor actual, limpiar, producir un conjunto vacío o recurrir a una fuente independiente. Dejarlo al resolutor genérico es confundir un convenio de datos con una decisión.

El control de tipo preserva el desacuerdo

Una vez resuelta la lista, el servidor valida el tipo. En /set, una incompatibilidad provoca invalidProperties; en /query, invalidArguments. El proyecto exige evitar conversiones oportunistas de cadenas a números o booleanos, y no serializar objetos complejos como texto para que pasen.

La prohibición conserva información. Si un filtro espera un número y la fuente entrega "01", convertirlo a 1 puede destruir la diferencia entre código e importe. Si una fuente entrega un objeto y el destino acepta una cadena, convertirlo a JSON textual oculta que el contrato no era el mismo.

La respuesta correcta a una incompatibilidad no siempre es “hacer que encaje”. A veces el tipo distinto revela que se conectaron dos dominios que solo parecían equivalentes. El rechazo mantiene visible ese desacuerdo hasta que alguien con contexto defina una transformación legítima.

Incluso con un tipo perfecto queda una pregunta. Un identificador de buzón puede ser una cadena válida y pertenecer a otra cuenta. Un ID seleccionado bajo un rol administrativo puede no ser reutilizable por un proceso ordinario. La validación sintáctica demuestra forma; la validación de dominio demuestra pertenencia; la autorización demuestra mandato. Ninguna sustituye a las otras.

El nivel intermedio no conoce el negocio

El proyecto permite que una capa intermedia aplique JSON Pointer o JSON Path sobre JSON opaco. No necesita comprender el tipo de método ni la semántica de la propiedad. Después, la capa de ejecución interpreta el resultado según la definición del destino.

Este desacoplamiento es valioso. Un proxy común puede resolver referencias para muchas familias JMAP. Pero su recibo debe ser estrecho: expresión aplicada, respuesta origen, número de nodos y forma resultante. No puede afirmar que el valor seleccionado sea el indicado para la decisión.

La doctrina de capa delgada de Heng Lu ayuda a no confundir participación con autoridad. El resolutor participa en el transporte. La implementación del método participa en la validación. La aplicación o institución decide qué evidencia puede gobernar una consecuencia. Un sistema sano permite que esas capas cooperen sin que ninguna absorba silenciosamente el mandato de las demás.

El registro de auditoría debe mantener la separación. resultOf, nombre de método, ruta, cuenta y principal de origen; cardinalidad y tipo resueltos; propiedad o filtro de destino; validación y decisión de autorización. Guardar solo el valor final borra la ruta por la que adquirió influencia.

El filtro dinámico no conoce su propio alcance

Las referencias mejoradas pueden aparecer dentro de FilterCondition, incluso en condiciones anidadas. Una consulta puede obtener dinámicamente un identificador de buzón de una respuesta anterior y usarlo en Email/query. Si la referencia falla, la consulta completa se rechaza con invalidResultReference; si aparecen a la vez la propiedad y su versión con #, la ambigüedad es invalidArguments.

Esto permite construir consultas precisas sin intervención del cliente. Pero una cadena de tipo correcto no demuestra que el buzón pertenezca a la cuenta prevista. Tampoco demuestra que el criterio anterior fuera suficientemente estrecho. Un valor seleccionado con demasiada amplitud puede alimentar una consulta cuya superficie sea mucho mayor de la imaginada.

La observabilidad debe abarcar ambas etapas. No basta medir cuántos nodos recorrió JSON Path. Hay que medir también cuántos objetos examinó o devolvió la consulta resultante, qué cuenta y tenant estuvieron implicados y qué control autorizó el encadenamiento.

Un filtro de coste pequeño puede abrir una operación de gran alcance. La gobernanza de recursos y la gobernanza de autoridad se encuentran en esa unión.

La expresividad tiene presupuesto

JSON Pointer sigue una ruta exacta. JSON Path añade filtros, wildcards y descenso recursivo. En respuestas grandes, una expresión puede producir listas enormes o consumir tiempo considerable. Varias referencias, anidamiento y copias de objetos agravan el coste.

El servidor necesita límites de complejidad, tiempo, tamaño de lista, número total de referencias y profundidad. Cuando se supera un límite debe rechazar, no truncar. Una lista truncada ya no representa la expresión original y puede cambiar precisamente qué elemento aparece “primero”.

Los analizadores JSON Path son dependencias de seguridad. Necesitan mantenimiento, parches, aislamiento y pruebas con expresiones hostiles. Tratar la ruta como metadato inerte deja fuera del modelo de amenazas al componente que ejecuta el recorrido.

Los límites también deben aparecer en los recibos operativos. Una oleada de invalidResultReference por presupuesto excedido puede señalar abuso, una respuesta que creció inesperadamente o una expresión cliente demasiado amplia. Reintentar con límites mayores sin revisar la intención puede convertir presión de recursos en incidente de alcance.

La caché debe vincular identidad y época

Almacenar el resultado de una selección puede ahorrar trabajo. Sin embargo, compartirlo entre usuarios o contextos de seguridad sería una fuga. Reutilizarlo después de un cambio de ACL puede devolver un valor estructuralmente correcto que ya no está autorizado.

El proyecto exige aislamiento e invalidación relacionados con el control de acceso. Una clave defensible vincula principal, cuenta, permisos relevantes y época de política, además de la respuesta y la expresión. El registro debe decir si el valor se evaluó de nuevo o salió de caché.

El tiempo de respuesta también puede filtrar existencia. Un atacante puede comparar aciertos y fallos para inferir si una ruta fue calculada en otro contexto. La defensa no termina en impedir que los bytes del valor crucen la frontera.

Un acierto de caché prueba que el sistema encontró una entrada bajo su clave. No prueba que la clave contenga todos los hechos necesarios para autorizar la reutilización.

Un buen error conserva autoridad

El error de cuatro coincidencias hizo algo valioso: evitó que la infraestructura eligiera por accidente. Los responsables podían refinar la fuente, pedir una matriz, presentar opciones o definir un criterio legítimo. Mientras tanto, invalidResultReference conservaba la incertidumbre.

Las pruebas deben cubrir cero, uno y varios nodos en destinos escalares, matrices y mapas; rutas exactas ausentes y wildcard vacíos; tipos incompatibles; pares ambiguos; filtros anidados; cambios de permisos y expresiones costosas. También deben verificar que el auditor reconstruya la selección desde la llamada anterior hasta el efecto final.

Las referencias mejoradas hacen que los datos fluyan con menos fricción. Su valor no está en conseguir siempre una respuesta verde, sino en conservar los límites cuando la evidencia no basta. Cuatro coincidencias frente a un destino singular no son cuatro oportunidades de automatizar. Son una invitación a decidir quién tiene derecho a escoger.

Fuentes