# module: process 职责: 流程层:流程包定义与版本、**边映射闭合校验**(连线即映射 · 画图不检查 · 不闭合不得激活)、 负责人四策略的确定性解析、工作流状态的聚合投影、失败走向的消化判定、节点实例重开 不负责: 活动的执行(见 task 与范式引擎)、触发器(与流程包**平级**,见 trigger)、 画布的绘制(见 apps/web 的 gov-process) 公开出口: index.ts - 类型:`ProcessService` `StartWorkflowInput` `WorkflowRecord` `ClosureReport` `ClosureViolation` `ActivityContractFace` `Candidate` `Resolution` `NodeInstance` `WorkflowState` `Dispatch` - 错误:`NotClosedError` `PinnedVersionError` `PositionVacantError` - 端口类型:`ProcessStore` `ActivityDirectory` `OrgDirectory` `TaskGateway` `ApprovalGateway` `Sfeel` `FlowEventPublisher` `ReceiptNotifier` - 用例工厂:`createProcessService(deps): ProcessService`(含 `setPackageState` 版本启停) - 纯函数:`checkClosure` `closed` `resolveOwner` `aggregateWorkflowState` (`resolveOwner` 的 `bound` 入参 = 已校验的工作组绑定,ADR-011) `isDigested` `nextInstanceNumber` `selectEdges` `assemble` `rejectRouteOf` `dispatchOf` `startNodeOf` `advanceOrder` (`advanceOrder` = 推进次序,按边拓扑排、排除回边、并行支按编号定序; 呈现用,不参与流转判断 —— 图纸坐标不配决定次序) - adapter:`createProcessStore`;Drizzle 表:`processPackageTable` `workflowTable` `nodeInstanceTable` 层级: L7(编码规范 §4) 依赖: @contracts;task(L6)、@sfeel 被依赖: trigger, app(治理台 · 工作流管理) 不变量(OS 03 / 3.2): - **编辑即其身**(产品决策 2026-07-28 第四轮):`savePackage` 对已存在的版本 **就地写回**(号不变、状态不变);新版本只出自显式新建(`asNew: true`)或 新流程首版(插入,`retired` 不生效)。两道底线: ① **在途钉版不可变** —— 该版有未完结工作流(按 (包, 版本) 钉定义)即抛 `PinnedVersionError`(HTTP 409),一字不落库;改动请新建一版。 ② **生效版必须始终可运行** —— 写回生效版跑 `checkClosure`,不闭合抛 `NotClosedError`(HTTP 412 带整份报告);未生效版画图不检查、随手存。 - **激活才查完整**:`setPackageState` 激活时跑 `checkClosure`, 不闭合抛 `NotClosedError`(HTTP 412 带整份报告)。 违规项:未完成边、必填未映射、类型冲突、孤立节点、多默认出边、 活动未装载、容忍分支被下游必填依赖 —— 任一即 `closed = false`,激活被拒。 (岗位不入编排,闭合校验没有岗位类违规。) - **纯编排模型**(产品决策 2026-07-28 二、三轮):流程包只决定**活动编排**与 **活动传递的契约**,不决定活动的实现方式(范式/版本住活动库,节点仅以 `activityId` 链接),**也不带负责人岗位**(分派归运营;运营分派机制未建前, 活动任务运行时默认全员轮值 —— 在岗候选并集、最闲者先、staffId 稳定排序。 审批点例外:「卡到人的工位」是它的功能语义,`approver` 留在声明里, 工作组绑定 ADR-011 也只对它生效)。节点只分**活动点**与**审批点** (起点/终点是结构件);`kind: 'gateway'` 已从 schema 摘除。 分支 = 源节点的多条条件出边(恰取一条,无条件边作默认兜底、至多一条), 汇合 = 多入边异或(上游互斥,只会来一条 —— `joinReady` 已删,没有「等回齐」)。 AND 并行暂无声明机制,将来以「并行组」加回(对应 Mastra `.parallel`,见 debt.md)。 - **边有编号身份**:语义边 id 即边号(E1、E2…,服务端/合并器铸号,旧边保号、 新边取下一个空号);画布线标带号、边在图上可选中,条件与映射住属性面。 顺序流一律画成**真边**(卡点画法已废除)—— 画布保存由画出来的边反推语义边, 图上没画的语义边会在存盘时丢失,种子与测试按「一一对应」守着。 - **激活双判据**:①图编排闭合完善(结构 + 属性 + 传递契约,`checkClosure` 的 非 unknown-activity 项)②活动装载(节点链接的实现已安装,`unknown-activity` 项)。 两面都清零才可激活;图照画照存,未装载不拦保存。 系统隐性上下文(审批 `verdict`、放行选口 `outcome` 的判据注入、起单载荷穿透) 由引擎决定,不进设计者的编排面。 - **一条流恰一个生效版本**(产品决策 2026-07-28):`setPackageState` 激活即独占 (同流其余版本一并停用);停用生效版 = 整条流下线,新起单被拒。 起单取**生效版**;在途工作流按启动时钉住的版本号读定义 —— 启停对它们零影响。 - **版本号服务端算**(新建时,不采信入参):工作流按 (包id, 版本) 读定义; store 的写回(`updatePackageDefinition`)只许命中已存在的版本,撞不存在报错; 「就地覆盖会改掉在途正在读的编排」由在途钉版闸守着,不再靠只插不改一刀切。 - **求值语义前后端同源**:画布的即时校验与后端裁决共用 `checkClosure` - **负责人解析确定性**:轮值并列时按 staffId 稳定排序;同输入必同结果,结果与依据留痕(owner-resolved 事件 + 实例 assignee) - **工作流状态是聚合投影**:流程层不另设状态机;计量对象是**节点实例**, 重开产生新实例、旧实例不再入算;XOR 未选分支从未激活、不入集合 - **「完成」凭到过终点节点**,不凭「没有在跑的了」:收敛但未到终点 = 卡住 = `abnormal`。 `aggregateWorkflowState` 收第三个入参(包的终点 id 集);不传则退回旧口径,新代码一律传 - **失败走向的消化**:改道 / 容忍 / 升审批一经生效即消化;终止流待人工处置中算异常 - **流级重做一律重开新实例** —— 同节点、新任务 ID、留痕关联,不复活旧任务 其它不变量: - **流转零 LLM**:选边与条件求值全部经 `@sfeel`;判定依据入事件记录 - **多出边一律异或,不分节点种类**:条件命中优先(按声明序),无条件的边作默认兜底; 一条都没中而该节点确有出边 = **死路**,发 `route-dead-end` 事件 (哪个节点、各出边的条件、判据里当时有哪些键 —— 只记键名不记值)。 审批点的裁决(`verdict`)由引擎注入判据,两个去向就是它自己的两条条件出边 - **异或汇合不等**:互斥分支结构上只会来一条,等齐 = 等一个不可能到来的分支, 流会无声卡死 —— 汇合等待机制已随网关整体摘除,容忍分支消化后直接推进 - **流程层不自动重试活动**(过程内重试归 Harness); 流级重做一律人裁决后**重开新任务实例** - **驳回走向声明式**:审批点的驳回按 `reject` 声明回指定节点重开新实例,不由临场决定 - **凡单必有来源**:`source` 必填;终点按输出声明交付、按来源回执 ## M5-1:运行时切面已立(2026-07-28),编译器实现仍欠 「Mastra 编译器作可替换 adapter、usecase 不动」的端口**已经存在**:`port.ts` 的 `FlowRuntime`(begin / onTaskTerminal / applyFailure / onApprovalVerdict / refreshState / terminate)。执行面的语义、留痕与副作用编排整体住在默认实现 `internal/runtime/self-hosted-runtime.ts`(自持确定性状态机 + `sys.node_instance` 持久);`process-service` 是薄壳:定义生命周期(保存/激活/校验)+ 起单前置 (取生效版/调用接口校验/工作组快照/建单留痕)+ 五方法委托。 替换路径:`ProcessServiceDeps.runtime` 注入第二实现(`internal/adapter/ workflow-compiler.ts`,编码规范 §6.1:流程包编译为 Mastra `createWorkflow`/ `createStep`,XOR → `.branch()`,AND → `.parallel()`,节点 `suspend()`/`resume()`)。 八例端到端(`unified-quote-flow.it.test.ts`)是两个实现的**等价性护栏**。 已核实的语义冲突清单(编译器必须绕):回边 reopen 无原语(spike 定案)、 `.parallel()` 任一失败即整体失败(step 内自吞,不让 Mastra 感知)、 三态聚合投影(abnormal 防假成功,Mastra run 无此态)、`node_instance` 投影表必须照写(治理台按行查)。