Skip to content

chore(spec): retire IDataEngine.batch? per ADR-0119 D3 — declared-but-unimplemented, zero callers #4618

Closed

Description

@os-zhuang

ADR-0119 D3 rules IDataEngine.batch? retired. This issue is the mechanical removal.

ADR renumbered. This issue originally cited ADR-0118. That record is now ADR-0119 (docs/adr/0119-plugin-reachable-transactions-and-honest-atomic-batch.md) — it merged the same day as an unrelated ADR-0118 (非用户 actor 的平台契约), and the earlier merge holds the number.

The finding

packages/spec/src/contracts/data-engine.ts:97-100:

/**
 * Batch Operations (Transactional)
 */
batch?(requests: DataEngineRequest[], options?: { transaction?: boolean }): Promise;
  • No engine implements it. ObjectQL has no batch method; there is no other engine in the tree.
  • No caller invokes it. DataEngineRequest is imported by exactly one non-spec file — the contract declaring it.
  • The doc comment is three words, specifying nothing about partial failure, ordering, cross-object refs, rollback scope, or what transaction: false means. Contrast the deliberate, evidenced optionality of its neighbours getDefaultDriverName?/getDriverByName? (:107-118), which name their implementer and their probing caller.
  • Its DataEngineRequestSchema union (packages/spec/src/data/data-engine.zod.ts:706-717) even nests batch requests recursively — a shape nobody designed against because nobody built it.
  • The only "test" is packages/spec/src/contracts/data-engine.test.ts:162-177, which builds an ad-hoc object literal with a batch property and asserts it is defined. It pins the type, not an implementation.

A declared capability that cannot be exercised is precisely ADR-0049's enforce-or-remove target. ADR-0119 D1 (transaction on IObjectQLEngine) and D4 (real atomic batchData) now cover its stated purpose in-process, and POST {basePath}/batch covers it on the wire.

Work

Follow the spec-property-retirement playbook, contract-member route — this is a TypeScript contract member, not an authorable Zod metadata key, so there is no retiredKey tombstone to add (nothing can "author" it; the removal is invisible to metadata authors and visible only to TS consumers).

  1. Delete the member at data-engine.ts:97-100; drop the type-only test case at data-engine.test.ts:162-177.
  2. Decide DataEngineRequest / DataEngineBatchRequestSchema's fate (data-engine.zod.ts:694-717, 764) — if the union has no other live reader after the member goes, it retires with it; if the wire-side batch still uses part of it, keep exactly that part and say so.
  3. Rebuild spec before running the generated-artifact check (pnpm --filter @objectstack/spec build && pnpm --filter @objectstack/spec check:generated) — check:api-surface reads dist, and a stale dist produces a phantom-removal diff.
  4. Changeset carrying the FROM → TO migration text, since it ships to consumers as the package CHANGELOG: "IDataEngine.batch? is removed. It was never implemented by any engine and had no callers. For in-process multi-write atomicity use IObjectQLEngine.transaction(cb); for a batch over one object use the metadata protocol's batchData with options.atomic: true; on the wire use POST {basePath}/batch."
  5. Upgrade-guide entry per ADR-0087's removal discipline.

Refs: ADR-0119 D3, ADR-0049, #4612.

Activity

  1. changed the title [-]chore(spec): retire IDataEngine.batch? per ADR-0118 D3 — declared-but-unimplemented, zero callers[/-] [+]chore(spec): retire IDataEngine.batch? per ADR-0119 D3 — declared-but-unimplemented, zero callers[/+] on Aug 2, 2026
  2. os-zhuang commented on Aug 2, 2026

    @os-zhuang
    ContributorAuthor

    已落地(#4687)

    按 issue 的 work 清单逐条:

    1. ✅ 删除 data-engine.ts:97-100 的成员;删除 data-engine.test.ts 的类型钉测试
    2. ✅ DataEngineRequestSchema 保留,去掉 batch 分支;DataEngineBatchRequestSchema 整体删除
    3. ✅ 先 build 再跑 check:generated(见下面那条教训)
    4. ✅ changeset 携带 FROM → TO
    5. ✅ data-engine-batch-retired 进入升级指南与 spec-changes.json

    第 2 条的判断

    DataEngineRequestSchema 剩下的九个分支现在也全都没有读者——树里没有 Virtual Data Engine 实现,只有这个描述它的 schema。已在文件内标注,值得单开一单;但退休一个已发布的线协议与退休 batch? 是两个不同的决定,不该塞进一个标题只承诺了后者的改动里。

    线上的 batch 未受影响:它用 api/batch.zod.ts 的 CrossObjectBatchRequestSchema / BatchUpdateRequestSchema 校验,是另一套 schema,与被删的那个从无关系。

    刻意不加 retiredKey() 墓碑

    墓碑是靠一次 parse 把处方送达的,而从来没有任何东西 parse 过 DataEngineBatchRequestSchema——落在 playbook 的第三条路径「没人能收到的处方就是噪音」。它的三行 authorable-surface.json 基线、json-schema.manifest.json 条目,以及那条已经陈旧的 docs-import-surface.baseline.json 豁免,都在同一改动里显式删除。执行渠道是 tsc。

    一条教训,值得下次 spec removal 前知道

    第 3 步的顺序不是形式主义。中途有一次我在不完整的 dist 上跑了 gen:api-surface,它静默抹掉了一个与本次改动无关的 ./studio 的 ActivationEvent (type) 导出,并顺手往 docs-import-surface.baseline.json 里为这个缺口加了一条棘轮豁免——正是那个工具自己警告过的「棘轮悄悄停止棘轮」。没有任何报错,是把生成物与 main 逐文件对比才发现的。

    这条已经变成机制:#4675 / #4702 让 check:generated --fix 在 dist 比 src 旧时拒绝运行 gen:api-surface,不再只是警告。


    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

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions