Skip to content

fix(metadata-protocol): boot hydration uses the shared package-scoped overlay registration (#4624) - #4635

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-4624-boot-hydration-scoped-lookup
Aug 2, 2026
Merged

fix(metadata-protocol): boot hydration uses the shared package-scoped overlay registration (#4624)#4635
os-zhuang merged 1 commit into
mainfrom
claude/issue-4624-boot-hydration-scoped-lookup

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #4624

问题

loadMetaFromDb(启动水合)的非 object 分支保留着 overlay→SchemaRegistry 注册规则的第三份内联拷贝,且其 artifact 查找是无包作用域的(lookupArtifactItem(normalizedType, name),不带该行的 package_id)——正是 #1828getMetaItems 中修掉的 pre-ADR-0048 形态:当两个已安装的包发布同名 type/name 时,一条同名 overlay 行会在每次内核启动时,把先注册的那个包的 _lock/_lockReason/_packageId/_provenance 嫁接到另一个包的行上(composite 扫描按 Map 插入顺序 first-match)。绑定在包 B 下的定制行,启动后可能顶着包 A 的身份和锁。

修复

按 issue 建议,将内联块替换为对 #4622 落地的共享实现 hydrateOverlayIntoRegistry 的调用,并传入该行自己的 record.package_id —— 一条规则、一份实现(读侧水合、#4521 写穿、启动水合三处共用),ADR-0048 的包作用域查找在启动时同样生效。

按 issue/PM 要求逐项核查过的两个前提

  1. 启动顺序假设:不存在依赖无作用域查找的启动顺序。当 artifact 在水合之后才加载时,scoped 与 unscoped 查找同样都找不到条目,行按原样注册(与修复前逐字节一致);artifact 先加载时,scoped 才产生差异——而那正是本修复要的差异。已有 pin test 固定该"artifact 后加载 = 无操作"行为。
  2. environmentId 闸门:共享 helper 本身不带环境闸门(闸门在调用方——读侧 getMetaItemsenvironmentId === undefined 判断、写穿 applyRegistryWriteThrough 第 6031 行)。因此切换到 helper 不改变哪些行进入注册表:loadMetaFromDb 的行选择完全由其查询决定,本 PR 未触碰。

另注:包无绑定(package_id IS NULL)的全局行保持遗留 best-effort first-match 嫁接语义,与读侧水合完全一致(pin test 第 3 例固定,断言故意宽松以免过度固定 first-match 顺序)。

Pin test(修复前必失败)

packages/objectql/src/protocol-boot-hydration-scoped.test.ts —— 两个包(com.acme.a 先注册、com.acme.b 后注册)发布同名 page/home artifact,sys_metadata 中一条绑定 com.acme.b 的 overlay 行;启动水合后 bare-key 条目必须携带 B 的保护封套。在修复前的树上验证过失败:

AssertionError: expected 'com.acme.a' to be 'com.acme.b'

测试

  • pnpm --filter @objectstack/metadata-protocol test → 25 files / 206 tests passed
  • pnpm --filter @objectstack/objectql test → 100 files / 1609 tests passed(含新增 3 例)
  • pnpm --filter @objectstack/objectql typecheck → exit 0(metadata-protocol 无 typecheck 脚本,系 ratchet ledger 中的既有 DEBT 条目;其 DTS 构建通过)

范围外发现(已另行建 issue,未在本 PR 修)

loadMetaFromDbobject 分支(约 8960 行)读取 record.packageId || 'sys_metadata',而 engine.find('sys_metadata') 返回的是 snake_case 行键(package_id,与 getMetaItems 第 2588 行、repository 写入路径一致),故 record.packageId 恒为 undefined——所有 object overlay 行一律以 'sys_metadata' 哨兵注册,包绑定在启动水合时丢失。详见新建 issue。

Changeset

.changeset/boot-hydration-scoped-lookup.md(@objectstack/metadata-protocol patch)。

🤖 Generated with Claude Code

https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5


Generated by Claude Code

… overlay registration (#4624)

loadMetaFromDb's non-object branch kept a THIRD inline copy of the
overlay->SchemaRegistry rule with an UNSCOPED artifact lookup — the exact
pre-#1828 shape: a name-colliding overlay grafted the first-registered
package's _lock/_packageId/_provenance onto another package's row at boot
(ADR-0048 gap). The branch now delegates to the ONE shared
hydrateOverlayIntoRegistry (#4521), passing the row's own package_id, so
the ADR-0048 package-scoped lookup applies at boot exactly as it does on
the read-side hydration and the write-through.

No other boot behaviour changes: artifacts-not-yet-loaded boot orders
register the row unchanged (scoped and unscoped both find nothing),
package-less rows keep the legacy best-effort graft, and the helper
carries no environment gate so row selection is untouched.

Pin test: two packages shipping the same-named artifact — boot hydration
must graft each row's envelope from ITS OWN package (fails pre-fix with
com.acme.a grafted onto com.acme.b's row).

Fixes #4624

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

vercel Bot commented Aug 2, 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 2, 2026 12:24pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Aug 2, 2026
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/metadata-protocol.

3 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-protocol)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/metadata-protocol)
  • content/docs/releases/v9.mdx (via @objectstack/metadata-protocol)

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.

@os-zhuang
os-zhuang marked this pull request as ready for review August 2, 2026 12:37
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 2, 2026
Merged via the queue into main with commit 58434f5 Aug 2, 2026
21 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-4624-boot-hydration-scoped-lookup branch August 2, 2026 12:48
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/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

loadMetaFromDb boot hydration keeps a third inline copy of the overlay→registry rule with an UNSCOPED artifact lookup (ADR-0048 gap)

2 participants