Skip to content

fix(objectql,metadata-protocol): 租户自己写的覆盖层不该被当成代码包产物 - #4429

Merged
os-zhuang merged 1 commit into
mainfrom
fix/runtime-overlay-not-artifact
Aug 1, 2026
Merged

fix(objectql,metadata-protocol): 租户自己写的覆盖层不该被当成代码包产物#4429
os-zhuang merged 1 commit into
mainfrom
fix/runtime-overlay-not-artifact

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

问题

saveMetaItem 会拒绝写入「artifact-backed 且该类型没开启 overlay 写」的元数据(not_overridable),而它判断谁是 artifact-backed 靠的是 registry.getArtifactItem。这个判据一直是「_packageId 不等于字面量 sys_metadata 就算代码产物」—— 但这个哨兵只在 save 路径上成立

启动时 loadMetaFromDbsys_metadata 的每一行按它真实的 packageIdapp.<slug>)注册进 registry,而自从 package 成为强制项之后,所有运行时创作的条目都带着这样一个 packageId

结果:用户刚在 Studio(或 AI 搭建 agent)里建好的应用,经过下一次 kernel 重建之后,看起来就像是代码包发布的产物 —— 于是之后对它的任何修改都被 403 拒绝,且是永久性的

线上实测(objectstack-ai/cloud#970):对同一个对象、相隔几秒的两次 modify_field,第一次 status: published 成功上线,第二次直接 [not_overridable] —— 因为第一次的 auto-publish 在中间触发了 kernel 重建。

这也正是 AI 授权 skill 里那条「apply_blueprint 之后你必须 update_metadata 把汇总配置补上」的指示为什么是空话:它指向的那条路根本走不通。

改动

真正区分两者的轴是 provenance(ADR-0010:'package' = loader 引入,'org' = 租户自己写的),所以就问它:

  • loadMetaFromDb 注册 object 时打上 _provenance: 'org' —— 这些行按定义就来自 sys_metadata,是租户的覆盖层。
  • getArtifactItem 的四个分支都不再把 _provenance === 'org' 的条目当作 artifact。

没有 provenance 的条目在真实 packageId 下维持原判定,所以本来受保护的东西不会悄悄变成可写。

测试

新增 registry-tenant-authored-artifact.test.ts(5 例):租户覆盖层不再被当 artifact;代码包产物仍然是 artifact;无 provenance 维持原状;sys_metadata 哨兵仍生效;非 object 类型同理。去掉 registry 改动后其中 2 例会失败(已验证)。

packages/objectql 92 files / 1506 tests、packages/metadata-protocol 21 files / 139 tests 全绿。

🤖 Generated with Claude Code

…ead back as a code artifact

`saveMetaItem` refuses to write an artifact-backed item of a type that has not
opted into overlay writes (`not_overridable`), and it asks
`registry.getArtifactItem` who is artifact-backed. That answer was "anything
whose `_packageId` is not the literal string `sys_metadata`" — a sentinel that
only holds on the save path. The boot-time rehydration of `sys_metadata`
registers each row under its REAL package id (`app.<slug>`), which every
runtime-authored item has carried since packages became mandatory.

So an app the user had just built through Studio (or the AI build agent) came
back from the next kernel rebuild looking code-shipped, and the following edit
was refused with a 403 — permanently. Live capture: two identical `modify_field`
calls on the same object seconds apart, the first published LIVE and the second
`not_overridable`, because the first one's auto-publish triggered the rebuild in
between (cloud#970). It is also why the AI authoring skill's "after
apply_blueprint, update_metadata to add the roll-up config" instruction pointed
at a road that does not exist.

Provenance is the axis that actually separates the two (ADR-0010 `_provenance`:
`'package'` for loader-introduced, `'org'` for tenant-authored), so ask it: the
`sys_metadata` hydration stamps `_provenance: 'org'`, and `getArtifactItem` no
longer treats such an item as an artifact. An item with NO provenance under a
real package id keeps the old answer, so nothing that was protected silently
becomes writable.

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

vercel Bot commented Aug 1, 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 1, 2026 5:17am

Request Review

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

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/metadata-protocol, @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-protocol, @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/metadata-protocol, @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/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/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 merged commit 1ee48bc into main Aug 1, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the fix/runtime-overlay-not-artifact branch August 1, 2026 05:23
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