Resumen

  • En RFC 9610 toda ContactCard viva pertenece al menos a un AddressBook, pero puede estar en varios; quitarla de una libreta no equivale a destruirla.
  • Los grupos guardan UID de miembros. Si se pierde temporalmente el acceso a la tarjeta correspondiente, el miembro desaparece de la vista, pero el UID no resuelto se preserva y puede volver a resolverse.
  • Una prueba de borrado necesita cuenta, ID del objeto, UID, pertenencias previas, argumentos exactos de /set, respuesta del servidor y una consulta autoritativa posterior.

El cierre del proyecto no cerró el ciclo de vida del objeto

Al terminar un proyecto, una empresa elimina la libreta compartida de proveedores. La interfaz vuelve vacía y el sistema de cumplimiento archiva una captura bajo la etiqueta «contactos borrados». Semanas después, uno de los mismos proveedores sigue apareciendo en la libreta de incidentes. La lectura apresurada habla de restauración o incumplimiento. La lectura del protocolo pregunta primero qué se destruyó.

RFC 9610 define un AddressBook como una colección con nombre. Una ContactCard puede pertenecer simultáneamente a varias colecciones. Al destruir la libreta del proyecto con onDestroyRemoveContents en verdadero, el servidor elimina esa pertenencia. Solo destruye la tarjeta si no queda vinculada a ninguna otra libreta.

La pantalla vacía describe correctamente la colección extinguida, pero no certifica el destino de cada objeto. Mezclar ausencia visual, eliminación de una relación y destrucción de una tarjeta convierte una observación local en una afirmación global que el servidor nunca hizo.

Una libreta agrupa; no adquiere propiedad exclusiva

Un Account compatible con el modelo contiene cero o más AddressBooks. Cada uno reúne ContactCards, y la propiedad addressBookIds enumera las libretas de cada tarjeta. Ese conjunto debe conservar al menos un elemento mientras el objeto exista.

Así, una sola ficha puede servir a «Compras», «Continuidad» y «Facturación». La retirada de «Compras» cambia una arista del modelo, no borra las demás. La ventaja práctica es evitar copias divergentes; la obligación probatoria es no presentar una modificación de pertenencia como desaparición del objeto.

El protocolo fija una estructura mínima para que implementaciones distintas sincronicen el mismo hecho. Cada producto puede dibujar carpetas o espacios, pero su metáfora no amplía la autoridad del cambio ejecutado.

La cascada depende del estado anterior

onDestroyRemoveContents vale falso por defecto. Si la libreta aún contiene tarjetas, el servidor rechaza su destrucción con addressBookHasContents. Ese error prueba un rechazo bajo los argumentos enviados. No prueba conservación eterna de las tarjetas ni dice nada sobre otros sistemas.

Con el argumento en verdadero, se elimina la libreta de las tarjetas que la incluían. Una tarjeta cae en la rama destructiva solo cuando, después de retirar esa pertenencia, no pertenece a ninguna otra libreta. La misma operación puede destruir la colección, preservar ciertos objetos y destruir otros.

Por eso un registro de auditoría que guarda únicamente el indicador de cascada está incompleto. Debe conservar el conjunto de pertenencias anterior por tarjeta y la respuesta material del servidor. La semántica reside en la condición, no en el nombre contundente del botón.

El ID del servidor y el UID conservan continuidades distintas

Cada ContactCard tiene un id inmutable asignado por el servidor. Además posee un uid de JSContact. RFC 9610 permite que ambos sean diferentes y prohíbe dos tarjetas con el mismo UID dentro de una misma cuenta.

El id selecciona el objeto JMAP que las operaciones consultan o modifican. El uid identifica la tarjeta en la representación de contactos y es la referencia que almacenan los grupos. Si un auditor conserva solo el nombre visible, pierde ambos. Si conserva solo el UID, no sabe qué objeto de qué cuenta cambió. Si conserva solo el ID, pierde la continuidad expresada por grupos y otros ámbitos.

Guardar ambos tampoco autoriza a identificarlos con una persona real. Destruir la tarjeta de una cuenta no elimina mensajes, exportaciones, dispositivos, CRM, copias independientes ni al sujeto descrito.

Un grupo mantiene la referencia durante la invisibilidad

Una ContactCard de tipo grupo contiene un conjunto de UID. El cliente intenta resolverlos en las cuentas accesibles que ofrecen JMAP para contactos. Si uno no se encuentra, debe omitirlo de la presentación actual, pero conservar la referencia.

El propio RFC describe el caso: una persona añade a su grupo privado contactos de una libreta compartida y pierde temporalmente el acceso a ella. Los miembros desaparecen porque sus UID ya no se resuelven. Cuando el permiso vuelve, las referencias conservadas encuentran de nuevo las tarjetas y los miembros reaparecen.

No hizo falta restaurar el grupo. La información de continuidad nunca salió de él. Una inspección durante la interrupción solo demuestra la visibilidad del principal en ese instante; no demuestra destrucción del objeto, pérdida del UID ni invisibilidad para terceros.

No aparecer en un filtro sigue siendo un resultado de filtro

La condición inAddressBook devuelve tarjetas de una libreta concreta. Si una tarjeta no coincide, la conclusión válida es que no pertenece a esa colección bajo la consulta efectuada. Puede seguir en otra libreta o fuera de la superficie accesible al solicitante.

Los estados JMAP y /changes permiten seguir transiciones, siempre que el cliente guarde el estado anterior, inspeccione listas de creados, actualizados y destruidos, y resuelva incertidumbre con /get en la cuenta correcta. La desaparición de una fila no reemplaza esa secuencia.

Incluso una destrucción confirmada tiene alcance limitado: ya no existe esa ContactCard en esa cuenta JMAP. No habla de otras cuentas, copias, respaldos, archivos de correo o sistemas externos.

Una petición aceptada puede no producir el estado esperado

El argumento onSuccessSetIsDefault pide cambiar la libreta predeterminada si el resto de las operaciones termina bien. Si el ID no existe o una política del servidor lo impide, el servidor ignora esa parte sin devolver error y mantiene el valor anterior.

El detalle ofrece una lección general: enviar una intención no equivale a observar el resultado. Un cliente serio lee propiedades devueltas o vuelve a consultar el estado antes de anunciar éxito. La solicitud es recibo de una tentativa; el estado actual es recibo del efecto.

Cómo construir un recibo de borrado

Primero se identifican la cuenta, el id de servidor y el UID. Después se captura el conjunto completo de addressBookIds previo y toda referencia de grupo pertinente. El registro especifica si la operación destruyó una libreta o una tarjeta y conserva el valor exacto de onDestroyRemoveContents.

La respuesta debe guardar destroyed, notDestroyed, updated, errores y nuevo estado. Una lectura posterior permite expresar una conclusión acotada: retirada de esta libreta; no resoluble actualmente para este principal; ContactCard destruida en esta cuenta; o hecho no establecido. RFC 9610 no emite el veredicto «la persona fue borrada».

Separar vista, relación, objeto y realidad externa no debilita la auditoría. La hace útil. Cada capa recibe el lenguaje y la autoridad que su evidencia puede sostener.

Fuentes