摘要
ifUnchangedBy可以同时核对目标对象和同类型的上下文对象,例如文件的内容标识、父目录与父目录名称,从而把写入依据限定在真正重要的状态上。- 条件成功只证明所列属性在方法开始时相符;
atomic:true只证明同一个Foo/set的变更全成或全不成。它们都不自动证明业务授权或外部系统已经执行。
文件编辑器最后一次同步时,f42 的 blobId 是 G_old,父目录是 d3,目录名是 Reports。用户离线修改了内容,准备把 blobId 换成 G_new。与此同时,协作者把文件移进了另一个目录。
如果客户端只检查 blobId,条件依然成立。服务器会把新内容写进客户端没有预期的位置。若客户端改用 JMAP Core 的 ifInState,任何同类型对象的变化都可能让整次写入失败,包括与 f42 毫无关系的活动。
真正需要表达的并不是“所有东西都没变”,而是三条有限命题:内容仍是我读过的版本;文件仍在 d3;d3 仍是我理解的 Reports。
这正是 JMAP Conditional Set 试图解决的边界。当前的 draft-ietf-jmap-conditional-00 日期为 2026 年 9 月 15 日,失效日期为 2027 年 3 月 19 日。研究截止时,它是 JMAP 工作组的活跃 Internet-Draft,预期进入 Standards Track,并在获批后更新 RFC 8620。它还不是正式 RFC,也不能证明任何产品已经实现或部署。
从类型级状态缩小到属性级事实
JMAP Core 的 ifInState 把账户内某一对象类型的状态字符串作为方法级门槛。只要该类型的任一对象发生变化,字符串就可能改变。新邮件到达、另一设备标记消息、服务器生成对象,都可能让一个只想更新单个文件的客户端得到 stateMismatch。
新草案加入 ifUnchangedBy。客户端用“对象 ID 到 PatchObject”的映射列出预期值。服务器判断:如果把这个 PatchObject 应用到当前对象,是否什么也不会改变。每个指针都相等,条件才成立;JSON null 表示该属性应当不存在。比较使用 Foo/get 会返回的表示。
这个机制没有发明新的版本号,而是复用已有的补丁语义。它的价值在于让客户端说明自己真正依赖什么。它的风险也来自同一处:成功回执只能覆盖被说明的那些事实。
如果只列 blobId,对象名称、共享权限和父目录都可以变化而不触发失败。系统不能把结果记录成“对象未变”。准确说法应是:“在方法开始的评估点,客户端可读的指定指针与预期值相同。”
若一种对象拥有由服务器维护、任何修改都会更新的 changed 标记,客户端可以把它当作整体比较交换令牌。但令牌的证据强度取决于所有写入路径是否都严格更新它。后台修复、迁移或管理员工具漏掉一次更新,就会让看似完整的版本回执出现盲区。
上下文条件不是完整的政策图
草案允许条件指向本次方法不会修改的同类型对象。因此,文件内容更新可以同时依赖文件的 parentId 和父目录的名称。条件都在方法开始时、任何本方法变更发生前评估。任一条件失败,整个方法都不做修改。
这种能力能阻止“内容正确、落点错误”的竞态。但它不会自动覆盖更高层父目录、外部挂载、法律保留、组织审批或业务所有权。客户端列出的上下文越精确,系统越不应假装它列出了全部上下文。
这与《heng-lu-note.md》强调的薄协调层相吻合。协议可以检查有限技术不变量,但不能因为检查做得准确,就取得对资产和后果的主权。数据库中的父目录是证据,不是委托书。
条件还可以引用服务器设置而客户端不能修改的属性,例如内容标识、大小或修改时间。这能把写入建立在更可靠的事实之上,但必须服从读取权限。服务器不得替无权读取该属性的客户端评估条件,否则成功与失败会成为探测隐藏值的二元预言机。正确结果是 forbidden。
可读取某个事实,也不等于有权执行变更。服务器仍须单独判断写权限。条件匹配回答状态问题;授权回答谁能行动的问题。
条件失败的单位是整个方法
只要 ifUnchangedBy 中一项不满足,服务器就必须返回方法级 stateMismatch,并且不创建、不更新、不销毁任何对象;该类型的状态字符串也保持不变。服务器可以指出失败的对象 ID,但不会返回当前值。
若客户端希望不同变更独立成功,就必须拆成多个方法调用,每个调用带自己的条件。拆分与合并都不是中性动作。把十项变更放进一个调用,意味着一个不匹配会阻止全部十项;拆开,则意味着外部观察者可能看到部分进度。
协议能提供明确选择,却不能替应用决定哪个失败形状可以承受。那个决定需要知道损失、恢复成本和真正的业务不变量。
原子性回答的是另一道题
草案同时增加可选的 atomic:true。JMAP Core 原本允许一个 Foo/set 内的创建、更新和销毁分别成功或失败。原子模式要求全部提交,或者全部不提交。
服务器应对所有变更共同产生的最终对象集合评估约束,而不是按某个中间顺序评估。这让两个同级文件可以交换唯一名称:单独改任何一个都会与另一个现有名称冲突,但最终集合仍然满足唯一性。
如果任一部分因补丁无效、权限不足、唯一性冲突或其他 SetError 失败,服务器返回 atomicFailure,全部变更不提交。错误映射可以指出原因;没有出现在映射中的对象也没有悄悄成功,它们只是没有造成失败。
若条件不匹配,错误仍是 stateMismatch,即使请求同时要求原子性。这个区分很重要:前者说明出发状态不再成立,后者说明提议的变更整体无法提交。
当服务器虽宣告支持能力,却无法把某一具体方法作为原子单元执行时,必须返回 cannotApplyAtomically,并且不得退化成部分应用。这是一条诚实边界。客户端可以在能容忍部分结果时去掉 atomic 重试,但那是新的政策决定,不是等价重传。
把弱化重试藏进通用错误恢复,会在压力最大时删除原有不变量。正确记录应保留被拒绝的请求、谁批准放宽、可能出现哪些半成品状态,以及如何对账。
提交边界不等于传播边界
一次成功的原子 Foo/set 只能证明响应服务器在其方法边界内共同提交了对象变更。搜索索引、通知服务、缓存、离线客户端、远端副本和工作进程通常不在同一事务里。
文件交换名称后,路径缓存仍可能显示旧映射;撤销共享权限后,已发出的能力令牌可能等待另一个系统处理;条件销毁邮件后,离线设备仍可能保留本地副本。这些现象不必推翻提交回执,却说明业务结果需要更多回执。
防御性证据链应分别记录:已认证主体、业务授权、所选条件、方法响应、提交后读回、各消费者看到的版本,以及用户端结果。把它们压缩为“操作成功”,会让第一个绿色信号替所有后续系统作证。
运行代码必须测试负面命题。改变无关对象,确认属性级条件不会像类型状态那样误报冲突;改变目标对象未选择的属性,确认狭窄条件依然成立;改变所选指针,确认整个方法完全无修改。尝试隐藏属性,必须得到 forbidden。让原子变更中的一项失败,确认其他项也未出现。提交成功后故意延迟索引和缓存,观察系统是否保留各自状态。
文件内容没变、所在位置却变了,并不是一个协议悖论。它提醒管理者:每一份回执都有自己的主语。条件知道被列出的属性,原子事务知道本方法的提交,最终结果必须由真正观察到它的系统来证明。
来源
- https://www.ietf.org/archive/id/draft-ietf-jmap-conditional-00.txt
- https://www.ietf.org/archive/id/draft-ietf-jmap-conditional-00.html
- https://www.ietf.org/archive/id/draft-ietf-jmap-conditional-00.xml
- https://datatracker.ietf.org/doc/draft-ietf-jmap-conditional/
- https://datatracker.ietf.org/doc/draft-ietf-jmap-conditional/history/
- https://datatracker.ietf.org/doc/draft-ietf-jmap-conditional/references/
- https://datatracker.ietf.org/api/v1/doc/document/draft-ietf-jmap-conditional/
- https://www.ietf.org/archive/id/draft-gondwana-jmap-conditional-00.txt
- https://www.ietf.org/archive/id/draft-ietf-jmap-filenode-14.txt
- https://www.rfc-editor.org/rfc/rfc8620.txt
- https://www.rfc-editor.org/rfc/rfc8620.html
- https://www.rfc-editor.org/rfc/rfc8620.json
- https://www.rfc-editor.org/rfc/rfc4918.txt
- https://www.rfc-editor.org/rfc/rfc9110.txt
- https://www.rfc-editor.org/rfc/rfc6902.txt
- https://www.rfc-editor.org/rfc/rfc8621.txt
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
