status: reviewed_passed created: 2026-07-12 complexity: 🔴复杂 parent-stage: Forge AI 中枢阶段 2.2 — 流程闭环
阶段 2.0 已建立 MCP USER/SERVICE 双身份,阶段 2.1 已交付已发布业务动作、字段白名单、幂等、elicitation 和双审计。当前 Agent 仍不能通过能力目录安全发起或办理 Flowable 流程。
本变更交付阶段 2.2 的最小流程闭环:把业务对象当前启用的真实 FLOW 绑定发布为不可变 FLOW_ACTION 能力,继续通过固定 capability.search/describe/invoke 发现和调用。首批只开放 START、APPROVE、REJECT,实际发起人/办理人固定为可信 USER 委托身份 A;任务、业务对象、流程模型、候选/签收状态和当前业务状态必须由服务端实时解析,不能信任客户端自报身份或任意 taskId。
/mcp Streamable HTTP,固定元工具不变,不新增旧 SSE、STATELESS、stdio 或 ASYNC Server;capability.search/describe/invoke 同时支持 BUSINESS_ACTION/ACTION/MEDIUM 与 FLOW_ACTION/FLOW/MEDIUM,仍按 Token scope、client grant、当前用户权限、tenant/activeOrg 实时过滤;flowModelKey、bindingId、objectCode、operation 固化到不可变能力版本;BusinessFlowService.startDocumentFlow 发起,固定 businessKey=<objectCode>:<recordId>,不接受客户端 flowModelKey、variables、发起人或组织;BusinessTaskActionDTO.userId 在服务层不再覆盖当前可信用户,FlowClient 办理人始终从当前执行身份解析;ACCEPT + confirm=true;同键同请求返回既有结果,同键异请求拒绝;forge-plugin-capability-flow-actions 组合模块;FLOW_ACTION 专用发布 API、Schema、策略快照和 source binding;START/APPROVE/REJECT 运行时解析、USER 办理人校验和真实 FLOW 绑定复核;BusinessFlowService.completeBusinessTask 接受 DTO userId 覆盖当前用户的问题;BusinessFlowService.startDocumentFlow 加载的已发布业务对象;/mcp Streamable HTTP
-> fdu USER + ExecutionIdentity(A/client/serviceUser/tenant/org)
-> capability.search / capability.describe / capability.invoke
-> GovernedCapabilityExecutionAdapter
-> BUSINESS_ACTION adapter(阶段 2.1,保持行为)
-> FLOW_ACTION adapter(本阶段)
-> resolved ai_capability_version + grant policy
-> MCP elicitation ACCEPT
-> Capability 审计预留
-> FlowActionExecutionService 幂等预留
START -> BusinessFlowService.startDocumentFlow
APPROVE -> task access/object/model 校验 -> completeBusinessTask
REJECT -> task access/object/model 校验 -> completeBusinessTask
-> ai_capability_flow_action_log + ai_capability_invocation_log + Flowable
forge-plugin-capability-secure-actions 继续拥有固定元工具和公共执行闸门;新增协议无关的受控执行适配 SPI。Flow Actions 模块依赖 Secure Actions、Generator 和 Flow Client,只注册 FLOW_ACTION 解析/执行适配器,MCP 模块不依赖 Flowable 或 Generator。
source_type=FLOW_ACTION;source_key={suiteCode}/{objectCode}/{operation},operation 仅 START/APPROVE/REJECT;source_version={publishedObjectVersion};behavior=FLOW、risk_level=MEDIUM、visibility=DISCOVERABLE;policy_snapshot 固化 bindingId、flowModelKey、operation、publishedObjectVersion、permission、confirmationMode=MCP_ELICITATION;field_policy.allowedOperations 必须非空且只能缩小版本操作集合;每个能力版本首期只对应一个 operation。capabilityCode、可选 version、recordId、idempotencyKey、arguments;recordId 必填,arguments 必须为空对象;recordId、arguments.taskId 必填,arguments.comment 可选且最多 500 字;recordId、arguments.taskId、非空 arguments.comment 必填且最多 500 字;additionalProperties=false,ID 按字符串处理;executeStatus/message/correlationId/idempotentHit,不返回完整 Flowable 任务或变量。FLOW_BINDING_MISMATCH,不自动跟随草稿或新绑定;BusinessFlowService 读取已发布运行配置与真实绑定;RUNNING 再产生副作用;活动 RUNNING 返回冲突,SUCCESS 返回既有结果;同摘要 FAILED 或超过 30 秒的 RUNNING 使用同幂等键进入受控恢复,异摘要始终拒绝;新增 V1.0.24__add_capability_flow_actions.sql:
ai_capability_flow_action_log,包含标准租户/审计字段、del_flag、request digest、幂等键、operation、task/process 安全引用、双身份和结果摘要;logic_delete_active 与唯一索引约束未删除幂等记录;tenant_id=1、显式列名、NOT EXISTS/信息架构防重复;Review 修复新增 V1.0.25__add_flow_task_action_idempotency.sql:
sys_flow_task 增加动作幂等键、规范请求摘要和动作类型;information_schema 防重复增加字段和索引,不修改已执行的 V1.0.24。/mcp Streamable HTTP;forge-ai-hub-high-risk-approval。forge.capability.flow-actions.enabled=false 关闭 FLOW_ACTION 发布和执行适配器,保留阶段 2.1 业务动作;forge-plugin-capability-flow-actions,完成 plugin parent、BOM、Admin 聚合和条件自动配置;FLOW_ACTION/FLOW/MEDIUM 继续通过固定 capability.search/describe/invoke 暴露,没有增加动态顶层 Tool 或第二 MCP 端点;bindingId/flowModelKey/publishedObjectVersion/operation,调用前实时复核当前启用、已发布对象和真实 FLOW 绑定;BusinessFlowService.startDocumentFlow;APPROVE/REJECT 在 elicitation 前通过 getActionableTaskFormContext 确认任务已由 A 签收,并在执行时再次校验;BusinessFlowService.completeBusinessTask 已忽略 DTO userId,FlowClient 办理人只取当前可信用户;FLOW_AUDIT_UNAVAILABLE 并保留失败/待对账证据,不宣称分布式原子提交;START 的 businessKey 和任务完成状态仍阻止重复业务副作用;review-date: 2026-07-12 conclusion: NEEDS_FIX
已满足:单 /mcp Streamable HTTP、固定元工具、FLOW_ACTION/FLOW/MEDIUM、专用发布入口、USER 委托身份、FLOW binding 快照、START/APPROVE/REJECT 范围、MCP elicitation、流程动作日志表、逻辑删除唯一键、稳定错误摘要和禁止依赖边界均已落地。
存在六个 Spec 不合规项:
getActionableTaskFormContext 检查 A 已签收,但 FlowTaskServiceImpl.approve/reject 收到 userId 后只校验节点动作策略,没有比较 task.assignee == userId,也没有用任务 tenantId 与可信租户做最终校验。确认后转签的 TOCTOU 竞态,或内部 Flow 接口被直接调用时,仍可能由非当前办理人完成任务,违反 §2、§6.4、§8 HARD-GATE。SecureActionMcpHandler.invoke 从原请求重建 targetInput 时只复制 recordId/idempotencyKey/arguments,因此顶层 userId/tenantId/activeOrgId/flowModelKey/variables/processInstanceId 和任意未知字段不会进入运行时 Schema 校验。MCP Tool 广告的 additionalProperties=false 不能替代服务端校验,当前实现违反 §3.2、§5.2、§6.3/6.6 与 HARD-GATE。REQUIRES_NEW 提交 RUNNING,本地事务随后包含远程 FlowClient 调用和 SUCCESS 日志更新。独立 Flow 服务一旦已提交、而本地 link/日志事务失败,远程流程或任务已变化,但本地记录会转 FAILED 或缺少实例 link;同键重试冲突,换键 START 又可能重复发起。当前没有远程幂等键、可恢复 outbox 或对账回填路径,违反 §2 的并发/关联成功标准和 §6.8~6.10。BusinessFlowService.resolveFlowBusinessKeyForStart 在记录已有历史 link 时把真正传给 Flowable 的 businessKey 改为 <objectCode>:<recordId>:R...,而本 Spec 冻结为 <objectCode>:<recordId>。若允许重新发起,应在能力契约和任务归属校验中显式建模 execution key;否则 FLOW_ACTION START 应拒绝有历史实例的记录。FlowActionSourceMapper.xml 只检查 ai_business_object.design_status/last_publish_version,没有验证同一 objectId、suiteCode、objectCode、publishVersion 的 ai_business_object_design_version.publish_status=PUBLISHED 记录存在。能力 sourceVersion 因而来自可漂移的主表数字,而不是可审计的发布版本事实,违反 §2、§5.1 的已发布对象版本要求。capability.search/describe 没有返回 Task 1 要求的 sourceType/behavior/operation;现有测试也没有覆盖 START 执行、顶层伪造参数拒绝、binding/version 漂移、任务转签/跨租户、远程成功后本地失败恢复。11/11 Flow Actions 与 29/29 Secure Actions 虽通过,但不能证明 test-spec §1 的这些 HARD-GATE。reviewed_with_findings,不得归档,也不得把阶段 2.2 或整个阶段 2 标记为完成;/fix forge-ai-hub-flow-actions,顺序固定为 R1 → R2 → R3/R4 → R5 → R6;/review。fix-date: 2026-07-12 status: fixed_pending_review
sys_flow_task 执行 FOR UPDATE,最终复核可信 tenant、原 assignee、任务状态,并再次比较 Flowable 当前 assignee;同请求完成态仅向同一办理人返回幂等成功。capability.invoke 在任何字段投影、目录查询和 elicitation 前校验顶层字段白名单,伪造身份、租户、流程控制字段及 unknown 均返回 INVALID_ARGUMENT。startDocumentFlowForCapability,FLOW_ACTION START 永远使用 <objectCode>:<recordId>,普通人工流程的历史重发规则保持兼容。ai_business_object_design_version,按 tenant/objectId/suiteCode/objectCode/publishVersion 且 publish_status='PUBLISHED' 锚定发布事实。sourceType/behavior/operation;补充 START、顶层危险字段、跨租户/转签、跨用户幂等、FAILED/超时恢复和发布版本契约测试。review-date: 2026-07-12 conclusion: PASS
IDEMPOTENCY_CONFLICT;FAILED 与超时 RUNNING 才进入受控恢复。ai:businessFlow:start 与内部委托标记;普通用户 Token 即使具有发起权限也不能调用内部入口。target_id 与 target_code 锚定真实业务对象,避免不同套件重名对象误绑定。sys_flow_task 状态与幂等凭证写回必须影响一行,否则抛错回滚同一事务。/mcp Streamable HTTP、USER A、发布快照、确认、幂等与双审计边界保持不变。最终状态为 reviewed_passed,允许归档阶段 2.2。