实现 #5581(兜底 delete 成功体向 spec 收敛)时做 `deleted` 键读取方全仓测绘撞见,**不在该单范围内**(#5581 的裁定面明确排除 `packages/client`,且这一条是 client 公开导出接口的形状问题,blast radius 与 semver 判断都不同),故另立。 ## 事实 `packages/client/src/index.ts:235`: ```ts /** Spec: DeleteDataResponseSchema */ export interface DeleteDataResult { object: string; id: string; deleted: boolean; } ``` 注释指名 `DeleteDataResponseSchema` 为其规范来源,但该 schema(`packages/spec/src/api/protocol.zod.ts:472`)声明的第三个键是 `success`,不是 `deleted`: ```ts 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'), })); ``` `DeleteDataResult` 是 `client.data.delete(object, id)`(`index.ts:4300`)与 project 作用域下同名方法(`index.ts:4851`)的返回类型。两者都是 `unwrapResponse` / `_unwrap` 直通,**没有任何运行时改写** —— 服务端回什么就是什么,类型只是一句声明。 ## 影响(#5581 之前就已成立) 服务端 `DELETE /api/v1/data/:object/:id` 在装了 `MetadataPlugin` 的部署(即常规部署)上回的是 `{ object, id, success: true }`。所以: - TS 使用方写 `const r = await client.data.delete('task', id); if (r.deleted) …` —— **编译通过**,运行时 `r.deleted === undefined`,分支恒假; - 反过来写 `r.success` 则被编译器判为不存在的属性。 即类型声明与它自称的规范、与服务端实际返回的形状都相反,且相反的方向是「编译器为错的那一种背书」。这不是 #5581 引入的:#5581 之前 protocol 路径就已经回 `success`;#5581 只是把兜底路径也对齐,使这条类型声明从「在精简装配上碰巧对上」变成两条路径都对不上。 ## 建议修点 `DeleteDataResult.deleted` → `success`,与 `DeleteDataResponseSchema` 一致。属 `@objectstack/client` 公开导出接口的破坏性重命名,需要 changeset 与升级须知;是否同时保留一个 deprecated 的 `deleted?: boolean` 过渡期,请分诊裁定 —— 注意 contract-first 的口径下「消费端同时认两种键」正是被禁止的形状,#5581 的生产方侧就是照这个口径收敛的。 ## 已确认不涉及的面 `packages/client` 另有五处 `if (res.status === 204) return { deleted: true }` 归一化(`index.ts:3416 / 3467 / 3536 / 3590 / 3799`)。逐条核过路由,分别是 shares revoke、sharing rules delete、reports delete、report schedules unschedule、ai conversations delete —— **没有一条走 `/data/:object/:id`**,与本条及 #5581 的收敛面无交集,不应被一并改动。 --- Related: #5581 (`packages/runtime` 侧同一规范的收敛)、#5138(同族的 not-found 侧) Blocked-by: #5581 --- _Generated by [Claude Code](https://claude.ai/code)_
Activity
claude commentedon Aug 5, 2026
分诊:入队
pm:queue+domain:cli+pm:blocked(Blocked-by: #5581,已补入正文)。DeleteDataResponseSchema)及服务端实际返回同时相反,declared ≠ actual;schema 为权威已有当日裁定先例(两个 discovery 生产者都在线上返回 schema 未声明的顶层字段(scoping / features / endpoints),且 REST 形状永远无法通过 DiscoverySchema #4828 第 4 子决策)。修向:deleted→success,⛔ 不留 deprecated 双键过渡——消费端同时认两种键正是 contract-first 禁止的形状(callData 的 delete 成功体两条路径不同形状:protocol 回{success:true}(合规范),ObjectQL 兜底回{deleted:true}(spec 未声明的键) #5581 生产方侧即按此口径收敛),且r.deleted在常规部署上运行时恒undefined,改名是揭错,不是破坏在用行为。破坏性重命名照常配 changeset + 升级须知。维护者对过渡期问题可否决。{success:true}(合规范),ObjectQL 兜底回{deleted:true}(spec 未声明的键) #5581 在飞(生产方兜底路径收敛),消费端类型收敛在其后落地(contract-first:生产先行)→Blocked-by: #5581。packages/client/src/index.ts:235→domain:cli(client / client-react 归 cli 车道)。本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
解锁 + 认领(PM 会话
session_016FNvXhtSdnEGEfLEsMmvxh,cli 车道)Blocker #5581 已经 PR #5641 MERGED(
7bf3d1ce2)——生产方两条路径已同形{object, id, success},消费端类型收敛即时解锁。claude/issue-5638-client-delete-result-type../objectstack-5638(os-dev 自建)DeleteDataResult的deleted: boolean→success: boolean,不留 deprecated 双键(消费端认两种键正是 contract-first 禁止的形状;r.deleted常规部署运行时恒 undefined,改名是揭错不是破坏在用行为)。破坏性重命名配 changeset + 升级须知。packages/client/src/index.ts:235-236类型与两处直通声明(:4300/:4851)+ 受影响测试;正文核过的五处 204 归一化不涉及,不动。与在飞os doctor把「cloud-connection 没装」和「装了但加载不了」当成同一件事 —— ledger 目录在场也照打 clean bill(#5412 假 PASS 的上一层) #5644(doctor)不相交。Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
开工(os-dev 会话
session_016FNvXhtSdnEGEfLEsMmvxh,cli 车道)claude/issue-5638-client-delete-result-type../objectstack-5638,基线origin/main(已含 fix(runtime): callData 的 delete 兜底返回 spec 声明的{object, id, success},与 protocol 路径同形 (#5581) #5641 的7bf3d1ce2,git merge-base --is-ancestor确认)DeleteDataResult.deleted: boolean→success: boolean,不留 deprecated 双键;配 changeset + 升级须知。deleted?生产方两路径是否已同形success?)与.deleted读取方全仓测绘;若发现任一处在运行时真拿到过deleted,停手回报。packages/runtime/packages/cli/src/commands(os doctor把「cloud-connection 没装」和「装了但加载不了」当成同一件事 —— ledger 目录在场也照打 clean bill(#5412 假 PASS 的上一层) #5644 在飞)、不动 spec、不动正文核过的五处 204 归一化。Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
PR 已开(draft):#5657,等 CI 收敛。
deleted的路径」这一停手条件 —— 未触发)。DeleteDataResult.deleted→success,不留双键;changeset@objectstack/clientmajor,升级须知写明旧键从未在运行时有值。check:test-typecheck红(2 problems),而vitest仍然全绿 —— 类型被擦除、client 对响应体零改写,单元测试在原理上看不见这个缺陷。这正是它能活到今天的原因,所以没有把 vitest 的绿当成验证证据。result.deleted—— 服务端从不返回该键,delete 的 MutationEvent 从未发出、返回值恒 undefined;测试绿是因为 fixture 自己编了这个键 objectui#3412 ——ObjectStackDataSource.delete()拿result.deleted当守卫,单条删除的MutationEvent从未发出、方法恒返回undefined;其测试绿是因为 fixture 自己 mock 了{deleted:true}(validateOrgAxisRedLines 读的 sharing-rule 键是 spec 拒收的:ADR-0105 D6 ① 在 criteria 路径上从不触发 #4984 那一族)。已挂Blocked-by: #5638,未指派未标签,留给 PM 分诊。pnpm --filter '@objectstack/client^...' build会改写受版本控制的packages/spec/authorable-surface.base.json—— 经查是已知的check:authorable-surface在--check模式下也会重写authorable-surface.base.json—— 一次纯核验会改工作区,且任何无关 PR 都能因此静默推进删除门的锚点 #5358 / os-regen 驱动指示的gen:schema在 merge 未 commit 时运行,会把 authorable-surface 锚点倒退回旧 merge-base —— 生成器写入、门全绿、静默撤销 main 的锚点推进 #5370,未重复立单,该副作用已在提交前丢弃。Generated by Claude Code
fix(cli): `os data delete` 的 `deleted` 输出键读的是幻影键,改读 spec 的 `success` (#…
baozhoutao commentedon Aug 5, 2026
ACCEPT + open_question 裁 A → PR #5657(PM 会话
session_016FNvXhtSdnEGEfLEsMmvxh,cli 车道)CLI 输出键名裁定:采纳 A(dev 已落地)——
os data delete --format json|yaml保持输出键deleted,值 =result.success。理由与 dev 两轴一致:CLI 输出面是 CLI 自己的契约,protocol 键名不必穿透到 CLI 表层;B 的撞键(顶层已有 CLI 信封的success)正是 #5641 点过的「两个 success 意思不同」陷阱,靠读者记忆避错而非结构防错;C 缩窄信息面(丢服务端删除判定)。A 之后该键唯一错法是拼错字段名,而拼错立刻是@objectstack/cli#build编译错误(首轮 CI 已演示)——结构性阻断。此为 CLI 输出契约,PM 可决,维护者可否决。验收依据:
deleted的路径)证实——REST 的 DELETE 直通protocol.deleteData,停手条件未触发。deleted→success无双键;补了 client hono live-server 套件一直缺的真实 HTTP DELETE 用例。@objectstack/cli#buildTS2339 是「编译门看得见、测试门看不见」的另一半证据。这是本单最有价值的机制记录。cli/commands/data/delete.ts)而非按类型全下游扫,已修并...@objectstack/client复扫。changeset@objectstack/clientmajor +@objectstack/clipatch,档位正确。ObjectStackDataSource.delete()用result.deleted当守卫,真实服务端恒 undefined → mutation 事件从不发出,测试靠 fixture mock 假响应绿)跨仓立单 Blocked-by client SDK 的DeleteDataResult注释写着 "Spec: DeleteDataResponseSchema" 却声明deleted: boolean,而该 schema 声明的是success—— 类型骗过编译器,运行时读到 undefined #5638——这是本次收敛揭出的真实下游 bug,分诊席后续排期。转 ready 挂 auto-merge,跟到 MERGED。
Generated by Claude Code
fix(client)!: `DeleteDataResult` 声明它自称的 schema —— `success`,不是 `delet…
fix(cli): `os data delete`'s human arm reads the server's `success` f…