Skip to content

feat(spec)!: 双源 C5 收敛 — ActivationEventSchema 归 ./kernel 结构化形状,./studio re-export (#4653) - #4662

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-4653-activation-event-dual-source
Aug 2, 2026
Merged

feat(spec)!: 双源 C5 收敛 — ActivationEventSchema 归 ./kernel 结构化形状,./studio re-export (#4653)#4662
os-zhuang merged 1 commit into
mainfrom
claude/issue-4653-activation-event-dual-source

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Fixes #4653

按维护者在 #4653 的裁决走路线 A:保留 activationEvents,收敛到 ./kernel 的结构化 z.object({ type, pattern }),./studio 侧 re-export。基线 22 → 21


1. 三仓(实为四仓)import 语句级扫描结论

扫了 objectstack @ 21676eb5dcloud @ bce2bec99objectui @ f5728490c,外加 org code search 追出来的 cloud-v1 @ e4c2040b9

ActivationEventSchema / ActivationEvent 的 import 语句,packages/spec 之外四仓为零:

结果
cloud 0 命中。该仓 @objectstack/spec/kernel 的 import 全是 ExecutionContext / PluginContext / PluginPermissions / ManifestSchema
objectui 0 直接 import。只有 packages/types/src/index.ts:940,943 的整命名空间 export type * as Kernel / as Studio —— 命名空间隔离,两侧不打架
cloud-v1 0 import,但 apps/cloud/lib/marketplace/plugin-runtime.ts 自己另写了第三份形状
objectstack 消费方只有两侧各自的父 schema、各自单测、生成文档

没有死侧可删,两个父 schema 都在作者面上(DynamicLoadRequest.activationEventsStudioPluginManifest.activationEvents,后者正是 defineStudioPlugin 的入参)。

2. 选定路线及为什么

裁决选 A。落地时确认了它成立的关键一点:结构化那一侧赢,不是因为它更常见,而是因为字符串那一侧什么都不校验。 z.string() 接受 '''banana',以及真正要命的 'onMetadatType:flow' —— studio/plugin.zod.ts 文档里列的词表(*onMetadataType:onCommand:onView:)只活在散文里,拼错永远静默通过。enum 把触发器类型在创作时钉死。

词表 = 两侧并集(9 值),每个值的来源

来源
onCommand kernel enum + studio 文档 onCommand:myPlugin.doSomething
onRoute kernel enum
onObject kernel enum
onEvent kernel enum
onService kernel enum
onSchedule kernel enum
onStartup kernel enum;同时是 studio '*' 的落点
onMetadataType studio 文档 plugin.zod.ts:281 + 测试 —— kernel 原本没有
onView studio 文档 plugin.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:schemaauthorable-surface.json 的实际改动只有新增:

+    "studio/ActivationEvent:pattern",
+    "studio/ActivationEvent:type",

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 同样零父嵌入 —— 是运行时请求载荷。
  • stack 的 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 测试抓不到的那种):

     × both entry points export the very same declaration 1292ms
AssertionError: expected [Function] to be [Function] // Object.is equality
 Tests  1 failed | 39 passed (40)

只有身份断言红,其余 39 条全绿 —— 证明这个 pin 不是在重复测形状。

Sabotage 2 —— studio 侧完整回退到 v17 前的 z.string():

     × should accept valid activation events
     × should reject the pre-v17 bare-string form
     × should accept minimal manifest with defaults
     × should accept full manifest
     × rejects a manifest still carrying the pre-v17 string activation events
     × should return a parsed manifest
     × both entry points export the very same declaration
     × the shared declaration is the structured kernel form on BOTH entries
     × the trigger vocabulary is the union of both pre-v17 vocabularies
 Tests  9 failed | 31 passed (40)

Sabotage 3 —— 从 enum 里拿掉 onMetadataType(即静默删掉一个 studio 作者在用的能力):

     × the trigger vocabulary is the union of both pre-v17 vocabularies
AssertionError: 'onMetadataType' must stay in the vocabulary: expected [Function] to not throw
 Tests  5 failed | 53 passed (58)

三次 sabotage 后均已还原,还原态 58/58 绿。

6. 全部门禁结果

packages/spec 下,前台跑、共享 flock 串行、--max-old-space-size=4096:

门禁 结果
build
check:dual-source-exports 4313 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:docs
test Test Files 291 passed (291) / Tests 7285 passed (7285)
check:liveness
check:strictness-ledger 67 file(s) across 5 triaged director(ies) — site counts match
check:empty-state
check:variant-docs
check:exported-any
check:skill-examples 202 prose examples type-check(content/docs/**os:check,即改过的 development.mdx 例子是真的过了编译)
全仓 pnpm typecheck Tasks: 122 successful, 122 total

严格性台账未动:本 PR 删的是一个 z.string()lazySchema,不是 z.object( 站点,check:strictness-ledger 自证站点数不变。

7. 文档

  • content/docs/plugins/development.mdx:387os: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/spec major,含逐条 FROM → TO 对照表、词表来源表、以及「为什么没有 conversion + 手工迁移步骤」。

9. 范围外发现(已立案,未在本 PR 修)


🤖 Generated with Claude Code

https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL


Generated by Claude Code


Generated by Claude Code

…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
@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 2:59pm

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/spec.

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

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

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 16:12
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 2, 2026
Merged via the queue into main with commit 65ca83a Aug 2, 2026
23 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-4653-activation-event-dual-source branch August 2, 2026 16:24
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
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.

spec 双源清账 C5:ActivationEventSchema(./kernel ≠ ./studio)—— 1 条

2 participants