feat: typed action handlers — enforce declared param contract at dispatch (ADR-0104 D2)#3432
Merged
Conversation
…hase 2 (D2) An action's declared params[] (type/required/multiple/options/reference) was a complete value contract that only informed the client dialog — the server passed reqBody.params straight to the handler unvalidated (REST handleActions + MCP invokeBusinessAction), and handlers read an untyped bag. - @objectstack/spec/ui: validateActionParams (+ ResolvedActionParam, ActionParamIssue, ACTION_PARAM_BUILTIN_KEYS) — pure check reusing the D1 valueSchemaFor so option membership / multiple arrays / reference-id shape ride the one value contract; plus typed authoring surface ActionHandler / ActionHandlerContext / ActionEngineFacade. - runtime: both REST and MCP action paths resolve declared params (field-backed resolved through the referenced object field) and validate the request bag before the handler runs — required/shape/unknown-key; recordId/objectName allowlisted. Warn-first unless OS_ACTION_PARAMS_STRICT_ENABLED=1 (then 400). Actions with no declared params are untouched. - ScriptContext.input doc + registerAction JSDoc state the validated contract. Tests: spec 6847 (incl. 9 action-params units), runtime 587, objectql 1043, new action-params dogfood 3 (warn-first passes / strict 400 / conformant passes) — all green. API-surface snapshot updated (+7 additive exports). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SHpGw3GBA9aFpfwVArRWfd
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 4 package(s): 114 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
July 24, 2026 12:48
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.
实施 ADR-0104 的 D4 阶段 2(D2):动作参数的声明契约在派发时强制执行,handler 从「无类型口袋」变成有校验、可类型化的输入。依赖已合并的 D1(#3429)值形状契约。
问题
动作的
params[]声明(type/required/multiple/options/reference)本是完整的值契约,但此前只喂给客户端弹窗:服务端把reqBody.params原样透传给 handler,零校验(RESThandleActions与 MCPinvokeBusinessAction两条路径),沙箱把它当input: unknown,handler 注册签名(ctx: any) => any,全靠裸as强转。AI/MCP 恰恰是最容易发出「看似合理实则错形」参数包的调用方,而唯一的校验在客户端——三个调用面里唯一的礼貌性表面。改动
@objectstack/spec/ui(新增action-params.zod.ts)validateActionParams(resolved, bag):纯校验函数,复用 D1 的valueSchemaFor,所以选项成员 /multiple数组 / 引用 id 形态全部走同一个值契约。返回问题列表(不抛),由调用方决定 warn-vs-reject。配套ResolvedActionParam/ActionParamIssue/ACTION_PARAM_BUILTIN_KEYS。ActionHandler/ActionHandlerContext/ActionEngineFacade——handler 作者用ActionHandler标注取代内联(ctx: any),这正是「让 handler 不再是无类型口袋」的落点。注册 seam 保持无类型,故为非破坏的 opt-in。runtime(
http-dispatcher.ts)recordId/objectName在白名单)。resolveActionByName透出obj,让 MCP 路径也能做字段引用式解析。warn-first 落地(ADR-0104 R3)
违规默认仅告警并放行——过去静默错配的参数包继续能用,漂移变得可见而非致命;设
OS_ACTION_PARAMS_STRICT_ENABLED=1则 REST 返回400、MCP 抛错。翻转为默认严格随后续 minor(与 D1 同姿态)。测试
validateActionParams单测:required / 选项 / 引用 id / multiple / 未知键 / 白名单 / 未知类型开放)showcase_action_param_gallery(feat(spec): let an inlinelookupaction param declare its reference target (#3405) #3406 的参数 gallery)真机 POST——warn-first 放行、strict 下畸形包被 400(错误信息含p_text/p_priority/bogus三处违规)、合规包通过。不在本 PR 范围
sys_file引用——依赖 file-as-reference(D3)。params数组推导ctx.params的逐名静态类型——延后的 DX 优化,运行时保证与其无关。🤖 Generated with Claude Code
https://claude.ai/code/session_01SHpGw3GBA9aFpfwVArRWfd
Generated by Claude Code