Part of #5225 (showcase 清扫流从未删过记录 —— 该单的根因,按跨车道协议转 spec 车道;发现与全部实测证据来自其 os-dev 的 needs_decision 报告,PM 转录)。
事实(真实 boot + built spec 的 safeParse 实测,origin/main @ ccba1bb )
PM 裁定(两轴分析由 #5225 的 dev 给出,PM 附议;留否决窗口 —— 维护者可否决,不等批准)
取 A:在 spec 给两个节点 config 声明批量意图键(一次命名,两节点共用),CRUD 执行器在作者声明后传 options.multi;B 与 C 否决。
长远轴:A 是唯一契约先行的形态 —— 破坏性批量写的安全要求在 authoring 时可见,而不是在旗舰示例上以运行时失败浮现;B 在 flow 层伪造「作者声明过批量」,把引擎刻意竖起的护栏溶解掉,并分叉出第二份事实契约。
防 AI 轴:A 最强 —— 破坏性批量删除需要一个显式、可 grep 的声明,AI 只写 filter 会得到点名拒绝而非静默 no-op;B 是该轴上最坏选项 :AI 元数据最常见错误就是 filter 字段名拼错,B 把它从「引擎拒绝」升级成「全表删除」(Flow node filters silently blank date macros: the template engine consumes {…} before the query engine sees it #3810 只防模板插值失败的条件擦除,不防语法合法、语义错误的字面字段名);C(示例改 get→loop→逐 id 删)是 PD [WIP] Fix error in step four of the action run #5 的 workaround、PD chore: version packages #10 的反面,且撞上 flow lint rules never descend into a loop body — the whole family is blind to nested nodes (8 real inert conditions shipped past flow-inert-node-condition) #5383 (flow lint 不进 loop 体),等于教 AI 一个 lint 盲区里的 N+1 删除惯用法。
两节点必须同改 :拆开必然让同一个概念在两个 CRUD 写入器上长出两个名字与语义(PD Add comprehensive test suite for Zod schema validation #12 的「N 方言」结局),且生成面翻倍。
时序注:这是恢复宣称能力的加性键 ,非 breaking,不占 v17 硬窗口;spec 车道按自身节奏排(authorable-surface / docs / api-surface 生成物随行)。
完成判据
关联:#5225 (现场与验收锚)、#5197 (检测器盲点)、#5383 (loop lint 盲区)、#3810 、PD #5 /#10 /#12 。
Part of #5225(showcase 清扫流从未删过记录 —— 该单的根因,按跨车道协议转 spec 车道;发现与全部实测证据来自其 os-dev 的 needs_decision 报告,PM 转录)。
事实(真实 boot + built spec 的 safeParse 实测,origin/main @ ccba1bb)
DeleteRecordConfigSchema(packages/spec/src/automation/builtin-node-config.zod.ts:242)是strictObject,只声明objectName与filter两键;multi/options.multi/bulk/all逐一实测被unrecognized_keys拒绝。options.multi。引擎契约(packages/objectql/src/engine-delete-dispatch.ts):标量where.id→ 按 id;否则options.multi为真 → deleteMany;否则抛Delete requires an ID or options.multi=true。name: 'Delete Records'/description: 'Delete records matching a filter.';writtenRowCount的文档与 Flow node filters silently blank date macros: the template engine consumes{…}before the query engine sees it #3810 擦除防护的前提都以「谓词 delete_record 会到达 deleteMany」为设计意图 —— declared ≠ enforced。update_record同病(engine.ts:5403同款抛错,UpdateRecordConfigSchema同样无批量键);showcase 三处update_record全用filter: { id: … }所以被掩盖。run-summary.test.ts:405内联 fake 接受真引擎拒绝的谓词删除,且不在 engine-double 基线内(已评论至 os-dev 派发词/定义可加一行:测试假引擎的 delete() 必须路由 assertEngineDeleteDispatch —— 同一门禁一日两红(#5173、#5192) #5197,检测器盲点)。PM 裁定(两轴分析由 #5225 的 dev 给出,PM 附议;留否决窗口 —— 维护者可否决,不等批准)
取 A:在 spec 给两个节点 config 声明批量意图键(一次命名,两节点共用),CRUD 执行器在作者声明后传
options.multi;B 与 C 否决。{…}before the query engine sees it #3810 只防模板插值失败的条件擦除,不防语法合法、语义错误的字面字段名);C(示例改 get→loop→逐 id 删)是 PD [WIP] Fix error in step four of the action run #5 的 workaround、PD chore: version packages #10 的反面,且撞上 flow lint rules never descend into aloopbody — the whole family is blind to nested nodes (8 real inert conditions shipped pastflow-inert-node-condition) #5383(flow lint 不进 loop 体),等于教 AI 一个 lint 盲区里的 N+1 删除惯用法。完成判据
options.multi;showcase_inquiry_purge清扫流从来没删掉过任何记录 —— delete_record 节点每次都失败(Delete requires an ID or options.multi=true) #5225(showcase 示例)在此单落地后以声明批量意图收尾(该单挂 Blocked-by 本单);关联:#5225(现场与验收锚)、#5197(检测器盲点)、#5383(loop lint 盲区)、#3810、PD #5/#10/#12。