spec.md 19 KB

Forge AI 中枢受控流程动作

status: reviewed_passed created: 2026-07-12 complexity: 🔴复杂 parent-stage: Forge AI 中枢阶段 2.2 — 流程闭环

1. 背景与目标

阶段 2.0 已建立 MCP USER/SERVICE 双身份,阶段 2.1 已交付已发布业务动作、字段白名单、幂等、elicitation 和双审计。当前 Agent 仍不能通过能力目录安全发起或办理 Flowable 流程。

本变更交付阶段 2.2 的最小流程闭环:把业务对象当前启用的真实 FLOW 绑定发布为不可变 FLOW_ACTION 能力,继续通过固定 capability.search/describe/invoke 发现和调用。首批只开放 STARTAPPROVEREJECT,实际发起人/办理人固定为可信 USER 委托身份 A;任务、业务对象、流程模型、候选/签收状态和当前业务状态必须由服务端实时解析,不能信任客户端自报身份或任意 taskId。

2. 成功标准

  • MCP 继续只有单 /mcp Streamable HTTP,固定元工具不变,不新增旧 SSE、STATELESS、stdio 或 ASYNC Server;
  • capability.search/describe/invoke 同时支持 BUSINESS_ACTION/ACTION/MEDIUMFLOW_ACTION/FLOW/MEDIUM,仍按 Token scope、client grant、当前用户权限、tenant/activeOrg 实时过滤;
  • 流程能力只能从启用业务对象、已发布对象版本和当前启用 FLOW 绑定发布,flowModelKey、bindingId、objectCode、operation 固化到不可变能力版本;
  • START 只通过平台 BusinessFlowService.startDocumentFlow 发起,固定 businessKey=<objectCode>:<recordId>,不接受客户端 flowModelKey、variables、发起人或组织;
  • APPROVE/REJECT 只办理当前 A 已签收、未完成、属于能力对象与流程模型的真实任务;taskId 只是定位符,不是授权依据;
  • BusinessTaskActionDTO.userId 在服务层不再覆盖当前可信用户,FlowClient 办理人始终从当前执行身份解析;
  • 三种操作均要求 16~128 位幂等键和同一次 MCP elicitation ACCEPT + confirm=true;同键同请求返回既有结果,同键异请求拒绝;
  • 20 路并发相同幂等请求最多产生一次流程发起或任务完成副作用;
  • Capability 审计、流程动作日志和流程实例/任务可通过 requestId、client、actor、serviceUser、tenant/org 关联;
  • 错误返回稳定代码,不泄露 Flowable 内部异常、Token、Header、完整变量或业务敏感数据;
  • Flow Actions、Secure Actions、Generator、Control Plane、Identity、MCP 与 Admin 聚合验证通过,不调用真实模型。

3. 范围

3.1 包含

  • 新增 forge-plugin-capability-flow-actions 组合模块;
  • 将阶段 2.1 固定元工具网关抽象为可扩展受控能力执行器,保留业务动作行为;
  • FLOW_ACTION 专用发布 API、Schema、策略快照和 source binding;
  • START/APPROVE/REJECT 运行时解析、USER 办理人校验和真实 FLOW 绑定复核;
  • 流程动作幂等预留、结果快照和双身份关联日志;
  • MCP elicitation R2 确认与稳定错误映射;
  • 修复 BusinessFlowService.completeBusinessTask 接受 DTO userId 覆盖当前用户的问题;
  • Flyway 权限资源和流程动作幂等日志表;
  • TDD、模块测试和聚合验证。

3.2 明确不做

  • 不开放 claim、delegate、return、withdraw、terminate、转办、加签、减签或任意 Flowable API;
  • 不允许客户端传 flowModelKey、processDefinitionId、processInstanceId、tenantId、userId、activeOrgId 或任意 variables;
  • 不通过任意 taskId 绕过当前 A 的签收人与任务归属校验;
  • 不建设第二套节点配置 UI;节点表单、字段权限、审批/驳回规则继续归真实流程设计器 BPMN 节点;
  • 不覆盖或重发用户已编辑的 BPMN XML;
  • 不把代码业务的自定义 submit 方法自动推导为通用 START;本阶段 START 仅覆盖平台托管且可由 BusinessFlowService.startDocumentFlow 加载的已发布业务对象;
  • 不实现 R3 高风险审批、消息能力、Nacos MCP Registry/Admin 或 Agent Runtime;
  • 不引入 Spring Authorization Server 或 Sa-Token OAuth2;
  • 不调用真实模型。

4. 架构

/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。

5. 能力契约

5.1 FLOW_ACTION source binding

  • source_type=FLOW_ACTION
  • source_key={suiteCode}/{objectCode}/{operation},operation 仅 START/APPROVE/REJECT
  • source_version={publishedObjectVersion}
  • behavior=FLOWrisk_level=MEDIUMvisibility=DISCOVERABLE
  • policy_snapshot 固化 bindingIdflowModelKeyoperationpublishedObjectVersionpermissionconfirmationMode=MCP_ELICITATION
  • grant field_policy.allowedOperations 必须非空且只能缩小版本操作集合;每个能力版本首期只对应一个 operation。

5.2 输入契约

  • 公共字段:capabilityCode、可选 versionrecordIdidempotencyKeyarguments
  • START:recordId 必填,arguments 必须为空对象;
  • APPROVE:recordIdarguments.taskId 必填,arguments.comment 可选且最多 500 字;
  • REJECT:recordIdarguments.taskId、非空 arguments.comment 必填且最多 500 字;
  • 所有对象 additionalProperties=false,ID 按字符串处理;
  • 输出沿用 executeStatus/message/correlationId/idempotentHit,不返回完整 Flowable 任务或变量。

6. 安全与业务规则

  1. 只有 USER Token 可 invoke;SERVICE Token 仍可发现但不能产生流程副作用;
  2. 发布时和调用时都复核业务对象启用、发布版本、FLOW bindingId 和 flowModelKey;漂移返回 FLOW_BINDING_MISMATCH,不自动跟随草稿或新绑定;
  3. START 不接受 flowModelKey/title/variables,记录和权限由 BusinessFlowService 读取已发布运行配置与真实绑定;
  4. APPROVE/REJECT 必须先加载 task detail,校验 status 未完成、assignee 等于 A、businessKey 可规范化为能力 objectCode + recordId、processDefKey 等于能力 flowModelKey;
  5. DTO 中的 userId 永远忽略,FlowClient userId 固定使用当前 A;
  6. REJECT comment 必填;APPROVE comment 可选;不允许客户端写任意流程 variables;
  7. elicitation 摘要只展示操作、对象、recordId、taskId 安全尾号和 canonical 请求短指纹,不展示业务字段值;
  8. 幂等唯一域为 tenant/client/capability/operation/idempotencyKey;request digest 绑定版本、recordId、taskId、comment;
  9. 流程动作日志先预留 RUNNING 再产生副作用;活动 RUNNING 返回冲突,SUCCESS 返回既有结果;同摘要 FAILED 或超过 30 秒的 RUNNING 使用同幂等键进入受控恢复,异摘要始终拒绝;
  10. Capability 审计预留失败、流程日志预留失败、授权目录故障或 Flow 服务不可用均失败关闭;
  11. 任务完成后的业务状态同步继续走现有 BusinessFlowService、Flowable 回调和业务 Provider,不在能力层复制状态机;
  12. 日志不得记录 comment 正文、流程 variables、Token、Header 或原始供应商/Flowable异常消息。

7. 数据变更

新增 V1.0.24__add_capability_flow_actions.sql

  • 创建 ai_capability_flow_action_log,包含标准租户/审计字段、del_flag、request digest、幂等键、operation、task/process 安全引用、双身份和结果摘要;
  • 使用生成列 logic_delete_active 与唯一索引约束未删除幂等记录;
  • 增加发布/调用受控流程动作权限资源并授权内置 admin;
  • 所有内置数据 tenant_id=1、显式列名、NOT EXISTS/信息架构防重复;
  • 不插入真实流程能力、grant、client、Token 或业务数据;
  • 不修改已执行的 V1.0.21~V1.0.23。

Review 修复新增 V1.0.25__add_flow_task_action_idempotency.sql

  • sys_flow_task 增加动作幂等键、规范请求摘要和动作类型;
  • 三个字段与任务完成状态在 Flow 服务同一事务内写入,用于跨服务失败后的同请求恢复;
  • 使用 information_schema 防重复增加字段和索引,不修改已执行的 V1.0.24。

8. HARD-GATE

  • 任一可信身份、scope、grant、权限、tenant/org、发布对象、FLOW binding、任务签收人、对象/流程归属、幂等或 elicitation 校验失败时,不得调用 FlowClient;
  • 客户端 userId/flowModelKey/variables 不得进入执行链;
  • 同幂等键并发不得重复启动流程或完成任务;
  • APPROVE/REJECT 不得办理 A 未签收的任务;
  • 流程设计器 BPMN 节点配置仍为运行时权威来源;
  • MCP 仍只有单 /mcp Streamable HTTP;
  • 任一硬闸门失败时不得进入 forge-ai-hub-high-risk-approval

9. 回滚

  • forge.capability.flow-actions.enabled=false 关闭 FLOW_ACTION 发布和执行适配器,保留阶段 2.1 业务动作;
  • 已发布 FLOW_ACTION capability/grant 可由控制面停用或撤销;
  • 新日志表和审计数据保留,不自动 DROP;
  • 回滚不得恢复 DTO userId 覆盖、任意 taskId、裸 Header 身份或旧 SSE。

10. 确认记录

  • 确认时间:2026-07-12;
  • 确认方式:用户要求归档阶段 2.1 并自动开始、执行下一阶段;
  • 批准范围:阶段 2.2 START/APPROVE/REJECT,不包含 R3、消息、流程管理 API 或代码业务自定义 START SPI;
  • 执行方式:Proposal 后直接 Apply,禁止 commit/push。

11. Apply 实现记录

  • 新增 forge-plugin-capability-flow-actions,完成 plugin parent、BOM、Admin 聚合和条件自动配置;
  • FLOW_ACTION/FLOW/MEDIUM 继续通过固定 capability.search/describe/invoke 暴露,没有增加动态顶层 Tool 或第二 MCP 端点;
  • 发布快照固化 bindingId/flowModelKey/publishedObjectVersion/operation,调用前实时复核当前启用、已发布对象和真实 FLOW 绑定;
  • START 只调用 BusinessFlowService.startDocumentFlow;APPROVE/REJECT 在 elicitation 前通过 getActionableTaskFormContext 确认任务已由 A 签收,并在执行时再次校验;
  • BusinessFlowService.completeBusinessTask 已忽略 DTO userId,FlowClient 办理人只取当前可信用户;
  • 流程幂等预留使用独立事务,本地流程编排与 SUCCESS 日志更新处于同一事务;最终日志更新失败时回滚本地事务并以独立事务落 FAILED,避免记录长期停留 RUNNING;
  • FlowClient 可独立部署,远程流程副作用不属于本地数据库事务。该边界失败时返回 FLOW_AUDIT_UNAVAILABLE 并保留失败/待对账证据,不宣称分布式原子提交;START 的 businessKey 和任务完成状态仍阻止重复业务副作用;
  • elicitation 不显示 comment 或完整 taskId,只显示 operation、对象、recordId、任务安全尾号和请求短指纹;
  • 未引入 Spring Authorization Server、Sa-Token OAuth2、Nacos MCP Registry/Admin、旧 SSE 或真实模型调用。

12. Review 结论

review-date: 2026-07-12 conclusion: NEEDS_FIX

12.1 Spec Compliance

已满足:单 /mcp Streamable HTTP、固定元工具、FLOW_ACTION/FLOW/MEDIUM、专用发布入口、USER 委托身份、FLOW binding 快照、START/APPROVE/REJECT 范围、MCP elicitation、流程动作日志表、逻辑删除唯一键、稳定错误摘要和禁止依赖边界均已落地。

存在六个 Spec 不合规项:

  1. R1 / P0 — 最终 Flow 服务没有重新绑定可信办理人和任务租户。 Admin 侧在 elicitation 前和执行前调用 getActionableTaskFormContext 检查 A 已签收,但 FlowTaskServiceImpl.approve/reject 收到 userId 后只校验节点动作策略,没有比较 task.assignee == userId,也没有用任务 tenantId 与可信租户做最终校验。确认后转签的 TOCTOU 竞态,或内部 Flow 接口被直接调用时,仍可能由非当前办理人完成任务,违反 §2、§6.4、§8 HARD-GATE。
  2. R2 / P0 — 顶层伪造参数被静默丢弃而不是失败关闭。 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。
  3. R3 / P0 — 远程 Flow 副作用与本地幂等/审计仍可能形成孤儿流程。 流程日志先以 REQUIRES_NEW 提交 RUNNING,本地事务随后包含远程 FlowClient 调用和 SUCCESS 日志更新。独立 Flow 服务一旦已提交、而本地 link/日志事务失败,远程流程或任务已变化,但本地记录会转 FAILED 或缺少实例 link;同键重试冲突,换键 START 又可能重复发起。当前没有远程幂等键、可恢复 outbox 或对账回填路径,违反 §2 的并发/关联成功标准和 §6.8~6.10。
  4. R4 / P1 — 固定 businessKey 契约存在实现偏差。 BusinessFlowService.resolveFlowBusinessKeyForStart 在记录已有历史 link 时把真正传给 Flowable 的 businessKey 改为 <objectCode>:<recordId>:R...,而本 Spec 冻结为 <objectCode>:<recordId>。若允许重新发起,应在能力契约和任务归属校验中显式建模 execution key;否则 FLOW_ACTION START 应拒绝有历史实例的记录。
  5. R5 / P1 — FLOW_ACTION 来源没有锚定实际已发布版本记录。 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 的已发布对象版本要求。
  6. R6 / P1 — 目录输出和 P0 测试证据未达到 Tasks/Test Spec。 capability.search/describe 没有返回 Task 1 要求的 sourceType/behavior/operation;现有测试也没有覆盖 START 执行、顶层伪造参数拒绝、binding/version 漂移、任务转签/跨租户、远程成功后本地失败恢复。11/11 Flow Actions 与 29/29 Secure Actions 虽通过,但不能证明 test-spec §1 的这些 HARD-GATE。

12.2 Review Gate

  • Spec Compliance 结论为 FAIL;按两阶段 Review 规则,本轮不进入 Code Quality Review;
  • 当前状态更新为 reviewed_with_findings,不得归档,也不得把阶段 2.2 或整个阶段 2 标记为完成;
  • 下一步执行 /fix forge-ai-hub-flow-actions,顺序固定为 R1 → R2 → R3/R4 → R5 → R6;
  • Fix 后为每项补 Red/Green 证据,增量复跑 Flow Actions、Secure Actions、Flow/Generator、Control Plane、Identity、MCP 和 Admin 聚合,并再次执行 /review

13. Fix 实现记录

fix-date: 2026-07-12 status: fixed_pending_review

  • R1:Flow 服务办理前对 sys_flow_task 执行 FOR UPDATE,最终复核可信 tenant、原 assignee、任务状态,并再次比较 Flowable 当前 assignee;同请求完成态仅向同一办理人返回幂等成功。
  • R2capability.invoke 在任何字段投影、目录查询和 elicitation 前校验顶层字段白名单,伪造身份、租户、流程控制字段及 unknown 均返回 INVALID_ARGUMENT
  • R3:APPROVE/REJECT 把幂等键与规范摘要传到 Flow 服务并和任务状态同事务落库;本地 FAILED 或超时 RUNNING 可用同摘要恢复,活动 RUNNING 和异摘要拒绝。START 依赖 Flow 服务固定 businessKey 的既有幂等,远程成功而本地 link 失败时重试回填。
  • R4:新增 startDocumentFlowForCapability,FLOW_ACTION START 永远使用 <objectCode>:<recordId>,普通人工流程的历史重发规则保持兼容。
  • R5:来源 SQL 精确 JOIN ai_business_object_design_version,按 tenant/objectId/suiteCode/objectCode/publishVersion 且 publish_status='PUBLISHED' 锚定发布事实。
  • R6:search/describe 实际结果和 output Schema 补齐 sourceType/behavior/operation;补充 START、顶层危险字段、跨租户/转签、跨用户幂等、FAILED/超时恢复和发布版本契约测试。
  • 修复未新增旧 SSE、STATELESS、stdio、ASYNC、Nacos MCP Registry/Admin、Spring Authorization Server、Sa-Token OAuth2 或真实模型调用。

14. 二次 Review 结论

review-date: 2026-07-12 conclusion: PASS

14.1 新增审查项

  • R7 / P0 — 成功幂等重放被任务可办理预检阻断:SUCCESS 同摘要现在直接复用安全结果;活动 RUNNING 在任务查询前返回 IDEMPOTENCY_CONFLICT;FAILED 与超时 RUNNING 才进入受控恢复。
  • R8 / P0 — MCP USER 身份无法跨独立 Flow 服务透传:Admin 为可信 USER ExecutionIdentity 签发 60 秒内部 Sa-Token,Token Session 绑定 LoginUser、tenant、activeOrg、client 和委托标记;签发失败禁止降级静态服务账号。Flow 增加专用 delegated START,发起人、办理人和租户最终只取服务端 Session。
  • delegated START 同时要求 ai:businessFlow:start 与内部委托标记;普通用户 Token 即使具有发起权限也不能调用内部入口。
  • 每次委托签发使用唯一 device 会话,避免 Sa-Token 共享/并发策略复用或替换普通登录 Token;空 Token、空 Session、非正 clientId 全部失败关闭。
  • FLOW binding 同时按 target_idtarget_code 锚定真实业务对象,避免不同套件重名对象误绑定。
  • Flowable 完成后的 sys_flow_task 状态与幂等凭证写回必须影响一行,否则抛错回滚同一事务。

14.2 两阶段结论

  • Spec Compliance:R1~R8 和 HARD-GATE 均通过;单 /mcp Streamable HTTP、USER A、发布快照、确认、幂等与双审计边界保持不变。
  • Code Quality:模块依赖方向、异常失败关闭、Session 隔离、Mapper XML、逻辑删除和迁移规则通过;未发现阻断归档的问题。
  • 验证:Flow Actions 19/19、Flow 最终授权 7/7、Flow Client 2/2、认证委托桥 7/7、Flow Controller 3/3、Secure Actions 31/31、Identity 35/35、Control Plane 29/29、MCP 16/16;Admin + Flow Server 聚合 43/43 PASS。
  • 条件边界:未执行真实 Flyway 和真实 Flowable START/APPROVE/REJECT E2E,也未调用真实模型;这些不影响代码归档,但仍是阶段 2 总体验收的环境验证项。

最终状态为 reviewed_passed,允许归档阶段 2.2。