Commit Graph
11 Commits
Author SHA1 Message Date
ChaiHaoandClaude Opus 5 03eb666ac2 三面拆分⑮:对齐 Mastra 数据流 —— 边只表达顺序,数据按输入/输出字段名流动
用户定的机制对齐:Mastra 的边不传数据,所有约束力靠输入/输出字段(schema 咬合)完成。
照此把「边映射」整个退役:

  · 契约:edge 去 mapping,审批 reject 去 mapping —— 边只剩 顺序 + 条件(读上游
    输出字段)+ 标签/回边。fieldMapping 只留给触发器的起单装配(系统边界)。
    存量包无需迁移:zod 解析时把旧 jsonb 里的 mapping 静默剥掉,图照常有效。
  · 运行时:assemble(边装配)→ flatScope(铺平作用域)——
    起单入参垫底 ← 沿途各输出口字段依次盖上 ← 刚发射的载荷(Mastra 语义:
    下一步的 input 首先是上一步的 output)。下游按自己的契约取字段;
    「__」前缀是运行时自留地,不入业务作用域。审批驳回重开、失败改道同一条路。
  · 闭合校验:边未映射/必填未映射/容忍依赖三条映射类检查退役
    (宽进之下必填有没有着落是运行时补全单的事,不拦激活);
    激活闸只留一条硬伤 —— **同名不同型**:名字即管道,名同型异必坏,
    容忍依赖改按名判。改名映射不存在:名不对改契约,不是加映射。
  · 种子:A2 的入参 material 更名 pn(它就是 PN;上游 A1 发的名就得是它收的名),
    契约 0.3.0、槽位 0.8.0;流程种子边全部去映射。
  · 前端:边属性卡砍掉「映射 · 载荷装配」整节,只剩 E号/方向/条件/标签;
    节点属性卡新增「数据接口 · 按字段名流动」——每个输入字段标出运行时从哪来
    (起单入参 / 上游 X / 补全单),输出口列出发什么名;沿边回溯推导,设计期看得见。
    画布保存与依赖文件导出同步去映射。

E2E 顺带把宽进接进真流:快速归档流的 A3 要 outcome 而流里没人产 ——
测试如实走补全路(等人 → 答卡 outcome=won → 开跑 → completed)。
实测走查:A2 节点卡上 pn←上游A1、rfqRef←起单入参、scenario←补全单,推导全对。

五闸绿;契约快照随本提交入库。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 14:25:27 +08:00
ChaiHaoandClaude Fable 5 f145bde875 三面拆分⑲:审批点卸岗位 —— 负责人一律运营时分配,绑员工组,实例记 assignee
模型(用户定):审批点不绑岗位;节点负责人是运营时分配的,绑定到员工组。

- 契约:approval 节点删 approver(功能属性只剩驳回走向/催办/委托消息);
  CLOSURE_VIOLATION_KINDS 删 missing-owner-position(岗位不入编排,无岗可核);
  治理审批列表删 approverPosition 字段
- 运行时统一口径(活动点=审批点):工作流绑了员工组按组轮值(组员并集最闲者先),
  没绑组全员轮值;staffId 稳定排序保证确定性,组员全不在岗退回全员。
  ADR-011「绑定先于策略」随岗位退场 —— 工作组快照的成员集合成为轮值池
- 实例记 assignee(迁移 0014 node_instance.assignee_id):分派结果是流转事实 ——
  审批箱收件(i.assigneeId === me)、裁决权(同一判据)、员工面链条报实际承接人、
  治理台审批列表报人,全部按它认,不再有岗位比对
- closure 卸 positions 入参;desk/desk-approval/governance-ops 三路由改口;
  web 属性卡删「审批岗位」选择与警示、positions 管线拆除;种子 A5 卸 PM;
  导出依赖文件审批段只留编排语义

测试:closure 25、save-package 6、seed 8、graph-to-pkg 5、端到端八例真库全绿;
五闸退出码全过。库:迁移 + v4 就地同步(唯一生效版)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 21:24:41 +08:00
ChaiHaoandClaude Fable 5 7f0d25c337 三面拆分⑭:纯编排第三轮 —— 活动卸岗位、卡点废除全真边、边号 E1–En 图上可选
活动契约不带负责人岗位(用户定):
- schema:活动节点删 owner(审批点的 approver 是「卡到人的工位」的功能语义,保留)
- 运行时:活动任务默认**全员轮值**(在岗候选并集、最闲者先、staffId 稳定排序,
  owner-resolved 事件岗位记「(全员轮值)」);运营分派机制落地后让位 —— 债已记
- closure:活动点不核岗位,missing-owner-position 只出自审批点
- 员工面链条:活动点报**实际承接人**(实例→任务→人),没起的如实报「轮值待派」;
  NodeInstance 公开 taskId/approvalId(店面读回,与端口型合流)
- 画布/导出依赖文件/属性卡全线摘岗位;属性卡活动点明说「分派归运营」

卡点画法废除,顺序流一律真边(用户定):
- 种子图重画:四条回跳/直达(E4 直接定价、E6 选型后定价、E10 不通过、E12 有异议)
  全部画成折线真边,车道分层零交叉(顶 y30 / y190 / y230 / 缝隙对开 / 底 y380);
  卡点节点删净,图=恰 10 语义节点 + 14 真边一一对应(测试守着)
- graph-to-pkg 卡点认亲机制删除;pkg-to-graph 直接按 from→to 认亲
- 元素盘删卡点件;图例、属性卡卡点分支、kindLabel/kindTone 随删

边号 E1、E2…(用户定):
- 语义边 id 即边号:种子 E1–E14;合并器铸号(旧边保号、新边取下一空号,回归测试守着)
- 画布线标带号(`E3 直接寻源`,无注记的边也标 `E1`);拣选条以边号立牌,
  **条件不再上按钮** —— 条件/映射只住属性面
- 边在图上可选中:FlowDiagram 连线加宽透明命中垫(边可点时注解层提到形状层上),
  点线即切属性卡到该边(实测 E4 命中)

测试:closure 28、advance-order 6、graph-to-pkg 5(新增铸号例)、seed 8、
端到端八例真库全绿(全员轮值下照跑);五闸退出码验过。
库:purge 后重种,唯一 unified-quote@v1 生效(双面判据齐)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 19:02:07 +08:00
ChaiHaoandClaude Fable 5 281f4ef084 三面拆分⑬:流程包纯编排化 —— 编排与传递契约归包,实现方式归库,激活看双判据
模型(用户定):流程包只决定活动编排 + 活动传递的契约,不决定活动的实现方式;
节点只分活动点与审批点;图只定名称与顺序,属性在卡上填,链接好实现即可运行;
激活 = ①Mastra 式图编排闭合完善 + ②活动装载,两面判据。

schema(库经外科手术清空,无历史包袱,网关彻底出局):
- contracts:删 gateway 节点变体 / GATEWAY_KINDS / GATEWAY_KIND_LABEL /
  'gateway-deprecated' 违规项 —— 节点四种:start/end(结构件)+ activity/approval
- routing:joinReady 整个删除(多入边即异或汇合,没有「等回齐」;AND 待并行组);
  selectEdges 精简;closure 删 checkGateway;process-service 删汇合等待与网关直传,
  节点一律只收装配后载荷(verdict/outcome 判据由系统注入,不走映射)

编排面(画布 = 名称 + 顺序,其余在属性卡):
- 元素盘五件:活动点(单一,不再分标准/案例 —— 那是实现方式)/审批点/起止/卡点
- 属性卡:节点类型二分(活动点/审批点);新增「链接活动实现」选择器(装载面,
  FlowNode.act 经 merge 成为语义 activityId);范式/版本降为只读装载信息
- 边属性可填:条件(S-FEEL)+ 映射(上游输出口/起单载荷/常量三种来源;
  workflow-var/expression 归系统隐性,不进设计者面)—— FlowEdge.condition/mapping
  工作副本,pkg-to-graph 回填、graph-to-pkg 合并,清空条件即变默认兜底边
- 异常看板 → 激活双判据看板:图编排(结构+属性+契约)与活动装载(unknown-activity)
  分面亮灯,两面清零激活才亮
- pkg-to-graph 去 paradigms 绿化与网关分支;图例/文案全线「活动点/审批点」

测试:closure 27(joinReady 两组 describe 随机制摘除)、advance-order 按真图形状重写
(去 as never 捏造的网关节点)、graph-to-pkg 9(新增 act 合并 + 边契约合并/清空用例)、
seed 8、端到端八例真库全绿;五闸退出码验过(api:check 提交后转绿)。

库:purge 后重种,唯一 unified-quote@v1 生效(10 节点 14 边,双面判据齐)。
债:M5-5 清账(兼容路径连 schema 一起摘);M5-4(并行组)仍挂。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 18:29:32 +08:00
ChaiHaoandClaude Fable 5 6854524784 三面拆分⑫:网关去节点化 —— 分支即条件出边,汇合即多入边异或
模型(与 Mastra .branch 同构,条件挂在步与步之间):
- routing.selectEdges:多出边一律异或,不分节点种类 —— 条件命中优先(按声明序),
  无条件边作默认兜底,恰取一条;单出边直通保留(历史并行网关的遗留通道)
- closure:含网关即 gateway-deprecated(历史版本仅可读、不可激活);
  「隐式合并」禁令删除(多入边=异或汇合,上游互斥无歧义);
  新规:多出边节点的无条件边至多一条,超出报 multi-default-edge
- contracts:CLOSURE_VIOLATION_KINDS 去 gateway-unbalanced/join-ambiguous-source,
  进 multi-default-edge/gateway-deprecated(下游零引用,api-report 随行)

种子(按用户要求:只留一条流一个版本,图/节点/边全部对账):
- MVP_PACKAGE 重写:10 节点 14 边零网关 —— G1/G2 展开为 A1 的三条出边
  (选型/直接寻源/默认直接定价)+ A2 的两条,G2J/G3 整颗删除,
  A5 审批点的两个去向就是自己的两条 verdict 条件出边(驳回边与 reject 声明字字对齐)
- 手绘图:顶车道 y30 补画 A1→A3「直接寻源」—— 画布保存只认画出来的边,
  不画这条语义边会在首次存盘被静默丢掉(新增图边对账测试卡死这类漏画);
  「供应商底价表」标注钉进 y190 车道空档,不再被卡点压住
- 开发库外科手术:清运行数据 + 删 v1–v4,重种为唯一生效版 v1(闭合过闸)

UI 与文案同步:
- 元素盘/追加盘不再有网关件(画布仍认得历史图);图例删「判断/并行网关」「菱形=网关」
- 新建流程补激活一跳(保存不生效模型下,不激活「建出来就能起单」就是谎言)
- 总览四种编排要素、「画图不检查,激活才查完整」贯穿 blueprint/memory/process 文案

测试:closure 43 通过(gateway-deprecated + multi-default-edge 两用例),
seed-mvp-flow 8 通过(含图边对账),端到端八例真库全绿(网关从不建实例,断言原样存活);
五闸 typecheck/lint/depcruise/api:check/test 全过(退出码验)。

债:M5-4 AND 并行待「并行组」声明(Mastra .parallel);M5-5 网关运行时兼容三处,
含网关在途流清零后随 schema 一并摘除。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 17:56:20 +08:00
ChaiHaoandClaude Opus 5 ba5f65e685 画图不检查,激活才查完整 —— 保存 bug 的根治 + 异常看板
你存不了图的根因:保存跑闭合校验,而画图必然经过不完整的中间态
(节点没接完边、活动没安装)—— 画到一半就 412 卡死。实测同一份图:
改前 412 拒存;改后存为未生效的新版,报告随行。

## 模型改成三段

  画图 = 只创建节点和边,图上真正生效可编辑的只有**名字**(双击不再出岗位一栏;
        边上的字是辅助阅读的注记;岗位/判据/映射这些**闭环要素在节点属性里决定**;
        分配到人是运营的事,设计侧不碰)
  保存 = 不检查、不生效:恒存为新版本号,谁也伤不着 —— 因此不设确认卡,直接存;
        任何版本都可编辑(在旧版上改 = 以旧版为底另起一版)
  激活 = 完整性闸:不闭合 412 拦下并点名缺什么;过了即独占生效

## 异常看板(左,与版本卡同列同风)

画图不拦,看板替你盯着:逐条列这一版缺什么,**点一条定位到那个节点的属性**;
零异常时给空占位说「可以激活」。版本行的「激活」按钮按闭合灰显 ——
不闭合点不了,亮了才能上线。实测:v4 两条异常全列出、激活灰;闭合的 v2/v1 亮。

## 顺手修一个画布盲区

packageToGraph 以手绘存证为呈现真相,**语义里有、存证里没有的节点画布看不见**:
异常看板指着一个图上不存在的节点,点了也定位不到(实测:API 直存的包新增节点后
picker 里根本没有它)。补画:缺席节点按 60px 一档排在图纸下缘 —— 位置丑没关系,
看得见才能修。实测点异常 → 选中 A8 → 五张属性小卡弹出。

## 布局照你定的

row2 = 异常看板(1/3,与版本卡对齐)+ 节点属性卡(2/3,与流程图同宽);
属性卡内部小卡**等高 250px**,输入/输出超高的内容自己滚(实测五张全 250)。

种子改为保存后显式激活;NotClosedError 文案「不得保存」→「不得激活」。

typecheck ✓ lint ✓ depcruise ✓ 498 测试 ✓

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 15:52:45 +08:00
ChaiHaoandClaude Opus 5 58d914b8a2 活动伪函数占位:机器步落台账 + 一张验收单 —— 顺手揪出三个引擎 bug
按你定的形态做:占位一律机器步,每个活动只留一张验收单要人签;
**不碰活动内部的业务判断** —— 打标、定价、比价那些一概不做。

## 占位怎么占

一枚纯工具 `slot.placeholder`:只穿透上游给的值、给显眼的默认(数值一律 0,
主键给「PN-占位」这类),行上写 `status: '占位'`。它不判断任何事。
骨架 = N 个机器步各落一行台账 + 末步一张验收单。
验收单的卡面要人填的正是**该活动该产出、而占位产不出的判断**(如两枚去向旗)——
人类步的回传值同样经 writeOutput 落台账、步序在后,所以人填的覆盖占位的默认。
占位期要走哪个分支,在验收时说,不必改代码。

六个槽位一律 flow 范式(A2/A3/A6 本该是 loop,但 loop 要 Agent 真调模型;
占位是固定序列,声明成 flow 才诚实),那份没人用的 loop 骨架顺手删了。
预算改成固定 humanCalls: 2(机器步不吃人工调用)。

## 三个引擎 bug,都是「无声卡住」

**① 异或汇合在等一条永远不来的分支。** `joinReady` 按并行汇合写(全部责任分支收敛才放行),
可 G2J 是异或 —— 两条分支互斥、结构上只来一条。于是「不需要寻源」这条路上永远在等 A3。
最坑的是**连死路事件都没有**:边是选中了的,只在汇合判定里被 continue 跳过,
从外面看就是 A1 办结后什么都不再发生。已改为异或汇合不等,加了三条测试。

**② 出口载荷取的是落地前的草稿值,不是落地事实。** `releaseWrite` 直接回 `draft.patch`。
人的回传值天生是字符串 `"true"`,列是 boolean,PG 存的时候转了,可发出去的口里还是字符串
—— 下游活动入参校验当场拒收「/needSourcing must be boolean」,节点报 blocked,
而台账里明明是对的。改为合并后**读回来**:出口载荷与台账逐字一致,类型由列定义说了算。

**③ 审批箱按岗位码筛,无视工作组绑定。** 引擎派审批时「绑定先于策略」(ADR-011),
装了组的单实际派给被绑定的人;而收件与裁决两处都只比 `me.position.code` ——
于是「审批派给了我、我的审批箱里没有」,单子谁也看不见,流永远卡在审批点(实测)。
`toChain` 早为同一件事修过一次,这是漏的两处,一并按派单口径改。

## 顺带

`cards.issue` 的验收分支写死 `fields: []`,而 `acceptanceWorkOrderSchema` 本来就有 `fields`
—— 是没填,不是设计上不要。执行与验收现在共用同一份字段解析。

我自己也踩了一个:验收步的出参映射键写成驼峰 `needSourcing`,但**键是台账列名**
(小写蛇形),draftWrite 抛「非法标识符」,而且是在放行之后抛 —— 任务卡在 running、
台账一行没有、推进器一秒一次无限重试。测试里加了「所有出参键必须匹配 ^[a-z][a-z0-9_]*$」。

## 实测走到哪

起单 → A1(两机器步落台账,一张验收单)→ 人填 needAlternative=false →
G1 判「不需要选型」→ G2 判「不需要寻源」→ **G2J 通过** → A4 成本定价办结 →
A5 审批点(审批箱可见)→ 裁决通过 → **G3 判到 A6**(链位 6/7)。
A6 的三个去向要选择组(T2),到那儿为止。

typecheck ✓ lint ✓ depcruise 374 模块 ✓ api:check ✓ 498 测试 ✓

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 13:16:17 +08:00
ChaiHaoandClaude Opus 5 b2f5f69d6a 流程包去掉发布机制 —— 严格检查 + 保存即生效,生效由运行时决定
用户要的是运行时机制:新建 + 编辑,存下去就生效,旧任务走完旧版本,
新任务调用时才加载新编排。所以「草稿 → 发布」两态整套去掉。

## 闸从「发布」挪到「保存」

`savePackage` 现在先跑闭合校验,不闭合抛 `NotClosedError`(路由 412 带报告)——
**一个字节都不落库**。存进来的每一版都能起单,所以不需要「已发布」这个标记。
`publish` 用例、路由、`publishPackage` 存储方法一并删掉。

实测:把进 A6 的边映射清空后保存 → 412,逐条点名「边 e-g3-a6 未完成载荷映射;
节点「报价议价」的必填字段未映射:rows」。

## 保存恒新增版本号,服务端说了算

这不是可选项,是「旧任务走完旧版本」的前提:工作流按 (包id, 版本) 去读定义,
就地覆盖 v1 就等于改掉所有在途 v1 任务正在读的编排 —— 它们会中途换了规则却毫不知情。

版本号由用例层算(当前最大 + 1),**不采信入参**。实测:入参故意填 version: 999,
落的是 v2。store 层因此改成**只插不改**:撞键宁可让唯一约束报错,也不静默覆盖。

起单取版从「最新已发布」改为「最新一版」(retired 除外);触发器的 requiredInputs 同口径。
实测:改完描述存成 v2 后,新起的单用 v2,早先那单仍挂 v1。

## 迁移:旧状态值不归一就是一读就炸

状态枚举从 draft/published/retired 收成 active/retired。列上和 definition 这个 jsonb 里
各存着一份 state,两处都要改 —— 不改,`processPackageSchema.parse` 读一行就抛。
这不是开发期小麻烦,任何已部署实例都会中招。加了迁移 0012。

## 界面:恒为 0 的假指标撤掉,不换个说法留着

- 编排面板:「已发布/草稿」芯片 → 「生效中/历史版本」(真正的区别是哪一版会被新起单取到);
  发布按钮撤掉,保存按钮改成「保存并生效(存为 vN)」并在确认卡里说清影响面
- 历史版本只读,但就地指路:「去 v(N-1) 改(生效中)」,不让人自己找
- 蓝图面:「草稿 N · 未闭合 M」两个计数在新机制下**结构上恒为 0**(不闭合存不进来),
  换成「共 N 个版本,保存即生效」
- 驾驶舱:「未闭合草稿」卡整张撤掉 —— 同理恒为 0。天然的第三张是「死路」
  (route-dead-end 事件),但那需要一条按事件类型聚合的路由,没有之前不摆(同死信卡的规矩)

## 顺手修:种子的幂等判断本来是坏的

比对用 `JSON.stringify` 认键序,而 jsonb 从 PG 读回来键是重排过的 —— 永远判不等,
每播一次种就多存一版一模一样的定义(实测一口气堆到 v3)。改成递归按键名排序后比对。
连播三次,只第一次存。

## 契约变更(破坏性,一步到位)

`publish` 删除、`NotPublishableError` → `NotClosedError`、`publishable` → `closed`、
状态枚举收窄。按规矩破坏性变更该走三步弃用 —— 这里一步改完,因为:
① depcruise 反查下游全在仓内(374 模块无违规),同批改完;
② 要弃用的是一个**产品决定不再存在**的机制,留弃用窗口没有意义。
CONTRACT.md 已同步,快照单独说明。

typecheck ✓ lint ✓ depcruise 374 模块 ✓ 495 测试 ✓

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 12:49:24 +08:00
ChaiHaoandClaude Opus 5 22aa44c775 手工走通整条流,揪出五处编排层问题 —— 最要命的是假成功
把 `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
2026-07-28 11:11:32 +08:00
ChaiHaoandClaude Opus 5 9201f6b094 判据 ⑥ 解锁:容忍分支推得动汇合,汇合不再等一个永不到来的网关
三处修:

① `joinReady` 把**网关直连汇合的直通道**也算作一票要等的分支。
   网关不是责任单元、永远不会有实例,于是汇合永远等不齐,整条流卡死。
   改为:来源是网关的入边不参与等待 —— 分叉一发生它就算过了。
   (统一报价图里这条直通道就是 TYPE-A 快路。)加了回归守卫测试。

② 容忍(tolerate)只把实例标成「已消化」就收手,不往下推 ——
   `joinReady` 认 tolerated,可没人再去问一次汇合够不够齐。改为标完即续推。

③ 蒸馏钩子失败会把已落定的终态掀翻(治理台终止返回 500,任务卡在中间态)。
   蒸馏是进化管线的入口、不是终态的一部分:失败就失败,终态照落。
   失败也不再往任务记忆里追加 —— 此刻记忆已封卷,那个守卫拒得对。

结果:A1 released → G2 分叉 → A3 / A2 两个 loop 起在正确工位 →
按声明容忍收束 → **汇合回齐 → A4 成本定价起到冯兵工位**。

gates: tsc / eslint / depcruise / 397 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 05:03:58 +08:00
JCAI Main AgentandClaude Opus 5 a919d2e961 M5(1/3): process 的 domain —— 闭合校验、四策略解析、状态聚合
- checkClosure:七类违规(边未映射 / 必填未齐 / 类型冲突 / 孤立节点 /
  网关不平衡 / 汇合来源不明 / 容忍分支被必填依赖)+ 活动未安装 + 岗位不存在;
  不闭合不得发布 —— 画布即时校验与后端裁决同源
- resolveOwner:四策略封闭(指定人 / 岗位唯一人 / 轮值 / 来源跟随);
  岗上多人退轮值,并列按 staffId 稳定排序 —— 解析必须确定性
- aggregateWorkflowState:聚合投影,流程层不另设状态机;计量对象是节点实例,
  XOR 未选分支不入集合,改道/容忍/升审批已消化即不入异常
- nextInstanceNumber:流级重做重开新实例,不复活旧任务

325 个测试通过,门禁五道全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 01:55:47 +08:00