Blocked-by: #5619
(分诊座位 2026-08-06 补入机器半边;理由见本单分诊评论。#5619 合入后即解锁。)
发现于 #5619 (把 engine-delete-dispatch.ts / engine-update-dispatch.ts 下沉到 @objectstack/metadata-core)执行过程中。按 Prime Directive #10 单开、未指派。#5619 的文件面被 PM 预裁限定为 两个 dispatch 模块的搬移 + 13 个 packages/metadata-protocol 测试接线 + 基线删该 26 条 ,下面这 6 条不在其中。
现象
scripts/engine-double-contract.baseline.json 里另有 6 条 条目,closes 明确写着「sink assertEngine{Delete,Update}Dispatch into a package BOTH sides already depend on —— tracked as #5619 」:
条目
verb
packages/core/src/utils/migration-journal.test.ts
delete + update
packages/metadata/src/migrations/migrate-sys-notification-to-event.test.ts
delete + update
packages/platform-objects/src/plugin.test.ts
update
packages/platform-objects/src/system/migration-flag.test.ts
update
它们被卡住的原因与 metadata-protocol 那 26 条完全同一个 :@objectstack/objectql 依赖这些包,反向 devDependency 即成环,turbo 2.10.7 直接拒绝任务图。#5619 把两个谓词搬到 @objectstack/metadata-core 之后,这个结构性阻塞对它们同样消失了 —— 但 pin 本身没做,closes 指向的 #5619 一旦关闭,这个引用就变成指向已关闭 issue 的悬挂处方(即 #5619 自己从 #4987 那里继承的那个形状)。#5619 已把这 6 条的 closes 改写成「阻塞已解除 + 剩余动作」并指向本单,本单是接住那个引用的落点。
每个包的剩余动作(已在 #5619 的 worktree 上实测)
@objectstack/metadata :dependencies 已含 @objectstack/metadata-core(workspace:*)—— 零配置 ,直接 import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core' 即可。
@objectstack/platform-objects :dependencies 同样已含 @objectstack/metadata-core —— 零配置 。
@objectstack/core :dependencies 只有 { @objectstack/spec, zod },需要新增一条 devDependency。已实测 :把 @objectstack/metadata-core: workspace:* 加进 packages/core/package.json 的 devDependencies,npx turbo run build --filter=@objectstack/core --dry 无 circular / cyclic 输出 (metadata-core 的依赖面只有 { @objectstack/spec, zod },不经过 core),随后已还原。这与该条目 why 里记录的旧测量(加 @objectstack/objectql 边 → turbo 拒绝)是两条不同的边,不矛盾。
完成范围
三个包的 fake 引擎 delete() / update() 分别以 assertEngineDeleteDispatch(options) / assertEngineUpdateDispatch(data, options) 开头(⛔ 不许手抄 if (!where?.id && !multi) —— 那正是 feat(plugin-email): 邮件投递接入持久化队列 —— send 走 email.send.async / sys_job_queue,三门可配置 (#5160) #5173 / fix(plugin-email): sys_email 的 queued 行在启动时被清扫,drain 失败升为 error (#5161) #5191 / fix(service-queue,platform-objects): sys_job_queue 的 completed 行按声明式 retention 到期即清(#5179) #5192 / fix(runtime): callData 的 ObjectQL 兜底对「记录不存在」统一答 404 RECORD_NOT_FOUND (#5138) #5584 各烧掉一轮 CI 的写法);
@objectstack/core 加 devDependency @objectstack/metadata-core;
跑三个包的 pnpm test,把基线里这 6 条整条删掉(gate 是 shrink-only 双向校验);
计数以实测为准 —— [engine-double-contract] 把 assertEngineDeleteDispatch 下沉到 @objectstack/metadata-core —— 七条 metadata-protocol 基线条目唯一存在的关闭路线(#4987 只修了处方文字) #5619 落地后的读数是 63 pinned / 139 ledger / 2 exempt。
影响(如实说明,请分诊定级)
与 #5619 同一族:不是用户今天会撞到的缺陷,而是测试替身比真契约松 的现存缺口(#4434 的形状)。这 6 条的 why 里,4 条(#5629 delete 批次)带 per-file dormancy probe 说明当前未被驱动,2 条(#5480 update 切片)明确声明没有 做 dormancy 探测。域应为 domain:engine-core。
参考
发现于 #5619(把
engine-delete-dispatch.ts/engine-update-dispatch.ts下沉到@objectstack/metadata-core)执行过程中。按 Prime Directive #10 单开、未指派。#5619 的文件面被 PM 预裁限定为 两个 dispatch 模块的搬移 + 13 个packages/metadata-protocol测试接线 + 基线删该 26 条,下面这 6 条不在其中。现象
scripts/engine-double-contract.baseline.json里另有 6 条 条目,closes明确写着「sink assertEngine{Delete,Update}Dispatch into a package BOTH sides already depend on —— tracked as #5619」:packages/core/src/utils/migration-journal.test.tspackages/metadata/src/migrations/migrate-sys-notification-to-event.test.tspackages/platform-objects/src/plugin.test.tspackages/platform-objects/src/system/migration-flag.test.ts它们被卡住的原因与 metadata-protocol 那 26 条完全同一个:
@objectstack/objectql依赖这些包,反向 devDependency 即成环,turbo 2.10.7 直接拒绝任务图。#5619 把两个谓词搬到@objectstack/metadata-core之后,这个结构性阻塞对它们同样消失了 —— 但 pin 本身没做,closes指向的 #5619 一旦关闭,这个引用就变成指向已关闭 issue 的悬挂处方(即 #5619 自己从 #4987 那里继承的那个形状)。#5619 已把这 6 条的closes改写成「阻塞已解除 + 剩余动作」并指向本单,本单是接住那个引用的落点。每个包的剩余动作(已在 #5619 的 worktree 上实测)
@objectstack/metadata:dependencies已含@objectstack/metadata-core(workspace:*)—— 零配置,直接import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'即可。@objectstack/platform-objects:dependencies同样已含@objectstack/metadata-core—— 零配置。@objectstack/core:dependencies只有{ @objectstack/spec, zod },需要新增一条 devDependency。已实测:把@objectstack/metadata-core: workspace:*加进packages/core/package.json的devDependencies,npx turbo run build --filter=@objectstack/core --dry无 circular / cyclic 输出(metadata-core 的依赖面只有{ @objectstack/spec, zod },不经过 core),随后已还原。这与该条目why里记录的旧测量(加@objectstack/objectql边 → turbo 拒绝)是两条不同的边,不矛盾。完成范围
delete()/update()分别以assertEngineDeleteDispatch(options)/assertEngineUpdateDispatch(data, options)开头(⛔ 不许手抄if (!where?.id && !multi)—— 那正是 feat(plugin-email): 邮件投递接入持久化队列 —— send 走 email.send.async / sys_job_queue,三门可配置 (#5160) #5173 / fix(plugin-email): sys_email 的 queued 行在启动时被清扫,drain 失败升为 error (#5161) #5191 / fix(service-queue,platform-objects): sys_job_queue 的 completed 行按声明式 retention 到期即清(#5179) #5192 / fix(runtime): callData 的 ObjectQL 兜底对「记录不存在」统一答 404 RECORD_NOT_FOUND (#5138) #5584 各烧掉一轮 CI 的写法);@objectstack/core加 devDependency@objectstack/metadata-core;pnpm test,把基线里这 6 条整条删掉(gate 是 shrink-only 双向校验);63 pinned / 139 ledger / 2 exempt。影响(如实说明,请分诊定级)
与 #5619 同一族:不是用户今天会撞到的缺陷,而是测试替身比真契约松的现存缺口(#4434 的形状)。这 6 条的
why里,4 条(#5629 delete 批次)带 per-file dormancy probe 说明当前未被驱动,2 条(#5480 update 切片)明确声明没有做 dormancy 探测。域应为domain:engine-core。参考
resolveEngineDeleteDispatch,update 的同款三分支只是 engine.ts 里的一个内联 throw #5480 / refactor(objectql): update 的三分支派发抽成生产者侧唯一判定 + 门禁 update 切片 (#5480) #5754(update 切片)