Skip to content

写入载荷里的算子对象:text 型字段不做类型校验,{ title: { $in: [...] } } 原样写进库(number 型会响亮拒绝) #5922

Description

@baozhoutao

范围外发现,来自 #5748(PR #5919)的实测过程。属 PD #10 的范围内记录,未在该 PR 内修改 —— #5748 只定 update 的派发语义(哪个值算主键),这条是派发之后载荷值本身的校验缺口,是另一条轴。

事实(worktree @ origin/main + #5919,记录型 driver 驱动真实引擎,packages/objectql)

对象 task 声明 title: { type: 'text' }n: { type: 'number' }。同一个算子对象写进两个字段,结果不一样:

PROBE declared-text  by-id: {"err":null,
  "calls":[{"fn":"update","args":["rec_1",{"title":{"$in":["a","b"]}}]}]}
PROBE declared-number by-id: {"err":"n must be a number","calls":[]}
  • update('task', { n: { $gt: 3 } }, { where: { id: 'rec_1' } })响亮拒绝,n must be a number,驱动一次都没被碰到;
  • update('task', { title: { $in: ['a','b'] } }, { where: { id: 'rec_1' } })零告警,算子对象原样作为第三个参数交给 driver.update(object, 'rec_1', { title: { $in: […] } })

也就是说「值是个谓词而不是一个值」这件事,number 型能发现,text 型发现不了。

为什么值得记

  1. 同一个错误,两种命运,取决于字段类型。 作者(或 AI)把 filter 形状误写进 SET 载荷,在 number 字段上立刻拿到清晰错误,在 text 字段上安静落库 —— 之后这一行的 title 在 SQL 侧是序列化后的 {"$in":["a","b"]} 或驱动自定的什么东西,在读回时才以「数据变成了乱码」的形态出现,离原因很远。
  2. 可达性来自外部载荷,不是理论输入。 flow 的 update_record 把作者字段直接铺进 data(packages/services/service-automation/src/builtin/crud-nodes.ts:409 data.update(objectName, fields, { where: filter, multi })),REST 的 PATCH body 同理。「AI 生成的 filter builder 掉光条件后 emit 空组合子」是 flow-multi-write-unfiltered 不判空组合子:filter: { $and: [] } + multi: true 是整表删除,却零告警 —— 身份归约在 producer 侧有三份,lint 侧不该再抄第四份 #5659 记的那一格,「AI 把 filter 形状 emit 进 fields」是这一格 —— 宽松的消费者正是 AI 生成的元数据错误藏身的地方(PD Add comprehensive test suite for Zod schema validation #12)。
  3. ObjectQL.update 的 data.id 不做标量测试 —— 载荷里的算子对象被当成主键绑定,且盖过显式 options.multi: true #5748 之后 id 也进了这一格。 裁 A 落地后,非标量 data.id 不再当主键,于是它作为普通字段留在载荷里:update(o, { id: { $in: ['a','b'] }, title: 'x' }, { multi: true }) 现在走 updateMany,而交给驱动的 SET 载荷仍是 {"id":{"$in":["a","b"]},"title":"x"}(实测):
PROBE data.id operator + multi: {"err":null,
  "calls":[{"fn":"updateMany","args":[{"object":"task"},{"id":{"$in":["a","b"]},"title":"x"}]}]}

这不是 #5748 引入的新缺口 —— 任何 text 型字段今天都是这样;#5748 只是让 id 从「被当主键绑定」挪进了「和其他字段一样不被校验」。但它说明这一格现在多了一个主键形状的居民,所以一并记在这里。

建议方向(不预设结论)

需要先测一遍其它标量类型(select / date / boolean / lookup)各自今天是拒绝还是放行,再定 A 的边界 —— 我只实测了 textnumber 两种。

关联:#5748 / PR #5919(发现来源)、#5659(同族:谓词形状在另一处无告警)、#5240(零算子字段约束)、#5393(flow update_record 的载荷来源)。


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions