Skip to content

callData 的 delete 成功体两条路径不同形状:protocol 回 {success:true}(合规范),ObjectQL 兜底回 {deleted:true}(spec 未声明的键) #5581

Closed

Description

@baozhoutao

观察类(finding):与 #5138 同样的可达性 —— 装了 MetadataPlugin(@objectstack/metadata-protocol,注册 protocol 槽)的部署走 protocol 优先路径,碰不到兜底。记录在案交分诊定级,不自行判轻重。

实现 #5138(PR 见下)时在同一函数里撞见,不在该单范围内(#5138 收敛的是「记录不存在」的答案,这一条是「删除成功」的答案),故另立。

事实

packages/runtime/src/action-execution.ts 的 callData('delete', …) 两条路径回的成功体不是同一个形状:

路径 返回 与 spec
protocol(deleteData,packages/metadata-protocol/src/protocol.ts) { object, id, success: true } 合规范
ObjectQL 兜底(action-execution.ts,delete 分支末行) { object, id, deleted: true } success 缺失,deleted 未声明

规范只有一个:

packages/spec/src/api/protocol.zod.ts:472
export const DeleteDataResponseSchema = lazySchema(() => z.object({
  object: z.string().describe('Object name'),
  id: z.string().describe('Deleted record ID'),
  success: z.boolean().describe('Whether deletion succeeded'),
}));

实测(#5138 的复现 harness,同一行数据,唯一差别是注不注册 protocol 槽,main @ c11369013):

PROTOCOL del (hit): {"object":"task","id":"r1","success":true}
FALLBACK del (hit): {"object":"task","id":"r1","deleted":true}

还有一处文档面与规范相反

packages/runtime/src/domains/data.ts:102 的路由注释写的是:

// Spec: returns DeleteDataResponse = { object, id, deleted }

DeleteDataResponseSchema 声明的是 success,不是 deleted。所以这条注释把兜底的形状当成了规范 —— 下一个读它的人(或 agent)会照着 deleted 写消费端。同文件 87/94 行的 get/update 注释与各自的 schema 是对上的,只有 delete 这条对不上。

为什么值得记

不在 #5138 处置的原因

#5138 的验收面是「记录不存在时三分支给同一个 404 RECORD_NOT_FOUND」,其 PR 已按此收敛并显式保持 deleted: true 原样(有测试钉住成功路径未变)。本条要决定的是「删除成功的规范键是 success 还是 deleted」,是一次独立取舍,且会动到 spec 或所有 deleted 的读取方,不适合搭车。

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 5, 2026
  2. added
    pm:queueReady for the PM dispatch loop
    domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they land
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 5, 2026
  3. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    发现分诊轮判级:晋级 —— 摘 finding 换 pm:queue + domain:cli。

    • 理由:具体缺陷、落点明确 —— packages/runtime/src/action-execution.ts 的 callData delete 兜底与 protocol 路径({success:true},合 spec 声明)形状分叉,返回 spec 未声明的 {deleted:true};同一操作两种成功体是活体行为分歧,收敛方向明确(向 spec 声明形状对齐 + 两条路径同形 pin)。packages/runtime 归 cli 车道。
    • 认领提示:packages/client 对 204 空体也自造 {deleted: true}(client/src/index.ts:3416 等四处,rc.2 变更记录在案)—— 先确认契约权威侧(spec 的 {success:true} vs client 的 204 归一)再动手;若牵动 client 公开返回形状,回分诊上报,勿静默扩面。

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  4. self-assigned this
    on Aug 5, 2026
  5. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    ContributorAuthor

    认领 + 方向裁定(PM 会话 session_016FNvXhtSdnEGEfLEsMmvxh,cli 车道;#5615 热修已落,action-execution.ts 面解锁)

    裁定(restore-invariant,带 veto window):兜底向 spec 声明形状收敛——DeleteDataResponseSchema(protocol.zod.ts:472)现物是 {object, id, success},protocol 路径已合规,兜底的 deleted: true 改为 success: true;domains/data.ts:102 那条与 spec 相反的注释一并改正。两条路径同形以测试钉住(照 #5138/PR #5584 的跨路径同一性断言先例)。


    Generated by Claude Code

  6. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    ContributorAuthor

    开工(os-dev,session session_016FNvXhtSdnEGEfLEsMmvxh 派发,cli 车道)

    • 分支:claude/issue-5581-delete-success-shape
    • 工作树:../objectstack-5581(基于 origin/main,含 hotfix(runtime): route #5138 test engine doubles through assertEngineDeleteDispatch #5615)
    • 按 PM 裁定执行 restore-invariant:兜底 delete 成功体 deleted: true → success: true,domains/data.ts 注释改正,两条路径同形以测试钉住。
    • 动手前先做 deleted 键读取方全仓测绘 + packages/client 204 归一化的消费关系测绘;若收敛牵动 client 公开返回形状则停手回报。

    Generated by Claude Code

  7. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    ContributorAuthor

    draft PR 已开:#5641(等 CI 收敛后交报告)

    前提复核成立,且裁定方向额外拿到一条独立佐证:公开 HTTP 文档 content/docs/protocol/kernel/http-protocol.mdx:649 一直写的就是 success(含 {"object","id","success":true} 示例体)。spec、protocol 实现、公开文档三者一致,兜底是唯一偏离方。

    两条警示的结论:

    1. deleted 读取方测绘 —— 无回归。全仓(packages/ / examples/ / apps/ / packages/qa 含 dogfood 与 http-conformance)没有任何消费方从 /data delete 响应体读 .deleted;三个 callData('delete') 调用点(domains/data.ts / domains/mcp.ts 的 remove / endpoint-executor.ts:434)全是直通。domains/automation.ts:472 那条 {name, deleted:true} 是 automation flow 注销面,protocol.delete-many.test.ts 那条是 engine.delete 的返回,两者都与本单无关,未动。

    2. client 归一化与本单面无交集。五处 204 归一化(index.ts 3416/3467/3536/3590/3799)逐条核过路由 —— shares revoke、sharing rules delete、reports delete、report schedules unschedule、ai conversations delete,没有一条走 /data/:object/:id;client.data.delete 走 200 + JSON 体,不经过 204 归一化。故未牵动 client 公开返回形状,无需停手扩面。

    测绘中另发现一条界外缺陷,查重(含 closed)无果后已无标签立单 #5638:client 的 DeleteDataResult 自称 Spec: DeleteDataResponseSchema 却声明 deleted: boolean,是纯直通类型声明,在装了 protocol 插件的常规部署上此前就已经是错的(TS 写 r.deleted 编译通过、运行时恒 undefined)。属公开导出接口的破坏性重命名,故未搭车。

    反向验证方向先判后跑,与预判一致:兜底改回 deleted: true → fallback 侧 6 条断言全红,protocol 侧 parse 保持绿(6 failed | 25 passed)。


    Generated by Claude Code

  8. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    ContributorAuthor

    ACCEPT → PR #5641(PM 会话 session_016FNvXhtSdnEGEfLEsMmvxh,cli 车道)

    验收依据:

    • 收敛方向获得第三方佐证:http-protocol.mdx:649 的公开文档一直声明 success(含示例体)——spec、protocol 实现、公开文档三者一致,兜底是唯一偏离方,「无第二种读法」。
    • 三层断言设计到位:两路径各自 safeParse + 跨路径逐字段相等 + 显式断言不含 deleted 残留键——第三层是必要的,z.object 剥未知键,单靠 parse 抓不到残留;两个消费面(真 dispatcher 的 /data + 声明式端点执行器)都钉了,且区分了 body.success(信封 ok)与 body.data.success(删除发生)两个事实。
    • 分诊的 client 警示正确执行:未扩面动 client,但测绘发现其 DeleteDataResult 类型自称对齐 schema 却声明 deleted: boolean(常规部署上此前就是错的类型)——以 client SDK 的 DeleteDataResult 注释写着 "Spec: DeleteDataResponseSchema" 却声明 deleted: boolean,而该 schema 声明的是 success —— 类型骗过编译器,运行时读到 undefined #5638 独立立单(公开导出接口重命名,blast radius 与 semver 另判),不搭车,正确。
    • 反向验证恰红预判 6 条、protocol 侧保持绿;runtime 1428 + mcp 83 全绿;os-regen 基线文件按其自述退回、净 diff 6 文件;CI 23 checks 零失败含 ESLint success,收敛后才交报告。

    转 ready 挂 auto-merge,跟到 MERGED。


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landpm:dispatchedDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loop

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions