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预演一次改动,实际会被执行

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

选项运行时消费点
atomicprotocol.ts:3482 + rest-server.ts:6607
returnRecordsprotocol.ts:3501
continueOnErrorprotocol.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

vercelBot commented Jul 30, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredJul 30, 2026 7:22am

Request Review

@github-actionsgithub-actionsBot 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 mainJul 30, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/retire-batch-validateonly branch July 30, 2026 07:38
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants

@os-zhuang@claude