Skip to content

Commit 9ac5ae5

Browse files
feat(spec)!: retire the unserved Virtual ObjectQL request protocol (#27028) (#27324)
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} --> _Requested by **Yibo Wang** · [project thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwBJUwudaPvUtLwcZS3w2akFV)_ Fixes #27028 Ruling-ref: 6472013580 Claim: 6472028553 Clause-②: no (narrowing) Metadata-protocol: narrowed Skills-docs: none — REASON: `skills/**` names none of the retired exports (`git grep` for the 16 names on base: 0 hits; the `_index.md` files point at `data-engine.zod.ts` by its header line, which stays, and `check:generated --fix` left them unchanged). The one hand-written docs page that taught the protocol, `content/docs/kernel/contracts/data-engine.mdx`, is corrected in this diff. ## 维护者速读 - **改了什么:** 删除 `data-engine.zod.ts` 里没人用的「Virtual ObjectQL」远程请求协议,包括 `DataEngineRequestSchema` 和它的 9 个分支、`DataEngineContractSchema`、5 个类型和 5 个私有辅助。同时登记 10 条 `RETIRED_DEFS_BY_MAJOR[18]` 和一条 D3 条目 `data-engine-rpc-protocol-retired`,并修好文档页里还在教已退役 `engine.batch?.()` 的段落。 - **为什么改:** 按您在 #27274 上的裁决 A。这套协议在仓内和 hotcrm、objectui、docs.objectos.ai 里都没有读者。按发布出去的样子,它还允许调用方自带 `isSystem`,`execute` 分支能直传原始 SQL,留着就是一个假入口。 - **风险与回滚:** 运行时行为不变。只影响 TypeScript 导入(升级后报 TS2305)和 npm 包里那 10 个 `json-schema/data/DataEngine*Request.json` 文件。回滚就是 revert 本 PR,没有存量数据和 conversion 要处理。 - **先看:** `packages/spec/src/migrations/entries/semantic/18.data-engine-rpc-protocol-retired.ts`、`packages/spec/src/data/data-engine.zod.ts`(第 8 节和第 9 节末尾的说明)、`packages/spec/src/data/data-engine-rpc-protocol-retirement.test.ts`。 - **两分钟验证:** 运行 `git grep -nE 'DataEngine(Find|FindOne|Insert|Update|Delete|Count|Aggregate|Execute|VectorFind)?Request(Schema|Parsed)?\b|DataEngineContractSchema' -- packages ui skills content ':!**/CHANGELOG.md'`,应该只剩退役登记、退役 pin 和说明性注释。 - **需要您做的:** 契约复审 PASS 后,请审批并合并(Tier H)。原因:`docs/adr/0119` 第 61 行锚定的 `DataEngineRequest` 被本 PR 删除,`check:adr-symbol-anchors` 要求修锚。`1a50dca1e` 保留名字,把锚改成文件级锚,并按该 ADR 自己 2026-08-05 的写法补一条带日期的编辑注。ADR 的决定本身没有改动。`skills/*/references/_index.md` 没有变化。 ## What changes - **Spec (`@objectstack/spec`, minor, BREAKING for TypeScript imports and the published JSON Schema files only).** `packages/spec/src/data/data-engine.zod.ts` loses: - the ten request schemas: `DataEngineRequestSchema` and its arms `DataEngine{Find,FindOne,Insert,Update,Delete,Count,Aggregate,Execute,VectorFind}RequestSchema`; - `DataEngineContractSchema`; - the types `DataEngineRequest`, `DataEngineRequestParsed`, `DataEngineExecuteRequest`, `DataEngineInsertRequest` and `DataEngineVectorFindRequest`; - the private helpers `RpcQueryOptionsSchema`, `foldRpcQueryOptions`, `RpcLegacyFilterMixin`, `foldRpcLegacyFilter` and `RPC_WHERE_SLOT`. Two in-file notes stand where the block stood: section 8, and the end of section 9 beside the older `DataEngineBatchRequestSchema` note, which they absorb. `RPC_QUERY_ALIAS_SLOTS`, `foldQueryAliasSlots`, `aliasConflictIssue`, every `*OptionsSchema` and the query-transport schemas stay. Route 3 of the `spec-property-retirement` kit (the #27182 and #4618 precedent): no metadata source authors these shapes, so there is no `retiredKey()` tombstone and no D2 conversion. - **ADR-0087: registered.** Ten `retired-defs/18.data__DataEngine*Request.ts` files, plus the D3 semantic entry `semantic/18.data-engine-rpc-protocol-retired.ts`, which names the doors that exist: `IDataEngine` in process, `ctx.api.object(name)` in a hook or action body, the REST data routes and `POST {basePath}/batch` on the wire. The changeset carries the FROM → TO table and the `registered data-engine-rpc-protocol-retired` marker. - **Generated and ledgers.** `json-schema.manifest/data.json` loses 10 defs and `authorable-surface/data.json` 35 rows. The build required both deletions, deliberately; `authorable-surface.base.json` is untouched. Further moves: `authorable-defaults/data.json` −1, `dropped-refinements.baseline.json` −8 entries (`measured` totals 252 → 244 schemas, 900 → 892 sites), `unemitted-schemas.baseline.json` −1 (`DataEngineContractSchema`), `docs-import-surface.baseline.json` −6 and `variant-docs.json` −1 (the `method:` union). `api-surface`, `export-origins`, `declaration-map`, the reference page and index (1560 → 1550 schemas), the strictness-ledger counts and `test-typecheck-debt.json` were regenerated. - **Pins that move.** `data-engine.test.ts` drops the ten request suites, the two integration cases that parsed request literals, and the request rows of the #26954 projection-parity table. `type-alias-convention.pin.test.ts` drops three `Iso_data_dataEngine__*RequestSchema` rows, and its census goes 799 → 796 (header, title, `toHaveLength` with the history line). - **New pin.** `packages/spec/src/data/data-engine-rpc-protocol-retirement.test.ts`, listed in `vitest.repo-tests.json`, asserts five things: - the ten defs and the D3 entry are registered; - the eleven value exports are gone from `/data` and from the root entry; - the option bags and `RPC_QUERY_ALIAS_SLOTS` survive (the lit control); - nothing in the declared radius still uses a retired name (a tree-scoped absence walk); - the matcher catches real uses and ignores neighbours (an anti-vacuity test). - **Docs and prose.** `content/docs/kernel/contracts/data-engine.mdx`: - drops the `DataEngineRequest` import and the retired `batch?` member from its `IDataEngine` listing; - replaces the copyable `engine.batch?.([...])` example with the real alternatives (`IObjectQLEngine.transaction(cb)`, `batchData` with `options.atomic`, `POST {basePath}/batch`); - stops calling the legacy-alias normalizer "the RPC layer". Comment-only rewords where the retired names were cited: `contracts/data-engine.ts`, `ui/view-grouping-query.ts`, `data-engine.zod.ts` and `packages/objectql/src/engine.ts` (`@objectstack/objectql` patch). The two `DEVELOPMENT_PLAN.md` rows are struck through. ## Why The maintainer's ruling A on #27274 (record 6472013580): retire the block rather than keep it as a planned contract. The phase-1 measurement is on the decision card. It found zero readers in this repo outside `packages/spec/src/data/` and zero in hotcrm `353dace`, objectui `b2c0ade` and docs.objectos.ai `cab35fd`, against controls of 311, 2095 and 74 files that import `@objectstack/spec`. The one real cross-VM engine boundary (the QuickJS sandbox) uses a different shape, and the published JSON Schema admitted a caller-supplied `context.isSystem` and a raw-SQL `execute` arm. ## Tests - New: `data-engine-rpc-protocol-retirement.test.ts`, 16 cases. - Moved: `data-engine.test.ts` (request suites removed; the option-bag and transport suites are unchanged) and `type-alias-convention.pin.test.ts` (census 796). ## Acceptance notes - `scripts/def-key-collisions.test.ts` (`--project repo`) fails locally with `MODULE_NOT_FOUND` before reaching its guard. Its fixture symlinks `packages/spec/node_modules` into a tmp clone, and the pnpm `.bin/tsx` shim resolves a relative path that does not exist there. The failure sits in the fixture's `tsx` resolution, before the guard runs, and this diff touches neither the fixture, `build-schemas.ts` nor `http.zod.ts`. NOT MEASURED locally; `Test Core` runs it. - `IDataEngine`'s doc comments still mention "remote/virtual engines" as hypothetical implementers that may omit optional members. That is about the TypeScript contract, not the retired protocol, so it is left as is. ## Verification Base `origin/main` `a0aa8a1f3` (merged in); head `644adb1e7`. <details><summary>Build and generated artifacts (merged head)</summary> - `pnpm --filter @objectstack/spec build` → exit 0. Before that, the build refused three times as designed: the manifest lines, the `unemitted-schemas` entry and the 8 `dropped-refinements` entries. - `pnpm --filter @objectstack/spec check:generated` → exit 0, 14 of 14 fresh. No `skills/*/references/_index.md` moved. </details> <details><summary>Typecheck and tests</summary> - `pnpm --filter @objectstack/spec typecheck` → exit 0 (merged head). - `pnpm --filter @objectstack/spec test` → Test Files 748 passed (748), Tests 22293 passed | 1 todo (merged head). - `pnpm --filter @objectstack/spec test:repo` → 82 of 83 files passed, 1370 of 1371 tests. The one failure is `def-key-collisions.test.ts` (`MODULE_NOT_FOUND`, see Acceptance notes). The new pin passes: 32 of 33 in the targeted re-run on the merged head, the one failure again `def-key-collisions`. - `pnpm --filter @objectstack/objectql typecheck` → exit 0, after `pnpm --filter '@objectstack/objectql^...' build`. - Full dogfood (`pnpm --filter @objectstack/dogfood test`, final head `644adb1e7`, after `pnpm --filter '@objectstack/dogfood^...' build`): Test Files 348 passed | 3 skipped (351), Tests 2806 passed | 20 skipped (2826). Lock verdict `command-exit 0`. </details> <details><summary>Derived gates (dispatch-gates --commands, 111 families)</summary> - 111 families run; 99 exited 0 on the first pass. The 11 that exited 3 (a prerequisite: dist predated an edited test file) and `check:generated` (stale dist, plus the test-typecheck ledger re-record) were re-run after a rebuild, and all exit 0. - `check-adr-0087-registration --base origin/main` → ✓ `registered data-engine-rpc-protocol-retired (new here)`. - `check-changeset-no-major --base origin/main` → ✓ no `major`; the narrowing ships `minor`. - `check:spec-parsed-alias`, `check:cross-package-test-inputs`, `check:variant-docs`, `check:doc-authoring`, `check:role-word`, `check:liveness`, `check:exported-any`, `check:dual-source-exports` → exit 0. </details> ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` passes (CI-owned run). - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. - [x] 6. `packages/spec` touched: its generated artifacts are regenerated and committed. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English. - [x] The *Before Submitting* list in CONTRIBUTING.md is done. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01WGufziUAPh2YojDuNQpVXp --- _Generated by [Claude Code](https://claude.ai/code/session_01WGufziUAPh2YojDuNQpVXp)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8d66cbe commit 9ac5ae5

37 files changed

Lines changed: 520 additions & 1459 deletions
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
'@objectstack/spec': minor
3+
'@objectstack/objectql': patch
4+
---
5+
6+
feat(spec)!: retire the unserved Virtual ObjectQL request protocol from `data/data-engine.zod.ts`
7+
8+
Clause-②: no (narrowing)
9+
Metadata-protocol: narrowed
10+
11+
<!-- adr-0087: registered data-engine-rpc-protocol-retired -->
12+
13+
**BREAKING** for TypeScript and JSON Schema consumers of one block that nothing ever served. `@objectstack/spec/data` published a serialized request protocol for a "Virtual Data Engine" in another process: `DataEngineRequestSchema` and its nine `method` arms, plus `DataEngineContractSchema`. No such engine existed and nothing parsed the protocol. A census found no importer or parser in this repo outside the defining module, and zero hits in hotcrm, objectui and docs.objectos.ai. As published it was also unsafe to implement: every arm admitted a caller-supplied `context` (`isSystem` included), and the `execute` arm carried a raw driver command. The whole block is retired (ADR-0049 enforce-or-remove, by the maintainer's ruling A).
14+
15+
| FROM | TO |
16+
|:--|:--|
17+
| `DataEngineFindRequestSchema`, `DataEngineFindOneRequestSchema`, `DataEngineCountRequestSchema`, `DataEngineAggregateRequestSchema` | in process, `IDataEngine.find` / `findOne` / `count` / `aggregate` with `EngineQueryOptions` / `EngineCountOptions` / `EngineAggregateOptions`; over the wire, the REST data routes (`/data/:object`, `POST /data/:object/query`) |
18+
| `DataEngineInsertRequestSchema`, `DataEngineUpdateRequestSchema`, `DataEngineDeleteRequestSchema` | `IDataEngine.insert` / `update` / `delete` with `DataEngineInsertOptions` / `EngineUpdateOptions` / `EngineDeleteOptions`; over the wire, the REST data routes, and `POST {basePath}/batch` for a batch |
19+
| `DataEngineVectorFindRequestSchema`, `DataEngineExecuteRequestSchema` | `IDataEngine.vectorFind?` / `execute?`, in process only |
20+
| `DataEngineRequestSchema` and the types `DataEngineRequest`, `DataEngineRequestParsed`, `DataEngineExecuteRequest`, `DataEngineInsertRequest`, `DataEngineVectorFindRequest` | none: there is no serialized engine-call protocol; call `IDataEngine` in process, or a hook or action body's `ctx.api.object(name)` |
21+
| `DataEngineContractSchema` | the `IDataEngine` interface (`@objectstack/spec/contracts`) |
22+
23+
The one-line fix: replace an import of any name above with the `IDataEngine` method or option type in the right-hand column. An import left behind is `TS2305` after upgrade.
24+
25+
The retirement kit:
26+
27+
- **`@objectstack/spec`**: the ten request schemas, `DataEngineContractSchema`, the five types and their private helpers (`RpcQueryOptionsSchema` and the `filter`-only fold) are deleted. The ten published defs `data/DataEngineRequest` and `data/DataEngine{Find,FindOne,Insert,Update,Delete,Count,Aggregate,Execute,VectorFind}Request` leave `json-schema/` and the reference docs, registered in `RETIRED_DEFS_BY_MAJOR[18]`, and the D3 entry `data-engine-rpc-protocol-retired` names the doors that exist. There is no `retiredKey()` tombstone and no conversion: no metadata source authors these shapes, and no parse remains for a prescription to reach. `IDataEngine`, every `*OptionsSchema`, `RPC_QUERY_ALIAS_SLOTS`, `foldQueryAliasSlots` and the query-transport schemas are unchanged. Runtime behaviour is unchanged.
28+
- **`@objectstack/objectql`**: a comment that named `RpcQueryOptionsSchema` now names `QueryWithTransportSchema`. No behaviour changes.

‎content/docs/kernel/contracts/data-engine.mdx‎

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import type {
2727
EngineDeleteOptions,
2828
EngineAggregateOptions,
2929
EngineCountOptions,
30-
DataEngineRequest,
3130
} from '@objectstack/spec/data';
3231

3332
export interface IDataEngine {
@@ -48,9 +47,6 @@ export interface IDataEngine {
4847
where?: any; limit?: number; fields?: string[]; threshold?: number;
4948
}): Promise<any[]>;
5049

51-
// Batch Operations (optional, transactional)
52-
batch?(requests: DataEngineRequest[], options?: { transaction?: boolean }): Promise<any[]>;
53-
5450
// Raw Command Escape Hatch (optional)
5551
execute?(command: any, options?: Record<string, any>): Promise<any>;
5652

@@ -470,8 +466,8 @@ declares one; none carries a `readonly` policy of its own any more — see
470466
<Callout type="warn">
471467
`WriteObservabilityOptions` is a **TS-contract-level, in-process-only** bag —
472468
all three members. It is deliberately not part of the serializable Zod options schemas:
473-
a function is unrepresentable in JSON Schema and cannot cross the RPC (Virtual
474-
Data Engine) boundary, so remote callers never receive these events; and putting
469+
a function is unrepresentable in JSON Schema and cannot be serialized, so remote
470+
callers (REST, the client SDK) never receive these events; and putting
475471
`strictReadonlyWrites` in the serializable bag would let any client toggle
476472
write-refusal on a security-adjacent path (#5126 ruling). A remote caller can set
477473
none of the three, and for the strips it gets NEITHER behaviour: its write is
@@ -569,17 +565,12 @@ const results = await engine.vectorFind?.('document', embeddingVector, {
569565
});
570566
```
571567

572-
### batch (Transactional)
573-
574-
Execute multiple operations in a single transaction:
568+
### Several writes, atomically
575569

576-
```typescript
577-
const results = await engine.batch?.([
578-
{ method: 'insert', object: 'project', data: { name: 'Website Redesign', status: 'active' } },
579-
{ method: 'insert', object: 'task', data: { title: 'Design mockups', status: 'open' } },
580-
{ method: 'insert', object: 'task', data: { title: 'Implement frontend', status: 'open' } },
581-
], { transaction: true });
582-
```
570+
There is no `batch` member: it was never implemented by any engine and was retired
571+
(ADR-0119 D3). In process, wrap the writes in `IObjectQLEngine.transaction(cb)`;
572+
for a batch over one object use the metadata protocol's `batchData` with
573+
`options.atomic: true`; over the wire, `POST {basePath}/batch`.
583574

584575
### execute (Raw Command)
585576

@@ -624,7 +615,7 @@ detection locate drivers.
624615
<Callout type="warn">
625616
**Deprecated Parameter Names**
626617

627-
The following legacy parameter names are accepted by the RPC layer for backward compatibility but should **not** be used in new code. The protocol normalizer resolves conflicts with canonical names taking precedence.
618+
The following legacy parameter names are accepted on the wire (the protocol normalizer) for backward compatibility but should **not** be used in new code. The protocol normalizer resolves conflicts with canonical names taking precedence.
628619

629620
| Legacy (Deprecated) | Canonical | Notes |
630621
|:---------------------|:----------|:------|

0 commit comments

Comments
 (0)