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

vercelBot commented Jul 23, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJul 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 mainJul 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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@os-zhuang