Skip to content

refactor(metadata-core,objectql): 两个写动词的派发判定下沉到 metadata-core —— 一次关闭 26 条 engine-double 基线条目 (#5619) - #5871

Merged
baozhoutao merged 3 commits into
mainfrom
claude/issue-5619-sink-engine-dispatch
Aug 6, 2026
Merged

refactor(metadata-core,objectql): 两个写动词的派发判定下沉到 metadata-core —— 一次关闭 26 条 engine-double 基线条目 (#5619)#5871
baozhoutao merged 3 commits into
mainfrom
claude/issue-5619-sink-engine-dispatch

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes #5619

前提核验(先做,再动手)

issue 的前提成立,PM 的扩展前提也成立,两条都是实测:

  • packages/objectql/src/engine-delete-dispatch.ts(168 行)与
    packages/objectql/src/engine-update-dispatch.ts(229 行)都是零 import 的自包含模块 ——
    grep -n "import" 两个文件的全部命中都在注释里(delete 的第 23 行、update 的第 22 / 44 行,
    都是「a double that imports the producer's own decision」这句散文)。所以下沉是一次搬移,
    不是重构:判定逻辑一个字未改。
  • @objectstack/metadata-coredependencies 只有 { @objectstack/spec, zod },不含 objectql;
    objectql -> metadata-coremetadata-protocol -> metadata-core 两条边都已存在。
    下沉后 npx turbo run build --dry(全仓)、--filter=@objectstack/metadata-core --dry
    --filter=@objectstack/metadata-protocol --dry 三次 grep circular|cyclic 命中数均为 0

作用域按 PM 预裁取扩展版:两个 dispatch 模块一并下沉,一次关闭全部 26 条
(metadata-protocol 26 条 / 13 文件 = delete 13 + update 13,#5754 给门禁加 update 切片后的现状)。

改了什么

1. 搬移(git mv,判定逻辑零改动)

packages/objectql/src/engine-{delete,update}-dispatch.tspackages/metadata-core/src/
两个模块的头部注释各加一节「为什么住在 metadata-core」,记下被拒的环与判据来源
(门禁台账里 packages/spec/src/contracts/data-engine.test.ts 那条 EXEMPT:反向 import 不可行时,
唯一出路是下沉到两边都已依赖的包)。

2. objectql 侧改为 re-export shim,公共 API 与全部既有调用点零变化

原路径 packages/objectql/src/engine-{delete,update}-dispatch.ts 保留,内容改为从
@objectstack/metadata-core re-export 那 10 个值 + 7 个类型。于是:

  • packages/objectql/src/engine.ts 零改动(它 import 的是 ./engine-delete-dispatch.js,
    shim 就在原路径)—— 与合并队列里的 PR perf(objectql): update() 单 id 前置行门按对象判定需求(#5284),并校准 #4743 事实一的三处注释 #5850 避让成功,本 PR 与其无文件交集;
  • packages/objectql/src/index.ts 零改动,@objectstack/objectql 的导出面一字未变;
  • 两个「拿真引擎跑 ENGINE_*_DISPATCH_CASES」的测试
    (engine-{delete,update}-dispatch.test.ts)留在 objectql 且零改动 —— 它们 import ObjectQL,
    不能随模块下沉,而「测试继续钉住真引擎与谓词一致」正是它们的职责。

构建产物实测:require('packages/objectql/dist/index.js').assertEngineDeleteDispatch === require('packages/metadata-core/dist/index.cjs').assertEngineDeleteDispatchtrue
(同一个函数对象,不是两份拷贝),10 个符号全部在位。

3. 13 个 metadata-protocol 假引擎的两个写动词都接上谓词

每个文件的 fake delete() 开头 assertEngineDeleteDispatch(opts)、fake update() 开头
assertEngineUpdateDispatch(data, opts),均从 @objectstack/metadata-core import。
其中 6 个 fake 原本 delete() / update() 不声明参数(async delete() { ... }),补上参数才能
把 options 交给谓词 —— 只补参数,不动行为。

⛔ 没有为了让 fixture 过而放松谓词,也没有手抄 if (!where?.id && !multi)
一条 fixture 都不需要改:13 个文件、461 个用例在装上谓词后全绿,说明这些替身此前虽然
结构上可以比真引擎松,实际驱动的调用形状都合规(生产侧 sys-metadata-repository.ts:577
protocol.ts 的删除路径都是 where: { id })。

4. 基线删 26 条 + 计数

改前(origin/main 实测) 改后
pinned 38 64
DEBT ledger 165 139
exempt 2 2

改前读数不是抄 issue 的(issue 的「24 pinned / 34 baseline」是立单时的旧世界),而是在
origin/main 的 detached worktree 上现跑的:38 pinned, 165 in the DEBT ledger, 2 exempt
差额 26 = 本 PR 关闭的条目;改后多出的那 1 条 pinned 来自 main 上新合入的 #5850
(engine-update-prior-read-scope.test.ts)。

issue 步骤 4 说的「tracked as #4987」引用与硬编码 sibling 计数,随这 26 条整批删除已自然消失
(grep 基线,残留的 #4987 只剩一处历史陈述,已改写,见下)。

5. 门禁两处配套改动

  • 两个 slice 的 modules 现在同时接受 @objectstack/metadata-core@objectstack/objectql
    两种拼写 —— 它们指向同一个函数,而这正是这份名单唯一在乎的性质。
    ⚠️没有放松 packages/spec 那条 EXEMPT:metadata-core -> spec,所以 spec 反向 import
    仍然倒置依赖,理由原样成立(已在 slice 注释里写明)。
  • PINNED 失败提示原文写死「from @objectstack/objectql(add it as a devDependency if the package
    lacks it)」—— 对 objectql 依赖的那些包这条建议现在是错的(那条边成环)。改为同时给出
    metadata-core,并明确「objectql 依赖你要 pin 的包时优先选 metadata-core」。

顺带修好的悬挂引用(与 issue 步骤 4 同一族)

删掉 26 条之后,台账里另有 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.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)。

本 PR 一合,#5619 关闭,这 6 条就指向一个已关闭 issue —— 正是 #5619 自己从 #4987 那里继承的
那个形状
。所以把它们的 closes 改写成「阻塞已解除 + 剩余的一行 pin + 各包的配置差异」,
并指向新开的 #5855(未指派)。各包剩余动作已实测:

  • @objectstack/metadata / @objectstack/platform-objects:dependencies 已含
    @objectstack/metadata-core零配置;
  • @objectstack/core:需新增一条 devDependency。已实测 —— 把
    @objectstack/metadata-core: workspace:* 加进 packages/core/package.jsondevDependencies,
    npx turbo run build --filter=@objectstack/core --dry 无 circular / cyclic 输出,随后已还原。
    这与该条目 why 里旧测量(加 @objectstack/objectql 边 → turbo 拒绝)是两条不同的边,不矛盾。

另有 12 条 why 写着「unlike the metadata-protocol family in this ledger」—— 那个 family 已被
本 PR 删除,改为「the metadata-protocol family this ledger carried until #5619 removed it」;
1 条「Same route, same refusal the #4987 and #5206 entries in this ledger already record」同理改写。
纯文字,unguarded 计数一个没动。

验证(全部前台阻塞,容器级 flock /tmp/os-heavy-verify.lock,--filter 限定)

origin/main 之后(⛔ 未 rebase;两次 merge 均无冲突,main 上 #5857 触及的
protocol.ts / discovery-schema-conformance.test.ts / protocol.metadata-store-outage.test.ts
与本 PR 接线的 13 个文件无交集)重跑全部:

@objectstack/metadata-core   build     ok
@objectstack/metadata-core   test      Test Files 8 passed (8)     Tests 103 passed (103)
@objectstack/metadata-core   typecheck tsc --noEmit && tsc --noEmit -p tsconfig.test.json  (clean)
@objectstack/metadata-protocol test    Test Files 47 passed (47)   Tests 461 passed (461)
@objectstack/objectql        build     ok
@objectstack/objectql        test      Test Files 126 passed (126) Tests 2079 passed (2079)
@objectstack/objectql        typecheck tsc --noEmit  (clean)

check:engine-double-contract  OK — 64 pinned, 139 in the DEBT ledger, 2 exempt.
check:engine-double-contract --self-test  OK
check:type-check-coverage     OK — 62/77 packages type-checked
check:nul-bytes               OK — 5700 tracked text files, no raw ASCII control bytes
check:published-files         OK
check:driver-conformance      OK
check:adr-anchors             OK
turbo build --dry (全仓)      circular|cyclic 命中 0

@objectstack/metadata-protocol 没有 typecheck 脚本(在
check-type-check-coverage 的 DEBT 台账里,本 PR 不改变它的状态)。

反向验证 —— 方向先预测后运行

预测:(常规方向)。条目已从基线整条删除,所以一旦把谓词调用拿掉,该 (file, verb) 既不
PINNED 也无台账条目,门禁必须报 PINNED 失败。两次都验了,delete / update 各一次:

  • 拿掉 sys-metadata-repository.recorded-by.test.tsassertEngineDeleteDispatch(opts)
    x PINNED [delete]: ... does not route through assertEngineDeleteDispatch (line 57),
    1 problem(s)。恢复后 OK。
  • 拿掉 sys-metadata-repository.history-counters.test.ts
    assertEngineUpdateDispatch(data, opts)
    x PINNED [update]: ... does not route through assertEngineUpdateDispatch (line 99),
    1 problem(s)。恢复后 OK。

额外测量:这 26 条里哪些是活的,哪些是休眠的

台账对 metadata-protocol 的 update 切片明确声明没有做过 dormancy 探测,delete 侧也只有
per-file 的旧探针。本 PR 顺手补了一次真测量:在已构建的 metadata-core/dist/index.js 里给两个
assert* 临时加一行 process.stderr.write 栈标记(只动 dist 产物,不动源码),跑一遍
@objectstack/metadata-protocol 全套(461 全绿),再把 dist 还原并重新构建。结果:

file verb 命中次数
migrations/recorded-by-sentinel.test.ts update 20
protocol.stored-migration.test.ts update 11
sys-metadata-repository.draft-drain.test.ts delete 9
sys-metadata-repository.history-counters.test.ts update 6
protocol-publish-drafts-endpoint-gate.test.ts delete 3
protocol-publish-drafts-org-scope.test.ts delete 2
protocol.read-decorations.test.ts update 1
sys-metadata-repository.recorded-by.test.ts delete 1
protocol.runtime-authoring-gate.test.ts delete 1

即 26 条里 9 条是当下就被驱动的(谓词真的在跑,且真引擎会拒的形状一个都没出现),
17 条是休眠的 —— 休眠不等于无害,它意味着今天没人走这条路,而将来第一个走的人会继承一个
比真引擎松的替身,这正是 #4434 的形状。两类都已 pin。

Changeset

.changeset/sink-engine-dispatch-to-metadata-core.md —— @objectstack/metadata-core +
@objectstack/objectql 各 patch(模块搬移 + re-export,公共 API 无变化;metadata-protocol 仅测试改动)。


🤖 Generated with Claude Code

https://claude.ai/code/session_019Q7oc7ASjh8yxyS3Yz78We


Generated by Claude Code

claude added 3 commits August 6, 2026 10:12
…cates into metadata-core (#5619)

Move `engine-delete-dispatch.ts` (#4550) and `engine-update-dispatch.ts` (#5480)
from `packages/objectql/src/` to `packages/metadata-core/src/` unchanged, and
keep the original objectql paths as re-export shims so no caller, no public
export and no pinned call site moves.

`@objectstack/objectql` depends on `@objectstack/metadata-protocol`, so that
package's 13 fake engines could not import either predicate without closing a
dependency cycle turbo 2.10.7 refuses outright. `@objectstack/metadata-core` is
a package both sides already depend on and which depends on neither, so the
sink is the one route that pins those doubles without inventing an edge.

- 13 metadata-protocol test files: both fake write verbs now open with the
  producer's own predicate, imported from `@objectstack/metadata-core`.
- 26 (file, verb) ledger entries deleted from
  `scripts/engine-double-contract.baseline.json`; the gate's counts move from
  37 pinned / 165 ledger / 2 exempt to 63 pinned / 139 ledger / 2 exempt.
- The gate's two slices now accept `@objectstack/metadata-core` alongside
  `@objectstack/objectql`, and its remediation message names the right one.
- Six ledger entries whose `closes` prescribed exactly this sink ("tracked as
  #5619") are rewritten: the blocker is gone, what remains is the one-line pin,
  tracked as #5855.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Q7oc7ASjh8yxyS3Yz78We
@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 6, 2026 10:29am

Request Review

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/metadata-core, @objectstack/objectql.

14 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata-core, @objectstack/objectql)
  • content/docs/data-modeling/formulas.mdx (via packages/objectql)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/objectql)
  • content/docs/deployment/vercel.mdx (via @objectstack/objectql)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/objectql)
  • content/docs/kernel/services.mdx (via @objectstack/objectql)
  • content/docs/permissions/authentication.mdx (via @objectstack/objectql)
  • content/docs/plugins/index.mdx (via @objectstack/objectql)
  • content/docs/plugins/packages.mdx (via @objectstack/metadata-core, @objectstack/objectql)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/objectql)
  • content/docs/protocol/objectql/query-syntax.mdx (via packages/objectql)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/objectql)
  • content/docs/releases/implementation-status.mdx (via @objectstack/objectql)
  • content/docs/releases/v12.mdx (via @objectstack/metadata-core)

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.

@github-actions github-actions Bot added size/xl documentation Improvements or additions to documentation tests tooling labels Aug 6, 2026
@baozhoutao
baozhoutao marked this pull request as ready for review August 6, 2026 10:40
@baozhoutao
baozhoutao added this pull request to the merge queue Aug 6, 2026
Merged via the queue into main with commit 51a587d Aug 6, 2026
24 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-5619-sink-engine-dispatch branch August 6, 2026 11:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests tooling

Projects

None yet

2 participants