Commit Graph
197 Commits
Author SHA1 Message Date
xcs 43917b559a org adapter:改正 explainJoseError 注释里的继承关系描述(评审 Important)
「JWTExpired 是 JWTClaimValidationFailed 的子类」是错的 —— jose 5.10.0 里两者都
直接继承 JOSEError,implements 只是 TS 结构化类型声明,运行时不建立继承。
判在前的真实理由是让「已过期」这条更具体的话先命中,不是靠父子关系兜底 ——
错误的继承说法会给日后「简化掉」判断顺序的人一个不存在的依据。仅改注释,
两条 instanceof 分支的顺序与内容一字未动,10/10 测试原样通过。
2026-08-25 16:28:18 +08:00
xcs cb143d6413 org adapter:jose 验签 —— RS256 写死、校 iss/aud、30s 容差、错误译人话(ADR-012;新依赖 jose,用户已批)
四项校验顺序即安全要点:algorithms 写死 RS256(绝不读 token header 的 alg,否则
alg:none 可绕过)、issuer、audience、clockTolerance 30 秒;jose 的错误经
explainJoseError 翻成人话后包成 TokenRejectedError,排错省时间。测试用
createLocalJWKSet 造本地 JWKS 当 Keycloak 替身,不联网,验签逻辑本身走同一个
jwtVerify。zod 的 .optional() 与本仓 exactOptionalPropertyTypes 有摩擦,
按 claims.ts::identityOf 已有的手法(undefined 就不带键)加了 toVerifiedClaims
做收窄,详见 task-3-report.md。
2026-08-25 16:21:17 +08:00
xcs 5108d7a580 org domain:claims 归一、角色→端与锁死不变量、名册差异、测试账号策略(ADR-012,纯函数)
为统一鉴权中心(Keycloak)落地铺地基:五个零 IO 的纯函数文件,后续 org 用例
重写(Task 8)直接复用。本任务只加不删 —— 旧的岗位授权 / 口令会话 / 停用检查
原样保留,现役 org-service 仍在用它们。

- claims.ts:token claims → Identity,滤掉三种 Keycloak 家具角色
- ends.ts:角色 → 端的并集,并守住「改完之后至少一人能进运营中心」这条锁死不变量
- roster-diff.ts:与 Keycloak 名册的插/改/停/复活差异(远端说了算)
- test-account.ts:测试账号判定与独立工作组构造(ADR-011 语义原样搬)
- in-flight.ts:停用前置检查要看的在途工作(与旧 disable-check.ts 并存一轮)

contract.ts / port.ts / index.ts / seed-data.ts 均为文件末尾追加,契约变更已
经 pnpm api:check --update 刷新快照。
2026-08-25 16:09:10 +08:00
xcsandClaude Opus 5 a5c8d4786d 契约:三个端与路由归属(access 必填)、Principal / 角色→端 / 名册同步 schema、退役路由标 @deprecated(ADR-012)
- packages/contracts/src/api/http.ts:新增 SURFACES / surfaceSchema / Surface / SURFACE_LABEL /
  RouteAccess;RouteContract.access 必填;API_ERROR_CODES 增 'gone'。
- packages/contracts/src/org.ts:staffSchema 补 email? / roles(realm 角色快照);新增
  principalSchema/Principal、roleAccessSchema/RoleAccess、rosterSyncOutcomeSchema/RosterSyncOutcome、
  inFlightWorkSchema/InFlightWork;旧岗位授权(grant* / governanceFunction*)与 sessionSchema/Session
  全部标 @deprecated 留一轮(web 编译不受影响,下个迭代删)。
- workbench.ts / governance.ts / ingest.ts:每条既有路由补 access(按所属端/两端共用/退役 public);
  新增 meRoute、authTicketRoute(access:'any')与 syncStaffRoute、setStaffPositionRoute、
  staffInFlightRoute、listRoleAccessRoute、setRoleAccessRoute、deleteRoleAccessRoute(access:'ops')。
- apps/api 的 org-service.ts 两处 staff.insert 补 roles: [](staffSchema 新必填字段,该文件下个
  迭代会整份替换,这里只是让本次 typecheck 过)。
- 新增 packages/contracts/src/__tests__/route-access.test.ts:95 条路由的 access 归属断言。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015kAzS35kMnZNt4YGgJXtfw
2026-08-25 15:54:20 +08:00
xcs d788140548 工作成果里摆着别单的资料:「这一单产出的」认本单碰过的行
放行存档(archiveAssetFiles)与在办列单(assetFilesOf)取行都用 taskView(where:{}) ——
那是「正式版全表 + 本单草稿」的合并视图,而资料常落在主数据上,整表里躺着别单放行过的行。
抽 assetRowsOf 两处同用,touched 为必填入参;e2e 补份数断言。
顺手清两笔:wake.test.ts 的 as unknown as(lint 红)、wake 契约的 api-report 快照(api:check 红)。
2026-08-25 15:38:10 +08:00
xcsandClaude Fable 5 f3397a60ef E04 修到零被拒线,harness 补七刀:跨进程租约与广播桥、原子写、引用墙、对话区按序号排
活动侧(E04 2.1.0 → 2.1.9,I01 1.2.2):
- 覆盖闭合成为机检:基座新增 distinct 读数,「计划盖住的客户数 = 候选行数」钉进
  S3 收步 / S4 哨兵 / 放行 L2;人加的候选客户不再被整单无视
- 「关键人待识别」占位句式全链退役:查无联系人先发数据录入卡收人;契约新增 refersTo,
  计划/回执的 contact_code 只许引用真实存在的联系人(安装期核引用目标)
- 台账更新确认摆全落库面:客户档案/联系人档案两张落库预览(touched: 数据源,
  正式现值 + 草稿叠加),可补改、可加行(自增主键由基座续号);姓名升必填
- 更新明细:update_key 位置键 + 「同一处只留一条」L2;依据写人话不带机器键;
  标题旁不摆单号;判据与文案不夹字段名;行标识去掉单标识那一段
- 回执骨架 = 计划行数钉进 S3 收步与 S4 哨兵;重做分支不许删计划凑数
- 阶段刻度对齐文档 7 步;起单样例预填满

基座侧:
- 两个后端连同一个库:task-claim 跨进程租约(迁移 0030)+ Postgres LISTEN/NOTIFY
  广播桥;对话区按任务内记忆序号排,不按墙上时钟;并卡「刚说过话」按记忆序列判紧邻
- 多行 write 整批先验后写(dryRun),被拒 = 一行都没落
- 决策卡意见与本单草稿字面比对,归属以观察进轨迹(note-anchors)
- 括号栈补「补闭括号」两形(少一个 } / 行对象没关直接跟下一行)
- 件上加行:空着的自增主键直进续号,不从别的行借号;未落下的行点名回给前端
- 人答复落库那一刻就把 runtime 翻 running(task.wake),两块同帧变脸
- 试跑单可落真库(land_master,迁移 0031,默认开);数据域按活动分组;
  JSON 列不再是 [object Object];按钮键感 + 在办进度条 + 防抖
- 报价链 A1–A7 从系统卸载(只卸不删源码),种子只装 E04/I01

契约变更(api-report 已刷新):FieldDeclaration.distinct / refersTo,
objectDeclaration.file,landMaster,unkeyed,assetFiles,ledgerByActivityRoute。
1700 测 / typecheck / lint / depcruise / api:check 绿。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EEJX8Z7CHejvwmDQyPQuBX
2026-08-25 01:23:30 +08:00
xcsandClaude Opus 5 0aa2fc11b0 资料文件真产出来了;E04/I01 补到验收线,顺手填了几个「墙拦住却不给路」的坑
**资料文件全链**(用户:审核资料这一步要真产出 word/excel/md/html,前端能渲、点资料名能开)
接手时这一步一个文件都产不出来 —— S3 剧本白纸黑字写着「file_ref 本 MVP 阶段可留空」。
文件是台账那一行的投影,不另存一份:
· 声明 `file:{titleColumn,bodyColumn,formatColumn}`,它同时是授权面(没声明就点不开)
· 现造真字节 —— docx/xlsx 是自己打的 OOXML 包(zip-write:store+CRC32,零依赖)
· 读回来渲 —— 解的就是造出来那份字节,渲得出来才证明文件是真的
· 件上 `data-file-of` → 工作区二级界面(Word 纸面/Excel 网格/渲好的 md/沙箱 html)+ 下载原件
放行落地前把每一份冻进 `sys.task_asset_file`(迁移 0029):归档件点开的必须是签字那一刻
那一份,而资料落在主数据上、试跑单不落正式表 —— 不存这一份,收工后一个都点不开。
工作成果里「产出的资料」自成一摞。Markdown 富文本渲染顺带销账(仍零依赖)。

**Harness**
· 画面按「这一拍办完之后」在办的那一步挑 —— 从前拿拍首的局面决定拍尾的事:
  收掉 S4、发出 S5 的卡,而屏上还摆着 S4 的只读件,人无处可填(墙要配路第四次现形)
· 验收「重做」真能退回重做,且打回后台账没动就不许再提交(软硬两段,不锁死单子)
· 立监听的授权面是清单声明;发卡的授权面是调人预算,不是计划项
· 读工具同参重调有兜底;空转写身后还有行动就不废串;finish 的 doneWhen 按写完后的草稿算

**界面**
· 翻件与翻页各归各位(从前二选一,多卡多页时页翻不动);没得翻写「—」不写 0/0
· 工作成果详情能翻份;表宽超出能横滑(E04/I01 抄版式时把 overflow-x 抄丢了)
· 查看面灰底滚过一屏变白 —— 两条独立的路都治了(沙箱内不同色 / 弹性子项不长个)
· 测试台「取不到」不再当成「还活着」

**活动**
E04 关系覆盖、I01 品牌内容各自补到验收线:判据全读基座数、判据指向的东西摆上卡面、
样例满载且名字 ≤14 字;提交前要裁的判据搬进说明书(模型会压拍,压过之后只有说明书还在)。

验收:e2e i01 4/4、e04 3/3 全部 released,资料在办中渲得出、放行后存了档点得开;
门禁 typecheck/lint/depcruise/1628 测全绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EEJX8Z7CHejvwmDQyPQuBX
2026-08-24 10:26:45 +08:00
ChaiHaoandClaude Opus 5 70e83d0b09 工作日志:一行摆首句,展开就把话说完
从前一条只有一行标题,而人真想回看的东西全躺在留痕里没露过面 ——
凭什么算这一步办完了、那一笔落下哪几行、被拒到底拒在哪儿、发的是哪种卡送到哪儿。
现在每条可展开,细节由 detailOf 摘成**一句句人话**(不摆 execution 这类内部名);
摘不出就是空数组,前端据此不给展开钮 —— 点开是空抽屉比不给还糟。

不摆二级条目(用户定):细节不是「键:值」两栏 —— 那是把留痕的字段名搬到人面前,
人还得自己在脑子里连成句子。每句自带主语与语境,单拎出来也读得通。

连带修一处文档与实现不符:「一轮一句」的口径说埋头办事那几拍的交代「留进工作日志」,
而实现把 internal 整类滤掉了,那几句哪儿都看不到。现在带交代的放行,
章写「交代进展」、记在 AI 名下;排障用的内部痕照旧不摆。
两种交代统一「首句上行、全文进抽屉」,一句话说完的不重复摆;截了才加省略号。

契约:任务详情的日志行新增可选 detail(字符串数组),api-report 同批更新。
门禁:typecheck / lint / depcruise / test(1378)全绿;浏览器实测折叠行高 34-36px 齐平、
展开无键值两栏残留。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 13:10:46 +08:00
ChaiHaoandClaude Opus 5 ade0fa5a94 A2-A7 全部补齐到验收线;顺手把几处「门拦住却不给路」的坑填了
活动:A2 选型 / A3 寻源 / A4 定价 / A6 议价 / A7 归档五件各补成真活动包 ——
契约宽进(input.required 空,归一在活动内)、台账必填声明(含行级 requiredWhen)、
入场哨兵与 L1/L2 判据一律读基座数、两份件(在办可编辑 + 办结静态快照)、
三案例常备、包内自测。e2e 各三案例 released、行动被拒 0、发口正确、提交闸每单真拦。

基座(共享面,改一处影响所有活动,故每处都带回归):
· 重发判断走在站上场之前 —— 人答完那步常已收掉,readyToWork 先抛「不能再往它上面挂活」,
  于是「重发已答过的卡 = 无事发生」这条唯一活路在最需要时够不着,A1 基线当场熔断;
· 决策卡补幂等兜底(与执行工单同一把尺):头两次无事发生,第三次起才算被拒;
· 输出没成形先就地重问一次,原话进工作日志、不再摆上卡面;
· 工具调用读数 tool_<名>_calls —— 「机检只读基座数」这条纪律第一次覆盖到工具;
· 执行卡 steps/standard 补进出参 schema(从前能到卡面全靠厂商 JSON 模式宽松);
· 件的就地更新改逐节点 morph,保存先把新值镜像进只读那份 —— 不闪、不等回声。

A1(基线,全程守住):措辞三档对齐(必填/建议/选填)、禁止拿历史价当客户目标价、
卡骨架从步骤剧本搬进说明书(压成一拍连做时剧本没摊开,会发出没有指导书的裸卡)。

契约两处**新增可选字段**(非破坏):FieldDeclaration.requiredWhen、工单 finalHtml;
api-report 同批更新。docs/adr 与 docs/archive 的 13 份文件在工作树里不见了,
本次予以恢复而非提交删除。

门禁:typecheck / lint / depcruise / test(1366)全绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 12:28:31 +08:00
ChaiHaoandClaude Opus 5 a9e66ceb39 话说的范围要盖住门拦的范围;报告上把缺哪几格红字直说
三件,都是「说的和做的不是同一件事」这一类的又一次现形。

**为什么模型会漏掉 start** —— 提示词那条规矩写窄了。
原文:「标了「须你启动」的项要先 start **再调工具**」——只说了调工具;
而拦截那一侧(`readyToWork`)管的是 tool / ask / human / decide / entry / finish 一整片。
模型那一拍要发的是 `human`(派工单),照字面读这条规矩管不着它,于是漏了 start,
撞上「S3_confirm 标了人工激活,要先 start 再干活」白烧一拍。
**话窄一格,模型就正好漏在那一格上。** 现在写全:动它之前先 start,发卡与 finish 都算;
只有 write 例外(它的 itemId 只是记账,挂不上照写)。

**目标价左对齐** —— 右对齐是给要竖着相加的那种数用的;这张表一行一个料、彼此不相加,
右对齐只让它跟自己的表头分了家:标题贴左、数贴右,中间空一条,眼睛来回找。
等宽字体留着(位数对齐仍有用),对齐跟表头走。

**报告上把缺哪几格红字直说** —— 从前只在空格子里摆一枚小小的「必填」胶囊,
九行料摊开就淹在表里;而人打开这一屏就是来填的。现在表上方一条红带,
点名还差几格、差在哪一行的哪一列。两个数由基座现算(`_missing` / `_missing_keys`),
与提交闸、放行门 L1 同一个数;**模版不算也不判** —— 「一格不缺就别出这条带」
交给样式表(`data-class-of` → `v-0` 那档 display:none)。
浏览器验过两态:缺 1 格时 v-1 显示,从件上补齐后重渲变 v-0 自动收起。

五道门禁全绿(975 passed)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JsTDjoHovERXyy6Wmw1ALp
2026-08-02 15:04:33 +08:00
ChaiHaoandClaude Opus 5 3cf9f10b86 进度条补回漏掉的那一格;删掉一条已经不存在的路
用户送来一条实测日志:中间被拒四次,卡片进度条也走得不对。两处都不是模型跑偏。

**进度条漏了一格** —— `INTAKE_PHASES` 里没有 `S3_confirm`(它是 08-01 才补回成一项的):
计划项六个、名单里五个。于是 S2 一收,前两格全过,条当场跳到「判定去向」;
而人这会儿正对着受理需求审定那张卡 —— **他手上办的那件事在条上没有格子**,
条却已经走过去了。那不是走快了一格,是它在说一件没发生的事。
补成四格(定位客户 / 归一受理 / 交你审定 / 判定去向)+ 基座统一加的放行收口;
包内自测钉死「除放行外每一项恰好属于一个阶段」「一项不进两个阶段」。

**那四次拒回是一条已经不存在的路** —— 说明书里还留着「人交回来还缺必填,就再发一张卡」。
提交闸上线后那条路没有了:缺必填根本按不下提交。模型照它办,每次都撞在
「这件事刚问过,人也答过了」上,白烧四拍。改成「这张卡一单只发一次」。
同批把提交闸补到**服务端**(收下回传之前把住):说明书向模型承诺
「卡回来时必填一定是齐的」,那句承诺只有服务端拦得住才算数。

A1 三案例复跑:9 拍 / 10 拍 / 14 拍,前两个**被拒 0**(修前是 12 拍被拒 1),
进度条五格逐格走对。五道门禁全绿(975 passed)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JsTDjoHovERXyy6Wmw1ALp
2026-08-02 14:13:24 +08:00
ChaiHaoandClaude Opus 5 259192f736 人手改的那一手真正落得下去;界面不撒谎那几处补齐
手改是**兜 AI 的错**的那一手 —— 这一轮把它从「摆在那儿但落不了地」做成真的:

件上就地改
· 保存**按地址收**,不看当下那张卡:载荷从前借道工单的 `blocks[i]` 取列名,
  于是熔断卡(没有 blocks)在屏上时,人补的那一格一个字都送不出去 ——
  而他要补的恰恰是把这一单卡住的那个必填格。授权面改由活动清单的台账声明把关。
· **能增删行**:错不止「这一格填错了」,还有「这一行不该在」与「漏了一行」。
  删挂记号不当场抹掉(看得见、可后悔),且**删要说出来**(`drops`)——
  「没回传就是删了」会把一次不完整的回传变成一次删表。
· **必填没填按不下提交**:与放行门 L1 同一个数同一套算法;闸上摆出差在哪一行哪一格。
· 只写真改了的那几行 —— 改一格却留「修订 4 行」的痕,那句话是假的。

判据与门
· 裁量判据带谓词时**谓词说了算**:「选填缺口已补齐」基座数得出来,
  人填好的目标价它照样判「客户未提供」的毛病由此消掉。
· 验收卡判据**读时现算** —— 人在成果件上补一格,判据跟着变。
· 放行门认「**办完了没有**」不认「有人写过」:从前写个 `false` 就把门推开,
  于是一单没打标就进了放行门。三个数全由基座现数。
· 拒回把「活没干完」说成「数或行对不上」的毛病:判据点名的表一行都没写时直说那一步没办。
  **指向两扇打不开的门,比不指还糟。**

界面不撒谎
· 日志只有三色:负责人绿 · 智能体蓝 · 系统灰(归侧五种是度量的分法,不是给人看的)。
· 验收收口答两件事:落了什么(按**交付物**点名,一份成果的几张表并成一行)、
  往哪儿去(转出哪一口、带过去哪些字段);一个口都没发就直说到此为止。
· 签完到收尾之间那一段有自己的话「字已签下,正在落地」—— 中间态本来就该说出来,只是要说对。
· 消息不再被内部事件刷屏:只有从通道进来的件才谈得上「无人认领」。
· 建客户公司与联系人**一次确认落两行**;联系人编码自增不问人;卡面摆表的人读名。

A1 三案例端到端全 released:全 A 类直通 12 拍 / 客户点名跳一条 10 拍 / 新客户缺必填 14 拍。
五道门禁全绿(971 passed)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JsTDjoHovERXyy6Wmw1ALp
2026-08-02 13:41:44 +08:00
ChaiHaoandClaude Opus 5 61ee63e6dd 模型卡改矮:图标一列 + 文字一栏对齐,图标恒蓝
· **矮**:132 → 96px。状态不再是横穿整卡的填色带,收成一行小字 + 一枚钮;
    段距、字号、图标各降一档。
  · **对齐**:名字 / 厂商型号 / 状态**同一条竖线起头**,与图标并成一块 ——
    从前名字与型号缩进 48px、状态条却横到卡边,三条线各走各的。
  · **图标恒蓝**(与全站主色同一支 #3370ff,不再靛紫):它是**身份**不是状态 ——
    能不能用由状态行说;先前未绑定就把图标灰掉,结果两条全灰、整片死气。
    「去配置」改实心蓝:那是这张卡上唯一该点的东西。

交互复核:⋯ 菜单仍落在卡内(短卡下 top 跟着上移)、去配置开抽屉、Esc 关得掉。五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-30 02:09:14 +08:00
ChaiHaoandClaude Opus 5 da8ac8f9bc 模型实例卡重做:名字不截、密钥不撒谎、不可用就别摆统计;只留 flash 与 pro 两条
三条毛病一次改净:

**① 名字被截断**。用途名是活动里声明的那个名,看不全等于没显示 —— 卡面改成
   40px 图标 + **名字独占一行、折行也不截**(overflow-wrap: anywhere),
   厂商与型号退到第二行小字。

**② 「已绑定」是谎**。种子从前塞一个 `sk-placeholder` 冒充密钥,卡上写着「已绑定」,
   一自检就是 `api key ... is invalid`;抽屉里那格也照「是不是新建」写占位,
   于是没钥匙的实例也显示「已绑定 · 留空保持原值」。现在:
     · 种子**读不到环境密钥就不绑**,如实显示未绑定;
     · 抽屉的占位与判词改看 `keyBound` —— 没绑就写「还没有密钥 —— 不填这条实例调不动」。
   **界面撒谎比缺功能更坏**:缺功能人会去补,撒谎的人会照着假状态做决定。

**③ 不可用还摆一排统计**。没密钥连调都调不起来,「系统用途/端点」那些格没有意义 ——
   未绑定时卡上只剩一句判词 +「去配置」;绑好了才谈端点与「测试」。
   系统用途从卡面撤了(用户:不要管是不是系统用途,两条都能用)。

**只留两条实例**:`deepseek-v4-flash` 与 `deepseek-v4-pro`,都不预设系统用途。
配套两件:
  · `pickSystemUse` 加**回落** —— 没人勾就取第一条能用的(启用且已绑密钥);
    从前非勾不可,没勾那天系统叙述整条哑掉,那是配置疏忽不该变成功能缺失(补了三条测试);
  · 六个活动包里声明的用途名 `quote-extractor` 改指 `deepseek-v4-flash`,各升一个补丁版。

顺带补 `DELETE /api/gov/llm/:id`(卡上 ⋯ 菜单):还有活动声明着这个用途名就拒(409)——
删了那些活动一调模型就是「用途名未绑定」,而人当时以为只是清一条没用的记录。
实测:用它把库里遗留的 quote-extractor 删掉,现在库里就是那两条,卡上如实写「未绑定密钥 · 不可用」。
五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-30 01:53:42 +08:00
ChaiHaoandClaude Opus 5 fffb46eae7 修抽屉两处真故障:详情页里被压成 129px、portal 后令牌全失效变透明
用户报「点开连输入框都看不见」,我前两轮量的是货架那条路 —— 那条本来就是好的。
**走详情页进去才踩得到**,两处叠在一起:

① **抽屉被钉进详情卡里**。`.g-drawer` 是 `position: fixed`,而详情页容器 `.g-detail`
   带着入场动画的 `transform` —— **带 transform 的祖先会成为 fixed 的包含块**,
   于是 `inset: 0` 解析成那张卡的盒子:实测面板矩形 520×**129**,头尾一挤,
   中间的输入框整片没了。改走 `createPortal` 挂到 body,与 DOM 位置解绑。

② **portal 之后面板变透明**。整套令牌(--card / --cline / --ink …)定义在 `.gov-root` 上,
   挂到 body 就出了那个作用域:实测 `background-color: rgba(0, 0, 0, 0)` ——
   顶栏与页面内容从抽屉里透出来,字叠字。修法是把 `gov-root` 类跟着portal 一起挂,
   并给面板背景与边框留了字面兜底值。

顺带:z-index 60 → 120(压过顶栏,先前顶栏那一条压在抽屉标题上)。

实测两条路都验:详情页与货架各开一次,面板均为 (760, 0, 520, 577)、背景 rgb(255,255,255)、
四个输入框全在屏内;详情页测试连接照旧只测不存(判词是厂商原话),Esc 与遮罩关得掉。
五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-30 01:36:44 +08:00
ChaiHaoandClaude Opus 5 51567d3b3b 接入模型抽屉:输入框一屏装得下 —— 供应商收成一行小签,身份两栏并排
上一版量出来是真看不见:视口 577 高、抽屉身只有 442px,而「模型」落在 y=557、
「用途名」落在 y=649 —— **定义这条实例是什么的两个字段全在折线以下**,点开只看得见
供应商牌子和端点。病根是把最不决定性的东西摆得最大:5 枚 146px 宽的大牌子一个人吃掉 118px。

重排(按决定性从大到小,且一屏装得下):
  · 供应商 → **一行小签**(圆角 chip,默认端点挂 title),118px → 30px;
  · 身份 → **用途名 + 模型两栏并排**(短字段不该各占一整行);
  · 连接 → 端点 + 密钥 + 测试连接;
  · 开关收进末段,说明并进同一行。
  段距 16→13、头尾 padding 各收 3–4px,长句说明砍短。

实测同一视口:四个输入框底边 258 / 258 / 366 / 450,**全部落在可视区(≤520)**;
「测试连接」487 也在;编辑态整屏不用滚(scrollHeight ≤ clientHeight)。
保存往返、密钥留空保持原值、Esc 与遮罩关闭,全部复核过。五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-30 01:22:57 +08:00
ChaiHaoandClaude Opus 5 f9318b1ae9 接入模型改成右侧抽屉:先挑供应商、再填连接、当场测连通(且只测不存)
上一版是把字段倒在地上:整页宽的内联卡、输入框拉到 1100px、动作钮掉出屏幕。
照模型接入面的通行做法重排 —— 520px 右侧抽屉,头固定 / 身滚动 / 底动作栏常驻:

  ① **供应商**:一排可点的牌子,挑中即预填它的默认端点(没有默认的标「端点自填」);
  ② **连接**:API 端点 + API Key(密码框带显示切换),下面就是「测试连接」;
  ③ **型号与用途**:模型(厂商侧型号名)+ 用途名(活动里声明的那个)+ 两枚开关。
  遮罩点击与 Esc 都关得掉 —— 抽屉盖住整屏,不给键盘出路是把人关在里面。

**默认端点从服务端取**(新 `GET /api/gov/llm/providers`):前端不自带一份 URL 表 ——
那种表迟早与 provider 档案漂移,而漂移那天没人会发现(端点错了只表现为「连不上」)。

**「测试连接」只测不存**(新 `POST /api/gov/llm/probe` + `llm.probeDraft`):
拿表单上正填的四元真发一次最小调用,一个字节不落库;密钥留空则取该实例已存的密文,
改端点、换型号不必重打钥匙。上一版是「先存再试」—— 人只想知道钥匙对不对,
结果端点被改了、实例被建了,点取消也收不回来。实测:改错端点后测试,
库里 instances 逐字节未变(测过 before/after 全等)。

顺带补 `eye-off` 图标。五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-30 01:10:49 +08:00
ChaiHaoandClaude Opus 5 21aea48c6c 大模型区能配了:四元绑定就地改 + 连通自检,不再是只读橱窗
后端的 upsert 与 probe 一直在(`POST /api/gov/llm` · `/api/gov/llm/:id/probe`),
只是**界面从来没用过**:进去只看得见「密钥已绑定」,却没有一处能绑 —— 那不叫配置面。

现在:
  · **实例卡**能配:名 / Provider / Base URL / Model / API-Key / 启用 / 系统用途,
    列表卡上一枚笔就地开表单,详情页也有同一张表(同一个组件,不写两份);
  · **API-Key 只写不读**(OS 7.3 凭证隔离):服务端永不回显,所以留空 = 保持原值,
    不是清空 —— 实测改型号后 `apiKeyBound` 仍为 true,密钥没被空表单洗掉;
  · **Base URL 留空取该 Provider 的默认端点**;`openai-compatible` 没有默认,
    前端先拦一道(服务端也拦)—— 不填就是连不上,别等自检才知道;
  · **连通自检**:真发一次最小调用,通了报延迟,不通把**厂商原话**摆在卡里,
    不改写成一句「连不上」—— 「密钥无效」和「端点不通」是两件要分头修的事。
    实测种子里的 key 是占位串,自检当场说清:`Your api key: ****lder is invalid`。
  · 幽灵卡新建实例(LLM 没有删除路由,所以本轮只验证了改,没造多余实例)。

卡片沿用刚定稿的管理系统风(着色图标 + 状态胶囊 + 计量块);端点那格占两格宽,
主机名不截断。五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-30 00:43:49 +08:00
ChaiHaoandClaude Opus 5 9b286ae4ba 流程卡与活动卡按管理系统风重做:着色图标 · 状态胶囊 · 计量块
上一稿的两段式卡(头行 + 竖线分格)信息没错,视觉是素坯 —— 没有身份色、
没有状态语义色、数字排一排像表格,整片看过去是灰的。按管理后台的规格重做:

  · **头行**:40px 着色图标定身份(流程靛 · 活动青 · 审批琥珀)+ 名/标识 +
    **状态胶囊**(圆点 + 词:生效/上架走绿,下线/停用是灰,下线的图标同步转灰);
  · **计量块**:浅底圆角小块、数上名下 —— 边闭合不全那格整块点红,不只字红;
  · 活动卡的业务分类并进副标行(`rfq-intake · 统一报价`)—— 分类是唯一的一维,
    不值一枚独立签;
  · 卡 12px 圆角软影,悬停抬升;幽灵卡同尺寸虚线位。
  · 计量字号 14px、卡最小宽 288 —— 「14/14」实测不再截断(scrollWidth 核过)。

中途试过一版「图纸风」(流程画几何缩略、活动画芯片、审批画比较器),
用户明确不要:**这是管理系统,不做电路隐喻** —— 图形三件连同珊格纸整体撤除,
只留这一套管理系统语言。

交互不变:整卡可点、⋯ 菜单(编辑/删除)、就地改名、幽灵卡新建/装入,全部复核过。
五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-30 00:25:42 +08:00
ChaiHaoandClaude Opus 5 1fd215cf40 范式退役:活动只剩一种、只跑 Loop;审批活动可管;活动库重做
用户定的两件,一并落地。

**一、活动不再分 flow 和 loop —— 彻底退役 flow**
  · `flow-engine` 模块整个删除(runner 379 行 + step-sequence 184 行 + 测试);
  · `paradigm` 从清单身份、`activity_package`/`task` 两张表、任务卡与活动库一并退场;
    `businessModel` 不再是判别联合 —— 只有案例模型(CMMN + 说明书 + DMN)一形;
  · task 的引擎分派从「按 paradigm 取两个之一」收成**唯一的引擎**;
  · `activities/` 四个 flow 活动(A1 受理 / A4 定价 / A6 议价 / A7 归档)各写了一份
    案例模型:阶段照原来的步分,触达世界的项一律 manualActivationRule,
    能算的交 DMN(A1 的三分类 P-03、A4 的 P-01/P-02)不交 Agent;
  · 六个占位槽位的骨架从「机器步落台账 + 一张验收单」改成案例骨架,包版本 0.8.0 → 0.9.0。

**代价写在明处,不假装没有**:`turn-runner` 每一拍都要 `agent.decide` ——
环境里没有模型 key,案例活动一步也走不动。三套端到端(统一报价 / 新建流程包 / 测试台
Trace)整套跳过,文件头写明恢复条件:①有可用模型 ②走法改写成按 Enabled 集推进。
**不许把断言改松让它变绿** —— 绿得不诚实比红着更坏。debt.md 已记。

**二、审批活动可管**(新能力)
  · `sys.approval_template`:审批点**可复用的那一半** —— 审批人看哪几项、按什么名字看、
    怎么催、说什么话。谁来审不在里面(与活动点同口径,运营时轮值);驳回回哪个节点
    也不在里面(那是每张图自己的事,留在节点上);
  · 三条路由 + 引用反查:还被审批点引着就不许删(409),删了那些节点会**静默**退回旧行为;
  · 运行时 `basisOf`:引了模板就按模板筛与改名,没引即旧行为(载荷全摊开)。
    模板改了只影响新发出的审批单 —— 在途单的依据在发出那一刻已定形。

**三、活动库重做**:一区两格 —— 「活动(装进来的)」与「审批活动(配出来的)」,
都用流程卡那套两段式卡片(头 + 四格数据板),幽灵卡当入口(装入活动 / 新建审批活动);
「标准/案例」那一维随范式一起撤,业务分类成了唯一的一维,以行内小签呈现。

迁移 0020:两张表 drop paradigm、建 approval_template。已在开发库跑过并重播种。
实测(丁子乔账号):建「定价审批」模板 → 流程包 A5 属性里选得到 → 引用反查计数正确。
四闸绿(api:check 随本提交)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 23:53:51 +08:00
ChaiHaoandClaude Opus 5 18c3e3fd09 测试台:抽键预检屏与收件箱格一并撤,台面改两栏对开
**抽键预检读数屏删了**。宽进之后它已经不是闸,只是一屏会亮会灭的字 ——
抽得出抽不出,进了活动由受理补全单说了算,不必在门口先演一遍。
镜像服务端正则的那份前端实现(`preflight`)随之退场:一套规则两处实现,
本就是迟早对不上的账。

**收件箱那一格删了**。投给哪个信箱是通道配置的事,不是造这封信的人该操心的 ——
契约里 `mail.to` 放宽为可空,空地址由服务端取在用的邮件通道(与线上真来一封信同一条路)。
信头从三行收成两行:发件人 / 主题 → 正文 → 附件签条。

**台面重排**:从「左读数屏 + 右两段」改成 **两栏对开** —— 左造信(01)、右派人(02),
起单条横跨两栏吸在底边,像仪器前面板压在桌沿上。被测流不再占一整栏:它是一次性的
决定,改成顶部一行卡片,且只在多于一条生效流时才出(没得选的选择器是纯占位)。

实测(丁子乔账号):不写收件箱照样起单成功,起后「停止仿真」连根销毁,
任务 0 / 工作流 0,试跑数据未留。五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 22:51:09 +08:00
ChaiHaoandClaude Opus 5 e5cfca638f 运营中心撤掉「数据」区;流程包首页重排:卡有层次、⋯ 管编辑与删除、新建变幽灵卡
**运营 · 数据(活动记忆四层)整个撤掉** —— 记忆的放行口还没成形,摆一个空区不如
不摆;真要做时随「数据资产」一并重开。区表、面归属、shell 映射、KnowledgeHome /
MemPage、活动详情里那枚入口一并清干净;旧深链 `#/gov/memory/layers` 落运营首页
(测试跟着改口径,不留死链)。运营中心自此六区。

**流程包首页**:
  · 「编排要素:四种」这枚计数删了 —— 网关早废,它是句没人用的口号;
  · 卡片重做。从前是「头 + 芯片行 + 一大片空 + 脚注」,158 高全靠留白撑;
    现在两段:头(图标 · 名 · 标识 · 生效版 · ⋯)+ **数据板**(活动/审批/边闭合/版本
    四格等宽、竖线分隔)。段段有内容、段间有线,高矮由内容说了算 —— 实测 111 高;
  · 卡上 **⋯ 菜单**:编辑(就地改名,落在卡面那一版上)/ 删除(整条流,菜单原地翻成
    确认,不另弹窗);
  · **新建按钮变幽灵卡**:虚线卡住在货架末位,与真卡同宽同高(111/111)。

删整条流是新能力:`DELETE /api/gov/process/:id` + `process.deleteFlow`。
生效版这道闸不设(明示动作,不是手滑),在途单那道照设(PinnedVersionError → 409);
**「还有调起规则指着它」由路由层反查** —— process 是 L7,不该知道 trigger 的存在。

实测(丁子乔账号):改名往返、删除被 2 条调起规则如实挡回、幽灵卡建 `tmp-drop`
再删掉整条流,库里回到只剩 unified-quote v4,试跑数据已清。五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 22:38:52 +08:00
ChaiHaoandClaude Opus 5 f631b5b8bb 版本号自己定:点编辑,整列版本进编辑态,取消/保存收尾
用户的目的是**自己改版本号**,不是让系统替他递增;顺带把上一轮那些
指示性交互全撤了 —— 这软件给专业业务设计人员用,不需要「点我改」的提示条。

界面:
  · 顶栏 编辑 → 取消 / 保存(与流程图卡「编辑 → 保存」同一套手势);
  · 行内两个字段:号(自己编)与名(各版不同),行尾 删除;
  · 改动攒在草稿里,按保存一趟落库;取消原样退出;
  · **删掉**:改名指示条、「点我改」虚下划线、`删掉 v4`/`激活 v4` 这类复述钮名的浮字。
    只留下禁用态那一句(生效版先停用 / 还不闭合),那不是指示,是钮为什么点不动。

后端 —— 号从「系统递增」放开为「设计人员自己编」,两道闸是数据本身要求的:
  · 撞号拒(VersionTakenError,409);
  · 在途钉版拒改号(那些单正按这个号找定义,搬号等于抽它们脚下的地板);
  · 已完结的单**跟着改指**:号在三处(包的列、definition、workflow.packageVersion)
    一起改 —— 号只是这一版的名牌,搬号连引用一起搬,留痕仍指同一份定义。
    先前写成「跑过单就不许改号」,实测等于任何试跑过的包永远编不了号,是过闸。
  · 名不设闸:标签不参与流转,在途钉版也能改;改名只动这一版(推翻前一日的
    「及于整条流」)—— 各版本正是靠名字互相区分,全同名等于没名字。

路由 POST /api/gov/process/:id/:version/edit 取代 …/:id/rename(单一消费者是本仓前端);
CONTRACT.md 与产品设计.md 同步,api-report 快照随本次提交。

实测(丁子乔账号,测后已 reset-runs 清运行数据):v4→v2→v4 往返,列表、画布图签、
库里三处同步;在途单存在时改号如实报 409 并原样退回。五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 22:15:19 +08:00
ChaiHaoandClaude Opus 5 05c0a57cad 四枚头钮真正同款:保存撤掉强调色,按钮字体不再被画布纸面改写
量出来两处差异,都不是错觉:
  · 「保存 v4」挂着 t-go —— 棕字(138,95,28)米边(217,201,164),另外三枚是
    墨字(58,68,82)灰边(216,222,230)。**撤掉 t-go**:可不可存由禁用态说,
    不靠换色抢戏;t-go 留给版本行的「激活」那种真·主动作。
  · 中卡那枚「编辑」字体族是 PingFang 栈,另外三枚是 Inter 栈 —— 因为
    `.g-ver-act` 用 `var(--sans)`,而画布纸面 `.process-doc` 把 --sans 换成了
    中文正文栈(那是给图上的字用的)。立 **--ui-sans** 令牌(控件专用、同栈但
    不被局部作用域改写),按钮改用它 —— 骑在纸上的按钮属于界面,不该跟着换脸。

实测四枚:字色 58,68,82 · 边色 216,222,230 · 字体 Inter · 高 26 —— 完全一致;
保存在可用态 opacity 1、禁用态 .45,是同一枚钮的两个状态,不是两种风格。
五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 21:18:32 +08:00
ChaiHaoandClaude Opus 5 cae4dbcb76 三卡头线对齐 · 题字调大 · 四钮各归其位 —— 两个「编辑」分工划清
· **头线对齐**:左右卡的头底线与中卡的**图框上边**同一水平(308/308/308)——
    中卡题下不再另画一条线,画布顶边就是它的分割线(几何:14 纸内距 + 26 题行 + 12)。
  · **题字**:9.5px → 11px,疏排大写照旧。
  · **四钮全部住标题栏右端**、同一族(图纸方钮 26 高):
      版本 → 新建 · 编辑    流程图 → 编辑    节点 · 属性 → 保存 v4
    左卡那条独立动作条(.g-veracts)整条撤掉。
  · **两个「编辑」划清**(用户定「标题栏的编辑只作用于版本记录」):
      · 版本卡的编辑 = **版本记录**:开着才出改名条、行尾钮换成删除;不碰画布。
      · 流程图卡的编辑 = 手绘画布;编辑态升为工作区级的做法就此回退 ——
        FlowFigureBlock 收回内部 state(canEdit 回来),两者互不相干。
    停用/激活照旧长在版本行尾(那是某一版的运行时开关)。

实测:头线 308/308/308;头钮 左[新建·编辑] 中[编辑] 右[保存 v4];
点版本卡「编辑」→ 行钮变删除 + 出改名条,画布进手绘 = false;点「完成」还原。
五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 21:11:51 +08:00
ChaiHaoandClaude Opus 5 89ea6e609c 版本栏动作再分工:启停回到版本行上,新建·编辑·改名住顶条,编辑态行钮换删除
· 顶条只放**建改类**(作用于整条流/工作区):新建 · 编辑 · 改名。
    「编辑」从图卡题行迁来 —— 编辑态升成**工作区级受控状态**
    (FlowFigureBlock 的 editing 提升为受控 props):版本行的按钮语义都跟着它变,
    这不是图卡的私事。编辑中顶条示「编辑中」,收尾走画布里的 保存绘图/取消。
  · 停用/激活是**某一版**的运行时开关 —— 回到每条版本行的行尾
    (矮一号的小钮,行不发胖;行本身照旧点击切版,小钮拦冒泡)。
  · **编辑态下行钮换成删除**:正在改定义的人,手边该是版本管理,不是启停开关;
    生效版照旧禁删(先停用)。

实测:顶条 新建·编辑·改名;平时行钮 停用/激活;点编辑 → 画布进手绘、行钮变删除
(生效版灰);取消 → 行钮变回停用。五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 19:29:11 +08:00
ChaiHaoandClaude Opus 5 af2d00a107 编排工作区三卡统一:按键一族 · 标题一规 · 顶部留白一档
量出来的病根:三张头三种几何(左 30px 顶距 / 中 0 / 右 13px),按钮两种血统 ——
而且 .g-ver-act 在 CSS 里有**两份定义互相覆盖**(图纸方钮版 + 圆角芯片版),
按钮忽方忽圆的怪样就是它。

  · 按钮:立**唯一规格** —— 图纸方钮,26 高、白底细线、无圆角;主动作 t-go 黄铜、
    危动作 t-bad 赤。中卡「编辑」(原 dc2-addbtn 蓝芯片)与右卡「保存 v4」
    (原 g-ver-new 蓝芯片)全部换族;g-ver-new 与两份旧定义连 CSS 一起清掉。
  · 标题:三条头同一几何 —— 14/16/11 内距 + mono 大写题 + 底缘细线;
    头行内容一律 26 高(= 一枚方钮),没按钮的头也不塌。
    实测三条头底线 308/308/308,按钮顶 270/270,完全同线。
  · 留白:头下内容起点一律 12px(版本列表 / 图框 / 属性明细)。

五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 19:18:53 +08:00
ChaiHaoandClaude Opus 5 4cd14d7849 版本栏与节点属性再调:比例 · 四钮同款同排 · 「实现」改成看得出能点的真选择器
· 比例:左栏 196–224 → 228–268(版本行整行排满),右栏 320–1.25fr → 264–1fr(节点属性收窄)。
  · 四枚按键(新建 · 激活/停用 · 改名 · 删除)**同款同排**收进顶部动作条 ——
    新建不再另作一枚蓝芯片挂在头上;白字不换行,右端 v 号去掉(选中行自己亮着)。
    右栏头顺带收掉闲置提示「点节点就地填写」(空态文案已交代),只留脏态。
  · 「实现」下拉从无框文字改成**真控件**:有边、有底、有箭头、焦点有落点 ——
    无框下拉在窄轨里读成一行普通文字,人不知道能点,这是可用性缺陷不是审美偏好。
    实测:7 个选项、换选即入脏态,保存路径原样。

五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 19:05:16 +08:00
ChaiHaoandClaude Opus 5 541b1c816e 版本栏三改:显示完整 · 动作统一住顶部 · 「实现」明确为链接自活动库
· 栏宽 132 → 196–224:一版一行排满「v4 生效 10 节点 · 14 边」,不再挤成三行。
  · 激活/停用 · 改名 · 删除收成**顶部动作条**(右端注明作用对象 v几,
    换版看,条上的钮跟着换语义);行里只剩事实,不在行内展开小钮。
    改名输入就地在动作条下方展开,不再吊在卡底。
  · 「实现」行改口:标签「实现 · 链接自活动库」,空选项写
    「从活动库链接一个活动 —— 未链接,激活会被拦」—— 节点不含实现,
    链接才算装载,这层语义直接写在控件上。

五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 18:48:25 +08:00
ChaiHaoandClaude Opus 5 9c947950ce 测试台与节点属性三改:拆盒 · 收色 · 让三件实物说话
上一轮的病根认下来:暗侧是「盒子摞盒子」—— bed/panel/panel2 三层深蓝几乎同色,
每节各带一条填色题头栏,纸信缩在盒子里像张明信片;磷光、琥珀、青蓝、暖纸四个
色温体系打架。节点属性那条竖格线逐行断裂,类型切换是个外来的灰块。

**测试台 · 拆盒**:台面上只留三件「实物」——纸信(暖白)、抽键读数屏(纯黑凹屏)、
起单钮(磷光);其余全部退成台面排版:
  · 左右两栏不再是描边圆角盒,一道竖细线分栏;节题从填色横栏改成
    疏排大写 + 底缘细线 —— 是标题,不是盒盖。
  · 被测流选中态只亮一道磷光左棱 + 提亮文字,撤掉整块青染 —— 色彩留给读数屏。
  · 读数屏撑满栏宽、值放大;「必填」从描框小徽退成缀在键名后的小字 ——
    屏上的字越少越像屏。
  · 纸信撑满右栏成为主角:内距 22px、主题 14px 半粗、正文行高 2;
    纸上聚焦一律墨色加深 —— 琥珀与磷光都留给机器侧,纸只有纸的颜色。
  · 起单条撤掉渐变毛玻璃,平铺台面 + 一道细线。

**节点属性**:335px 窄轨里逐行断裂的竖格线比没有更乱 —— 改标签在上、值在下的
叠排,行距放足,图签味交给 mono 大写与行线;类型切换从灰色分段控件改成
**两枚迷你节点皮肤**:选活动点就是一小块画布蓝,选审批点就是一小块琥珀 ——
切换器长成它代表的东西。

教训一并修:上一轮一段 CSS 替换因原文不匹配**静默没吃上**(没加 assert),
截图看着旧样还以为改了 —— 这轮逐条 grep 验证每段都落了。

五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 18:27:00 +08:00
ChaiHaoandClaude Opus 5 f8f208e945 两处 UI 重做:节点属性 = 图签 + 画布同款节点芯片;邮件输入 = 台面上的一张纸信
**流程包 · 节点属性**:泛用表单换成**图签**(title block)——
  · 卡顶一枚从画布上「拎下来」的节点芯片:活动蓝 E8F1FB/4E7DAF、审批琥珀
    FBF0DC/B98432,左上角标同画布 —— 属性改的是哪一件,一眼对上,不用回图上找。
  · 字段收成图签行:76px 标签格(mono 竖签 + 格线)+ 值格,行间细实线 ——
    表格,不是表单;值格输入无框,格子本身就是边界。
  · 出边收成路由小表:带题一行(共用提示住右角:活动点「条件读本节点的输出字段」/
    审批点「条件读审批裁决 verdict」),每行 E号 → 去向 + 去向节点名,条件在值位;
    从前三条重复的长提示删成一条,空条件的语义进 placeholder(留空 = 默认兜底)。

**测试台 · 邮件输入**:表单换成**一张纸信压在暗台面上** —— 整台仪器里唯一的浅色面,
把「机器说 mono、信是外界」推到视觉结论:
  · 暖白纸面(FBFAF6)+ 纸边细线 + 投影浮起;信上全是无衬线,标签是小号暖灰。
  · 解剖照邮件写:信头三行(发件人 / 收件箱▾ / 主题加粗)→ 正文(纸上的一片空,
    不描边不描线 —— 写信不是填表,resize 手柄也摘了)→ 附件签条(虚线隔开,
    纸质小签 + 「加一个 BOM」虚框钮)。
  · 聚焦色在纸上转琥珀(纸是暖的,磷光绿留给机器侧)。
  实测:改坏主题 → 预检 0/2,改回 → 2/2 —— 灯对纸上的字照样实时。

旧 .tb-ml / .g-att 两组样式退役。五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 18:11:44 +08:00
ChaiHaoandClaude Opus 5 6cff6ab34c 删掉节点的「说明」字段 —— 它填得进、存得下,却从来画不出来
`sub` 声称是「画布上的第二行小字」,但画笔里那支只在 `variant !== 'business'`
(步骤图)才走,而全仓的调用点一律是 business:这个字段写了、存了、
一次也没显示过。属性面上那句提示是句假话。

整条清:属性面的一行 · `ProcessNode.sub`(契约) · `FlowNode.sub` ·
图↔包两处映射 · 画笔里那支画不出来的分支(连同它带来的「两种画法」分叉,
现在节点框里就一行活动名) · 节点宽度算法里 `node.sub || node.ghost` 的宽框判据
(sub 没了,只剩 ghost 决定宽窄)。

存量数据不受影响:库里没有一条带 sub 的定义(查过),schema 非严格,
真有旧值也只是解析时被剥掉。

五闸绿;契约快照随本提交入库(去一个可选字段,加法的反面,无下游)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 17:48:12 +08:00
ChaiHaoandClaude Opus 5 28623cd1cb 节点属性平铺 —— 不分类,也不写数据契约声明
分类卡(身份与命名 / 数据接口 / 类型与责任 / 链接活动实现 / 出边)全撤:
节点本来只决定这么几件事,分成五张小卡反而把四五个字段摊成半屏。
现在是一列字段直排,字段间一条细线断句:
  节点 ID(只读)· 名称 · 说明 · 节点类型 · 链接实现 · 出边条件(每条一格)。

「数据接口 · 声明」整节删掉 —— 数据契约**归活动自己**,编排面不复述它。
链好实现后只留一枚直达钮:「去活动库看 X 的契约」。

顺带清掉两条一直漏网的说教横幅(前一轮 ⓘ 清扫时因为文案里夹了 <b> 没匹配上):
「编排不带岗位 ——…」与「审批点是系统内置要素 ——…」。前者的意思已收进
「节点类型」那行的提示,后者本就是常识性交代,不必占一整块。

CSS 里 .g-props/.g-propcol/.g-eprops/.g-prop* 与 .g-dif* 两组样式随之退役,
换成一条 .g-nodeform。

五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 17:29:11 +08:00
ChaiHaoandClaude Opus 5 5414e99778 清掉「节点决定数据契约」的三处遗留 —— 编排面从此一个字段都不碰
讨论定的界线:节点只决定四件(身份 · 类型 · 链接哪个活动 · 出边条件),
数据契约全归活动自己(它的 manifest,随活动升版),流程包的 callInterface 是
「这条流被调用时的签名」另算。照此清三处化石:

  ① `ProcessNode.in/out` —— schema 上还留着「这个节点**声明**吃什么、吐什么」,
     注释还写着「闭合校验以**边映射**为准」;边映射上一轮已退役,这两行是上个模型的化石。
     连同图↔包的两处映射一并撤。
  ② 手绘编辑器属性卡的 **进 / 出 / 查 / 执行** 四行 —— 其中「查」(use)与「执行」(owner)
     连 ProcessNode 都没有,填了保存就丢:写了不生效的输入框。
     同卡里**网关**与**卡点**两支也一并删(两种要素早已从模型里去掉,分支不可达,
     而且正是网关那支在写 owner)。
  ③ 只读图双击卡的 **执行** 行、`onEditNode` 的 owner 形参、画笔里的**责任人角标** ——
     编排不带岗位,图上不该画它。上一轮图例注释说「图上早已不画责任人角标」其实说错了:
     画笔一直画着,只是没人写得进 owner;这次真的撤了,注释也改对。

连带:`FlowNode` 的 owner/in/out/use 四个字段退役;岗位选择器 support.tsx 成了孤儿
(depcruise no-orphans 当场逮住)—— 编排不带岗位,它没有归宿,删。

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 16:44:30 +08:00
ChaiHaoandClaude Opus 5 c9ac058bdf 三面拆分⑯:流程包详情改三栏 · 字段只声明 · 版本可删可改名
**字段只声明,不做任何要求**(用户定):编排层不再碰字段 ——
  · 激活闸只剩两面:结构闭合(dangling-node / multi-default-edge)与活动装载
    (unknown-activity);字段类的检查(同名不同型、容忍分支被必填依赖)全部退役。
  · 节点属性卡的「数据接口」从「推来源」改成**纯声明**:照活动契约列出吃什么、吐什么,
    不标必填、不推来源、不提补全 —— 缺了怎么补是**活动内实现**的事,不在这一层现形。
  · 字段类型支持数组:统一写成 `T[]`(如 `any[]`),出口口的字段也带上类型
    (原来只有字段名)。实测 A2 的 benchmark 口显示「rows any[] · needSourcing boolean」。

**详情页改三栏**:左窄轨版本(132px) | 中流程图 | 右节点属性。
  · 版本条一版一行(v几 · 状态 · 点/边计数),动作只在**看着的那一版**上展开 ——
    窄栏放不下每行一排钮,也不该让人误点别版。
  · 删掉「激活 · 双判据」整卡:没选节点时,属性栏就地列出还差哪几条(点一条定位过去);
    两面都齐时盖一枚小检验章,不再占一整张卡。
  · 删掉节点拣选行 —— 直接在图上点节点。
  · 属性卡用包壳绝对定位:行高由中栏的图定,属性长了在卡内滚,不把图拉长
    (实测卡高 467、明细内容 1039、可滚,图框不受影响)。窄轨里属性小卡改单列竖排。
  · 顺带校正:上一轮那条「图框下沿对齐左列底栏顶线」的 20px 留白,
    三栏改版后左栏已无底栏,没有对齐对象了 —— 改回四边等距(18px)。

**版本可删可改名**(新):
  · 删:生效版不可删(先停用,ActiveVersionError → 409)、在途钉版不可删
    (那些单要按它跑完,PinnedVersionError → 409);删掉正看的那版会落到剩下的最新版,
    一版不剩就回货架。
  · 改名:名字是**这条流的身份**,一次改及于所有版本 —— 版本列表上只显示 v1/v2…,
    若只改一版的名,列表上什么也看不见,人会以为没生效。
  · 5 条单测守两道闸与改名口径;实测走查:改名落库 → 改回;生效版删 409、停用版删 200。

process CONTRACT.md 与产品设计.md 同步。五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 16:14:54 +08:00
ChaiHaoandClaude Opus 5 f03f23f2ca 编排页两处收口:图框下沿对齐左列底栏;边不再是可编辑对象
**对齐**:图框下边原本停在纸面内距上方,与左列版本卡底栏的顶线差 16px,
两条本该连成一线的横线错开。改法不是拿魔数把图框往下推 ——
纸面改成 flex 列、图框 flex:1 吃满(被栅格拉高时跟着长,不会又浮回上面),
下方留出**恰好一条底栏的高度**:20 = 38(底栏净高) − 18(纸面下内距)。
底栏那侧加 min-height:38 锁住基线,两边注释互指。实测差 0。

**边不再是可编辑对象**:上一轮边已瘦成「顺序 + 条件」,再给它一张属性卡、
一条 E1…E14 拣选行、一套与节点互斥的选中态,就是为一个条件养一整套机制。
按 Mastra 的语义,分支本来就归**发起它的那一步**管
(`.branch([[条件, 下一步], …])` 挂在上一步上)—— 于是:
  · 删掉边属性卡、边拣选行、selEdge 选中态;
  · 节点属性卡新增「出边 · 往哪走」:列出本节点的每条出边(E号 → 去向)与条件,
    单出边显示「无条件直连」,留空即默认兜底;
  · 审批点的提示单写一版 —— 它的判据是**系统注入**的 verdict,不是自己的输出字段;
  · 点画布上的线不再打开边卡,而是选中发起它的那个节点。

顺带清掉三处失真文案:头注与「节点 ID」提示里的「边映射」、空态里的
「边填传递契约(条件 + 映射)」。

五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 15:13:55 +08:00
ChaiHaoandClaude Opus 5 4cbfea5b46 流程图图例收进图框下沿 —— 删掉「责任」那两格
图例本来是画布下面一个带边框、带钢青左线、带灰底的独立盒子,读起来像图之外
又摆了一块内容。工程图的图例画在图框**里**,不另起一张纸 —— 挪进 .hero,
做成与顶部图签(.cap)对称的一条框内小字:细线横贯整框(负外边距抵掉框内距),
左右 16px 与图签的字对齐同一竖线,mono 9.5px 同一记法。展示态与编辑态共用。

「责任 · 右上角标 责任人」删了:编排**不带岗位**(负责人是运营时分配的),
图上早就不画责任人角标 —— 图例里留着是指着一件不存在的东西。

顺带两处对账:
  · 图签右格原本写「蓝 = 活动点 · 琥珀 = 审批点 · 线标 = 边号」——
    图例进框后这就是同一框内说两遍(蓝/琥珀本来就由图例的图标自己带);
    改成说这张图**是什么**:「顺序与条件 —— 数据按字段名流动」,
    边号那句并进图例的「顺序流 · 线标即边号」。
  · oneLiner 的兜底文案还写着「活动 · 网关 · 顺序流」—— 网关早已去节点化,改掉。

图例小图标从 vertical-align + translateY(-1px) 的手抬改成 flex 居中(行已是 inline-flex)。

五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 14:44:26 +08:00
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 Opus 5 8d50ceda6a 三面拆分⑭:宽进收敛 —— 起单不卡缺项,进活动受理归一,信息不全派补全单
用户定的逻辑:「调用活动,输入数据可以不定或者为空;进入活动后受理归一,
信息不全派补全单。」把收敛点从门口挪进活动 —— 三道门口闸全撤:

  · 触发装配:缺必填**不再入死信**(AssemblyResult 的 missing 改 partial,带上已装配的);
    装到多少带多少照样起单。死信只留给真错误(勾了确认没指定人这类配置错误)。
  · process.start:撤掉调用接口缺项闸 —— 从前缺一个字段整条流都起不来,
    现实是客户来信本来就常缺客户码,拦在门外等于要求外界替系统把信息备齐。
  · task.start(替代旧 AM 12.1「缺项不得启动」):缺必填的任务落成「等人」,
    缺的字段做成**补全卡**(elicitation,标签取 schema 的 title)发到负责人的
    任务对话流,并武装 human 监听(IntakeDesk 端口;不占活动的人卡预算)。
    答复只收契约声明过的键,合并进 data;齐了或答「没法填」才转 running 开跑;
    答一半就就缺的部分再派一张卡。等人期间谱一步不走、不扣步数。

  · 测试台预检改成**信息**不是闸:灯灭不拦起单,文案直说
    「抽不出的键由受理补全单找人收齐」。

5 条受理归一单测 + 全链实测:投一封只写「想问下工控板价格」的信(零键)→
流照起 → A1 落负责人工位、等人、补全卡在对话流 → 答卡(customerCode/rfqRef)→
任务醒、合并、谱跑 3 步到验收。修一处接线错误:监听 deadline 要 ISO-8601
时长(P2D)不是时刻,传错整个补全监听静默没装上。

trigger/task/process 三份 CONTRACT.md 与产品设计.md 同步(宽进纪律成文)。
五闸绿;契约快照随本提交入库。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 13:46:13 +08:00
ChaiHaoandClaude Opus 5 f9b2c07731 三面拆分⑬:触发确认链路 + 运营中心「工作流」区 —— 设计只管设计,运营管细节
**触发确认链路**(用户口述五步的第 4/5 步):
  接收邮件 → 分类识别 → 命中 RFQ 事件 → ④(可选,运营勾)系统消息到指定人
  工作台(带邮件内容)→ ⑤ 工作台点「确认起单」,流程才起。
  · 命中不等于必起:勾了「需人工确认」,装配好的入参存成待确认单
    (sys.trigger_pending,migration 0019),ConfirmDesk 端口把带来件内容的
    系统消息送指定人(eventRef 挂票号,消息列表就地贴确认状态与那枚钮)。
  · 先认领后起单:consumed_at 空才认得到 —— 两人同时点、一人点两次,都只起一条流;
    起单失败退回认领,不留死票。确认人记进 source.by,留痕可查。
  · 登记触发不走确认(登记那一下本身就是人在确认);勾了没指定人 = 配置错误入死信。
  · 4 条单测 + 全链实测:投信 → triggersHit=1 且零直起 → AI 工作台收到确认消息
    → 确认起单 → 二次确认幂等回同一流号 → source.by = AI。

**运营中心重排**(区名即运行时:工作流是流程包的运行时,任务是活动的运行时):
  · 新「工作流」区:在途看板(从任务区迁入)+ 运行配置 —— 每包的触发器
    起单开关 / 确认打勾 / 确认人,和节点负责人(sys.node_owner)。
  · 负责人三层:显式指派 > 运营配置 > 轮值 —— 合并点在 process.start,
    复用既有派发链一行不改。
  · 任务区瘦身成活动运行时(任务/审批/需处置);知识库区改名「数据」
    (与设计中心的知识库解开同名);系统区只剩通道实例。
  · 设计中心触发器详情页摘掉启停按钮 —— 设计只管设计,启停/确认全在运营。
  · 旧深链有改嫁:tasks/board → runs/board,tasks/trg → runs/conf。

reset-runs 补 sys.trigger_pending(待确认单是运行痕 —— 和上回漏 trace_span 同类洞)。
邮件分类 Agent(第 ② 步)现由抽键正则 + S-FEEL 代位,升级路径记进 debt.md。
产品设计.md 运营章、trigger/process 两份 CONTRACT.md 同步。

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 13:09:16 +08:00
ChaiHaoandClaude Opus 5 70b261d067 测试台重制:浅色桌面上的一台仪器 —— 抽键预检读数屏是戏眼
产品:
  · 抽键预检(新):通道的抽键正则**实时**跑在正打的字上 —— 键名/抽到的值/一盏灯,
    该抽的必填全亮,起单钮才「上膛」发光。从前的头号困惑是投出去才知道
    「抽不出客户码」,现在打字就知道。契约把 extract 规则原文回给治理台
    (正则不是密钥),前端镜像服务端 extractFields 的取料与取值;服务端仍是唯一裁判。
  · 收件箱改成通道下拉 —— 投给哪个信箱决定用哪套抽键规则,手打地址错一位,
    预检整屏熄灯还不知道为什么。
  · 「全派 AI」一键(测试一律用 AI 账号,把项目规矩做成一枚钮)+「全部轮值」清空。
  · 双层页头砍成一层:区壳的英雄头留着,屏内改成一根「仪器顶条」——
    一盏灯 + 状态词,装配态与观测态共用同一根骨架,起单前后面对的是同一台机器。
  · 观测态删掉两枚手动「刷新」(2s 自动轮询早就在),唯一动作是珊瑚红的停止仿真。

视觉:
  · 概念:页面是浅色桌面,测试台是桌上**一台有边有圆角的暗色仪器**——
    不是把纸刷黑(上一版的问题:半迁移的暗色,TRACE 里十几处浅色时代的硬编码
    在深底上要么刺眼要么隐形,如 k-node #161b22 深底深条完全不可见)。
  · 三色律:磷光绿 = 机器活着(灯/命中/上膛);琥珀 = 人(指派/审批/等人/人卡);
    珊瑚红 = 坏(异常/销毁)。其余全是冷灰蓝结构色,集中在一组变量上。
  · 机器说 mono,那封信说无衬线 —— 它是外界唯一伸进仪器的东西。
  · 指派轨:节点挂在一条竖轨上,活动是圆点、审批是琥珀菱形,插了人点亮琥珀。
  · 呼吸灯尊重 prefers-reduced-motion;焦点环全部磷光可见。

实测走查:改坏主题 → 灯灭/计数 0/2/钮退膛/状态行说因;重置样例 → 全派 AI →
起单 → 观测态(呼吸灯+TRACE 示波记录+派工带)→ 停止 → 库里零残留。

四闸绿;契约快照随本提交入库(listChannels 增 extract,加法)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 11:12:22 +08:00
ChaiHaoandClaude Opus 5 72f90f293b 测试台改仪表台:启动输入换成一封信;卡片化触发器与大模型;清掉 ⓘ 说教条
**测试台**
  · 启动输入不再是「调用参数」表 —— 这条流真实的起法就是客户来信,
    界面上就该是一封信(发件人 / 收件人 / 主题 / 正文 / BOM 附件)。
    服务端拿**真通道的抽键正则** + **真触发器的装配映射**推出调用入参:
    测试台自己不解析邮件,否则试通的是测试台而不是这条流。
    抽不出必填就如实报「哪个字段没命中、通道的正则要什么」,不静默起空单。
  · 一屏两大块:左选流,右两节 —— 01 输入配置、02 节点指派。
  · 起单钮只剩一枚(原来页头一枚、RUN 卡里一枚)。
  · 改暗色仪表台:调色板集中在 .g-tb/.g-rig 的一组变量上,
    TRACE 那张树 + 甘特的结构一行没动,只是纸变成了面板。

**触发器 / 大模型** 列表改卡片:一条规则、一个实例都要一眼看全
(何时起 · 起哪条流 · 开没开 / 谁家的 · 什么型号 · 密钥绑没绑)。
触发器卡是 div 不是 button —— 卡里还坐着「改规则」那枚真按钮。

**同类卡等高**:底栏钉在卡底、说明恒占两行、卡头一行截断。
实测同一货架内 13 张工具卡、6 张活动卡、3 张模型卡各自完全等高。

**删掉 19 条 ⓘ 说教横幅**(「只列有生效版的包…」那一类)。
留下的是三种:确认带里的影响说明(点了动作才出现,是决策依据)、
warn/ok 的真反馈、以及「X 不存在」这类空态。

删掉入站邮件演练整屏 —— 它验的那两步已经并进测试台的起单路径了。

新增一条接缝测试:通道抽出来的键叫 keys.customerCode,触发器映射也得照这名字取;
哪头改了名字单还是能起,只是入参悄悄变空、流走到 G1 才莫名其妙地停。

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 10:42:01 +08:00
ChaiHaoandClaude Opus 5 331fd25922 知识库补图标 —— 顺带堵掉「图标名写错静默留白」这个洞
左轨那一格是空的:ZONES 给知识库写的 `library` 在 Ico 字典里根本没有,
而 Ico 查不到名字时返回一个**空 svg** —— 图标掉了不报错、不留痕,
八格有图标一格没有,看上去像布局塌了。是用户指出来才发现的。

三件事:
  · 补 library 字形(书脊排在架上,与运营侧知识库的 layers 明显不同形)
  · 查无此名时画一枚虚线空框(字体界的「豆腐块」),不画空气 —— 缺图标得看得见
  · 导出 hasIco,加一条测试逐格对 ZONES / ZM / TABS 的图标名,
    并自证查名管用(不在册的要答不在,否则前三条是空转)
    全库 92 个手写图标名扫过一遍,现在零缺

顺手改掉知识库占位卡的语气:原来用 Clear(绿对勾),读着像给「还没建」打了勾;
换成中性 Note + 三行未建清单。

四闸绿(api:check 未动契约)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 09:02:10 +08:00
ChaiHaoandClaude Opus 5 8cb00d1ff6 三面拆分⑫:设计台九区一级目录 —— 一区一内容,测试台收成单例仿真
设计中心从「蓝图 + 四库」摊成九区,顺序即设计的次序:
蓝图 → 触发器 → 流程包 → 活动库 → 工具箱 → 数据域 → 知识库 → 大模型 → 测试台。
触发器与大模型从「并进流程包 / 塞在系统区」里拿出来独立成区 —— 前者与流程包平级
(不入包结构、不随包版本),后者是设计者天天要碰的东西;知识库先立个诚实的空占位。

一区一内容,于是区内页签栏整条删掉(壳层在只剩一格时收起):
  · 流程包:总览的三枚计数并进货架顶端
  · 测试台:入站邮件演练移到触发器区就地验(它验的正是那一区定的规则)
  · 大模型:从系统区拆出,系统区只剩通道实例

测试台一次只跑一条流。起单前先销毁上一单,刷新页面能认回在跑的那一单,
「停止仿真」把工作流连同它派出的任务、工单、实例、留痕一并拔掉 ——
不留半单挂在别人工作台上。实测:起单 → 1 单落到 AI 工作台 → 停止 → 库里零残留。

功能工具补中文名(migration 0018,读回退到逻辑名),治理台一律主显示中文名。
顺带清掉几处说教式文案(「这些是工具,不是模型 —— 模型是它们跑在上面的发动机…」那类)。

五闸:typecheck / lint / depcruise / test 绿;api:check 快照随本提交入库。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 04:35:36 +08:00
ChaiHaoandClaude Fable 5 ffb71def4b 修:工作台列表不实时刷新、办完的活不进「已完成」—— 两个 bug 叠在一起
用户实测报的。查下来是两处各自独立、叠在一起才显形的缺陷:

**① SSE 订阅层的 queryKey 与实际键对不上(推送白推)**
TanStack 的失效按**前缀**匹配,而工作台的键都以 `desk` 打头
(`['desk','tasks']` / `['desk','task',id]` / `['desk','messages']`);
订阅层却手写着 `['tasks']` / `['task',id]` / `['messages']` —— 一条也匹配不到。
推送照发、画面纹丝不动。修:订阅层一律取自 `queryKeys`,不写字面量;
`['approvals']` 也收进 queryKeys(app-shell 原来手写)。

**② 推进器推完不广播(压根没推送)**
只有派发器(事件投递)广播;而任务从在办走到终态是**推进器**推的 ——
于是「办完的活不会自己挪到已完成」。修:推进器在 runtime/terminal 真变了时
广播 task + workflow(比对本轮前后,不变不发,免得每两秒给在线浏览器发噪声)。

实测(全程用 AI 测试账号,不碰真人工作台):起单 → 以 AI 身份答验收单 →
浏览器停在工作台,探针记到**任务列表自动重取 1 次**(修复前 0 次),
SSE 三条 touch 齐到(task / task-advanced / workflow)。测完清运行数据。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 03:46:37 +08:00
ChaiHaoandClaude Fable 5 e962bb526b 清运行数据 + reset-runs 补 trace_span:试跑一律用 AI 账号,不碰真人工作台
用户纠正:我在验证测试台时把节点指派给了他本人(Chaihao),七条测试单堆进了
他的工作台 —— 而我自己就有 AI 测试账号。真实员工的工作台是他干活的地方,
不是试验场;混进去的测试单还要他自己分辨、自己清。

- 清掉全部运行数据(reset-runs:50 张表,配置与组织原样保留)——
  柴浩名下任务 0、工单 0;流程包/员工/活动配置一条没动
- **reset-runs 补上 sys.trace_span**:span 是运行痕,与工作流同生共死;
  漏清它,清完运行数据后观测面还挂着 62 条孤儿 span(实测)
- 规矩记进记忆:试跑指派一律给 AI 账号,测完主动清运行数据

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 03:33:44 +08:00
ChaiHaoandClaude Fable 5 d98cdddca3 修:点了通过却以 exhausted 收场 —— 放行落地失败是终态,不是可重试的中间态
用户实测报的:任务起起来了,点通过就卡住,测试台也看不到日志。查下来是一条真事故:

**机理**(证据链完整):`land()` 抛错(草稿与正式版并发冲突)→ 异常穿到推进器 →
推进器写一行 stderr 就 break;而这一拍**已经把 runtime 落回 running、已经扣了
一步预算** —— 两秒后又来一次,空转到 steps 触顶。实测:3 步的活跑了 40 步,
终态 `exhausted`,而真正的原因只在服务端 stderr 里刷屏
(`草稿与正式版并发冲突:2 处字段已被他单改动` 刷了几十行),
任务记忆、界面、trace 上一个字都没有 —— 这正是「看不到日志」。

冲突检测本身**是对的**(多单并发写同一行,基线过期即冲突,不该静默覆盖);
坏的是失败处理。三处修:

① **落地失败落终态**:`land` 抛错 → 就地 `blocked` + 原因写进任务记忆(人读得到),
   推进器再也不会来推它 —— 空转到预算耗尽那条路断了
② **失败在时间轴上标红**:非放行终态的节点 span 走 `fail()` 并带原因,
   不再收成一条无害的「已结束」(从前失败的单在观测面上与走完的单长得一模一样)
③ 顺带修:`listInstances` 没读回 `assignee_id`(写了不读等于没写)—— 上一提交已含

实测复核(真库 + HTTP 全链):正常路径 A1 四步 released、流转到 A4(修复前是 40 步
exhausted);单测三例锁死失败路径(blocked 终态 / 只调一次 land / 不误伤正常路)。
五闸全过,测试台六例端到端照旧绿。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 03:27:43 +08:00
ChaiHaoandClaude Fable 5 48bc664c7e 仿真测试台(界面):装配一次试跑 → 起单 → 全链 TRACE 看穿(frontend-design 专项)
测试台从「只能造一封邮件」升级成仿真试跑台,两种试法同屏切换:

**装配态**:选生效版流程包 → 按 callInterface.input 现生成参数表单(必填标出)→
节点指派表(每个活动点/审批点选账号,留空即轮值)→ 起单试跑;
起不来把后端判词原样上屏(如「must have required property 'rfqRef'」)。

**观测态**:WF 工作流图签 · DSK 任务落到了谁的工作台(明说测试台不代答)·
**TRC 全链 TRACE(签名元素)** · NOD 节点实例。
TRACE 做成一张走查记录纸:左半 span 树(细线方角枝线),右半同轴甘特(方格纸底纹)。
三处判断值得留:
- 轴的右端**只认已知时刻,不认 now** —— 按 now 收口会被不收尾的工作流 span 拉到
  十几秒,真干活的两三毫秒压成发丝;而根 span 常常一辈子不收尾,拉到「此刻」
  等于替它编了个结束时间
- 未收尾的段用剖面线 + 箭头(图纸的「未完待续」画法)
- 包络(流/节点自己不干活)画尺寸线而非实心条 —— 实心会盖过真正干活的那几笔
颜色只花在动作三色(工具石青 / 模型靛 / 人黄铜),结构走灰阶。

顺带修:区头 desc 是纯文本渲染,里面的 markdown `**` 会原样露星号 ——
六处全清;测试台页签名改「联调试跑」(它现在不止入站邮件)。

实测:真起单三次,指派两处都落地(TRACE 的 attributes.assigneeId 与节点实例
受理人一致);浏览器核对装配态与观测态。五闸全过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 02:46:31 +08:00
ChaiHaoandClaude Fable 5 5fc6dfdfe1 仿真测试台(后端):节点指派 + 全链 Trace —— 起单定向到指定账号,真实任务落工作台
用户定的形态:测试台是**后端检测活动与流程**的,真实任务照旧到工作台
(不然指定账号干嘛)—— 所以测试台只管「起单 + 看穿」,人那一环还是真的。

**节点指派**(迁移 0016 workflow.assignments):
- StartWorkflowInput 增 `assignments {节点id → 员工id}`;分派改三级取人:
  ①节点指派(点名的人在岗就是他)②员工组轮值 ③全员轮值 —— 指派是加法不是替换,
  点名的人不在岗退回轮值(单不能没人接);事件里如实记 `(节点指派)`
- **顺带修一个真 bug**:`node_instance.assignee_id` 写了但 `listInstances` 从没读回来
  (审批箱收件、员工面链条、治理列表全按它认人 —— 写了不读等于没写)

**全链 Trace**(新模块 trace,L2;迁移 0017 sys.trace_span):
- span 由 **Mastra Observability 组件**产出(执行不经 Mastra 图,所以手动打点),
  一开就落库、一收就补 —— 观测面不该比被观测的事晚(不走 exporter 的批量异步路)
- 打点覆盖:工作流 root → 节点(记着派给了谁)→ 活动内每次工具调用 / 模型调用 / 人卡
- **root span 挂在 `runtime.begin`**:那是「单已建好、还没进第一个节点」那一刻 ——
  挂在 start 返回之后就晚了,起单同步走到第一个节点,节点 span 会先出生、另起孤树(实测)
- 观测尽力而为:写 span 失败吞掉,不掀翻业务
- 三样东西各管各的:trace(机器读时间轴)/ 任务记忆(人读留痕)/
  **工作区报告(活动自持的 HTML)** —— 谁也不替代谁

路由:`POST /api/gov/testbed/run`(带指派起单)、`GET /api/gov/workflows/:id/trace`。

端到端六例(真库):指派生效 / 任务真落到被指派人手上并由他答单 / 下游节点同样生效 /
全链 span 逐层挂得上且耗时齐备 / 一条流一个 traceId / 不指派照旧轮值。五闸全过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 01:43:49 +08:00
ChaiHaoandClaude Fable 5 9df2294f6e Mastra 胶合层:FlowRuntime 的第二实现 —— run ↔ 实例,发号权留在主工程
编译器只管推图,胶合层管一单一单的账(createMastraRuntime):

- **发号权在主工程**:实例号 nextInstanceNumber 算、sys.node_instance 落笔;
  Mastra 不发实例号也不发任务号(spike 实测)
- **run ↔ 实例**:runId = <workflowId>#<seq>,重开 = 新 run(seq+1),旧 run 冻结;
  当前 run 的入口记在 vars.__runEntry —— 重开后从回边目标那份变体起步
- **迟到 / 重复回调不甩给 Mastra**:先在实例表定位、确认是当前 open 的那个,
  不是就发 stale-callback 丢弃(spike 实测:错投的 resume 会打坏 run,
  嵌套下甚至不可恢复)
- **失败走向不进 Mastra**:改道/升审批/容忍都当「从目标节点重新入场」,
  起一个以它为入口的新 run —— 绕开 .parallel() 那套「任一失败即整体失败」
- **状态仍是聚合投影**:refreshState 读 sys.node_instance,不读 Mastra 快照
  (run 只有 running/suspended/success/failed,没有「收敛未到终点=abnormal」)
- MastraRunner 是 Mastra 侧的最小口子(startRun/resumeRun),换版本只改它

四闸过。**尚欠**:MastraRunner 的真实现(Mastra 实例 + PostgresStore 挂
mastra schema)与接线开关 —— 编译器与胶合层都有单测但没在真库上跑过整条流,
转正前自持实现仍是唯一在跑的路径;已如实记进 debt M5-1。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
2026-07-29 00:19:37 +08:00