Skip to content

fix(runtime): callData 的 delete 兜底返回 spec 声明的 {object, id, success},与 protocol 路径同形 (#5581) - #5641

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-5581-delete-success-shape
Aug 5, 2026
Merged

fix(runtime): callData 的 delete 兜底返回 spec 声明的 {object, id, success},与 protocol 路径同形 (#5581)#5641
baozhoutao merged 2 commits into
mainfrom
claude/issue-5581-delete-success-shape

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes #5581

前提复核:成立

callData 是 protocol 优先 + ObjectQL 兜底,两条路径对「删除成功」给的是两种形状:

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

规范只有一个 —— DeleteDataResponseSchema(packages/spec/src/api/protocol.zod.ts:472)声明 { object, id, success },deleted 从未被任何 schema 声明。

裁定方向(向 spec 收敛)在实现中额外得到一条独立佐证:公开 HTTP 文档一直就写的是 successcontent/docs/protocol/kernel/http-protocol.mdx:649 明文 “Delete returns a DeleteDataResponse: the object name, the record id, and a success flag”,示例体也是 {"object","id","success":true}。所以 spec、protocol 实现、公开文档三者一致,兜底是唯一的偏离方,收敛方向没有第二种读法。

改动

  1. packages/runtime/src/action-execution.ts —— 兜底 delete 分支末行 deleted: truesuccess: true。删除行为本身(含 callData 的 ObjectQL 兜底路径对「记录不存在」给三种不同答案(get→200 null / update→500 / delete→200 deleted:true) #5138 落的「记录不存在 → 404 RECORD_NOT_FOUND 且不发出写」)一字未动,只改成功体这一个键。
  2. packages/runtime/src/domains/data.ts —— 那条 // Spec: returns DeleteDataResponse = { object, id, deleted } 改正为 success。这是该文件 get/update/delete 三条路由注释里唯一与自己的 schema 对不上的一条(87/94 两条本来就对),它把兜底的off-spec形状当成了规范。
  3. 测试(action-execution-calldata-not-found.test.ts,fix(runtime): callData 的 ObjectQL 兜底对「记录不存在」统一答 404 RECORD_NOT_FOUND (#5138) #5584 落的同族) —— 新增 #5581 describe 与两个消费面的成功用例;engine double 的 assertEngineDeleteDispatch 接法(hotfix(runtime): route #5138 test engine doubles through assertEngineDeleteDispatch #5615)原样保留未回退。
  4. packages/mcp 两处 test double —— 模拟 callData('delete', …) 返回值的 remove() 同步改口径。无断言读该键,纯粹是不给下一个读者留一份生产方已不再返回的形状。

测试怎么钉的

z.object 会剥掉未知键,所以单靠 schema parse 抓不到残留的 deleted;反过来只比较两条路径也会在「两边一起漂」时保持绿。因此三种断言都下了:

消费面两个都覆盖:/data 走真实 HttpDispatcher 的 DELETE 200 体,以及声明式端点执行器(#5092/#5136)。后者顺带钉住了两个 success 是不同的事实:body.success 是 HTTP 信封的 ok 标志(successAnswer),body.data.success 才是 DeleteDataResponse 的「删除发生了」—— 这个形状最容易被读串,所以两个都不留作隐含。

反向验证(方向先判后跑,结果与预判一致)

预判:兜底改回 deleted: true 应当,且只红 fallback 侧 6 条;此处无 ?? 链、不涉及 schema 具名拒绝,兜底是字面量构造,不存在 #5018 那类反转风险。

实测:

× a real delete still deletes, and answers the SPEC’s `success: true`
× the fallback’s success body parses as DeleteDataResponse
✓ the protocol’s success body parses as DeleteDataResponse      ← 预判保持绿
× fallback success body === protocol success body, field for field
× neither path carries the undeclared `deleted` key
× [#5581] DELETE on a row that exists answers 200 with the spec’s `success` body
× [#5581] a declared DELETE endpoint carries the spec’s `success` body too
 Tests  6 failed | 25 passed (31)

deleted 读取方测绘(本单最大回归风险,先测后动)

全仓(packages/ / examples/ / apps/ / packages/qa,含 dogfood 与 http-conformance)搜 .deleted 读取方,没有任何消费方从 /data delete 响应体里读这个键:

  • domains/data.ts / domains/mcp.tsremove / endpoint-executor.ts:434 —— 三个 callData('delete') 调用点全是直通,不读键;
  • packages/qa 里 17 处 DELETE /data/... 只断言状态码与库内副作用,不读响应体的 deleted;
  • domains/automation.ts:472{name, deleted:true}http-dispatcher.test.ts:295spec/api/automation-api.zod.test.ts —— 都是 automation flow 注销面,与本单无关,未动;
  • protocol.delete-many.test.ts:18{deleted:true}engine.delete 的返回(IDataEngine.deletePromise< any >),不是 callData 的成功体,未动。

分诊警示的结论:client 归一化与本单面无交集

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。本单的 delete 面(client.data.delete,index.ts:4300 / 4851)走的是 200 + JSON 体,不经过任何 204 归一化。故收敛不牵动 client 公开返回形状,未扩面。

测绘中另发现一条界外缺陷并已立单:clientDeleteDataResult 注释自称 Spec: DeleteDataResponseSchema 却声明 deleted: boolean —— 该类型是纯直通声明,在装了 protocol 插件的常规部署上此前就已经是错的(TS 使用方写 r.deleted 编译通过、运行时恒 undefined)。属 @objectstack/client 公开导出接口的破坏性重命名,blast radius 与 semver 判断都不同,故未搭车 → #5638

验证

  • pnpm --filter @objectstack/runtime test:97 files / 1428 tests 全绿
  • pnpm --filter @objectstack/runtime typecheck:绿(tsc --noEmit 无输出)
  • pnpm --filter @objectstack/mcp test:8 files / 83 tests 绿;typecheck 绿
  • node scripts/check-nul-bytes.mjs:OK;另做 grep -naP 控制字符自扫,改动文件全净

changeset:@objectstack/runtime patch,行为变化写了升级须知(仅影响未装 MetadataPlugin 的精简装配,DELETE /data/:object/:id、MCP delete_record、声明式 delete 端点三个面的成功体键由 deleted 改为 success)。未触碰 content/docs/releases/、spec、packages/metadata-protocolpackages/client


🤖 Generated with Claude Code

https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh


Generated by Claude Code

…5581)

`callData` 是 protocol 优先 + ObjectQL 兜底,两条路径对「删除成功」给的是两种
形状:protocol 回 `{object,id,success:true}`(合 `DeleteDataResponseSchema`),
兜底回 `{object,id,deleted:true}` —— `success` 缺失,`deleted` 从未被任何 schema
声明。按 spec 写的客户端在未注册 `protocol` 槽的精简装配上,会从一个 HTTP 200 里
读到 `success === undefined`,而调用方无从分辨自己走的是哪条路径。

规范只有一个,且 protocol 路径与公开 HTTP 文档都已站在 `success` 一侧,所以兜底
是唯一的偏离方。消费端兼容 `success ?? deleted` 两种拼写正是 contract-first 禁止
的形状,故修在生产方。

- `action-execution.ts` delete 兜底末行 `deleted: true` → `success: true`
- `domains/data.ts` 那条把兜底形状写成规范的注释改正(同文件 get/update 两条
  本来就是对的,只有 delete 这条对不上)
- 测试钉住两条路径同形:schema safeParse + 跨路径逐字段相等 + 显式断言不带
  未声明的 `deleted` 键(`z.object` 会剥掉未知键,单靠 parse 抓不到残留),
  并覆盖 `/data` 与声明式端点执行器两个消费面
- `packages/mcp` 两处模拟 `callData('delete')` 的 test double 同步改口径

反向验证:把兜底改回 `deleted: true`,新增/更新的 6 条断言全红(fallback 侧),
protocol 侧 parse 仍绿 —— 与动手前预判的方向一致。

Fixes #5581

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 5, 2026 9:29pm

Request Review

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Aug 5, 2026
上一提交的 `git add -A` 扫进了 `packages/spec/authorable-surface.base.json`
—— 那是本地跑 `pnpm --filter ... build` 时 `gen:schema` 顺带重生成的产物
(把 `baseRev` 重锚到本工作树的基点,并带进 main 上此后新增的
`EmailServiceConfig` 三个键),与本单毫无关系。

该文件是 #4650/#5235 删除门禁的锚点,按其自述「只应由 gen:schema 从 git 解析
出的基线写入,绝不由被检查的这次构建写入」,PR 里不该出现它的改动。退回基点
版本。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/runtime, @objectstack/spec.

115 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via packages/runtime, @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/runtime, packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/runtime, @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/runtime, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@baozhoutao
baozhoutao marked this pull request as ready for review August 5, 2026 21:43
@baozhoutao
baozhoutao added this pull request to the merge queue Aug 5, 2026
Merged via the queue into main with commit 7bf3d1c Aug 5, 2026
24 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-5581-delete-success-shape branch August 5, 2026 21:54
baozhoutao pushed a commit that referenced this pull request Aug 5, 2026
…5638)

CI 抓到的漏网消费方 —— 我的读取方测绘按派单枚举的路径(client 自身测试、
client-react、examples、docs)扫,没有覆盖 `packages/cli`,而
`packages/cli/src/commands/data/delete.ts:65/68` 正是 `DeleteDataResult` 在
仓内唯一的具名字段读取方,`@objectstack/cli#build` 因此红。

该处 `deleted: result.deleted` 恒为 `undefined`,`JSON.stringify` 会把
undefined 丢掉 —— 也就是说这个命令声明了很久的 `deleted` 键,在
`os data delete --format json` 的任何一次运行里**都没有出现过**。现改读
`result.success`。

输出键名保持 `deleted` 不变:它是本命令自己的输出键,不是 protocol 的键;
而同一个 payload 顶层的 `success` 表达的是另一件事(CLI 信封的「命令完成」)。
把两者拼成同一个名字正是 #5641 点过的 `body.success` / `body.data.success`
混淆风险。改名属输出契约决定,已在 PR 里交维护者裁定。

与 #5644 无交集:那单整单落在 `packages/cli/src/commands/doctor.ts`。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 6, 2026
…ed` (objectstack-ai#5638) (objectstack-ai#5657)

* fix(client)!: `DeleteDataResult` 声明它自称的 schema —— `success`,不是 `deleted` (objectstack-ai#5638)

`DeleteDataResult` 顶着 `Spec: DeleteDataResponseSchema` 的注释,却把该 schema
的 `success` 声明成了 `deleted`。两个 delete 面(`client.data.delete` 与
project 作用域下的同名方法)都是 `unwrapResponse` / `_unwrap` 纯直通,这个接口
是对服务端响应体的一句声明、而非改写,所以声明必须是 schema 的那一句。

`deleted` 从未被任何 schema 声明、也从未被 `/data/:object/:id` 的任何服务端路径
返回:objectstack-ai#5581 / PR objectstack-ai#5641 之后 protocol 与 ObjectQL 兜底两条路径同形返回
`{object, id, success}`。因此 `r.deleted` 编译通过、运行时恒 `undefined` ——
改名是揭错,不是破坏在用行为。不留 deprecated 双键(消费端同时认两种拼写正是
contract-first 禁止的形状)。

- 新增 `data-delete-result-shape.test.ts`:类型层钉 `DeleteDataResult` 与 spec
  `DeleteDataResponse` 双向可赋值,加两个面的直通形状 + 「不合成 `success`」反钉。
- `client.hono.test.ts` 补上这套 live server 套件一直缺的 delete 用例:真实
  HTTP DELETE,读 `deleted.success`,并逐字断言键集(`z.object` 会剥未知键,
  单靠 parse 证不了没有残留的 `deleted`)。
- `data-service.mdx` 的 delete 返回值由「success marker / deleted ID payload」
  写实为 `{ object, id, success }`。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh

* fix(cli): `os data delete` 的 `deleted` 输出键读的是幻影键,改读 spec 的 `success` (objectstack-ai#5638)

CI 抓到的漏网消费方 —— 我的读取方测绘按派单枚举的路径(client 自身测试、
client-react、examples、docs)扫,没有覆盖 `packages/cli`,而
`packages/cli/src/commands/data/delete.ts:65/68` 正是 `DeleteDataResult` 在
仓内唯一的具名字段读取方,`@objectstack/cli#build` 因此红。

该处 `deleted: result.deleted` 恒为 `undefined`,`JSON.stringify` 会把
undefined 丢掉 —— 也就是说这个命令声明了很久的 `deleted` 键,在
`os data delete --format json` 的任何一次运行里**都没有出现过**。现改读
`result.success`。

输出键名保持 `deleted` 不变:它是本命令自己的输出键,不是 protocol 的键;
而同一个 payload 顶层的 `success` 表达的是另一件事(CLI 信封的「命令完成」)。
把两者拼成同一个名字正是 objectstack-ai#5641 点过的 `body.success` / `body.data.success`
混淆风险。改名属输出契约决定,已在 PR 里交维护者裁定。

与 objectstack-ai#5644 无交集:那单整单落在 `packages/cli/src/commands/doctor.ts`。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants