feat(spec)!: 双源 C5 收敛 — ActivationEventSchema 归 ./kernel 结构化形状,./studio re-export (#4653) - #4662
Merged
Merged
Conversation
…io re-export (#4653) `ActivationEventSchema` 过去在两个入口解析到两份不同声明,插件作者拿到 哪套校验取决于 import 路径(#4411 陷阱):`./kernel` 是结构化的 `z.object({ type, pattern })`,`./studio` 是裸 `z.string()`。 四仓(objectstack / cloud / cloud-v1 / objectui)import 语句级扫描: spec 之外零消费方,两侧都只被自己的父 schema 引用,且两个父 schema 都在 作者面上 —— 没有死侧可删。按维护者裁决走收敛:`./studio` 现在 re-export `./kernel` 的那一份声明。 结构化的一侧赢,因为字符串那一侧什么都不校验:`z.string()` 接受 `'onMetadatType:flow'` 及一切拼写错误,文件里记的词表只活在散文里。 enum 取两侧词表并集(kernel 7 值 + studio 的 onMetadataType / onView), 没有能力被静默拿掉;`'*'` 落到 `{ type:'onStartup', pattern:'*' }`。 未采纳 cloud-v1 的 priority / onInstall / onWebhook —— 四仓无人读, 新增 declared-but-unenforced 键正是 ADR-0049 在清的债。 零可作者化 key 消失、零 tombstone:kernel 的 2 个 key 原样存活, studio 侧新增 2 个(字符串无 key,对象有),属 gen:schema 允许的新增。 未手编 authorable-surface.json。基线 22 → 21。 无 ADR-0087 conversion:conversion 层接在 normalizeStackInput 上只走 stack 树, 而两个父 schema 都是根 schema,不在 stack 里 —— 伪造一个跑不到的 conversion 只会制造已自动迁移的假象。迁移手工进行,漏改在 parse 处响亮失败。 回归 pin 用运行时模块命名空间断言(#4642:本包编译期 pin 空转), 三组 sabotage 已验证其真的会红。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
August 2, 2026 16:12
This was referenced Aug 2, 2026
os-zhuang
pushed a commit
that referenced
this pull request
Aug 2, 2026
生成物冲突以三路集合合并解决(等价于重新生成),手写登记表以 base→ours 的 hunk 打到 main 版上,双方条目均保留: - dual-source-exports.baseline.json: 22 → 19(C8 去 RetryPolicy ×2, main 的 #4662 去 ActivationEventSchema ×1) - conversions/registry.ts: retryPolicyConverged 与 main 的 objectManagedBySystemToSystemData 同时注册 - migrations/registry.ts: job-retry-policy-constraints-tightened 保留 - protocol-upgrade-guide.md: 两侧表格行都保留 未跑本地全套门禁 —— 由 CI 的 check:generated 验证生成物确实等于 重新生成的结果,这是与维护者商定的快路径(main 上 spec PR 密度使 本地十几分钟的门禁跑完即过期)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4653
按维护者在 #4653 的裁决走路线 A:保留
activationEvents,收敛到./kernel的结构化z.object({ type, pattern }),./studio侧 re-export。基线 22 → 21。1. 三仓(实为四仓)import 语句级扫描结论
扫了
objectstack@21676eb5d、cloud@bce2bec99、objectui@f5728490c,外加 org code search 追出来的cloud-v1@e4c2040b9。ActivationEventSchema/ActivationEvent的 import 语句,packages/spec之外四仓为零:cloud@objectstack/spec/kernel的 import 全是ExecutionContext/PluginContext/PluginPermissions/ManifestSchema等objectuipackages/types/src/index.ts:940,943的整命名空间export type * as Kernel/as Studio—— 命名空间隔离,两侧不打架cloud-v1apps/cloud/lib/marketplace/plugin-runtime.ts自己另写了第三份形状objectstack⇒ 没有死侧可删,两个父 schema 都在作者面上(
DynamicLoadRequest.activationEvents与StudioPluginManifest.activationEvents,后者正是defineStudioPlugin的入参)。2. 选定路线及为什么
裁决选 A。落地时确认了它成立的关键一点:结构化那一侧赢,不是因为它更常见,而是因为字符串那一侧什么都不校验。
z.string()接受''、'banana',以及真正要命的'onMetadatType:flow'——studio/plugin.zod.ts文档里列的词表(*、onMetadataType:、onCommand:、onView:)只活在散文里,拼错永远静默通过。enum 把触发器类型在创作时钉死。词表 = 两侧并集(9 值),每个值的来源
onCommandonCommand:myPlugin.doSomethingonRouteonObjectonEventonServiceonScheduleonStartup'*'的落点onMetadataTypeplugin.zod.ts:281+ 测试 —— kernel 原本没有onViewplugin.zod.ts:283+ 测试 —— kernel 原本没有未采纳 cloud-v1 的
priority/onInstall/onWebhook(裁决第 2 条):四仓无人读,新增一个 declared-but-unenforced 键正是 ADR-0049 在清的债。['*']的去处落到
{ type: 'onStartup', pattern: '*' },即维护者的倾向,没有给 eager 独立type。理由:'*'一直就是「立即激活」,而 kernel 侧onStartup的原文就是 "Activate immediately on kernel startup" —— 再加一个枚举值只会造出两个同义词。StudioPluginManifest.activationEvents的.default()同步改成该值,并有测试钉住。3. 可作者化 key:零消失,零 tombstone ✅
gen:schema对authorable-surface.json的实际改动只有新增:kernel 的
ActivationEvent:type/:pattern原样存活;studio 侧原本 0 key(字符串没有 key),收敛后有了 2 个 —— 属gen:schema允许的新增重写。check:authorable-surface自己确认了零 vanish。⛔ 未手编
authorable-surface.json(#4650)。唯一另一处非新增的改动是该文件 description 行的—→ 字面—,那是生成器自身的规范化输出(顺带说明该文件此前曾被手工改过 —— 已按军规立案,见下)。另有两条 ratchet 按各自门禁的明确指令删行:
dual-source-exports.baseline.json删掉 C5 那行(22 → 21),docs-import-surface.baseline.json删掉studio/ActivationEvent — no type export(144 → 143,./studio现在确实导出该类型了)。两者都是门禁主动点名要求删的 stale 行,与 authorable 基线不是一回事。4. conversion walker 可达性:已验证,不可达 —— 故不写 conversion
裁决第 4 条要求查实而非假装。证据:
applyConversions接在normalizeStackInput上,只走 stack 树(conversions/apply.ts:6-11)。StudioPluginManifestSchema没有任何父 schema 嵌入:全仓引用只有它自己的声明、studio/index.ts的导出、defineStudioPlugin的.parse()和测试。它是根 schema,由作者直接 parse,从不进 stack。DynamicLoadRequestSchema同样零父嵌入 —— 是运行时请求载荷。plugins[]装的是 ObjectStack 内核插件实例(metadata-collection.zod.ts:72明写plugins/devPlugins"not named metadata schemas"),不是 Studio 插件清单。⇒ 任何
mapCollection/mapFlowNodes都够不到这两处。不伪造跑不到的 conversion,改为在 major changeset 写清手工迁移步骤。字符串遇到对象 schema 在 parse 处响亮失败(StudioPluginManifestSchema还是strictObject),这是可接受的失败模式,并已单独钉测试。5. Sabotage 验证(#4642:本包编译期 pin 空转)
新 pin 是运行时模块命名空间断言(
src/studio/plugin.test.ts末尾),import 两个真实入口../kernel/index/../studio/index并断言符号同一性 —— 与check:dual-source-exports的判据(alias 解析后的符号身份)一致。三组 sabotage 全部验证其真的会红:Sabotage 1 —— studio 重新声明一份「形状完全相同」的 schema(shape 测试抓不到的那种):
只有身份断言红,其余 39 条全绿 —— 证明这个 pin 不是在重复测形状。
Sabotage 2 —— studio 侧完整回退到 v17 前的
z.string():Sabotage 3 —— 从 enum 里拿掉
onMetadataType(即静默删掉一个 studio 作者在用的能力):三次 sabotage 后均已还原,还原态 58/58 绿。
6. 全部门禁结果
在
packages/spec下,前台跑、共享flock串行、--max-old-space-size=4096:buildcheck:dual-source-exports4313 names across 16 entry points — 162 re-exported (single declaration), **21 accepted dual-source** (baseline)check:generated(8 项)check:authorable-surface/check:api-surface/check:docstestTest Files 291 passed (291) / Tests 7285 passed (7285)check:livenesscheck:strictness-ledger67 file(s) across 5 triaged director(ies) — site counts matchcheck:empty-statecheck:variant-docscheck:exported-anycheck:skill-examples202 prose examples type-check(含content/docs/**的os:check块,即改过的development.mdx例子是真的过了编译)pnpm typecheckTasks: 122 successful, 122 total严格性台账未动:本 PR 删的是一个
z.string()的lazySchema,不是z.object(站点,check:strictness-ledger自证站点数不变。7. 文档
content/docs/plugins/development.mdx:387的os:check例子改为结构化形式(由check:skill-examples实际编译验证)。packages/spec/PLUGIN_STANDARDS.md:165词表更新。gen:docs)按 docs-drift 提示全量重生成,顺带修好一个既有缺陷:kernel/ActivationEvent此前被生成到错误的 reference 页kernel/plugin.mdx,现在回到kernel/plugin-runtime.mdx(与 C4 修的同类问题);studio/ActivationEvent则落到新的studio/plugin-runtime.mdx。content/docs/releases/。8. Changeset
.changeset/converge-activation-event-schema.md,@objectstack/specmajor,含逐条 FROM → TO 对照表、词表来源表、以及「为什么没有 conversion + 手工迁移步骤」。9. 范围外发现(已立案,未在本 PR 修)
activationEvents声明四仓零 reader —— declared-but-unenforced,且 studio 侧z.string()零校验 #4657 —— 两份activationEvents声明四仓零 reader(cloud-v1/docs/ROADMAP.md:641自记未实现:"All plugins activated immediately on install",计划 v0.4.0)。裁决已明确 ADR-0049:两份activationEvents声明四仓零 reader —— declared-but-unenforced,且 studio 侧z.string()零校验 #4657 不因本 PR 关闭。authorable-surface.json在 main 上不是gen:schema的输出 —— 基线手编的字节级实锤(#4650 加固建议) #4663 ——authorable-surface.json曾被手工编辑的直接证据:本次gen:schema把 description 行的—规范化为字面—,说明该文件此前的内容不是生成器输出。是 authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 那个洞的实锤,归 authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 的加固范围。🤖 Generated with Claude Code
https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL
Generated by Claude Code
Generated by Claude Code