Archived
把 `unified-quote` 从起单一路手工答到底(这是逐个开发活动之前该做的验证),
一路撞出五处,按撞到的顺序:
① 七个活动派出七张一模一样的「请处理」
槽位骨架给的是 `card: {}`,工单标题/字段全落回默认。收卡的人不知道自己走到
哪一步、这一步要干什么,整条流没法手工走通。→ 卡面自述:标题就是步骤标签,
依据带「第几步 / 共几步」,并如实说「这一步的自动化还没开发,先由你来办」。
② 走到第 3 步就 `exhausted` 终态、工作流转 abnormal
六个槽位共用 `humanCalls: 3`,而 A1 声明了 6 个人类步 —— 活动**结构上永远走不完**。
→ `budgetFor(n)` 按各槽位自己的步数给。步/项清单提成 `STEPS` 常量,
预算与骨架共用同一个数组,数不上不会漂移。治理台申报值也同源(否则台上摆假数)。
③ 六步答完,任务卡在「等人,却没有任何东西等人答」
`flow-runner` 写死了 `released = lastStepIsAcceptance && lastVerdictPassed` ——
末步不是验收工单,活动就永远不 release。→ 声明的六步来自 MVP 作业指导书,
不篡改语义,在其后**追加**一步「收口验收」。
④ 只走了 A1(一个节点实例)却报 `completed` ← **最危险的一处**
状态聚合把「没有在跑的了」当成完成。界面上是一单已完成的报价,业务上一步没走。
→ 「完成」凭**到过终点节点**;收敛而未到终点 = 卡住 = `abnormal`,进驾驶舱异常卡。
`aggregateWorkflowState` 收第三个入参(终点 id 集),不传退回旧口径。
⑤ 异或网关一条边都选不中时,流无声停住
④ 让它至少报异常了,但只说「有问题」不说「哪儿」。→ 发 `route-dead-end` 事件:
哪个节点、各出边的条件、判据里当时有哪些键。只记键名不记值 —— 诊断够用,
载荷不进事件明文。实测这条痕直接指出「G1 要 needAlternative,而键里没有」。
顺带:改槽位内容必须升包版(0.1.0 → 0.4.0)。「安装恒为新增、版本并存」是硬不变量,
同版重装是 no-op、manifest 一字不动 —— 我第一次改完重播种,屏幕报「已装入」而库里还是旧的。
`installSlots` 现在先问库、如实报「已装」还是「已在库,未改动 —— 要换内容请升包版」。
**走查后的诚实状态**:A1 走得完、活动 released;流**过不了 G1**,因为出口的必填去向旗
产不出来。这不是缺陷 —— 出口载荷由台账落地事实推导,槽位没实现台账写入就没有事实,
凭空捏一个就是在系统内部 mock。于是 A1 的开发完成判据也具体了:必须让
`needAlternative` / `needSourcing` 成为落地事实,否则 G1 永远判不了。债务簿已记。
另记一条闸的盲点:api:check 只快照 index/contract/port.d.ts,而 index 是 re-export 名单 ——
给纯函数加形参它看不见(本次实测)。改签名要手动同步 CONTRACT.md,别指望闸提醒。
typecheck ✓ lint ✓ depcruise 374 模块 ✓ api:check ✓ 490 测试 ✓(均以退出码验)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
4.0 KiB
4.0 KiB
module: process
职责: 流程层:流程包定义与版本、边映射闭合校验(连线即映射 · 画图即校验 · 不闭合不得发布)、 负责人四策略的确定性解析、工作流状态的聚合投影、失败走向的消化判定、节点实例重开 不负责: 活动的执行(见 task 与范式引擎)、触发器(与流程包平级,见 trigger)、 画布的绘制(见 apps/web 的 gov-process)
公开出口: index.ts
- 类型:
ProcessServiceStartWorkflowInputWorkflowRecordClosureReportClosureViolationActivityContractFaceCandidateResolutionNodeInstanceWorkflowStateDispatch - 错误:
NotPublishableErrorPositionVacantError - 端口类型:
ProcessStoreActivityDirectoryOrgDirectoryTaskGatewayApprovalGatewaySfeelFlowEventPublisherReceiptNotifier - 用例工厂:
createProcessService(deps): ProcessService - 纯函数:
checkClosurepublishableresolveOwneraggregateWorkflowState(resolveOwner的bound入参 = 已校验的工作组绑定,ADR-011)isDigestednextInstanceNumberselectEdgesassemblejoinReadyrejectRouteOfdispatchOfstartNodeOfadvanceOrder(advanceOrder= 推进次序,按边拓扑排、排除回边、并行支按编号定序; 呈现用,不参与流转判断 —— 图纸坐标不配决定次序) - adapter:
createProcessStore;Drizzle 表:processPackageTableworkflowTablenodeInstanceTable
层级: L7(编码规范 §4) 依赖: @contracts;task(L6)、@sfeel 被依赖: trigger, app(治理台 · 工作流管理)
不变量(OS 03 / 3.2):
- 不闭合不得发布:未完成边、必填未映射、类型冲突、孤立节点、异或出边缺条件、
汇合同名字段来源不明、容忍分支被下游必填依赖 —— 任一即
publishable = false - 求值语义前后端同源:画布的即时校验与后端裁决共用
checkClosure - 负责人解析确定性:轮值并列时按 staffId 稳定排序;同输入必同结果,结果与依据留痕
- 工作流状态是聚合投影:流程层不另设状态机;计量对象是节点实例, 重开产生新实例、旧实例不再入算;XOR 未选分支从未激活、不入集合
- 「完成」凭到过终点节点,不凭「没有在跑的了」:收敛但未到终点 = 卡住 =
abnormal。aggregateWorkflowState收第三个入参(包的终点 id 集);不传则退回旧口径,新代码一律传 - 失败走向的消化:改道 / 容忍 / 升审批一经生效即消化;终止流待人工处置中算异常
- 流级重做一律重开新实例 —— 同节点、新任务 ID、留痕关联,不复活旧任务
其它不变量:
- 流转零 LLM:选边与条件求值全部经
@sfeel;判定依据入事件记录 - XOR 恰取一条:条件命中优先,无条件的边作默认分支兜底;
一条都没中而该节点确有出边 = 死路,发
route-dead-end事件 (哪个节点、各出边的条件、判据里当时有哪些键 —— 只记键名不记值) - AND 汇合要回齐:未回齐就不进汇合节点;容忍分支以「已消化」计,不阻汇合
- 流程层不自动重试活动(过程内重试归 Harness); 流级重做一律人裁决后重开新任务实例
- 驳回走向声明式:审批点的驳回按
reject声明回指定节点重开新实例,不由临场决定 - 凡单必有来源:
source必填;终点按输出声明交付、按来源回执
M5 待补(docs/PROGRESS.md · docs/debt.md M5-1)
internal/adapter/workflow-compiler.ts —— 编码规范 §6.1 规定流程包动态编译为 Mastra
createWorkflow/createStep(XOR → .branch(),AND → .parallel(),节点 suspend()/resume())。
当前流转由本模块自持的确定性状态机 + sys.node_instance 持久承担,语义等价且已可测;
Mastra 编译器作为可替换的 adapter 后补,替换时 usecase 不动。