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

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions