Skip to content

feat(spec)!: retire BatchOptions.validateOnly — a dry-run flag never implemented (#4052) - #4057

Merged
os-zhuang merged 2 commits into
mainfrom
claude/retire-batch-validateonly
Jul 30, 2026
Merged

feat(spec)!: retire BatchOptions.validateOnly — a dry-run flag never implemented (#4052)#4057
os-zhuang merged 2 commits into
mainfrom
claude/retire-batch-validateonly

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #4052。承 #3963 一线的"声明 ≠ 强制"(PD #10)清扫,收两处批量 API 的悬空契约。

主项:退役 BatchOptions.validateOnly

validateOnly 声明了 dry-run —— "validate records without persisting changes" —— 但运行时没有任何一处读它updateManyData / deleteManyData / batchData 全部无条件落库。一个调用者发 options.validateOnly: true预演一次改动,实际会被执行

对比同组三个兄弟(都真实生效),唯独它悬空:

选项 运行时消费点
atomic protocol.ts:3482 + rest-server.ts:6607
returnRecords protocol.ts:3501
continueOnError protocol.ts:3486,3610
validateOnly

这是 PD #10 里危害最高的一类:不是能力缺失,而是契约主动误导数据安全。选择退役而非仓促实现 —— 真正的 no-commit 批量有独立设计空间(rollback 下的 cascade/约束语义、逐行 would-succeed 的响应契约),应在有真实需求时单独立项做对。

破坏性变更

  • BatchOptionsSchemavalidateOnlyretiredKey() 墓碑:写它 → 解析报错并给出处方,而非静默剥除(ADR-0104 / ComputedFieldCacheSchema 是 2026-06 字段剪除留下的第二个孤儿(#3726 表格误记为「已清理」) #3733)。BatchOptions 类型该键变为 never
  • 纯 HTTP 请求体、从不进入 stack metadata,故登记为 protocol-18 迁移链 step18 的一条 semantic 记录(batch-options-validate-only-retired)—— 与 analytics-query-request-format-retired 同型:声明但从未实现、无存储可改写,是给 API 调用者的 semantic TODO 而非 stack conversion。
  • 重跑生成物:authorable-surface.json([RETIRED] 标记)、content/docs/references/api/{batch,protocol}.mdx;major changeset(仅 @objectstack/spec,随同一未发布的 major 18)。

顺带:#2 悬空文档引用

plugin-rest-api.zod.ts:918/createMany 路由声明 requestSchema: 'CreateManyRequestSchema' —— 从未有 schema 导出此名(真实契约是 protocol.zod.tsCreateManyDataRequestSchema)。该字符串运行时和 OpenAPI 生成都不消费,是文档字符串失真。改指向真实存在的 CreateManyDataRequestSchema

迁移

停止在 /batch/updateMany/deleteMany 上发送 options.validateOnly。它从不预演任何东西,删掉不改变任何行为。若确需"校验不落库",跟进 #4052 单独设计一个真正的 no-commit 预览。

测试

  • packages/spec 全绿:266 文件 / 6937 测试通过(含 batch.test.ts 新增的"退役键被拒并给出处方"断言、migrations 链重放、conversions)。
  • 生成物守门全绿:check:authorable-surface / check:api-surface(surface 无变化)/ check:spec-changes(major 18 未发布,不投影,与 feat(auth)!: retire the api.requireAuth opt-out — anonymous data access is always denied (#3963 step 2) #4043 一致)/ check:upgrade-guide / check:docs / check:skill-docs / check:skill-refs
  • 无下游消费者:全仓 validateOnly 仅出现在 batch.zod.tsbatch.test.ts,类型变 never 不影响任何构造点。

审阅指引

  • 契约核心:packages/spec/src/api/batch.zod.ts(retiredKey 墓碑)。
  • 退役登记:packages/spec/src/migrations/registry.tsstep18.semantic[]
  • ✨ Set up Copilot instructions #2:packages/spec/src/api/plugin-rest-api.zod.ts:918

🤖 Generated with Claude Code

https://claude.ai/code/session_01TzLE9cw4gZKNyPN2ZP4iTt


Generated by Claude Code

…implemented (#4052)

`BatchOptions.validateOnly` promised a dry-run ("validate records without
persisting changes") but no batch surface ever read it — updateManyData /
deleteManyData / batchData all persist regardless. A caller sending
`options.validateOnly: true` to PREVIEW a mutation got it executed: a declared
flag lying about a data-safety guarantee, the dangerous direction of "declared
≠ enforced" (PD #10).

Retired rather than half-implemented — a real no-commit batch has its own design
space (cascade / constraint semantics under rollback, a per-row would-succeed
response contract) and should be reintroduced deliberately, not back-filled to
match a promise nothing kept.

- Tombstone `validateOnly` with `retiredKey()` in BatchOptionsSchema so writing
  it fails with the prescription instead of being silently stripped (ADR-0104 /
  #3733). The BatchOptions type's key becomes `never`.
- HTTP-only (never stored in stack metadata), so recorded as a semantic
  migration on the protocol-18 chain step (`batch-options-validate-only-retired`)
  — a TODO for API callers, not a stack conversion.
- Regenerated authorable-surface, references docs; major changeset.

Also fixes a dangling doc reference: the /createMany route named
`requestSchema: 'CreateManyRequestSchema'`, a schema no module ever exported —
pointed at the real `CreateManyDataRequestSchema`.

Closes #4052.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TzLE9cw4gZKNyPN2ZP4iTt
@vercel

vercel Bot commented Jul 30, 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 Jul 30, 2026 7:22am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Jul 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

105 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 @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/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via 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 packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @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/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • 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/spec)
  • content/docs/kernel/cluster.mdx (via @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/permissions/authorization.mdx (via @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/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/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.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/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/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.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.

…#4052)

The docs-drift-check flagged four hand-written references that still presented
`validateOnly` as a working dry-run option — a `data-api` / `wire-format` batch
example, a `client-sdk` example, and the client-sdk Batch Options table row
("Dry-run mode — validate without persisting"). The key is retired and now 400s,
so these advertised a feature that no longer exists. Removed the key from the
three examples (fixing JSON trailing commas) and deleted the table row. The
generated references already carry the [REMOVED] prescription.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TzLE9cw4gZKNyPN2ZP4iTt
@os-zhuang
os-zhuang marked this pull request as ready for review July 30, 2026 07:38
@os-zhuang
os-zhuang merged commit ec796d5 into main Jul 30, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/retire-batch-validateonly branch July 30, 2026 07:38
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.

BatchOptions.validateOnly 声明了 dry-run 但从不实现 —— "预演"会真实落库(PD #10)

2 participants