Skip to content

fix(objectql): bridge late-registered manifest objects into the metadata service#3428

Merged
os-zhuang merged 1 commit into
mainfrom
claude/agitated-lamport-3dfec0
Jul 24, 2026
Merged

fix(objectql): bridge late-registered manifest objects into the metadata service#3428
os-zhuang merged 1 commit into
mainfrom
claude/agitated-lamport-3dfec0

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

问题

Marketplace 安装的模板包对象(manifest 服务 → ql.registerApp)只进 ObjectQL registry,永远不进 metadata 服务(IMetadataService):bridgeObjectsToMetadataService 只在 ObjectQLPlugin.start() 里一次性运行,而 marketplace 的 install / ledger rehydrate 都发生在 kernel:ready 之后。

后果:所有 IMetadataService 消费者对 marketplace 对象 miss——AI describe_object、Studio 对象清单、metadata.listObjects 等。种子加载器的引用图盲区已由 #3422 用 engine.getSchema fallback 单独修复,但那只救了 seed 一条路。

修复

manifest 服务的 register 在注册进 engine registry 后,把该 manifest 自己的对象 bridge 进 metadata 服务(packages/objectql/src/plugin.ts):

  • 调用时刻解析 metadata 服务——objectql plugin init 时 MetadataPlugin 可能还没注册它;
  • 载荷取自 registry(registry.getAllObjects(packageId)):数组/映射两种 objects 形态、extension 合并、applySystemFields/provisionPrimary 归一化都拿到规范形状,且盖上 _packageId 印记;
  • register('object', name, obj, { notify: false })——与启动 bridge 同一 MetadataManager.register() never notifies subscribe() watchers — runtime consumers go stale on every non-saveMetaItem write #3112 通知契约理由:定义本来就来自 SchemaRegistry,announce 会经我们自己的 subscribe('object') 回环并把 provenance 覆盖成 metadata-service;
  • 不覆盖别人的条目:已存在且非本 bridge 同包印记的条目一律跳过(authored / artifact 解析副本安全);同包再注册(热升级)则刷新自己的副本;
  • 旗标门控:只在 start() 跑完一次性 bridge 后才生效(启动期行为零变化,启动期注册仍由一次性 bridge 覆盖),且项目级 kernel(environmentId 有值)永不生效——与一次性 bridge 同门;
  • register 返回 bridge promise(从不 reject);marketplace install/rehydrate 两处 await 它,安装返回 200 后立刻读 metadata 是确定性的(packages/cloud-connection/src/marketplace-install-local-plugin.ts)。

测试

plugin.integration.test.ts 新增 4 个真 kernel 集成测试(late manifest.register bridges objects to the metadata service):

  1. bootstrap 后经 manifest 服务安装 → metadata.getObject('crm_contact') 返回 registry 解析形状(_packageId 印记、字段完整),listObjects 可见;
  2. 同包重装(热升级)→ bridged 副本刷新;
  3. 已有同名 authored 条目 → 不被覆盖(护栏);
  4. 启动期注册仍走一次性 bridge(路径不回归)。

门先证红:还原 plugin.ts 后测试 1/2 失败、3/4 通过(护栏测试本就该绿),确认非假绿。

🤖 Generated with Claude Code

…ata service

Marketplace-installed template packages register through the manifest
service on kernel:ready (rehydrate) or an HTTP request (install), but the
one-shot SchemaRegistry-to-metadata bridge runs once during
ObjectQLPlugin.start() - so their objects only ever reached the ObjectQL
registry. Every IMetadataService consumer (AI describe_object, Studio
object lists, metadata.listObjects) missed them; only the seed loader had
grown an engine-side fallback (#3422).

The manifest service's register now bridges the manifest's own objects
(registry-resolved, so both objects forms and extension merges come out
canonical with _packageId stamped) into the metadata service:

- resolved at call time: at objectql init the metadata service may not be
  registered yet
- register('object', name, obj, { notify: false }) - same #3112 rationale
  as the startup bridge: announcing would loop the definitions back
  through our own subscribe('object') handler and overwrite provenance
  with 'metadata-service'
- entries it did not bridge itself are never clobbered; its own copy is
  refreshed on same-package re-install so a hot marketplace upgrade stays
  fresh
- armed only after start() ran the one-shot bridge, and never on project
  kernels (same environmentId gate) - boot-time behavior is unchanged

register returns the bridge promise; marketplace install/rehydrate await
it so metadata reads right after a 200 are deterministic.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 23, 2026 5:58pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

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

  • content/docs/concepts/metadata-lifecycle.mdx (via @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/objectql)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/objectql)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/objectql)
  • content/docs/releases/implementation-status.mdx (via @objectstack/objectql)
  • content/docs/releases/v9.mdx (via @objectstack/objectql)

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 merged commit 402f534 into main Jul 24, 2026
21 of 29 checks passed
@os-zhuang
os-zhuang deleted the claude/agitated-lamport-3dfec0 branch July 24, 2026 11:27
os-zhuang added a commit that referenced this pull request Jul 24, 2026
…ls too (#3436)

The per-manifest bridge added for marketplace installs (#3428) armed
itself inside the same `environmentId === undefined` gate as the one-shot
startup bridge - but `os dev` boots the kernel project-scoped
(environmentId 'env_local'), which is marketplace install-local's primary
home, so the fix was inert exactly where it matters. Caught by
browser-dogfooding the install flow: the install succeeded, yet the
process never logged a bridge pass and the flag could never arm.

The gate is correct for the one-shot bridge (it copies the ENTIRE
process-wide SchemaRegistry, which would leak sibling-project objects on
multi-environment servers) but does not apply to the per-manifest bridge:
it only copies the objects of the one package this kernel just
registered - nothing to leak. Arming now happens unconditionally at the
end of start(); boot-time behavior on every kernel shape is unchanged
(the flag still flips only after the startup path has run) and the
one-shot bridge keeps its gate.

Regression test: a project-scoped kernel (environmentId 'env_local' -
the exact `os dev` shape) now asserts a post-bootstrap manifest.register
lands its objects in the metadata service; red before this change.

Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant