Skip to content

Commit 2614aef

Browse files
baozhoutaoclaude
andauthored
fix(runtime): route #5138 test engine doubles through assertEngineDeleteDispatch (#5615)
PR #5584(#5138)新增的 packages/runtime/src/action-execution-calldata-not-found.test.ts 里两个 fake ObjectQL 引擎的 delete() 没有走 @objectstack/objectql 的 assertEngineDeleteDispatch,合入 main 后 check:engine-double-contract (挂在 ESLint job)转红,阻塞后续所有 PR 的 ESLint。 按门禁处方第一条修:两处 delete 以 assertEngineDeleteDispatch(opts) 开头, 并用它返回的 by-id dispatch 里的 id 作为 store 键,而不是自己再从 opts.where.id 取一次。@objectstack/objectql 已是 @objectstack/runtime 的 dependencies 条目,无需新增 devDependency,也不需要 MEASURED 例外。 这与 #5138 的取舍一致且互补:那个 PR 刻意不读 ql.delete 的返回值(引擎侧 IDataEngine.delete 只声明 Promise<any>),而这里收紧的是 fake 的入口谓词 —— 断言顺带证明了 callData 兜底发出的是标量 by-id 删除,即真引擎会执行的形状。 Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh Co-authored-by: Claude <noreply@anthropic.com>
1 parent 79b7fa1 commit 2614aef

1 file changed

Lines changed: 22 additions & 2 deletions

File tree

‎packages/runtime/src/action-execution-calldata-not-found.test.ts‎

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@
3737

3838
import { describe, it, expect } from 'vitest';
3939
import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol';
40+
// [#4550, from #4434] The REAL engine's delete-dispatch predicate. A fake whose
41+
// `delete` is looser than the implementation it stands in for turns a green
42+
// suite into no suite at all; importing the producer's decision (rather than
43+
// mirroring it) is what makes that impossible. `@objectstack/objectql` is
44+
// already a `dependencies` entry of `@objectstack/runtime`, so no manifest
45+
// change is needed to reach it.
46+
import { assertEngineDeleteDispatch } from '@objectstack/objectql';
4047
import { ApiEndpointSchema } from '@objectstack/spec/api';
4148
import type { ApiEndpoint } from '@objectstack/spec/api';
4249

@@ -81,7 +88,14 @@ function fallbackHarness(store = rows()) {
8188
return store.get(id);
8289
},
8390
delete: async (_o: string, opts: any) => {
84-
const id = String(opts?.where?.id);
91+
// [#4550, from #4434] Open on the producer's own dispatch predicate,
92+
// so this double cannot accept a call the real `ObjectQL.delete`
93+
// refuses. It also earns its keep here: the assertion is what proves
94+
// `callData`'s fallback issues a SCALAR by-id delete — the shape a
95+
// running engine executes — rather than a predicate-shaped one that
96+
// would 500 in production while this suite stayed green.
97+
const dispatch = assertEngineDeleteDispatch(opts);
98+
const id = String((dispatch as { kind: 'by-id'; id: string | number | bigint }).id);
8599
deleted.push(id);
86100
return store.delete(id);
87101
},
@@ -109,7 +123,13 @@ function protocolHarness(store = rows()) {
109123
store.set(id, { ...store.get(id), ...data });
110124
return store.get(id);
111125
},
112-
delete: async (_o: string, opts: any) => store.delete(String(opts?.where?.id)),
126+
// [#4550] Same pinning as the fallback harness above — this engine sits
127+
// under the REAL protocol implementation, so its `delete` is reached by
128+
// `deleteData`'s own by-id call and must be held to the same contract.
129+
delete: async (_o: string, opts: any) => {
130+
const dispatch = assertEngineDeleteDispatch(opts);
131+
return store.delete(String((dispatch as { kind: 'by-id'; id: string | number | bigint }).id));
132+
},
113133
};
114134
const services: Record<string, any> = {
115135
metadata: { getObject: async () => ({ name: 'task', fields: {} }) },

0 commit comments

Comments
 (0)