Skip to content

beforeUpdate hook 在 multi:true 批量更新上拿不到 ctx.previous —— sys_fetch_previous_update 依赖 input.id;引擎已为校验取 priorRows 却不喂 hook(17.0.0-rc.2) #5574

Description

@yinlianghui

Part of objectstack-ai/hotcrm#779

现象

ctx.previousbeforeUpdate 上的唯一来源是内建 sys_fetch_previous_update(priority 5,object: '*',由 kernel 的 registerAuditHooks() 装载)——引擎主体只在 afterUpdate 分支里赋 hookContext.previous。而该内建第一行是:

if (hookCtx.input?.id && !hookCtx.previous) { … }

multi: true 的批量更新没有 input.id(目标由 where 圈定),内建取不到任何东西,ctx.previous 在批量路径上恒为 undefined

证据(pinned 17.0.0-rc.2,真 object schema + 真 hook + 内建忠实复刻,priority 299 探针 hook 观测)

=== single-row update (category only) ===
  [prev-fetch] input.id="crm_knowledge_article-…-1" previous=undefined
  [knowledge-hook sees] previous.status="published" input={"id":"…","category":"api"}
  => last_reviewed_at refreshed: true

=== MULTI update (category only, every published row) ===
  [prev-fetch] input.id=undefined previous=undefined
  [knowledge-hook sees] previous.status=undefined input={"category":"troubleshooting"}
  => last_reviewed_at refreshed: false

=== MULTI update writing last_reviewed_at: null ===
  [knowledge-hook sees] previous.status=undefined input={"last_reviewed_at":null}
  => A: last_reviewed_at=null
  => B: last_reviewed_at=null

应用侧影响(hotcrm 实测,详见 hotcrm#779)

hotcrm 有 15 个 hook 文件读 ctx.previous,几乎全用 previous?.x 可选链——批量路径上不抛错,而是静默空转或走进「当作首次转换」分支。已实测的两种后果:批量编辑不刷新知识文章的 last_reviewed_at(打破 stale 报表前提);批量写能把 readonly: truelast_reviewed_at 写成 null(单行路径 hook 会补戳盖掉,批量不会)。守卫语义的 hook 在批量路径上失效方向是放行(如 contract.hook 的 previous?.status === 'activated' 守卫)。

关键问题(设计定夺,不预设是 bug)

引擎在 needsPriorRecord(updateSchema) 为真时确实会取 priorRows(用于校验规则),只是没有把它喂给 hook。所以:

  1. 批量路径不供给 previous 是设计取舍还是遗漏?若是取舍,请在 hook 契约文档里写明「multi:true 上 ctx.previous 不可用」,应用侧好据此重排不变量(挪到校验规则/flow);
  2. 若愿意供给:per-row previous 的代价与语义(N 行 N 份、hook 逐行执行还是一次批量执行)需要平台定夺——priorRows 既然已取,喂给 hook 的增量成本可能有限。

应用侧的修复方向(hook 逐个显式化 vs 不变量搬家)取决于这个答案,hotcrm#779 因此 Blocked-by 本单。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions