Repository navigation
ADR-0049:两份 activationEvents 声明四仓零 reader —— declared-but-unenforced,且 studio 侧 z.string() 零校验 #4657
Description
Activity
🔒 认领:PM 会话
session_0176qgxgCXTJCUv4YFLtusP9,分支claude/issue-4657-activation-events-retirement。ADR-0049 队列接派(前序 #4616 → PR #4809 审毕,正在补 main 同步)。派发前快检(08:1xZ):
- 本单前提已被 spec 双源清账 C5:ActivationEventSchema(./kernel ≠ ./studio)—— 1 条 #4653 解决一半:main 上
studio/plugin.zod.ts:396已是z.array(ActivationEventSchema)(结构化),studio/index.ts:29re-export kernel 侧唯一声明 —— 问题 2(studio 侧z.string()零校验)与「双源」都已不存在,「两单一起裁」的耦合也随之解除(spec 双源清账 C5:ActivationEventSchema(./kernel ≠ ./studio)—— 1 条 #4653 已选定编码并合入 main)。 - 剩下的正是问题 1:ADR-0049 declared-but-unenforced —— 四仓零 runtime reader,所有插件安装即激活,
activationEvents键在语义上撒谎。cloud-v1 ROADMAP 自记 ❌ 未实现(v0.4.0 计划)。 .changeset/pre.json仍mode: pre,v17 窗口内 → 按 enforce-or-remove 走 remove。
区域:
kernel/plugin-runtime.zod.ts+studio/plugin.zod.ts+ 两处文档;与在飞 #4616(system/notification+kernel/metadata-plugin)文件不相交,可并行实施,入队排其后。
Generated by Claude Code
- 本单前提已被 spec 双源清账 C5:ActivationEventSchema(./kernel ≠ ./studio)—— 1 条 #4653 解决一半:main 上
✅ 实施完成 — draft PR:#4831(分支
claude/issue-4657-activation-events-retirement,会话session_0176qgxgCXTJCUv4YFLtusP9)。按 remove 处置,三处三种形态(由
gen:schema的 #4650 门禁实跑输出裁定,实报贴在 PR body):DynamicLoadRequest.activationEvents→retiredKey()墓碑(非 strict schema,裸删即静默 strip);StudioPluginManifest.activationEvents→ strict 删除 + guidance 处方(原activation/events/onActivatealias 一并移入 guidance 同一处方);ActivationEventSchema/ActivationEventdef → 整体删除(authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 路线 3:两个 manifest 条目与 4 条 authorable 行有意删除,门禁裁定"def no longer emitted");compiler-API 零 holder pin,三轮 sabotage 实跑全红(输出见 PR)。
ADR-0087:D2 不适用(两父 schema 均非
sys_metadata存量,无源可改写),登记 D3 semanticplugin-activation-events-retired。changeset major,FROM → TO:删掉该键(v16 字符串形或 v17-rc 结构形皆同),所有插件本来就是安装即激活,行为零变化。消费方复核(裸名重扫,实施时点):objectstack / cloud / objectui 三仓零 runtime reader;仅存命中为 VS Code 扩展自身
package.json(不碰)与 cloud 一条 changeset 散文。验证:
check:generated8/8、check:dual-source-exports0、spec test 295 files / 7358 passed、全仓 typecheck 122/122,均在合并 #4616(PR #4809)后的 main 基础上实跑;四张 ratchet 按规程整体重生成,#4616 的删除未被复活。范围外发现已立案(未 assign):#4832(PLUGIN_STANDARDS.md §5.3 罗列 #3896 已删 schema)、#4834(
plugin-runtime.zod.ts剩余家族零 consumer 的 enforce-or-remove 悬置)。Draft/入队归 PM。
Generated by Claude Code
✅ 验收通过 → PR #4831 已转正 + auto-merge
对照 GitHub 实际 diff 逐项复核(
4f136c55vs merge-basecb680f27),全部合格:退役形态的非对称判定 —— 本单最关键的论证,已自行核实成立
DynamicLoadRequestSchema实为z.object((非 strict)→ 裸删会被 Zod 静默 strip,必须retiredKey()墓碑。已核plugin-runtime.zod.ts:125墓碑在位。StudioPluginManifestSchema实为strictObject((:319)→ 裸删后 strict 响亮拒绝,配guidance处方即可。- 两种形态不是照抄先例,是由两个父 schema 的实际严格性推出来的,且与
gen:schema的 authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 三条实报一一对应(kernel 键走墓碑豁免 / studio 键走路线 2 不可达 / def 走路线 3 整删)。
避开了
triggerPhrasessuggester 陷阱 —— 三个 VS Code 味 alias(activation/events/onActivate)未留在原地指向已删键,而是与activationEvents一同映射到同一条退役处方(:330-340)。这正是 #4001 战役里那条「永远不要建议一个 schema 根本不接受的键」的教训,本单主动执行了。ratchet 三处与自述逐条吻合(三点式实测)
manifest −2 : kernel/ActivationEvent, studio/ActivationEvent authorable −6 +1: 4 条 def 行 + studio 键删除;kernel 键 → [RETIRED] api-surface −4 : 两入口 × (ActivationEvent + ActivationEventSchema)dual-source-exports.baseline.json与renamed-defs.ts均未触碰;content/docs/releases/零触碰;三个 VS Code 扩展的package.json零触碰。并行单成果未被复活:#4616 删除的
system/EmailTemplate/SMSTemplate/PushNotification/InAppNotification在本分支 manifest 中均为 0 命中,而幸存的system/EmailTemplateDefinition(不同 def)仍在 —— 精确名断言,没有误伤。D3 conversion 登记正确:
plugin-activation-events-retired,两个 clause 均以键名结尾(满足 gate (b) 的 endsWith 匹配);D2 不适用的论证成立(studio 侧是defineStudioPlugin的 TS config 入参、从不入 stack 树,与 #4579 同构;kernel 侧是 runtime 请求形状且四仓零 caller)。入队说明:分支落后 main 一个
c4ab50b6(#4823 / #4728,packages/metadata/+durability-degradation.baseline.json),实测与packages/spec及生成物零交叠,无静默回退风险,交由合并队列消化。范围外发现(
PLUGIN_STANDARDS.md§5.3 仍列已删的PluginDiscoveryConfigSchema/DynamicLoadingConfigSchema,及DynamicLoadRequest家族整族 enforce-or-remove 的悬置问题)已另行立案,处置正确 —— 不夹带进本 PR。
Generated by Claude Code
- added 4 commits that reference this issue
on Aug 4, 2026 - added a commit that references this issue
on Sep 28, 2026 - added a commit that references this issue
on Oct 7, 2026
从 #4653(双源清账 C5)的三仓 import 扫描里掉出来的范围外发现,不在 #4653 的 PR 里修,单独立案。
事实
packages/spec有两份ActivationEventSchema,分别嵌在两个父 schema 的activationEvents:上:kernel/plugin-runtime.zod.ts:74z.object({ type: z.enum([...7 项]), pattern: z.string() })DynamicLoadRequestSchema.activationEvents(.optional())studio/plugin.zod.ts:285z.string()StudioPluginManifestSchema.activationEvents(.default(['*']))四仓(objectstack / cloud / cloud-v1 / objectui)全量扫描:没有任何运行时读取
activationEvents。 命中的只有 spec 自身的源码与测试、生成文档,以及三个 VS Code 扩展自己的package.json(packages/vscode-objectstack、objectui/packages/vscode-extension、objectql/packages/tools/vscode-objectql)—— 那是 VS Code 的字段,与本平台无关。外部佐证 ——
cloud-v1/docs/ROADMAP.md:641自己记着这条没实现:即:所有插件安装即激活,惰性激活是 v0.4.0 的计划,不是今天的行为。
两重问题
declared ≠ enforced(ADR-0049)。 作者在 studio plugin manifest 里写
activationEvents: ['onMetadataType:flow'](content/docs/plugins/development.mdx:387,带os:check标记的示例),期待插件被延迟到该事件才加载;实际它立即加载。这不是惰性 no-op,是一个语义上撒谎的键。studio 侧零校验。
z.string()接受任何字符串:''、'banana'、'onMetadatType:flow'(拼写错误)全部通过,作者拿不到任何反馈。文档里列的词表(*、onMetadataType:、onCommand:、onView:)完全不被 schema 表达 —— 这正是 AI 生成的元数据出错后能长期潜伏的地方。对比 kernel 侧的z.enum([...])至少挡得住 trigger 类型拼错。建议处置(需维护者裁决,故不自行动手)
按 enforce-or-remove:要么在 v0.4.0 实现惰性激活并把词表收进 schema,要么按 ADR-0087 tombstone 掉这两处
activationEvents。注意:ActivationEventSchema的双源问题正由 #4653 处理,而「选哪个编码」的裁决与本单强耦合 —— 如果这个键最终要被 retire,#4653 就不该先为它挑一个编码。建议两单一起裁。关联:#4653、#4535、ADR-0049、ADR-0087