Skip to content

record-change flow trigger 在 predicate 批量写上:previous 不绑定、record 只是裸 payload —— 官方文档与 showcase 正在教的 transition 起始条件在批量写上不成立 #4862

Description

@os-zhuang

来源

#4775(hook condition fail loud)落地过程中,为核实 B1 错误文案能不能把「改用 record-change flow trigger」写成出路而做的实测。核实结论是不能,#4775 因此没有在错误信息里指这条路(维护者定的硬防线:不允许在修 declared ≠ enforced 的 PR 里于错误信息中再造一个同类缺陷)。核实过程本身暴露出这条独立缺陷,按 PD #10 单独记录。

#4800 相邻但不是同一件事:#4800 是「批量写上 hook 要不要按行触发」的设计卡;本条是 record-change flow trigger 这一层,在批量写上交付给 flow 起始条件的上下文本身就是残缺的。

事实(实测,非推断)

对一次 predicate 批量写(multi: true,无 id):

  1. 引擎只在单 id 分支赋值 previous packages/objectql/src/engine.ts:4888if (priorRecord) hookContext.previous = ...,而 priorRecord 仅在 if (hookContext.input.id) 分支内被 fetch;批量分支始终为 null
  2. plugin-audit 的 __previous 兜底也不覆盖批量。 packages/plugins/plugin-audit/src/audit-writers.ts:425:if (!id) return; // bulk update/delete — too costly to snapshot every row here
  3. flow trigger 读的正是这两个。 packages/triggers/trigger-record-change/src/record-change-trigger.ts:291-293:
    const previous = (ctx.previous ...) ?? ((ctx as ...).__previous ?? undefined);
    → 批量写上 previous 恒为 undefined
  4. record 在批量写上也不是行。 引擎批量分支 result = await driver.updateMany(...) 返回的是受影响行数(number)。buildContextafter && typeof after === 'object' 因此为 false,record 退化成 inputDoc —— 即本次写入的裸 payload,而不是任何一行的状态。
  5. hook 只触发一次,所以即使匹配了 N 行,flow 也只被评估一次。

为什么这条要单独立单

这不是一个理论缺口 —— 官方文档与 showcase 正在教的写法,恰好就落在这一格上:

  • content/docs/data-modeling/formulas.mdxskills/objectstack-formula/SKILL.md §5 教的 transition 写法是 previous.x != ... && record.x == ...;
  • examples/app-showcase/src/automation/flows/index.ts 里至少 10 条 flow 的起始条件是 status == "done" && previous.status != "done" 这个形状(第 39/317/424/671/780/896/976/1064/1148/1463 行等)。

对一次批量更新(例如把一批 task 一次性置为 done),这些 flow 的起始条件面对的是「previous 未绑定 + record 只有 payload」:该触发的自动化要么不触发,要么按一条并不存在的『记录』触发一次,而且没有任何东西会说出来。审计/通知类 flow 的缺失是不可见的缺失。

#4775 的对照值得注意:hook condition 在这一格现在会响亮地失败(B1 专门诊断);而 flow trigger 这一格依然是静默的。同一个平台对同一个物理限制给了两种相反的处理。

可选方向(未拍板,留给维护者)

倾向 A,并与 #4800 一起定方向;若 A 成本过高,B 比 C 更符合本仓已经选定的「declared = enforced」路线。

关联

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions