Commit Graph
198 Commits
Author SHA1 Message Date
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 78622b8799 审批点后面补上网关 G3,并让引擎**真的走它** —— 顺带给去向旗找到落脚处
两件事,都是「图上画着、实际走不到」这一类。

## ① 审批点后面没有网关(用户提出)

A5 只有一条出边 A5→A6,驳回走向藏在 `reject` 声明里,图上只是一枚牌子。
BPMN 的常规是审批的两个去向都由网关决定 —— 补 G3「审批结果」,
`verdict = "pass"` → A6,`verdict = "reject"` → A4(回边)。

补的时候撞上真问题:`onApprovalVerdict` 只在 pass 时走 `advanceFrom`,
而且 payload 里**不含 verdict** —— 于是 G3 没有判据可读。异或分叉的每条出边都得带条件、
没有无条件兜底边,判据一缺就全不成立,流会无声停在 G3。

能让闸过的最省事办法是在 `e-a5-g3` 上喂一枚常量 `verdict: "pass"`。**没那么做** ——
那样 G3 的条件恒真、驳回边永不可达,网关就是个摆设,又是一处「画着两个去向、
其中一个结构上走不到」的谎。

改的是引擎:裁决进载荷,通过与驳回**都先看图**,只有没画驳回边的包才退回 `reject` 声明
(它 schema 必填,且是通用机制)。`advanceFrom` 因此回报「有没有真的推出去」,
并加 `quiet` 参数 —— 「先试边、不成再退回声明」这一步试空是正常分支,不是死路,
不该报 route-dead-end 假警。

`reject` 保留:schema 必填、CONTRACT.md 的不变量、且审批人界面拿它渲染人读文案。
它与 `e-g3-a4` 必须字字对齐,加了测试守。

## ② 几何重排:两带换行,不回形

原坐标逐点抄自 MVP 的 SVG,是回形走线(row 0 左→右、row 1 右→左、row 2 折回最左)——
这正是上一轮流程链读成 A1→A7→A2 的根源。重排为两带:
受理·选型·寻源(y 60..100)→ 换行车道 y=190 → 定价·审批·议价·成交(y 310..350)→
未成交闭环(y 410..450)。每带内 x 随推进次序单调递增。

实测渲染(画布 639×325):带 0 的 A1 57→G1 159→A2 223→G2 325→A3 389→G2J 491,
带 1 的 A4 38→A5 153→G3 242→A6 293→G4 395,**零框重叠**。
两枚回 A4 的卡点同一条车道、同朝向(向上=回退)。

## ③ 顺带:两枚去向旗终于有地方落

上一轮我在债务簿写「A1 过不了 G1 是诚实状态、不是缺陷」——**判断错了**。
出口的标量字段只从落地事实取,而 `needAlternative` / `needSourcing`
在任何台账对象上都没有列,活动实现了也一样取不到。

新增 `project.intake_verdict`「受理结论」**一单一行**(主键只有询价单号)。
为什么不挂在按料号分行的「统一受理记录」上:`flat` 是把这一单所有落地行 reduce 展开,
六个料号就有六行同名列、最后合并的那行赢 —— 而归并规则是「任一条命中 C 即需选型」,
last-write-wins 会静默给出错的去向。测试正反两面都守:结论表主键只能是 rfq_ref,
且**其它对象上不许出现去向旗**。

A2 也要回写这一行,所以 `rfqRef` 进了 G1→A2 的边映射,并**正式声明进 A2 的入参**——
不声明也能偷渡(闭合校验遇到未声明的目标直接跳过),但那是默许不是正当。
A2 的 contract.version 因此升 0.2.0,包版升 0.5.0。

顺手删了一个陈旧草稿 v2:它是我早前测编辑器留下的旧图(14 节点、无 G3),
而种子刚把 v1 用新图重发布 —— 草稿内容比已发布版更旧,谁发布它 G3 就没了。
删前确认零工作流引用。系统没有「丢弃草稿」的入口,这条记进债务簿。

typecheck ✓ lint ✓ depcruise 374 模块 ✓ api:check ✓ 495 测试 ✓
发布闸实测:15 节点 / 18 边,边映射闭合校验通过。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 12:24:40 +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 5826b6f976 流程链按拓扑序读 —— 图纸坐标不配决定推进次序
任务详情里的「流程链」在 MVP 包上读作 **A1 → A7 → A2 → A6 → A3 → A5 → A4**。
不是随机:`toChain` 按 `layout.col` 排,而 MVP 图是**回形走线**(第 0 行左→右、
第 1 行右→左、第 2 行折回最左),A7 的列位(1)正好跟 A1 并列、A6(3)跟 A2 并列。
原注释还写着「列位是流程的推进次序(拓扑的可视化)」—— 那句话只对 v1 那种一行
从左画到右的包成立,换一张图就是错的。图纸声明为「不影响语义」,那它也不配决定次序。

改为按**边**做拓扑序,新增 `advanceOrder`(process 的 domain,纯函数零 IO):

  · 回边(reopen)排除在外 —— 它是重新入场不是往前推进;留着 G4 → A4 就成环,
    A4 会等自己的下游,拓扑序无从下手
  · 真并行支(G2 分出的 A2 / A3)图上本无先后,按**节点编号**定 ——
    同一个包在谁手上都读作同一条链
  · 进不了拓扑序的节点(不可达、或排除回边后仍有环)按编号缀在末尾:少排序,不丢节点

实测链已读作 A1 → A2 → A3 → A4 → A5 → A6 → A7(A1 current)。
六条 domain 测试盯住它,第一条就是那张回形图。

顺带修了两处会互相传染的闸:
  · `api-report.mjs` 在 tsc 失败那条路径不清 `.api-tmp`,半成品留在盘上,
    eslint 扫到生成的 .d.ts 报 1004 条假错 —— 于是 tsc 一红 lint 跟着红。实测踩到。
  · eslint 只忽略了 `api-report/**`,把同为产物的 `.api-tmp/**` 一并忽略

契约变更(加法,非破坏):①depcruise 反查六处下游无违规 ②CONTRACT.md 已注明
③快照 api-report/…/process/index.d.ts 仅多一个导出名。

typecheck ✓ lint ✓ depcruise 374 模块 ✓ 487 测试 ✓(以退出码验,不以 echo 验)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 10:45:41 +08:00
ChaiHaoandClaude Fable 5 5619d86ce4 编排层③:活动装入/换版入口 —— 开发完能装进来,不必跑种子
此前活动只能靠 seed 装入,治理台没有任何入口 —— 这是「逐个开发活动」的拦路石。
补 POST /api/gov/activities(无代码通道:交清单 + .js 产物,都是数据),
两审在服务端跑;不过审按发布门同样的式样回 412 + ApiError.detail 带审计结论
(直接回业务体的话类型化客户端拿不到详情)。活动库给「装入 / 换版」卡:选文件或粘贴两份。
实测:0.1.0 → 0.2.0 版本并存;声明未注册的工具即 412 并点名到工具。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 10:01:25 +08:00
ChaiHaoandClaude Fable 5 9de641459e 编排层①:改图入口下沉画布 + 活动契约面全链打通
① 已发布包就地给「起草新版本并去编辑」,不用去页头找;
② 修一个我自己引入的 bug:卡点还原把审批点的「退回调整」牌子当成边,凭空造出 e-A5-A4 ——
   卡点只认亲、不新建(旧包有这条边才认);实测编辑器往返 16 边 14 节点无损;
③ 活动契约面接进治理台:列表出参带必填入参/输出口/声明依赖,活动详情摆成一屏,
   导出依赖文件一并带上 —— 开发一个活动要照着的东西,现在有一处能看全。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 03:02:44 +08:00
ChaiHaoandClaude Fable 5 ec0b78c550 UI②:数据对象全用中文名 —— label 随物化落 PG 注释,全链读回
此前 label 在建表那一步就丢了,治理台只剩 project__intake_record 这种键给人看。
用表/列注释而非另建元数据表:名字与表同生共死,不会对不上。
设计台/运营台/对象详情/触发器下拉一律中文名在前、键在后。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 02:33:09 +08:00
ChaiHaoandClaude Fable 5 8e7509f65b MVP底座⑤:自定义工具导入路由 —— 与第一方同门两审
顺手补两处底座:试运行审此前传空连接,靠 endpoint 干活的工具一律过不了门(这道门
只对不需要连接的工具有效);现传本次申报的连接值。未注册第一方处理器的工具走通用
HTTP 实现 —— 导入的工具由此可真调、可真审:端点不通就是不通,不入目录。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 01:58:38 +08:00
ChaiHaoandClaude Fable 5 0fe5222f79 MVP底座④:统一报价 1:1 流程包单实例 —— 四域物化,种子整体切换
14 语义节点/16 边:A5 是内置审批点(驳回走 reject 声明 reopen A4),
G2 的两条互斥分支显式汇合于 G2J —— 隐式合并过不了闭合校验(实测)。
顺手修 graph-to-pkg:卡点带 to 时还原成语义边,否则回边画成卡点一存盘就没了。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-28 01:49:49 +08:00
ChaiHaoandClaude Fable 5 90ca92aa0e MVP底座③:六活动槽位清单 —— 契约就绪,实现留白,工具按名解耦
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 22:45:32 +08:00
ChaiHaoandClaude Fable 5 d00e29091e MVP底座②:四域十八对象声明 —— 流转归项目,沉淀归客户/情报/供应商
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 22:41:25 +08:00
ChaiHaoandClaude Fable 5 6f36f8340a 三面拆分⑩:工作组管理落员工区 —— ADR-011 欠账清账
建组/改组:逐岗位选人,留空即回落四策略。绑定先于策略,起单时快照进工作流;
实测改绑定后新起单的 work_group 快照即含新成员表,在途不受影响。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 21:28:30 +08:00
ChaiHaoandClaude Fable 5 de283acbdb 三面拆分⑥:触发器 upsert 路由 —— 定义面的 HTTP 口(启停仍走 toggle)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 21:12:44 +08:00
ChaiHaoandClaude Fable 5 9fce0fdaa0 三面拆分④:驾驶舱首页 —— 度量改接 report 真八指标,纠正率/DMN 不再恒为 0
治理台原先调 memory 的五指标版,还把 submissions/corrections/judgements
硬塞 0 —— 仪表在说谎。八指标本就在 report 里算好,这里接上,与工作台汇报同源同口径。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 21:08:42 +08:00
ChaiHaoandClaude Fable 5 ac85ecf2ea 基线:鉴权会话+工作组+工作台三区修复+编排工作区+产品设计文档
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 20:43:35 +08:00
ChaiHaoandClaude Opus 5 61fe181678 度量八指标全部接真:DMN 覆盖率与单位成本不再恒为 0
两处度量是空的,查下来都是「没人记」而不是「算错了」:

① **DMN 覆盖率恒 0**:判据只认标题里的「求值:」,把跑得最多的**纯工具步**整个漏掉。
   DMN 决策表与机检正是落在纯工具/工具步上。改为按步类型分:
   确定性求值(pure-tool / tool)÷ 判断总数(再加 LLM 步)——「临场搬进确定」的进度表。
   顺带把**步类型显式写进留痕**:判据该由引擎给出,不靠解析标题后缀。
   现读数 66%。

② **单位成本恒 0**:任务消耗只记步数,token / 活跃时长 / 调人次数**从来没人累加** ——
   于是八指标里的单位成本永远是 0,预算熔断与打扰上限也形同虚设。
   · tick 计这一拍真正花掉的时间(挂起等人的不算活跃,那是世界等待);
   · flow 的 LLM 步与 loop 的每一回合都把 token 计入;
   · 每发一张卡计一次调人。
   现读数:A2 单轮 12k token、A3 3.4k;单位成本 73 token 每放行单。

另修:执行卡的 ask 优先取 `card.ask`(此前只认 `reason`,新卡面格式下会退化成标题)。

第四轮端到端复跑:整条链闭环,消耗数据真实。

gates: tsc / eslint / depcruise(336 模块)/ api-report / 429 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 11:44:10 +08:00
ChaiHaoandClaude Opus 5 94f31f267b 调优:并发推进的真根因 + loop 的三处行为修正
E2E 跑 loop 时 A3 一口气发了八张一模一样的「请处理」卡。逐层查下去,四处:

① **并发推进的真根因**:`pg_try_advisory_lock` 是**会话级**的,而我们经连接池取连接 ——
   加锁与解锁多半落在不同连接上,解锁解不掉自己那把;同一连接被复用时又因可重入而直接放行。
   两头都不对,于是同一任务被并发推进(现象:同一步跑两遍、同一张卡发两张、
   同一行草稿写出两条互相打架的版本)。前一轮「共用同一把锁」的修法方向对、器械错。
   改用**进程内按目标互斥**(MVP 单进程,确定且够用),推进器与派发器共用一把;
   多进程部署时再叠事务级 `pg_try_advisory_xact_lock`(随事务释放,不依赖连接归属)。
   实测:同一单从 8 张卡降到 1 张,2 回合后落到等待。

② **非法行动会把回合打死**:AI 提了不合法的生命周期迁移(Available → Disabled),
   `applyAction` 抛出、运行时没落笔、推进器一遍遍重来。引擎拒绝它是对的
   ——「语义忠实:引擎不得私改迁移拓扑」——但不该因此崩掉。
   改为:拒绝 + 留痕 + 把理由喂回下一回合的上下文。AI 提出非法行动是预期内的事。

③ **副作用抢在校验之前**:卡在迁移合法性判定**之前**就发出去了,于是每个被拒的回合
   都白发一张卡 —— 卡收不回,负责人工作台上堆起一摞没人知道怎么答的「请处理」。
   human / tool 两个分支改为**先验迁移再动手**。

④ **裸调用**:模型只回一个「请处理」。按「调用必附上下文,裸调用不得发出」(AM 06)
   把卡面结构写进出参 schema(title / ask / basis / fields 必填),提示里讲明要求,
   归一时用当下局面兜底;卡片装配也修了 —— 结构化 basis 优先,嵌套对象转 JSON,
   不再出现一行 `[object Object]`。
   实测卡面:「请确认 NE555P 历史报价并判定采用策略」+ 三个回填字段。

gates: tsc / eslint / depcruise(336 模块)/ api-report / 429 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 11:31:41 +08:00
ChaiHaoandClaude Opus 5 374206b408 六个活动的汇报界面与技能补齐;skill-engine 接上装配面
汇报界面(AM 07):
  · 视图外壳与卡片件提到 `@sdk`(viewShell / kvCard / tableCard / stagesCard / noteCard)——
    六个活动共用一套面貌,不各自发明;样式内联自带(沙箱页面不继承工作台 CSS)。
  · flow 四活动按**步序位置**挂模版:
    A1 事态全景 / 打标判据 / 成果预览;A4 取价基准 / 定价与门禁 / 草案待放行;
    A6 正式报价单 / 放行即发出;A7 结果登记 / 闭环待放行。
  · loop 两活动按**阶段与里程碑**组织:案例全景一屏,画阶段生命周期态、当下可为、目标缺口 ——
    素材全部来自语义引擎,零 LLM 即可成屏;模型只决定下一步做什么,不负责画面。
    为此给 loop-engine 补了视图端口,与 flow 共用同一个网关。
  · 每张模版都把「这一屏在说什么 / 放行意味着什么」写在数据旁边 ——
    人要在数据上作判断,判据就得摆在手边。

技能(AM 08):
  · 六个活动各写了 1–2 条真技能:适用描述 + 方法正文 + 结晶片段脚本。
    正文写的是**方法经验**而非流程复述(如「原文没写的不要补」「该等还是该问」
    「无基准不是异常,是一种基准」)。
  · 资源声明放**技能 ID**(权力面),资产放**定义本体**(方法面),两处分清。
  · **skill-engine 从来没有被构造过** —— 模块实现完整却无人调用,这是它一直没被用上的原因。
    容器里补上:目录与白名单都取自活动清单,装配前查扩权。
  · loop 的叙事面接入**技能目录**(渐进披露:常驻上下文只给「有哪些方法、何时适用」,
    正文等 AI 说要才加载),装配随即**盖戳入任务记忆** —— 回放与归因依赖之。

gates: tsc / eslint / depcruise(334 模块)/ 423 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 10:59:13 +08:00
ChaiHaoandClaude Opus 5 ac2fecd005 汇报流:活动按步序位置推视图,容器沙箱渲染
「flow:按**步序位置**推送声明的模版」(AM 07)。原先这条链只有写面没有读面,
活动的 viewTemplates 是一行占位字符串,工作台视图区永远只显示一份硬编码概览。

补齐整条链:
  · 步声明新增 `view`:这一步呈现哪张模版 —— 推什么由声明给定,不由临场决定。
  · 新增模版填数的纯函数(interaction/domain):`data-slot` 取值、`data-rows` 逐条展开。
    **填数只做取值与转义**,没有表达式、没有分支、没有循环 —— 一旦模版能算,
    它就成了代码,容器的「无脚本执行权」也就形同虚设。填充**消费槽位**,
    交出去的是干净 HTML,不是带模板属性的半成品。
  · interaction 补读面 `viewOf`;desk 路由把推送的 HTML 交给前端;
    ViewRegion 经 `@ui` 的 ViewContainer(sandbox="" 的 iframe)渲染 —— feature 不碰 innerHTML。
  · A1 写了三张真模版(事态全景 / 打标判据 / 成果预览),内联自带样式
    (沙箱页面不继承工作台 CSS),按步序位置挂在 S3 / S5 / S6 上。

沿路两处修:
① 取值路径遇到**本身带点号的键**(台账地址 `域.对象`)会被拆成两级、永远取不到。
   改为整键优先、找不到再下行;`view-render` 与 `step-sequence` 两处同修。
② 「本单交付」不能画成台账全表:任务视图是正式版 + 我的草稿的合并结果,
   直接拿来列会把**别单**放行过的记录一并列出。本单自己写下的行单独放在
   `mine:域.对象` 下(整键,取值不歧义)。

另:视图推送失败原先静默吞掉 —— 会让「视图区一直空着」变成查不出原因的怪事;
改为留痕(仍不影响步序推进,呈现是投影)。

实测:一封 RFQ 入站 → 放行前那一屏列出本单交付 LM358DR / TI / 12000 / 8.2 / 10周,
以及 Type A「直接快答」的分类结论与四项打标判据。

gates: tsc / eslint / depcruise(321 模块)/ api-report / 423 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 10:47:20 +08:00
ChaiHaoandClaude Opus 5 abd371b51c DeepSeek provider + 判据 ③ 机器路径跑通(零人工兜底)
Provider 侧:
  · 新增 `provider-profile`(纯数据):各家的默认端点 / 结构化出参姿势 / 是否回推理
    集中一处,adapter 只按画像行事 —— 新增 provider 只改画像,不写一族 if-else。
    DeepSeek:`https://api.deepseek.com`,支持 json_object,v4 系列是推理模型。
  · 建实例时 URL 可留空 → 取该 provider 的默认端点(openai-compatible 本就是
    「随便哪个兼容端点」,没有默认,必须自填)。
  · 推理正文归 `reasoning` 单列:那是**过程**不是结论,不进出参、不参与 schema 校验、
    不入录制(录的是语义入参与结论)。
  · 两档实例 deepseek-v4-flash / deepseek-v4-pro 已建;`quote-extractor` 是**用途名**,
    指向 flash 档 —— 换档只改这一处绑定,活动一行不动。密钥只从环境读、落库即密封,
    治理台只回「是否已绑定」(实测:库里是密文,视图无明文字段,三个实例探活全通)。

沿路修掉五处真问题:

① **同一任务被并发推进**:推进器与派发器各推各的,用的不是同一把锁 ——
   实测同一步跑两遍、同一张卡发两张、同一行草稿写出两条互相打架的版本。
   两者改用同一把 advisory lock(键的推导提取共用)。
② **LLM 步出参从不校验**:声明了 outputSchema,解析不出来就静默当 `{}` 写下去,
   毛病要到下游缺字段时才炸、还炸在别处。改为「出参必过 schema」(AM 12.3),
   不过即按声明的失败走向,并把模型原文记进留痕,好让人看见它到底回了什么。
③ **出参路径不认点号**:入参能走 `a.b.0.c`,出参只认扁平键 ——
   模型按 schema 回嵌套结构(最常见的情形)就写出一条空记录。两边共用一份解析。
④ **归一步拿不到原文**:通道载荷只带指针不带正文、start→A1 边也没把主题正文传下去,
   模型只拿到一个单号,于是回空 records。通道载荷带原文,边映射一路带到 A1。
⑤ **出参形状没讲给模型听**:声明了 schema 却只在提示里写「只输出 JSON」,
   模型只能猜键名(实测回 `{"items":[]}` 而声明要 `{"records":[...]}`)。
   改由网关按 outputSchema 统一附上说明 —— 这是系统的事,不该每个活动作者各写一遍。

另修:连接池没有 error 处理器,空闲连接被服务端掐断会让整个进程退出(一次运维操作
就能把 API 带崩)。

结果:一封 RFQ 入站 → 模型从正文抽出 pn/brand/eau/目标价/交期 →
D1 判定跳过补全 → 查历史价 → DMN 三分类 Type A → 验收放行卡,**全程零人工兜底**。

gates: tsc / eslint / depcruise(319 模块)/ api-report / 409 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 10:25:57 +08:00
ChaiHaoandClaude Opus 5 bfe7828380 判据 ⑨⑩ 收口:确定性蒸馏 —— 零 LLM 也留得下事实
终态封卷的蒸馏钩子原先「模型不可用就整次返回空」,活动记忆一条也留不下。
按「结构化部分零 LLM,叙述是视图不是事实」拆成两段:

  · 先落**确定性骨架**:这一单确实发生了什么 —— 终态、几步转了人兜底、
    放行被驳回几次 —— 全写在归侧条目里,不需要模型来讲。每条带证据链。
  · 模型可用时在其上补模式层 / 裁决层的归纳;归纳不出来也不丢掉整次蒸馏。

实测(A1 一单):3 条 fact 候选,各带证据链。

至此 MVP 十条判据:① ② ③ ⑥ ⑦ ⑧ ⑨ ⑩ 在真实系统上端到端跑通;
④ ⑤ 的 loop 机制(CMMN 装载 / Enabled 集 / 断点判定 / 回路调人)跑通,
余下部分受限于 LLM 端点 —— loop 的 Agent 每一轮决断都要模型。

gates: tsc / eslint / depcruise(317 模块)/ api-report / 402 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 05:58:43 +08:00
ChaiHaoandClaude Opus 5 c3cb82ef64 打扰上限要覆盖「人步 + 人兜底」;发卡失败走声明的失败走向
A7 归档卡在最后一步:调人预算 1/1 触顶,S4 放行卡发不出来,
而引擎每一拍重发一次 —— 六行一模一样的「调用:步 4」,卡永远不出现,也永远不报错。

两处修:

① 发卡被 Harness 拦下(调人预算触顶等)= **这一步失败了**,走它声明的失败走向。
   不接住就是无限重发:预算照烧、负责人什么也看不到。
② 四个 flow 活动的打扰上限只按**人步**算,没算**声明的人兜底**。
   声明了 `fallback: human` 就等于承认这一步可能要调人,预算却不给它留位置 ——
   兜底一触发,后面的放行卡必然发不出。按「人步 + 人兜底」重算:
   A1 4 / A4 3 / A6 3 / A7 2。

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 05:50:56 +08:00
ChaiHaoandClaude Opus 5 1577927214 判据 ⑨ 解锁:选择组 → 出口 → 网关判据,三处断点接通
A6 放行选了 lost,却始终走不到 A7。三处各断一截:

① 装配输出口只看**必交付口**。A6 根本没有必交付口(它的输出是选择组
   won/revise/lost),于是得到一张空表,下游连判据都读不到。改为必交付口与
   选择组的口一并装配。
② `onTaskTerminal` 只取**第一口**的载荷做路由作用域;没有必交付口时就什么都拿不到。
   改为各口载荷合并成一份。
③ 网关拿到的是**边映射装配后**的载荷,而 A6→G4 这条边没有映射,装配出来是空的 ——
   判据依据在这一步整个丢掉,异或网关一条分支都选不中,流悄无声息地停住。
   改为:网关按**到达的东西**路由(上游载荷原样穿过);活动与审批点仍只收装配后的载荷,
   它们有契约,不该被上游多余字段污染。

另立一条约定并写进注释:**选择组发射的那一口就是这次运行的 outcome**
(「恰发一口,随放行一并确认」),下游异或网关的判据读的就是它。

现在:A6 放行选 lost → G4 按 `outcome = "lost"` 判定 → **A7 情报归档起到冯兵工位**。

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 05:48:04 +08:00
ChaiHaoandClaude Opus 5 691c61b6b8 选择组的出口选择要走到落地:恰发一口,随放行一并确认
A6 的输出是**选择组**(negotiation: won / revise / lost),回传协议里本来就有
`selectedPorts`,human-tool 也接住了 —— 但落地那一步硬写 `selectedPorts: {}`,
选择从未抵达。结果:放行了、台账写了,却「发射输出口:(无)」,
G4 异或网关拿不到 outcome,整条流悄无声息地停住。

按 verdict 同样的路子把它串起来:人事件载荷 → 末步运行时 → 谱走完时报上去 →
落地收敛时照它发射。

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 05:34:13 +08:00
ChaiHaoandClaude Opus 5 3af6252394 人兜底也要问**行标识**:主键问不到就写不进台账
A6「生成正式报价单」转人兜底时只问了出参的值(unitPrice / leadTime),
没问报价单号 —— 而 quote_no 是 formal_quote 的主键之一。结果人填完照样落不了地:
放行合并时被非空约束挡下(实测:null value in column "quote_no")。

`fallbackFields` 改为**键与值一起问**:出参声明里的主键路径,凡作用域里没有的都要问;
上游已给过的不再重复问。与前面「出参契约属于步、不属于执行者」是同一条:
这一步该产出的**行**和**值**,换谁来做都得齐。

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 05:28:13 +08:00
ChaiHaoandClaude Opus 5 227764b7da 判据 ⑦:审批点两条走向跑通 + 修草稿基线按字段捕获
审批点(AP 定价审批)卡到 PM 丁子乔工位,依据快照齐、驳回走向按声明呈现。
  · 驳回必附意见:空意见被拒 ✓
  · 驳回 → **回 A4 重开新实例**(A4 #2),旧实例不复活 —— 已裁定 ①④ 的落地 ✓

沿路两处修:

① 审批点的 `reject.mapping` 是空的 —— 重开的是**新的 A4 实例**,它照样要过 A4 的
   入参契约,空映射等于把「驳回回 A4」写成一句空话(实测:重开必失败)。按 G2J→A4
   同样的口径补齐。

② 草稿基线只在**建行那一刻**捕获一次:后续步新写的字段没有基线,冲突检查把它们
   一律当成「他单改过」。于是重开的实例分步写同一行,放行时必被自己的前一版挡下
   (实测 A4#2:「4 处字段已被他单改动」= margin/quoted_price/deviation/disposition)。
   改为**按字段首次写入时捕获**(jsonb 右操作数胜:已有基线不动,新字段补上)。
   加了真实 PG 的回归测试。

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 05:23:28 +08:00
ChaiHaoandClaude Opus 5 c17ccaf049 判据 ⑥ 跑通:A4 成本定价全链 —— 补齐取价基准这一环
A4 卡在 S3 底价自检要 `deviation`,而 S1「取价基准」调的是历史价工具,
那个工具**根本不回价格**:声明说出 deviation,工具给不出,于是永远缺一环。

按业务本意补齐:
  · `crm.history-price-read` 增回 `lastPrice`(上次成交单价)—— 一个不回价的
    「历史价工具」取不出价格基准;无历史的新料号回 0,由下游按「无基准」处置,
    不凭空编一个偏离率。
  · 新增纯工具 `quote-pricing.basis`:基准价 ↔ 拟报价 → 偏离率。
    偏离率要等 S2 定出拟报价才算得出来,所以落在 S2 之后(新步 S2B)。
  · A4 声明:S1 改落 `last_price`,新增 S2B,台账加 `last_price` 列。

顺带修:样例集一份喂所有工具,`quote-pricing.basis` 的必填 `quotedPrice` 不在其中,
新工具过不了两审 → 活动包安装被拒 → 旧资产继续生效,现象是「改了没反应」。
样例改为各家必填的并集。

现在 A4 跑完整条:取价基准 → DMN 定价(利润模型 P-01)→ 算偏离率 →
DMN 底价自检(底价门禁 P-02,处置=直接放行)→ 条件跳步 → 报价草案验收放行。

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:14:01 +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
ChaiHaoandClaude Opus 5 c68a562db1 loop:模型问不出结果时转人裁断,而不是抛异常空转
A3 / A2 起来后每一拍都抛 `Authentication Fails` 并被推进器吞掉:
任务永远 running、预算照烧、负责人工作台上什么也看不到。

模型这一轮给不出行动(端点不可达 / 鉴权失败 / 超时),**不是异常路径,是断点的一种**:
机器当下决断不了就该调人 ——「人在环是一种被调用的工具」。世界一步都没碰,
交回给人是安全且诚实的落点。改在 app 的 agent-runner 收口(引擎保持纯粹),
与 flow 的步级 `failure.fallback` 同构。

缺口作为**依据**摆在卡上,不当表单项让人逐条填。

现状:A3 渠道寻源(林佩萱)装载 21 个计划项、A2 替代选型(王梓名)装载 19 个,
两个 loop 都在等人回卡,不再空转。

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 04:57:16 +08:00
ChaiHaoandClaude Opus 5 9de33a5416 判据 ④⑤ 解锁:G2 并行网关起出 A3 / A2 —— 输出口发射的是落地事实
G2 之后一直不分流,根因三条,逐条修:

① 输出口载荷是空的。`outputPortsOf` 原先从**作用域**里捞字段拼载荷,
   而放行那一刻草稿层已合并并清空,捞到的只剩起单入参 —— 下游节点必然缺字段。
   改为:载荷取自**落地收敛的事实**,由 `releaseWrite` 回报合并了哪些行,
   经 release → task → app 一路带上来。这也正是「落地收敛,输出口才发射」的字面意思:
   发射的就该是已经落地的那些事实。
   `LandedFacts` 给两种读法:铺平(标量取值)与逐行(数组取值),
   输出口声明里 `type: 'array'` 的属性填逐行,标量属性填铺平值(驼峰/下划线两种写法都认)。

② 一条分支起不来,把整条终态上报连坐掀翻 —— 于是**上游任务的终态也报不上去**,
   流停在原地,一行日志都没有。改为:该分支记 `node-start-failed` 事件 + 落一个
   blocked 实例,其余分支照走,在治理台「需处置」里现形。
   (这条是先修的:正因为它,前面两条才一直查不出来。)

③ 边映射引用了不存在的路径:`G2→A3` 的 pn 取 `intake.records`(那是想象中的 LLM 出参形状)、
   `G2J→A4` 的 records 取 `initiation.records`(起单时根本还没有这些行)。
   按输出口的真实声明改正。

结果:A1 released → G2 并行分叉 → **A3 渠道寻源落到林佩萱、A2 替代选型落到王梓名**,
两个 loop 活动同时在跑,岗位解析正确。

gates: tsc / eslint / depcruise(317 模块)/ api-report / 393 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 04:52:53 +08:00
ChaiHaoandClaude Opus 5 1721bcf6e3 修:引擎作用域不得吸入他单事实 + 记录 G2 未分流的排查线索
任务视图铺到顶层的字段,原先取「该对象最新一行」—— 那一行很可能是**别的任务**
放行后的正式版记录。实测:NE555P 的打标读到了上一单 LM358DR 的情报
(historyDays 30 / 在产),被判成 Type A;修正后按自己的事实判成 Type B「重估后报」,
与 P-03 规则一致。

改为只铺**本任务自己写下的**草稿(读己之写),别人的事实仍在 `域.对象` 整表里、
要用得显式取。ledger 门面因此新增 `taskDrafts(taskId)` —— 与 `taskView` 的区别是
它只回我写过的那些行。

顺带记录:A1 已能 released 且节点实例正确落 terminal,但 G2 并行网关未起出
下游 A3 / A2;排查线索写进 PROGRESS.md 待办 1。

gates: tsc / eslint / depcruise(317 模块)/ 393 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 04:39:32 +08:00
ChaiHaoandClaude Opus 5 e72182003a M5/M6 修复串:判据 ③ 全链路跑通 —— 六处「声明与引擎对不上」
判据 ③ 现在从入站到 released 一路走通:步序推进 → LLM 步(密钥是占位符,
按声明降级为人兜底)→ 台账草稿层 → D1 条件跳步 → S4 工具 → S5 DMN 三分类
(LM358DR → Type A · 直接快答)→ 验收放行 → 草稿合并正式版 2 行 → 输出口
intake 发射 → 终态 released。

沿路修掉的六处,每一处都是「声明是这么写的,引擎不这么读」:

1. 人兜底卡只问一个笼统「结果」框 → 改问**这一步声明的出参字段**。
   出参契约属于步、不属于执行者:同一步谁做完,落进作用域的形状都得一样。
2. 人事件的载荷是回传协议壳 `{mode,workOrderId,values}`,
   引擎把整个壳当出参写 → 取 `values`。
3. 引擎作用域是 `{'域.对象': 行数组}`,而所有活动的步声明写的都是裸字段名 →
   任务视图三层铺开:起单入参在底、各对象最新行的字段铺顶层、地址式整表保留。
4. 起单入参从不落库、也进不了作用域 → task 存 `input_data`,断点续跑后仍在。
5. 步出参无法声明**写哪一行** → 出参加 `key`(主键列 → 作用域路径);
   六个活动包的每处出参补上键。台账几乎都有主键,不声明键就只能写无主键行。
6. `tick` 不处理 `finished`:谱走完仍按 running 一拍拍推,把预算烧到 exhausted,
   把「没人裁」误报成「跑爆了」→ 放行通过则落地收敛后 released;未放行则挂起等人。
   `flow.advance` 据末步验收裁决报 released —— **完成只出自放行通过**。

另两处装配缺口:
  · `release.land()` 实现完整却无人调用 —— 放行后从不落地。经 LandingGateway 接上。
  · `process.onTaskTerminal()` 实现完整却无人调用 —— 任务终态报不到流程层,
    流就停在那个节点上,既不流转也不走失败走向。task 在 L6 不得反向依赖 L7,
    这一跳由 app 缝合(延后绑定,同 container 里 TriggerMatcher 的手法)。

还有一处版本化缺陷:资产播种恒用 v1,`shouldSeedAsset` 一比就跳过 ——
只有**第一个**包版本的资产此生有效,之后装什么都跑旧的。改为播下一版;
进化管线放行出的更高版仍不被盖过;同版重复安装不再播种。

gates: tsc / eslint / depcruise(317 模块)/ api-report / 393 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 04:31:23 +08:00
ChaiHaoandClaude Opus 5 3b9587563a M6(4/n): 工作台五要素齐活 —— 审批 / 消息 / 纪要 / 汇报
四个 desk-* feature 自 workbench 原型 ModuleWorkspace.tsx 平移(jc-* 类名原样),
共用件落 shared/desk/module-kit;mock 数据换成服务端投影:
  · desk-approval:审批点卡到审批人工位;依据快照、驳回走向(声明式)、驳回必附意见
  · desk-message:通知 + 跨任务征答**就地作答**;卡面表单由 card.ts schema 驱动,
    与后端回传校验同 schema;跨人卡不占任务清单,不开放任务对话流
  · desk-minute:纪要维护 + 决议登记起单;正文可续、决议只增
  · desk-report:四周期草案 + 度量八指标 + 确认即提交
左轨角标常驻(待批 / 未读),责任面要一眼看见什么在等我。

修一个真 bug:process.start 从不校验流程包的 callInterface,
先插工作流再由 task.start 撞活动契约 —— 失败就留下一条永远推不动的在途单。
改为**先校验后建单**(CallInterfaceViolationError),一条工作流都不留;
路由回 400 并带上缺哪个字段。已清掉这次触发出的两条孤儿单。

判据 ⑩ 纪要一环跑通:决议 → 登记触发 → 工作流 → A1 落到 BD 冯兵,
登记人即来源已记在单上;同一决议重复登记被 412 挡下。

gates: tsc / eslint / depcruise(316 模块)/ api-report / 380 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 03:53:36 +08:00
ChaiHaoandClaude Opus 5 a60acb2e02 M6(3/n): minute 与 report —— L8 两个模块补齐
minute(纪要):工作台五要素里唯一的主动动作。
  纪要本身不产生责任,唯一通往责任的路是决议经登记触发起单 —— 登记人即来源。
  正文可续、决议只增;同一决议不重复起单(起单一刻已有一条带来源的流在跑)。

report(汇报):日/周/月/年对任务日志的聚合投影,零手工汇报。
  未提交的草案每次取回都重算 —— 汇报是投影不是账本,提交那刻才固定为事实快照。
  度量八指标落在这里(§4 注:度量是只读投影,不设独立模块):
  自主率 / 纠正率 / 有效自主率 / 打扰率 / 断点率 / DMN 覆盖率 / 单位成本 / 终态分布。
  口径全部挂归侧标签与事件流,零埋点;单位成本的分母只认放行通过。
  周窗口以周一为首日,按 UTC 切分(单组织单时区)。

FactSource 只读 memory 与 task,一行都不另记 —— 五要素同源。

gates: tsc / eslint / depcruise(305 模块)/ api-report / 377 测试 全绿
日报已在真实系统上由 A1 任务日志聚合出来,含治理干预两行

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 03:39:10 +08:00
ChaiHaoandClaude Opus 5 a9cd6d10c7 M6(2/n): 治理台九功能 + SSE 订阅层 + 读/治分权
治理台按 §9.1 拆成九个 gov-* feature,共用件落 shared/gov:
  · 外壳(左轨/顶栏/面包屑/页签/整页下钻)自原型 Governance.tsx 平移,
    DOM 与 g-* 类名原样;路由状态即应用状态,区/页签/下钻栈全编码进 hash 可深链
  · 编排画布 diagram-js 画布件 1:1 平移(flow-layout/flow-node-paint/FlowDiagram),
    新增 pkg-to-graph 把 ProcessPackage 转成画布图模型;统一报价 v1 全图 12 节点 15 边渲染通过
  · 后端补四路由:审批单 / 工作流下钻 / 通道实例 / 度量仪表

SSE 订阅层(§9.2):app 层单一连接,按信封目标失效缓存;
组件不再自行轮询(去掉 refetchInterval)。广播只说「哪个目标动了」,不带业务载荷,
且在投递已落库已送达之后才发 —— 不是第二条投递链路。

两处实质修正:
  · 治理路由一律要 govern → 读路由改要 read。客体三类 × 动作三种的分法就是为此:
    BD 有 task:read 能看在途、动不了控制事件;一律 govern 等于把三种动作压成一种
  · 控制事件/恢复/改派原记为 engine-transition(归机器产出)→ 新增 control 条目种类,
    归人裁决侧。归侧是按动作类型的纯推导,所以「谁干的」必须体现在 kind 上;
    否则人的叫停会被算进自主率的机器分子

判据 ⑩ 治理台一半跑通:在途监控 / 叫停 / 恢复,治理动作留痕可查。
无权查看不再画成空清单,按岗位说明缺哪一项。

gates: tsc / eslint / depcruise(286 模块)/ api-report / 360 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 03:28:40 +08:00
JCAI Main AgentandClaude Opus 5 3cfaa04098 M6(1/n): 工作台任务要素 —— 原型 1:1 平移的第一屏
样式整文件搬(README 平移规则 1):app.css 2767 行 + proto.vendor.css +
theme.css + console.css 原样搬,设计令牌与全部 jc-* / g-* 类名不动。

前端(按 §9 重排,渲染输出 1:1):
- shared/:Ico / ScrollArea / useChatWidth 自原型搬,去掉 "use client" 等 Next 专有件;
  失效的 react-hooks disable 指令按 §17 清掉(不改渲染)
- shared/typed-fetch.ts:服务端交互唯一通道,路由契约来自 @contracts/api;
  不引 Hono RPC 客户端(那要求前端 import 后端类型,违反 §5.1)
- app/query.ts:TanStack Query;缓存失效由订阅层驱动,组件不轮询
- features/desk-task:任务列表(一条 = 一个活动的一次运行,不是一整条工作流)/
  标题区 + 工作区四页签 / 对话区(气泡二元制 + 卡族 + **composer 锁**)
- @ui:ViewContainer 用**沙箱 iframe(sandbox 不含 allow-scripts)** —— 结构上无脚本执行权,
  不依赖净化算法的完备性;ViewBlocks 渲染十一种视图块
  feature 不得自行 dangerouslySetInnerHTML,eslint 有规则守着

后端:工作台路由 /api/desk/*(任务清单 / 任务详情 / 工单回传 / 自由输入 / 消息);
回传与后端校验**同 schema**;任务详情是服务端投影 —— 前端零过程状态,刷新即重建

已验证(真机):任务卡「A1 RFQ需求分析 · 序位 1/7 · awaiting-event」、
预算 2/40 步、1 张工单(LLM 步失败后转人兜底那张)、7 行带归侧标签的任务日志

358 个测试通过,门禁五道全绿;web 构建通过

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 02:45:42 +08:00
JCAI Main AgentandClaude Opus 5 2f01eda3fb M5 收官:六个活动包 + 统一报价全图 + 任务推进器
活动包(按 MVP示例工作流 归一化):
- quote-intake  A1 受理归一(flow):LLM 抽取 → 条件跳步补全 → 查历史价 → DMN 打标 → 验收
- quote-pricing A4 成本定价(flow):DMN 利润模型 P-01 + 底价门禁 P-02;超限条目调人决策
- quote-negotiate A6 报价议价(flow):写类动作登记意向、放行即落地;建 D+3 跟进监听;
  议价结果建模为选择组三口(成交/有异议/拒绝)—— 业务分支走输出口,不用异常终态编码
- quote-archive A7 情报归档(flow):写共享域(历史价格情报/客户资料库/落地率统计)
- quote-sourcing A3 渠道寻源(loop):CMMN 四阶段 + 里程碑 + 裁量项 + 两个时间监听;
  DMN 采用策略判定;案例说明书与 XML 同版本
- quote-alternative A2 替代选型(loop):CMMN 三阶段 + userEventListener(客户改需求);
  DMN 替代等级判定;禁区「差异没核清的不放行」有机检形态

流程包全图:7 节点 + 3 网关 + 1 审批点
- 已裁定①:A5 = 审批点,G3 并入驳回走向(驳回 → 回 A4 重开新实例)
- 已裁定②:G2 = 并行网关,A3/A2 失败走向 = 容忍
- 已裁定④:议价回环 = 流程层回边(reopen)

闭合校验在此拦下一个真实建模错误(A4 有两条并发入边映射同名字段),
按规范改拓扑:TYPE-A 直通也走汇合;同时把「回边不是并发汇合」写进判定 ——
reopen 边不参与隐式合并检查。

app:task-advancer worker —— 过程在后端,运行中的任务一拍一拍推,不依赖浏览器在线;
进入等待或终结即停手,不空转。第一方工具补齐 P-01/P-02/画像/落地率/出站发送。

已验证(真机):
- 六个活动包经安装通道装入,静态审各 0 条提示
- 流程包闭合校验通过并发布
- 台账自生长:11 张表由活动声明物化(含 shared 三张共享域表)
- 邮件入站 → 触发器 → 工作流 → A1 落到冯兵工位 → 推进器推 2 拍:
  装载 5 步声明 → 执行 LLM 步 → 按声明重试 2 次 → 转人兜底 → awaiting-event
  (LLM 端点是占位 key,失败路径因此走通了 —— 正是声明给定的兜底)

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 02:37:04 +08:00
JCAI Main AgentandClaude Opus 5 78dc03bb58 app 装配收尾:18 个模块接上,MVP 判据 1-2 端到端跑通
装配(app 是唯一组装层):
- wiring/engines.ts:skill/flow/loop/task/process/trigger 六个模块经端口接起来;
  两个范式引擎按统一 ParadigmEngine 契约暴露给 task —— 对上层不可区分
- agent-runner.ts:loop 的 Agent 回路经 ModelGateway(两缝之一,回放审看得见);
  出参过 schema 框住三型行动,不合规退化为「等人」而不是乱动世界
- container:interaction / human-tool / activity-registry / release 全部接上;
  event 的 TriggerMatcher 与 org 的 InFlightWorkProbe 以延迟绑定解环,端口不变
- workers/consumers.ts:派发器的两个消费者(任务监听推进旧单 / 触发器开新单,独立判定)
- tools/first-party.ts:查历史价(录制回放替身)+ 三分类打标(纯工具,DMN 确定性求值)
- seed-quote.ts:治理台四件事一次做完 —— 绑 LLM / 注册工具两审 / 经安装通道装活动包 /
  发布流程包(闭合校验通过)+ 配触发器与邮件通道

已验证(真机):
1. 治理台配置全过;活动包静态审 0 条提示、流程包闭合校验通过
2. 一封 RFQ 邮件入站 → 归属解析 → 触发器命中 1 → 起一条工作流 →
   A1 任务按岗位唯一人解析落到 BD 冯兵,runtime=running

修复:zod 判别式重复值(周期触发两型展开为 periodic-calendar / periodic-data,
triggerKindOf 对回三类分类学);活动构建脚本移出 activities(它要用 fs,
而活动包零环境能力 —— depcruise 拦下后按边界搬家)

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 02:24:36 +08:00
JCAI Main AgentandClaude Opus 5 4ad901c452 M5(3/3): trigger —— 三类触发器与起单幂等
- matchesEvent:事件触发的命中判定(S-FEEL 规则;规则写坏按不命中处置,不让事件流停摆)
- assembleInput:字段映射装配;缺必填即起单失败入死信,不静默丢弃
- 幂等:同一事件对同一触发器至多起一单;数据日历型同一行同一日期只触发一次
- 周期两型:日历表达式到点扫描 + 数据日历型(日期字段 + 偏移 + 过滤)逐行起单
- 登记触发:人工起单的统一形态,登记人即来源
- 触发器与流程包平级:配置独立存放,增删启停不改流程包版本

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 02:03:58 +08:00
JCAI Main AgentandClaude Opus 5 a8f6eef610 M5(2/3): process 用例与流转 —— 流程引擎的确定性调度
- routing domain:选边(XOR 恰取一条 + 默认分支兜底;AND 全走)、边映射装配(四类来源 +
  S-FEEL 转换)、AND 汇合回齐(容忍分支不阻汇合)、审批点驳回走向声明式
- process-service:起单 → 调度节点 → 负责人四策略解析(结果与依据留痕)→
  活动起单 / 审批点卡工位 / 终点收束按来源回执;任务终态到达继续流转或走失败走向四选一;
  审批驳回按声明回指定节点重开新实例;状态每次变动后重算聚合投影
- adapter:流程包(id × version)、工作流实例、节点实例三表持久 —— 崩溃后可续跑

ADR 待补项登记为 debt M5-1:§6.1 的 Mastra workflow 编译器作为可替换 adapter 后补,
当前由自持确定性状态机承担,语义等价、usecase 不动

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 02:01:08 +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
JCAI Main AgentandClaude Opus 5 3c974d2860 M4: 范式引擎与任务运行时
skill-engine(L4):载方法不载权力(白名单外工具即拒)、结晶片段经 ToolInvoker 留痕、
  装配入信封、技能目录渐进披露

flow-engine(L5):四种步型、确定性谓词跳步、重试与声明给定的兜底、
  异步步即监听(时限必配)、写类工具登记动作意向、步序位置持久

loop-engine(L5):自研 CMMN 子集解析器(表外构件直接报错,子集封顶可机器证明)、
  两副标准生命周期与迁移拓扑(引擎不得私改)、Enabled ≠ Active、
  语义性前提标待裁量评估(引擎不代裁量)、DMN 确定性求值 + 命中行留痕、
  DRD 缺口演绎与拓扑序、双向驱动与交集导航(断点即人环)、三型行动、
  终局唯放行与 Harness

task(L6):终态五名裁定(released 唯一成功)、Harness 预算环外强制与停滞熔断
  (监听中是健康态)、控制三语义(叫停不是终态,记最重档纠正)、改派留痕通知双方、
  断点续跑三份持久状态、封卷触发蒸馏钩子

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 01:51:22 +08:00
JCAI Main AgentandClaude Opus 5 2850e6d4ef M3(完成): interaction 与 activity-registry
interaction(L3):
- 控制权按态转交:活动在跑归活动,流转/审批/终态归系统;输入侧永远归系统(单入口)
- 视图区净化门:含 <script> / on* / 外部资源的模版一律拒推 —— 容器无脚本执行权
- 对话流单入口:自由输入同写任务记忆并抛人事件;SSE 单连接 + 按目标失效广播
- 前端零过程状态:对话流与视图都是服务端投影

activity-registry(L4):
- 安装两审:静态审(签名/SDK/工具契约齐备/模型名已绑定/schema/悬空监听/模版无脚本/
  零环境能力/动态执行/验收等级不得谎报)+ 回放审(旧成不坏是硬门,旧败能成只入报告)
- 资产与包分离版本化:包只携资产初始版,不覆盖已有更高资产版;装载 = 包版本 + 生效资产版
- 进化管线状态机:候选 → 回放 → 人放行 → 生效;回退是显式治理动作

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 01:36:05 +08:00
JCAI Main AgentandClaude Opus 5 561a2474ae M3(2/5): human-tool 与 release —— 卡协议与放行门
human-tool(L3):
- 三规矩机检:调用必附上下文(裸调用拒发)/ 回传即留痕 / 完成只出自放行通过
- 工单两模式 + 对话卡族的形态校验与回传校验;驳回必附意见;补全卡「没法填」旁路;
  决策卡自定义收尾项必附理由;已答不得再答(只增不改)
- 到达面两路(负责人 → 任务对话流;他人 → 系统消息);驳回重答 = 新卡实例、原卡闭合
- 调人预算由基座在环外强制;落地失败卡 = 执行工单的 preset

release(L4):
- 落地预检五项(入参 schema / 工具可用与授权 / 连接可达 / 目标预校验 / 数据冲突)
- 预检全过才发验收工单,卡面即已验证的动作清单;不过即打回环内,不发卡
- 放行写合并 + 幂等落地(任务 × 意向);落地收敛才发射输出口;
  受阻走落地失败卡且 emittedPorts 恒空;已成动作留存不回滚

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 01:28:49 +08:00
JCAI Main AgentandClaude Opus 5 146e9bbfad M3(1/5): @sfeel —— S-FEEL 子集的解析与求值,前后端同源
- lexer / parser(递归下降)/ evaluate / static-check,四文件纯函数,零 IO 零外部调用
- 子集封顶(ADR-006):比较 · 逻辑 · 算术 · 区间(开闭四态)· 列表与 in ·
  封闭内建函数集(字符串 / 数字 / 日期);未知函数一律拦下
- 单元格谓词(DMN 一格):`-` 任意 / 比较 / 区间 / 逗号析取
- staticCheck 给「画图即校验」用:语法 + 未知函数 + 引用路径清单
- app 侧以它替下 passthroughEvaluator:监听内容条件真求值,求值异常按不命中处置并留痕

32 个 sfeel 测试;全仓 182 个测试通过,门禁五道全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 01:21:45 +08:00
JCAI Main AgentandClaude Opus 5 f0444f1417 M2: 基座能力 —— memory / toolbox / channel / message
- memory   任务记忆四性质(只追加·信封盖戳·治理先行·归侧)、活动记忆四层与条目三件套、
           任务日志两级投影(结构化零 LLM / 叙述性小结不入事实库)、度量八指标只读投影
- toolbox  注册两审(静态审 + 试运行审)、效应等级决定运行时待遇、契约演进只增不破坏、
           白名单与纯工具私有作用域、ToolInvoker(两缝之二,live/record/replay)
- channel  通道实例配置、入站归一(解析 → 系统写 → 数据事件)、出站发送与关联记录登记
- message  通知 / 跨任务征答(就地作答 · 驳回重答只增不改)/ 死信 / 无主兜底

app:message 接上 event 的 MessageFallback;派发器按目标 ID 取 advisory lock 串行消费 +
消费幂等表;/api/ingest 模拟邮件通道(mock 只在外界)

已验证:无主 RFQ 邮件入站 → 归属解析 no-match → 事件落库 → 兜底落 OP 岗位的消息要素
门禁五道全绿;150 个单元测试 + 1 个 PG 集成测试

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 01:16:52 +08:00
JCAI Main AgentandClaude Opus 5 14d4fa046a M1: 底座 —— @contracts 首版 + event / ledger / org / llm
@contracts 首版(§8.1 九个文件):
- id 品牌 ID / terminal 终态五名与归侧四标签 / envelope 信封六字段与四类事件
- card 工单两模式 + 对话卡族(形状对齐 2026-07-26 原型定稿)
- contract7 契约七件 / ledger 三级寻址与写三分 / process-package 流程包 DSL 与触发器三类
- manifest 活动包清单六区(含 CMMN·DMN·步序声明的资产形状)/ org / api 路由契约

模块(L1):
- event   信封存储、归属解析三级短路、投递五诺、监听注册表、三级消费裁定
- ledger  schema 自生长(最大化合并/最宽类型/只增不破坏)、任务视图叠加、写三分、冲突检查
- org     岗位授权(客体三类×动作三种)、停用前置检查、会话、种子播种
- llm     四元绑定、ModelGateway 三模式(live/record/replay)—— 两缝之一

app 装配:Hono 服务 + 鉴权中间件 + 治理台/工作台路由;drizzle 迁移;AES-256-GCM 凭证密封

ADR-007 工具链与门禁 · ADR-008 投递队列 · ADR-009 凭证加密
(ADR 编号自 007 续:编码规范 §14 已用到 006,README 写「从 005 续」是笔误)

门禁五道全绿;96 个测试通过,含对真实 PG 的 ledger 集成测试

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-27 00:59:14 +08:00
JCAI Main AgentandClaude Opus 5 7cd664af3a M0: 工作区骨架 + 五道门禁 + 环境自举
- pnpm workspaces / tsconfig 双工程(node · web)/ 路径别名(§11.1)
- eslint flat(§11.3 + §12.5 可机检项)/ dependency-cruiser 基线八条 + JCAI 增补(§11.4)
- tools/module-tiers.json + gen-depcruise-tiers.ts 生成 tier-order 逐层规则
- tools/api-report.mjs 契约快照只留契约面(ADR-005)
- docker-compose(PG16)+ db/init 四 schema;种子数据五岗位五员工冻结为常量
- docs/debt.md · docs/adr/ADR-005

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