Skip to content

[engine-double-contract] 四条 metadata-protocol 基线条目的 closes 指向一个不可能的动作:加 @objectstack/objectql devDependency 会让 turbo 直接判环 #4987

Closed

Description

@xuyushun441-sys

发现于 #4867(PR #4980)在 scripts/engine-double-contract.baseline.json 里新增条目时。仅记录,未在该 PR 中修改 —— 改别人的基线条目正文不属于那个 PR 的文件面,按 Prime Directive #10 单开,未指派。

现象

scripts/engine-double-contract.baseline.json(#4550 / PR #4948)里四条 metadata-protocol 条目写着同一句 why / closes:

"why":    "@objectstack/metadata-protocol does not depend on @objectstack/objectql.
           Pinning needs a devDependency + lockfile change, which is a separate reviewable act."
"closes": "add @objectstack/objectql to devDependencies, then open the fake's delete with
           assertEngineDeleteDispatch(opts)"

涉及:

  • packages/metadata-protocol/src/protocol-publish-drafts-org-scope.test.ts
  • packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts
  • packages/metadata-protocol/src/protocol.save-flow-canonicalization.test.ts
  • packages/metadata-protocol/src/sys-metadata-repository.recorded-by.test.ts

closes 描述的动作做不到:@objectstack/objectql 的 dependencies 里已经有 @objectstack/metadata-protocol,反向加 devDependency 就是一个环。实测(加上边、跑 turbo、再回退):

$ pnpm turbo run test --filter=@objectstack/metadata-protocol --dry
 WARNING  Circular package dependency detected: @objectstack/objectql, @objectstack/metadata-protocol
  x Cyclic dependency detected:
  |     @objectstack/metadata-protocol#build, @objectstack/objectql#build

turbo 2.10.7 直接拒绝任务图 —— 不是警告,是 turbo run 失败。所以这四条不是「一次单独的 review 就能关掉」的债,而是这条路径根本关不掉。

为什么值得单开

这正是本仓库反复付费的 declared ≠ actual 形状,只不过长在账本上而不是代码上:一条 shrink-only 账本的 closes 就是给下一个作者的处方。按现在这句去做的人会加 devDependency、跑 turbo、撞环、回退,然后才发现处方本身是错的 —— 而账本存在的意义正是让他不必重新发现这件事。

同一个文件里已经有一条把这个方向写对的条目(packages/spec/src/contracts/data-engine.test.ts 的 EXEMPT:「it cannot be pinned even in principle: @objectstack/objectql depends on @objectstack/spec, so the import would invert the dependency」)—— 说明判据本身早就在,只是没有套用到 metadata-protocol 这四条上。

建议

  1. 把这四条的 why 改成实测的环(而不是「a separate reviewable act」),closes 改成唯一存在的路线:把 assertEngineDeleteDispatch 下沉到两边都已依赖的包 —— @objectstack/metadata-core 是现成的共同依赖(objectql 与 metadata-protocol 都依赖它);@objectstack/spec/contracts 是另一个候选,但注意 spec 的那条 EXEMPT 说明 objectql→spec 方向同样不能反向 import,所以下沉到 spec 只有在「谓词本身属于契约层」成立时才对。
  2. 下沉之后,这四条 + [metadata-protocol] SysMetadataRepository 的 nextEventSeq()/nextItemVersion() 同样把读失败当「表还没建」,静默从 1 重新发号 —— #4825 在 canonical 路径上的同形缺陷 #4867 新增的那条(sys-metadata-repository.history-counters.test.ts)可以一起关掉,plugin-approvals 等「本来就依赖 objectql」的条目不受影响。

PR #4980 已按现状新增了一条,其 closes 写的是下沉路线并注明四条同族条目同理 —— 但没有改动它们的正文。

参考

Activity

  1. added a commit that references this issue on Aug 4, 2026
  2. added a commit that references this issue on Aug 4, 2026
  3. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    分诊:入队 pm:queue,域 domain:devx。

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  4. self-assigned this
    on Aug 5, 2026
  5. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    PM 派发(devx 车道第 6 轮,会话 session_01GX3sL71LFq8m2usg6VqTSE):


    Generated by Claude Code

  6. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    认领(os-dev 座位,devx 车道第 6 轮):

    • 会话 ID:session_01GX3sL71LFq8m2usg6VqTSE
    • 分支:claude/issue-4987-baseline-closes-cycle
    • worktree:/home/user/objectstack-issue-4987
    • 文件面:仅 scripts/engine-double-contract.baseline.json(四条 metadata-protocol 条目的 why/closes 台账文字)

    先在 worktree 内自行核对四条条目在 origin/main 上的现状(分诊 2026-08-05 已核,我再核一遍),再按 issue 建议 1 修正处方文字:why 写实测的 turbo 依赖环,closes 改为下沉 assertEngineDeleteDispatch 到共同依赖包的路线,措辞与 PR #4980 新增的同族条目相互引用一致。

    ⛔ 本单不实施下沉代码改动(engine-core 域),不增删条目,不改 file/lines 定位字段,不改检查脚本。


    Generated by Claude Code

  7. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    进展(会话 session_01GX3sL71LFq8m2usg6VqTSE):draft PR #5624 已开。

    前提成立,已在 worktree 自核而非依赖分诊结论:四条条目在 origin/main 上原文未动,why/closes 仍是「add @objectstack/objectql to devDependencies」;文件里该处方共 12 处,本次修 4 处、余 8 处。

    环是重测的,不是引用的:把边加进 metadata-protocol 的 devDependencies,turbo 2.10.7 对 build 与 test 两个 task graph 都拒绝(exit 1),随后回退(commit 只含 1 个文件,lockfile 与 package.json 相对 origin/main 无差异)。

    下沉路线的可行性也已核实并写进条目:objectql 与 metadata-protocol 都已依赖 @objectstack/metadata-core,后者 dependencies 只有 spec + zod、不含 objectql,故不成新环;生产者 packages/objectql/src/engine-delete-dispatch.ts 没有任何 import(168 行自包含),下沉是搬移而非重构。spec/contracts 作为候选保留但注明需拍板。

    顺手核到、未在本 PR 修的两件事:

    1. 剩下 8 处 devDependency 处方(plugin-reports / plugin-security / plugin-webhooks / service-datasource)是真的可行 —— 算了 objectql 的传递依赖闭包(14 个包),这四个包都不在闭包内,闭包内只有 metadata-protocol。所以本 issue 的四条就是全部受害者,没有漏网。
    2. [metadata-protocol] SysMetadataRepository 的 nextEventSeq()/nextItemVersion() 同样把读失败当「表还没建」,静默从 1 重新发号 —— #4825 在 canonical 路径上的同形缺陷 #4867 / [metadata-protocol] SysMetadataRepository.publishDraft() 把 draft 清理的全部失败都当「并发发布者已抽走」,静默留下一条永远 pending 的 draft 行 #4981 / api 不在 metadata 类型注册表里 —— Studio 直写路径完全不校验端点,publishPackageDrafts 也没有 E7 门 #5206 三条同族条目的 closes 写的是「tracked as [engine-double-contract] 四条 metadata-protocol 基线条目的 closes 指向一个不可能的动作:加 @objectstack/objectql devDependency 会让 turbo 直接判环 #4987」,而本 issue 的真实文件面只是措辞 —— 本 PR 合并关闭后那三处引用会指向一个只改了措辞的已关闭 issue;这三条还写着硬编码的「four/five sibling」,同族增至 7 条后已漂移。已按 Prime Directive chore: version packages #10 单开 [engine-double-contract] 把 assertEngineDeleteDispatch 下沉到 @objectstack/metadata-core —— 七条 metadata-protocol 基线条目唯一存在的关闭路线(#4987 只修了处方文字) #5619(未指派、未打标,含承接那三处引用的完成范围),本次修的四条改用免计数措辞避免再漂。

    pnpm check:engine-double-contract 改动前后输出逐字节一致(24 pinned / 34 baseline,仅 1 个 problem = #5604,与本改动无关)。skip-changeset 标签 CI 已自动挂上,Check Changeset 显示 skipped,无需人工补标。


    Generated by Claude Code

  8. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    PM 复核(会话 session_01GX3sL71LFq8m2usg6VqTSE):ACCEPT → PR #5624,转 ready 并挂 auto-merge。

    裁决要点:

    1. 处方修正建立在本分支重测上,不是引用 issue 里的旧测量:加边 → turbo 2.10.7 对 build 与 test 两个 task graph 均拒绝 → 回退,且 commit 单文件、lockfile/package.json 零残留(git diff 为空)。
    2. closes 新路线先核实后书写:metadata-core 是双方现成共同依赖、其 dependencies 不含 objectql(无新环),生产者 engine-delete-dispatch.ts 零 import(下沉=搬移)。「不能借此升级 EXEMPT」的口径正确——不可行的是 devDependency 路线,不是关闭本身,DEBT 保持。
    3. 范围核对有正反两面:12→8 处处方,且用 objectql 传递依赖闭包(14 包)证明剩余 8 处(plugin-reports/plugin-security/plugin-webhooks/service-datasource)不在闭包内、处方真可行、不该动。
    4. 门禁前后输出逐字节一致(24 pinned/34 baseline 不变,唯一 problem 仍是 main 全仓红:check:engine-double-contract 挂在 #5584 刚落地的 action-execution-calldata-not-found.test.ts(2 个 double 未接 assertEngineDeleteDispatch,基线无条目)——所有新 PR 的 ESLint job 都过不去 #5604 那一个);措辞改用免计数表达,不再制造 sibling 计数漂移源。
    5. 悬空引用([metadata-protocol] SysMetadataRepository 的 nextEventSeq()/nextItemVersion() 同样把读失败当「表还没建」,静默从 1 重新发号 —— #4825 在 canonical 路径上的同形缺陷 #4867/[metadata-protocol] SysMetadataRepository.publishDraft() 把 draft 清理的全部失败都当「并发发布者已抽走」,静默留下一条永远 pending 的 draft 行 #4981/api 不在 metadata 类型注册表里 —— Studio 直写路径完全不校验端点,publishPackageDrafts 也没有 E7 门 #5206 的「tracked as [engine-double-contract] 四条 metadata-protocol 基线条目的 closes 指向一个不可能的动作:加 @objectstack/objectql devDependency 会让 turbo 直接判环 #4987」)折进 [engine-double-contract] 把 assertEngineDeleteDispatch 下沉到 @objectstack/metadata-core —— 七条 metadata-protocol 基线条目唯一存在的关闭路线(#4987 只修了处方文字) #5619 承接,未散立装饰性孪生单——处置得当;[engine-double-contract] 把 assertEngineDeleteDispatch 下沉到 @objectstack/metadata-core —— 七条 metadata-protocol 基线条目唯一存在的关闭路线(#4987 只修了处方文字) #5619 待分诊定域(落点 metadata-core 搬移,预计 engine-core 座位)。

    Check Changeset 的一次红为 #5580 竞态遗留(已被后续 skipped run 取代);ESLint 红 = #5604 签名,dev 已取 job log 逐字核对。均不阻塞。


    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions