摘要
- RFC 9610 要求存续的 ContactCard 至少属于一个 AddressBook,但允许它同时属于多个地址簿;移除一项归属关系因此不等于销毁卡片。
- 群组保存成员 UID。若用户暂时失去对相应卡片的访问,成员会从当前群组视图消失,但无法解析的 UID 仍应保留,访问恢复后成员可以重新出现。
- 可辩护的删除结论需要账户、服务器对象 ID、UID、操作前的完整归属集合、
/set参数与响应,以及随后在正确账户中的权威查询。
一个空白页面越过了它的证据边界
项目结束后,管理员删除了为项目建立的共享地址簿。客户端返回空白列表,审计记录也写下“联系人已删除”。几个月后,其中一位供应商又出现在运营地址簿里。直觉会把这解释成恢复失败、备份回灌或违规保留;RFC 9610 提供了更基础的答案:此前发生的可能只是集合关系被移除。
在规范的数据模型中,AddressBook 是有名称的 ContactCard 集合。一张卡片可以同时属于“项目”“值班”和“续约”三个地址簿。使用 onDestroyRemoveContents:true 销毁项目簿时,服务器会把项目簿从相关卡片的 addressBookIds 中移除;只有在卡片不再属于任何其他地址簿时,它本身才会被销毁。
因此,界面清空、请求成功、对象继续存在可以同时为真。把这三个事实压缩成“已删除”,不是简化,而是把视图状态、关系变化和对象生命周期混成一个未经证明的结论。
地址簿组织卡片,但不天然拥有卡片
支持 JMAP 联系人的 Account 可以包含零个或多个 AddressBook,每个地址簿包含零个或多个 ContactCard。存续卡片的 addressBookIds 必须非空。这个结构刻意允许一张卡片被多个工作场景共同使用,而不是为每个视图制造一份可能漂移的副本。
这样的最小共享规则很重要。协议规定各实现都能理解的归属与同步状态,产品可以自行把它画成文件夹、标签或工作区。但界面隐喻不能扩大操作的权力:从一个文件夹消失,并不会自动取得在其他集合中销毁对象的授权。
运行中的代码所需的是清晰的边界。移除一条归属边,回答的是“这张卡片是否还在这个地址簿”;销毁对象回答的是“这张卡片是否还存在于这个账户”。二者不能共用一张没有范围说明的绿色成功徽章。
onDestroyRemoveContents 是有条件的级联
onDestroyRemoveContents 默认是 false。地址簿非空时,服务器会以 addressBookHasContents 拒绝销毁。这个错误证明当前参数下的集合销毁没有完成,却不能证明卡片永远保留,更不能说明其他账户或外部系统的状态。
参数为 true 时,服务器先从卡片的归属集合中移除目标地址簿;某张卡片只有在失去最后一个地址簿归属时才被销毁。于是同一次方法调用可能产生三类结果:地址簿被销毁、多归属卡片继续存续、失去最后归属的卡片被销毁。
审计若只记录“开启级联”,就丢掉了决定结果的前置条件。真正需要保存的是每张卡片操作前的完整 addressBookIds、请求对象、参数值、服务器返回的 destroyed、notDestroyed、updated 与错误字段。命令名称是意图,不是结果。
服务器 id 与 JSContact uid 维护不同的身份连续性
ContactCard 有不可变、由服务器赋值的 id,也有 JSContact 定义的 uid。RFC 9610 明确允许二者不同,并要求同一 Account 内不得有两个 ContactCard 使用相同 UID。
服务器 ID 指向 JMAP 方法实际读取或修改的对象。UID 则用于联系人表示中的连续性,也是群组成员保存的引用。日志只留显示名称,两种身份都丢失;只留 UID,无法证明哪个账户里的哪个服务器对象被改动;只留服务器 ID,又可能看不到群组或跨可访问账户通过 UID 维持的连续性。
可靠证据应同时保存二者,但也必须承认它们都不是现实中的人。销毁某个账户内的一张卡片,不会自动删除邮件、导出文件、其他设备、CRM、备份或被描述的人。
群组会保存当前用户看不见的线索
群组类型的 ContactCard 在 members 中保存一组 UID。客户端会在当前可访问且支持 JMAP Contacts 的账户中寻找匹配卡片。某个 UID 暂时找不到时,客户端应在显示上忽略它,却仍然保留这个 UID。
规范给出了直接示例:用户把共享地址簿中的联系人加入私人群组,随后暂时失去对共享地址簿的访问。由于 UID 无法解析,成员从群组中消失;权限恢复后,保留的 UID 再次找到对应卡片,成员便重新出现。
这里没有必然发生恢复写入。贯穿中断期的连续性证据一直存在,只是对当前主体不可解析。中断期间的截图最多证明“这个主体此刻看不到”,不能证明对象被销毁、UID 被清除,也不能证明其他主体同样不可见。
查询无结果只回答了查询范围内的问题
inAddressBook 过滤条件要求卡片属于指定地址簿。某张卡片没有命中,只能说明它不在该过滤范围;它仍可能属于另一个地址簿,或位于调用者当前无法访问的表面。
JMAP 的状态字符串与 /changes 能帮助客户端追踪变化,但前提是保留旧状态、检查创建、更新、销毁的对象 ID,并用正确 Account 下的 /get 消除不确定性。“列表里少了一行”不能替代这条证据链。
即便服务器明确确认 ContactCard 已销毁,结论也只覆盖该 JMAP Account 中的这个对象。它不能证明其他账户、复制卡片、备份、邮件历史或外部应用中的数据已经消失,更不能自动等同于法律意义上的擦除。
默认地址簿请求也说明意图不等于结果
onSuccessSetIsDefault 会在其他创建、更新和销毁全部成功后尝试设置默认地址簿。但如果 ID 不存在,或服务器政策不允许变更,服务器必须忽略该请求,不为这部分返回错误,并保留原默认簿。
这不是删除机制,却揭示同一条证据纪律:发出请求只能证明尝试,不能证明服务器最终状态。客户端必须读取返回的服务器属性,或再次获取当前状态后才能向用户宣告成功。
删除凭证必须是一条可复核的链
第一步是明确 Account、ContactCard 的服务器 id 与 UID。第二步保存操作前完整的 addressBookIds,以及群组中任何相关 UID 引用。第三步记录究竟销毁 AddressBook 还是直接销毁 ContactCard,并保留 onDestroyRemoveContents 的准确值。
随后保存方法响应、新状态和后续权威查询。最终结论应限定为四种之一:已从这个地址簿移除;当前对这个主体不可解析;这个账户内的 ContactCard 已销毁;证据不足。RFC 9610 无权替系统声称“这个人已从所有地方被擦除”。
现实层分离不是文字游戏。视图、关系、对象和外部世界分别控制不同的决策与风险。只有让每一层使用自己的凭证,删除报告才不会在重新出现的联系人面前崩塌。
来源
- https://www.rfc-editor.org/rfc/rfc9610.html
- https://www.rfc-editor.org/info/rfc9610/
- https://www.rfc-editor.org/rfc/rfc9610.txt
- https://www.rfc-editor.org/rfc/rfc9610.xml
- https://datatracker.ietf.org/doc/rfc9610/
- https://datatracker.ietf.org/doc/rfc9610/history/
- https://www.rfc-editor.org/errata/rfc9610
- https://www.rfc-editor.org/rfc/rfc8620.html
- https://www.rfc-editor.org/rfc/rfc8620.txt
- https://www.rfc-editor.org/rfc/rfc9553.html
- https://www.rfc-editor.org/rfc/rfc9553.txt
- https://www.rfc-editor.org/rfc/rfc9670.html
- https://www.rfc-editor.org/rfc/rfc2397.html
- https://www.rfc-editor.org/rfc/rfc6350.html
- https://www.rfc-editor.org/rfc/rfc8259.html
- https://www.iana.org/assignments/jmap/jmap.xhtml
- https://www.rfc-editor.org/rfc/rfc2119.html
- https://www.rfc-editor.org/rfc/rfc8174.html
- https://heng.lu/running-code-primary-the-patch-needed-to-preserve-the-internet-original-design/
- https://heng.lu/minimum-initial-specification-localized-future-decision-voluntary-adoption-internet-coordination-system/
- https://heng.lu/on-reality-layers-symbolic-power-and-why-clarity-feels-so-hostile/
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
