You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
如果 spec 是对的 —— 作者把 type 从 script 改成 url 之后,会以为那段 body 已经不再执行了,而它还在;
如果 runtime 是对的 —— spec 在教作者一件不成立的事,而且 type 就不该出现在这句话里。
目前无人被这个坑到,是因为把 body 写在非 script action 上本来就少见。但"改了 type 以为逻辑停了、其实还在跑"这种形状,踩到时非常难查。
已经受影响的地方
#4344(action body 写集 lint)刻意跟了 runtime:检查所有带 body 的 action,不看 type,理由写在 packages/lint/src/validate-action-body-writes.ts 的 collectActionBodies 注释里 ——
type is deliberately not consulted: the runtime binds a handler from action.body alone
(actionBodyRunnerFactory never reads type), so a body on a non-script action still runs
and still fails silently. Checking what executes beats checking what the schema says should.
现象
ActionSchema.body的 spec 声称 body 只在type === 'script'时生效,运行时不看type。packages/spec/src/ui/action.zod.ts:JSDoc 里更明确:"Only meaningful when
type === 'script'. When set, the runtime invokes the body inside the sandbox … and ignorestarget."运行时两处都不过滤
type:packages/runtime/src/app-plugin.ts的collectBundleActions只要a.name是字符串就收,type完全不参与;packages/runtime/src/sandbox/body-runner.ts的actionBodyRunnerFactory只判action.body在不在、HookBodySchema.safeParse过不过,从不读type。所以一个
type: 'url'且带body的 action 照样ql.registerAction(...),handler 可以从POST /api/v1/actions/:object/:action调起来并在沙箱里执行。为什么值得掰扯
这是 declared ≠ enforced 的一个小切口(Prime Directive #10):spec 说"只在 script 下生效",runtime 说"有 body 就跑"。两种读法各自会引出不同的正确行为:
type从script改成url之后,会以为那段 body 已经不再执行了,而它还在;type就不该出现在这句话里。目前无人被这个坑到,是因为把 body 写在非 script action 上本来就少见。但"改了 type 以为逻辑停了、其实还在跑"这种形状,踩到时非常难查。
已经受影响的地方
#4344(action body 写集 lint)刻意跟了 runtime:检查所有带
body的 action,不看type,理由写在packages/lint/src/validate-action-body-writes.ts的collectActionBodies注释里 ——这个选择在"两边不一致"的前提下是对的,但它同时把不一致固化进了第三个地方。定了之后 lint 那边要跟着调。
两条出路(需要决策)
actionBodyRunnerFactory(或collectBundleActions)在type !== 'script'时不绑 handler。附带要想清楚type缺省是'script'(ActionType.default('script')),所以只影响显式写了别的 type 的 action;还要决定"带 body 但 type 不是 script"要不要在作者时报错 —— 按 ADR-0087 的姿态,这种自相矛盾的元数据应该在 publish gate 上被拒,而不是静默忽略。.describe()和 JSDoc 里的 type 条件,改成"body 一旦存在就是这个 action 的实现,target被忽略",并说明type只影响渲染侧的呈现。倾向 1 + 作者时拒绝:
type: 'url'配一段沙箱 body 是自相矛盾的元数据,静默各跑各的比报错糟。但这会改变现有行为,得确认没有 app 在依赖"非 script 也能跑 body"。参考
packages/spec/src/ui/action.zod.ts(ActionSchema.body的 describe + JSDoc)packages/runtime/src/sandbox/body-runner.ts(actionBodyRunnerFactory)packages/runtime/src/app-plugin.ts(collectBundleActions)packages/lint/src/validate-action-body-writes.ts(collectActionBodies—— 当前跟的是 runtime)