This repository has been archived on 2026-09-13. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
BPOS-TMP-REPO/CLAUDE.md
T
xcsandClaude Fable 5 5a7bb9b58f fix(w05): 数据工单三病一改 —— 档案卡上桌、类型守卫、prune 跳过已落地
2026-08-31 用户实测三连 + 「设计只是头上加了动画,操作感没变」:

① 类型「自己给上了」:data-by 行缺键落回外层同名字段(debt I3),查名 pill 摆出
  案卷锚(原 PN)的类型 —— 这一行根本没有的值。守卫认 selectCurrent 按行作用域写的
  option[selected]:真选上才摆名,没选摆「待选择」。守卫必须单层 :has ——
  :has() 里嵌 :has() 是非法选择器,整条被浏览器静默丢弃(第一版栽过,预览截图逮回)。

② 「品牌…点保存根本不会保存」:块① 行源是 sub_eval.part,那张案卷表没有主数据列,
  renderTemplate 只认行作用域 —— 保存真落草稿,显示与孪生件永远空白(四步重写后的
  潜伏缺陷:e2e 走 API、浏览器走查在 swap 版上,两条验证线都照不到,真人一填才现形)。
  行源改 mine:parts.profile 本身(S1 ④ prune:true 恒有两行),行里天生有全部列。

③ 「改回同一类型,下面还是两个类型」:②③ 自投影为绕「已落地行撤不掉」的死锁
  (2026-08-30 e2e 案例 2)特意不带 prune,没落地的陈旧行也跟着积在屏上。
  治在平台:draftDrop 加配方专用旗 skipLanded(跳过并出声「N 行已随数据工单入库、
  这一笔不清它」,不炸;模型那一路的硬拒一个字不变),②③ 恢复 prune:true ——
  死锁与积行两头都收,debt「prune 与确认即入库的架构性冲突」销账。
  quiet 拍仍不撤行(F3),清理落在每次确认工单那一拍。

④ 设计:块① 从 11 列横滑表推翻成电路板工作台 —— 深色板底上两张可就地编辑的
  芯片档案卡(SOIC 封装 SVG + 角色/在库徽 + 类型行 + 双栏主数据格),编辑态整卡
  变表单;三级占位(必填红/建议橘)上卡与参数值表;参数值表所属料号列加角色徽。
  嵌套的角色/在库查表全只读(嵌套行里有 data-col 会被 collect 并成一条,测钉死)。

契约:loop-engine port draftDrop +skipLanded/+landed(纯新增,CONTRACT.md 已记,
api-report 已刷)。测:107 包内(三锚变异验证)+ auto-runner skipLanded(变异验证)
+ 2520 全仓;2.7.0 装库 SQL 核过(档案卡宿主/守卫/胶囊/S1 四笔 prune)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
2026-08-31 14:12:10 +08:00

1833 lines
187 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# JCAI-WOS —— 企业级 AI Native 任务操作系统
> 一句话:组织的工作定义为可编排的工作流,工作流由**活动**编排而成;活动是完成一项任务的
> Agent 机制,系统外开发、安装即用。人只在责任点与放行点出现 —— 确定交系统,临场交 AI,落地交人。
## 现状快照(2026-08-22)
- **三面一体**:设计中心 `/design`(九区:蓝图/触发器/流程包/活动库/工具箱/数据域/知识库/
大模型/**测试台:三格 —— 流程(投一封信)/ 活动(按契约填入参)/ 日志(历次试跑存档)**)· 运营中心 `/ops`(六区:驾驶舱/工作流/任务/员工/台账/系统)· 工作台 `/`。
`/gov` 302 → `/ops`。
- **编排层与流程引擎已跑通并测死**:起单宽进(门口不拒缺项)、数据按字段名流动(无强制
类型)、边只表达顺序与条件(对齐 Mastra)、闭合校验只查结构闭合 + 活动装载、一条流恰一个
生效版本、在途按启动版本跑完、版本号与名归设计人员自己定。
- **活动一律案例模型**(2026-07-29 范式退役):flow-engine 已删,业务模型只有
CMMN + 说明书 + DMN 一形;`defineActivity` 已去 `paradigm`,`run` 改为可选 ——
行为全在清单里。`turn-runner` 每拍要 `agent.decide` —— **环境无模型密钥时
案例活动一步走不动**,三套端到端(unified-quote-flow / new-package-flow / testbed-trace)
整套跳过,恢复条件写在各文件头。
- **A1 客户RFQ受理已是真活动包**(2026-07-30):`activities/quote-intake@2.0.0` 经**安装通道
读文件**装入(`seed-activities.ts` 读 `dist/{manifest.json,index.js}`,不经 import ——
与 activities 之间只有安装通道)。五对象台账(record / type_table / verdict / alt_request /
rfq_request)、两张判定表(F-01 完整度 · P-03 三分类)、三条技能、四张 HTML 报告模版;
**案例模型照 SOP 图一步一项**(S1…S6 + 放行,7 项,扁平无阶段)—— v2.0.0 重写:
上一版 12 项(擅自加阶段/里程碑/裁量项)让 Agent 全程跟 harness 较劲,实测无限死循环;
流程包 A1 节点已指向它。其余**五**槽位照旧占位。
- **模型实例**:只留 `deepseek-v4-flash` / `deepseek-v4-pro` 两条;种子读不到
`JCAI_DEEPSEEK_API_KEY` 就**不绑密钥**(卡上如实显示不可用),去治理台大模型区补。
- **A1 已真跑通**(2026-07-30):起单 → Loop 逐拍 → 写台账草稿 → 提交放行 → 人签 →
releaseWrite 合并进正式版 → 发射 intake 口 → `released`。三分类与双去向旗业务正确
(A 直通 / B 寻源 / C 选型)。为跑通它补了 Loop 的七个洞:`write` 行动 · `finish` 宣告完成 ·
进行中的项进局面 · 工具清单进单拍提示词 · 里程碑自达成 · 在途验收不被兜底 save 擦掉 ·
必交付物只数本单草稿。**A1 的槽位 `rfq-intake` 已退役卸载**(库里两个同名活动会骗人)。
- **A1 两条路径都跑通并零卡壳**(2026-07-30):常路五步与最长路径(含 S2 补全卡来回)
各跑一遍 `released`,**行动被拒 0 次**。补全卡走对话卡族(`ask` 行动);
连续 5 拍被拒即熔断交人(`stalledTurns`)。
- **一拍一串行动**(2026-07-30,`AgentTurn.actions`,封顶 6):从前一拍只许一个行动,
每个 write/finish/start 都单烧一遍完整上下文 —— A1 六步恰花 21 拍(19 拍是该约束下的
最短路径)。收成串后 **7 拍 released、56k token**(自 21 拍 173k);纪律引擎强制:
被拒停在谁那儿(前缀生效)、tool 后截断、挂起型收拍。浏览器 UI 点「确认通过」→
released 全链亦验证过。
- **写的授权面是台账声明,不是计划项**(2026-07-30 修死锁):`write` 的 itemId 降为记账,
挂不上(项已完成/人工激活未 start/阶段/不存在)照写不拦、留痕注明。此前绑死在项生命周期上,
实测死锁:S5 收完才发现打标没写全,能挂的项全 Completed,每拍补写被「要先 start T_release」
拒回,连拒五拍熔断 —— 而数据本身合规。台账声明与空转检查仍是硬门。
同批修:`finish` 对非人工激活的项就地过 Active 再收(白按一下省一拍);
事件到达痕**只记 task 层一条**(此前 task 与 loop 各记一条,同一次回传日志三行像结巴)。
最长路径(含补全卡人环)复测:**8 拍 released、64k token、行动被拒 0 次**。
- **每拍时延 20-56s → 1.5-4.9s**(2026-07-30):trace 拆出 tokIn/tokOut/reasonChars 实证 ——
慢全在**隐藏推理解码**(最慢拍可见 1538 字、推理 9808 字)。`ModelCall.reasoning: 'off'`
经 provider-profile 的 `reasoningControl` 译成 DeepSeek `thinking:{type:'disabled'}`
(探针核过;`low` 在该厂无效)。配套:write patch 只带有值列、scope 摊平字段前置整表殿后
(rest 3000→1800)、轨迹剔除装配技能戳、旧出参截 120 字、技能戳版本不变不重写、温度 0.2。
off 档一次误判(缺目标价当关键字段)以**说明书写死规则**治(「关键字段只有 PN/EAU/交期」),
不给思考额度 —— 判断归判定表与说明书,模型只做编排。复测:7 拍 49k token released、零被拒。
- **工作台交互按 PRD 补全**(2026-07-30):①对话区点卡 → 视图区 locate 跳转(待办跳页位、
办结跳成果详情);②工作成果页签真实现(一行一份 → 定稿报告[印章+verdict+嵌 HTML 汇报] →
返回列表);③执行工单挂作业指导书卡组二;④工单办结回执以人事件进对话流,引擎内部观察
(internal 标)与裸「事件到达(human)」不再污染对话区;⑤空待处理四态分明(推进中动画 /
等外部回音 / 都办完了 / 已收尾)。
- **AI 工作中动画**(2026-07-30):对话区**办事条**(均衡条,语义「在办事」不是「在打字」;
三点气泡仍留给回话中)+ 头像呼吸环;空工作区**推进场景**(涟漪 + 微光工作线)。
纯 CSS、只动 transform/opacity、prefers-reduced-motion 全静止;
状态源自任务投影 `runtime === 'running'`,等人/等外部/已收尾不亮 —— 界面不撒谎。
- **活动开发规范已重写为开发手册**(2026-07-30 第二版):销账史砍掉(在 git),
精华收进建模八纪律与排障速查表;余账在 §15(④受理分支误吞验收裁决 ·
⑤治理台白名单授权口 · ⑦dist 真编译 · ⑧单拍工具缝 · ⑨⑩死代码 · ⑪评价卡暂不做)。
语义源两卷(操作系统/活动模型)已归档 `docs/archive/`。
- **实时同步补齐五处**(2026-07-30 第二轮,测试台为引子):①订阅层不失效
`['gov','testbed',*]` —— 测试台全靠 2s 轮询而轮询到终态即停,一单跑完那屏就此定格;
②`testCurrentRoute` 把已终结的试跑单当成「在跑」,旋钮永久锁死(现返回 `live` 分开
「摆出来」与「占着仪器」);③试跑起单/销毁不广播 —— 销毁掉的真任务还挂在别人工作台上;
④**`kind:'system'` 声明了却全仓从未发布** —— 治理台所有配置面(活动/工具/模型/流程包/
数据域/驾驶舱)永不实时刷新;现由 `/api/gov/*` 写路由中间件统一发(一处拦住,新路由自动生效),
任务走到终态也补发一次(台账与指标不以任务为轴);⑤本地 id 活过服务端事实 ——
别处销毁后面板还钉着旧号,显示「取数失败」的鬼卡片(渲染期对齐,服务端说没了就松手)。
订阅映射已抽成纯函数 `invalidateFor` 并按「哪一屏靠什么刷新」逐屏断言(8 条)。
- **MVP 工作流第一轮跨节点跑通 A1→A2**(2026-07-31),并挖出**七个编排缺陷**(全已修):
①六节点绑的是退役槽位 id ②流程包入参还是 `customerCode`+`rfqRef`
③**触发器装配映射是空的** —— 事件触发的 scope **不打底**(只有 registration 才铺 scope),
「同名会自动带过去」是错觉,`subject`/`body` 同名照样缺
④E5 读 `needSourcing` 而 A2 出口不发 ⑤E10/E11/E12 读 `outcome` 而 A6 三口载荷是空对象
⑥A2 要 `originalPn` 而 A1 发的是 `altRequests`(上游发一批、下游要一个)
⑦**自动收步与行动串并行** —— 引擎在拍首收了 T_select,而模型这一拍原本就打算 write 完再 finish,
`Completed → Active` 当场抛非法迁移,连拒五拍熔断;现与 `start` 同款:收过了就当已完成。
④⑤⑥ 同一类:**边读什么 / 下游要什么,上游就得发什么** —— 光测单活动测不出来,只有真跑跨节点才现形。
- **六个活动全部转正为真活动包**(2026-07-31):`REAL_PACKAGES` 六件齐,经安装通道读
`dist/` 装入 —— 治理台里不再有 `viewTemplates: []` 的占位槽。六份案例模型统一到 A1 的
状态机模式(剧本 `steps`:intent / guide / writes / tools / doneWhen):
**A2/A3 各只有「派一张执行单 + 放行」两项**(专家判断,建细了只是跟 harness 较劲);
**A4 定价**三项(算价归判定表 · **超限才叫人**的决策卡 · 放行);
**A6 议价**三项(落单 · **发出去人工激活 + 立监听等回音** · 放行);
**A7 归档**两项(一步落三张表 —— 它们互不依赖,分开只多两次 finish)。
凡触达世界的项一律不给 `doneWhen`(给了等于给引擎一把替人签字的钥匙)。
- **A2/A3 的简化口径**(同日):案例模型从九个 humanTask 砍成**两项** ——
`T_select`/`T_source`(派**一张执行单**,卡面两张可编辑表)+ `T_release`(人工激活)。
上一版把「FAE/采购脑子里怎么想」当成了「系统要管几步」;而那一整段在业务上是**一件事**。
剧本与 A1 同一套(`doneWhen` 真了引擎自己收步)。`REAL_PACKAGES` 已含这两个,
不再是治理台里 `viewTemplates: []` 的占位槽。
- **判据三态 + 表格默认锁着**(2026-08-01,`quote-intake@20.0.0`,用户两问):
①「这条未达标为啥还在」—— `acceptanceCriterionCheckSchema` 只有 `{label,level,pass}`,
**裁断与理由传不到卡面**,于是「裁了但裁成不满足」与「压根没裁」都是一个红叉。
补 `settled` + `rationale`,卡面变三态:达标(绿)/ **AI 判为不满足 · 交你定**
(琥珀 + 左侧色条 + 理由)/ 未达标(红)。更早的注释写着「理由随卡交给人」——
**那句话描述的行为从来没实现过**,因为契约里没有那两个字段。
②**表格默认锁着**:每张可改的表各带一道闸(`[data-edit-for]`),锁着只出「编辑」,
开了换「取消 / 保存」;取消还原成按下那一刻的值,保存才交给外层缓冲。
**看与改是两件事** —— 从前一进屏 54 个输入框一起亮着。
途中踩了跨 realm 陷阱:`event.target instanceof Element` 在 iframe 元素上**恒为 false**
(`Element` 是父文档的构造器),症状是点「编辑」毫无反应而 class/CSS/选择器逐个查都对。
**认能力不认血统**;监听挂载也改成幂等的(srcdoc 换文档时机抓不准,每次有机会就挂一遍)。
验收:6/6 released;浏览器里走完「编辑→改→取消还原→再改→保存→提交」,落草稿层。
- **A1 连跑 10/10 全 released、行动被拒 0 次**(2026-08-01,`quote-intake@19.0.0`,
10-11 拍 / 99-112k token)。基线是 5 轮熔断 1(其中一轮 13 次拒回、23 拍、234k token)——
五处 harness 改动逐轮逼出来的(见下两条与 `docs/debt.md`)。
- **最后一条自报的机检判据也交给基座数**(2026-08-01):台账字段声明加 `required`(可选,
不建 NOT NULL —— 草稿层的本分就是过程中允许缺),基座据此出 `域_对象_missing` 与
`_missing_keys`(缺在哪几行、缺哪一列)。A1 的「必填齐(PN/年用量)」原读活动自写的
`missing_key_total` —— 人在卡上补了年用量、基座已写回草稿层,而那个数要模型自己重算,
**漏算一次这道门就再也开不了**:十轮里三轮死在这。这是「机检只许读基座数得出来的数」
这条纪律第二次被违反,第一次是 missing_minor_total 被改小那次。
- **Harness 三条死胡同已通**(2026-08-01,连跑 A1 摸底逼出来的:5 轮熔断 1、再 6 轮熔断 2)。
三条全是同一个病 —— **判据正确地拦住一件办错的事,而模型没有一个动作能把它办对**:
①**写错一行没有退路** → 加 `drop` 行动(`ledger.draftDrop` → `DraftStore.drop`):
只撤本单草稿层那一笔,正式版一个字都动不了、不抛事件,**不是第四种写**。
起因:客户明说本轮跳过的那颗料被写进有效清单,数全对(9 有效/1 跳过)而表里 10 行,
`record_rows = line_total` 拦住 —— 模型唯一能改的是那个数(改了 skipped_total 又不对),
13 次拒回、23 拍、234k token;
②**拒回只给数字** → 读数连**主键名单**一起摆(`域_对象_keys`,封顶 12 行):
两份名单一比,多的那个 PN 就在里面对着,一句话能办的事;
③**拒回把模型指上死路** —— 「要先 start,当下是 Completed」,而 start 一个 Completed
项同样被拒,两堵墙对着撞;现按状态分开说,且 start 已收的项改为无事发生。
**拒回的话是模型下一拍的行动指南,指错方向比不给指引更糟** —— 同一条也改了提交门的
结尾建议:先分清差的是**数**还是**行**,行不对就 drop,别去改数。
顺带:**收步判据与验收判据同源**(S2/S5/S6 都改读基座的 `_rows`)——
松出来的那一截就是返工;S2 那条把「多写一行」的发现点从第 10 拍提前到**第 2 拍**。
还删了孤儿模版 `intake-gaps`(7 处 `view:` 无一指向它)。
- **对话区一轮一句(不是一拍一句)**(2026-08-01,用户:「太密集了」):形状是
**设定目标 →(分析现状 → 规划 → 执行)× N 轮 → 一个气泡**,气泡可以是仅结论,
也可以是**结论 + 功能卡两部分**。三处:①`turn-runner` 的 `handsOff` ——
只有交出控制权那一拍(ask/human/decide/listen/submit)的交代进对话区,
别的拍留进工作日志(`internal`);②提示词与 say 字段说明明写这条规矩,
否则模型照旧每拍写播报、只是被默默丢掉(白烧 token 还写不好总结);
③`chat-projection` 把交代与卡**并成一个气泡**,并把收尾三条引擎回声
(裁决 / 发口 / 终态)收成一条。并卡的判断按**来路**认(只有 terminal 不认领卡)——
一度写成 `tag !== 'conclusion'`,而交代本身常是结论口吻,于是第一轮并对、第二轮没并。
账:同一条 11 拍的 A1,对话区 **9 条 → 5 条**;压下的 8 条交代一条不少留在工作日志。
- **放行卡不摆 L5、去向不再有 L4 裁量**(2026-08-01,用户当场指出):
L5「BD 放行」是**责任关**,而那张卡本身就是这道关 —— 列进判据表等于摆一条恒为
「未达标」的项,「n/m 达标」永远差一条;声明留着、呈现去掉(滤在基座组卡处,六活动通用)。
L4「去向判断合乎业务常理」删掉 —— 去向已由出口谓词算出,再让模型裁一次是**给自己
没做的决定盖章**:裁「满足」是废话,裁「不满足」也改不动什么(能改的是三类条数,
那已由 route-alt / route-rfq 两条机检看着)。**判据得能指向一个可做的动作。**
- **三个区各归各位:件归工作区,判据与指导书归对话区**(2026-08-01,`quote-intake@14.0.0`,
用户指出「你用你自己的报告格式嵌套了一层我要的报告格式」):工单报告组件自带一整套外壳
(题头/编号带/依据带/判据表/章节头),又把活动推的那一屏包在里面 —— 两套版面语言叠着。
现在 **待处理与工作成果只放那份 HTML 模版**;作业指导书 · 依据 · 判据 · 填报表单 ·
**提交与裁决**全在对话区的卡上。**待处理是可编辑态**:可改的格子在模版里挂 `data-col`、
行容器挂 `data-edit="域.对象"`,渲染时每格多渲一个 `<input class="jc-cell">` 孪生件,
只读那份与输入那份**由样式表按根节点的 `editing` 二选一** —— 同一份 HTML 两处用,不存两份。
收值在外层(`allow-same-origin` 读得到 DOM),**iframe 里仍然一行脚本都没有**;
收上来按台账地址对上工单 `blocks[i]` 的 `ledger`/`fields`,仍走老的 `table:N` 回传。
同批修两个只在真人点的那条路上现形的洞:①**监听挂在 about:blank 上** ——
`srcDoc` 异步换文档,渲染那刻挂的监听随旧文档作废,人改了两格提交时载荷一个字都没有;
②**算出来的去向没交回去** —— `routedPort` 那一路 `selectedPorts` 恒空,按「确认通过」
当场判「选择组未选出口」,台账都合并进正式表了单子却死在最后一步(`blocked`)。
验收:浏览器里走完两道人环 —— 件上改两格 → 提交 → 落草稿层 → 放行 → **released**,
九行数据(含人补的 eau/brand)落进正式表;工作成果那一屏零输入框、零外壳。
- **阶段2 补回成一项:受理需求交人审定**(2026-08-01,`quote-intake@13.0.0`,用户指出
「我都没确认需求 它就让我验收了」):「经过人」从前不是一项,而是归一那步收步条件里的半句
`missing_minor_total = 0 or answered_total > 0` —— **只在缺东西的时候才叫人**。
一封字段齐全的询价进来,这半句在拆完那一刻就为真,引擎自己把那步收了,
人一眼没看过受理需求,下一次被叫到已是终局验收。现在 `S3_confirm` 是独立一项:
**人工激活 + 不给 doneWhen**(与放行同款),`view: intake-overview`,一单必发一张;
S4 的入场前提改读 `confirmed_total`(只有人回卡才产生的数)。
规范 §7.1 立纪律 3.5:**判据是「这件事办完了没有」,不是「要不要办」**。
连带修掉一个零条死锁:**没写过 ≠ 写了 0 行** —— 全 A 类那条路上替代请求表一行没写,
`quote_intake_alt_request_rows` 整个键不存在,而判据 `= type_c_total`(0=0)本该成立,
未绑定的名字比较为假 → 永远过不去、连撞五拍熔断;现按 `declarations.ledger` 先铺 0。
验收:常路 **11 拍 released、被拒 0**;全齐无 C 类那条 **10 拍 released**、去向 `to-sourcing`。
- **A1 两份报告改为从 PRD 目标件整份搬过来**(2026-08-01,`quote-intake@12.0.0`):
`views/prd-style.ts` 是机械抽取的整段样式表 + 图标精灵(`PRD_CSS`/`PRD_SPRITE`,数值未改),
`views/report.ts` 逐块搬标记、只把写死的数据换成绑定 —— **不再用 `@sdk` 拼装件复述**
(那套外壳有自己的版面语言,「照着做」出来的是第二种版面;前三轮报「25 块到位」都是
结构断言,对版面零约束)。规范 §10.3.1 立此法:**视觉目标件只能看,不能用 DOM 断言验收**。
连带三件:①**`data-class-of` 不再以 `data-slot` 为前提** —— 纯色块(格里不写字、只按值上色)
从前整条静默失色,屏上一排灰格子看着像「还没算出来」(补 4 条用例);
②**去向进视图**:`case:routeKey/routePort/routeTo/routeWhy` 由基座按出口谓词求值后注入,
与放行发口是同一次判定,报告只摆不算(分布条按条数分宽也走同一招:条数投影成 class + 宽度梯子);
③`contact_name` 落进 `verdict` —— 老客户不重写主数据,联系人卡从前会显示公司名。
端到端复跑:**10 拍 released、96k token、行动被拒 0 次**,去向 `to-alternative(type_c_total > 0)`。
- **A1 五轮端到端全部 released**(2026-07-31):行动被拒 **0** 次,判据 7/8(只剩 L5 人放行)。
跑测逼出并修掉两个「人答了什么 Agent 看不见」:①可编辑表的修改只活在组件局部 state,
回传载荷一个格子都没有(加 `onTableChange` 链,键 `table:N`、首行列名);
②决策卡选了哪个不进轨迹(`payloadOf` 只认 values/output/error,补 `detail.value`)。
两者都会让 Agent 重发同一张卡 —— 人以为自己白填/白点了一次。
- **工作台空占位统一**(2026-07-31):任务那一栏的空态从裸 `execution-panel` 改挂
`jc-panel-card`(其余四模块一直有,只它是画布上飘着的一段文字);
`.jc-empty` 由固定内边距改 `margin:auto` + `justify-content:center`,在栏内真居中。
- **活动状态机:每步一条剧本,成果已在就自己收**(2026-07-31,治 A1 空转)。
`LoopModel.steps` 一个计划项一条:`intent` / `guide` / `writes` / `tools` / `doneWhen`。
引擎每拍开头先对任务视图求 `doneWhen`,**真了就自己 finish 那一项,不问模型**
(人工激活的项不自动收 —— T_release 触达世界,不给它 doneWhen);
上下文按状态组织:只摊开当前这一步的做法与它该用的东西,其余步骤各留一行。
起因是实测死循环:S1 一次写齐八字段后 S3「补齐八字段」已无活可干,而每拍喂整本说明书,
模型只能把同样三行再写一遍 → 「写了等于没写」被拒 → 下一拍再来一遍,连拒到熔断。
**`doneWhen` 的坑**:S-FEEL 里未绑定的名字 `!= null` 求值为 **true**,写它等于那一步开局即收;
布尔列也不能当判据(分不清「没写」与「写了 false」)—— 一律取同步写下的计数列(测里拦下过)。
实测三连:**A1 三次端到端全部 `released`,行动被拒 0 次,S3 每次自动收步**;
8 拍 / 58k token(状态机之前是 11 拍 / 82-90k)。
- **决策卡 Agent 侧接通**(2026-07-31):新增 `decide` 行动(contract / port / turn-runner /
engines / 提示词 / 解析)。此前决策卡**只有 UI 没有 Agent 侧**,岔路口只能写成补全卡 ——
人拿到一张要敲字的表单而不是两个可点的选项。少于两个选项拒发。
- **真实文件进得了活动**(2026-07-31):`sys.upload`(迁移 0024)存原字节 + 读出来的文本;
`POST /api/gov/upload`(base64,8MB 封顶)/ `GET /api/gov/upload/:id`;
xlsx **不引依赖**自己读(ZIP 中央目录 + `inflateRawSync` + XML,13 条测试);
契约字段标 `format:'file'` → 测试台出文件选择器。读不出文本的类型如实说读不出。
- **沟通记录接通**(2026-07-31):`sys.task_comm`(迁移 0025);活动清单声明
`contract.input.inboundComm`(哪几个入参字段合起来是那封来件),基座**起单那一刻**归档 ——
人一点开这单,沟通记录里就已经躺着那封信,不必等模型跑几拍。附件那一行照抄基座的读取说明。
- **测试台改三格 + 试跑日志**(2026-07-30):两档旋钮长在内容里(别处跳不进来、刷新记不住
试的是哪一台,第三样东西也塞不进二档),提到页签 —— **流程 / 活动 / 日志**;单在另一台上
不抢页签,只挂一句「它在那边」。日志是**拔之前先存一份**:停止仿真照旧连根拔掉,拔前
`archiveRun` 存一条(逐拍轨迹 + 台账草稿 + 发出去的人卡 + 读数),**一次试跑一条**
(流程包把名下节点任务合成一条,痕带节点名前缀、按时刻排);可单删可清空,`reset-runs` 一并清。
库表 `sys.testbed_run`(迁移 0023),路由四条挂 `/api/gov/testbed/logs`(写路由中间件自动广播)。
顺手修:单活动那一台的负责人下拉掉进 `.tb-asn-r` 的 40px 那一格(它比流程那台少一列),
现给 `.solo` 四列版 + 插座列加宽到 184–238px。
- **台账列归型前移到写入那一刻**(2026-07-30):模型用 `""` 表示「原文没给」,草稿层照收,
到 `releaseWrite` 才被 PG 掀桌(`invalid input syntax for type double precision: ""`)——
**而那是人签完字之后**,整单落 `blocked`。现在 `draftWrite` 按声明列型归:空值=不写这一列、
数值/布尔字符串转真类型、归不了当场拒(理由喂回下一拍)。台账字典也带上列型给 Agent 看。
- **前端实时刷新已通**(2026-07-30):前端那一侧一直是好的(单条 SSE + 按前缀失效缓存),
三处**后端没广播**:①`task-advancer` 只在 runtime/terminal **换名字**时广播,而案例活动
连跑十几拍全程 `running`(改为 `progressed` 即广播);②`interaction` 的推送一个订阅者都没有
(加 `onPush` 系统级转接);③发消息不经事件投递,收件人的消息气泡不动(outbox 处补广播)。
- **四类人类工具:前三类已通**(2026-07-30):执行(工单 · 报告页填报提交)、
**补全**(对话卡 · `ask` 行动,两条路必走其一)、验收(工单 · 判据表 + AI 已填好可编辑 +
裁决在对话区)。决策卡(第四类)UI 已在、Agent 侧未接。
验收修订链原来断在五处「声明了没接线」——契约 `revisableAtRelease` 定死哪几个值可改、
改完落哪儿;拟值放行前从台账现读,不让模型重述。
- **A1 的两份执行页照 PRD 目标件重做并跑实**(2026-07-31,`quote-intake@9.5.0`):
`~/coding/JCAI_PRD/docs/活动执行页/` 的两份 HTML 是「办完该长什么样」的答案 ——
**询价受理需求**(来件原文 → 受理要素四卡 → 指标带 → PN 清单 → 本轮不报)与
**统一受理记录**(要素 → 逐条记录带标 → 分级依据 → 分流去向 → 两类请求 → 结论 →
这一签下去会发生什么)。`@sdk` 补 `letter` / `factCards` / `actionList` 与列样式
`req`/`opt`/`num`/`pill`;`data-blank` 让空值真的留空,必填/选填胶囊与缺项标底
由模版自己的 CSS 出 —— **模版仍不许算**(分布条宽度、命中高亮这类算出来的画面一律不做假)。
顺手删掉 `@sdk` 里五个零调用方的拼装件(kvCard/tableCard/noteCard/stagesCard/critList)。
- **A1 六轮端到端,末轮九行数据全对**(2026-07-31):每轮 `released`、**行动被拒 0 次**,
9-10 拍 / 76-89k token。逐轮逼出并修掉五个洞:
①**机检判据两边都由活动自报** —— 条数报 9 而表里 10 行、三类条数报 7A/2B 而判定器给
5A/3B,派单数同源同错于是「2 = 2」顺利过关;现加基座读数 `域_对象_rows`(本单写下几行),
判据必有一边不是自报,`classify` 出参也带 `counts` 供照抄;
②**问过 ≠ 答过** —— 收步判据写 `asked_total`(卡一发就为真),人填完提交这一步当场被收,
答案没轮到写回台账;改等 `answered_total`;
③**归档件被冲掉** —— 收口后引擎再跑一拍,推固定的 `case-overview` 退到「声明的第一张」,
把人刚签过的放行页冲成阶段二的执行件;现按剧本 `view` 推、活步收完不推;
④**说明书与剧本各写一份六步**,分叉出三个案例模型里不存在的计划项名(S1_register 等),
模型照它报 itemId 一报一个被拒;说明书现在只讲整单的事,逐步做法归剧本(有测试钉死);
⑤三类数据失真(PN 抄漏后缀→同一料两行、数值缺失写成 0、制表符 BOM 拆错列)——
逐条在说明书里写死实测账。
- **Harness 可靠性:三处「门本身教模型撒谎」已修**(2026-08-01,两条样例路径连跑逼出来的):
①**机检判据读活动自报的数** —— 一颗料只缺目标价,模型如实记 1、被连拒四次,
第五拍把那个数**改回 0** 就绿了(台账从此写着「缺选填 0 条」);
**机检只许读基座数得出来的数**,数不出来的别假装机器判得了 —— 该条已降 L4 交人;
②**裁量判据也被要求「为真」** —— 它如实裁「未满足」并写了理由,提交照样被拒,
判-提-拒十二轮 21 拍 187k token,最后把裁断翻成「满足」才过去;
提交门已改:机检必须为真、**裁量裁过即可**,裁断连理由随卡交给签字的人;
③**熔断数不出「同一堵墙」** —— 拒回标题带着串位(「第 2 个」),整条一比成了 N 堵墙,
叙事窗 20 条也装不下几次撞墙;一单被同一条判据拒回 **33 次**、40 万 token 烧到
`exhausted`。已修:削掉串位前缀比对 + 熔断另开 60 条窗。
顺带:计划项号认唯一前缀简写(`S4` → `S4_history`)。
**验收**:Itelma 与新客户两条路径各三轮全部 `released` ——
10 拍 / 88-90k / 被拒 0 与 9-11 拍 / 71-88k / 被拒 0-1,数据逐轮对得上。
- **执行页补到「能做的极限」**(2026-08-01):新增 `data-class-of`(把值消毒成 class 后缀,
仍只是取值,判断留在样式表)—— 于是类标 A/B/C 三色、两枚旗的是/否、**一条料一格的刻度条**
都真做得出来;要素卡补方/圆标(方=组织、圆=人,里面放图标不放算出来的首字母)与大号计数;
G2 那段改成**三条规则连着本单计数**的规则表 —— 命中由编排层求值,这份件不画对勾替它宣布。
仍不做的只剩两类:按条数分宽的分布条(宽度得算)、编辑态(沙箱无脚本,改数走执行卡)。
- **试跑日志吞主键已修**(2026-08-01):存档那一屏只渲染 `patch`,`key` 整个不显示 ——
三行受理记录屏上只剩「eau / lead_time」,看的人据此判「PN 没提取到」,而 PN 一条不少。
两处观测面已合并到 `gov-testbed/internal/drafts.tsx` 一份实现。
- **就地改的三处不老实已修**(2026-08-02,同一单实测逼出来的):
①**保存按地址走,不看当下那张卡** —— 载荷从前是 `{workOrderId, values:{'table:0':…}}`,
列名由那张工单的 `blocks[0]` 给出,于是「这份件能不能改」被绑在了「此刻开着的那张卡
长什么样」上。一单在放行门连拒五拍熔断,引擎发的是**没有 blocks 的熔断卡**,而屏上摆着的
正是受理记录那份件 —— 闸在、编辑进得去、保存按得下,前端找不到匹配的块,**一格都没往下送**;
人要补的恰恰是把这一单卡在那儿的那个必填格。现在收件自己说的话(`data-edit` 地址 +
`data-col` 列名),授权面改由**活动清单的台账声明**把关。
②**必填还空着就按不下提交**(`ExecutionWorkOrder.gate`,基座按声明现算,
与放行门 L1 `域_对象_missing = 0` **同一个数同一套算法**);闸上摆出差在哪一行哪一格,
人在件上补齐、保存,闸自己开。算不出来(卡上没绑表)就不给闸 —— 没有依据的时候不拦人。
③**只写真改了的那几行**:件上按一次保存整张表都回传,照单全写会留「就地修订成果:4 行」
的痕而人只改了一格。
端到端:12/12 判据、`released`、被拒 0(另一轮 3 次、亦 released)。
- **日志只有三色**(2026-08-02 用户定):负责人绿 · 智能体蓝 · 系统灰(`LogLine.who`)。
从前按归侧上五色 —— 那是**度量**的分法(自主率要把「等外面」与「机器干的」分开),
对读日志的人不构成区别。连带两件:放行那一刻四条痕说的是同一件事(合并 / 发口 / 流转 / 终态),
日志只留说得出实情的那一条(带「几行没进正式表」);台账写入认 `by` 定主语 ——
放行合并归系统,人工修订归人。
- **件上的表能增删行**(2026-08-02 用户:「编辑列表应该还能增删行」):手改本来就是
**兜 AI 的错**那一手,而错不止「这一格填错了」——「这一行根本不该在」(客户点名跳过的料
被写进了有效清单)与「漏了一行」是同一类错,只给改格子就没有出口。
序号那一格编辑态换成 ×(一列两用),表尾一条「加一行」;删是**挂记号不当场抹掉**
(看得见、可后悔),「取消」把加的撤掉、把记号摘掉、把值放回去,三样一起才叫还原。
**删要说出来**(载荷 `drops`),不靠「没回传就是删了」—— 那种口径会把一次不完整的回传
变成一次删表。撤的只是本单草稿层那一笔(`draftDrop`),正式版一个字不动。
痕里点名撤了哪几行并写「别再写回去、条目数跟着改对」—— 那条痕是**下一拍模型的行动指南**,
不说清它会照「条目数 9 而表里 8 行」判成少写了一行,把人刚删的写回去。
实测:删一行 + 加一行 + 补必填 → **released、11 拍、被拒 0**。
- **裁量判据带谓词时谓词说了算**(2026-08-02 用户:「这个价格是我填写的,但是它判错了」):
「选填缺口:已补齐,或由你放行时确认可以先受理」是复合命题 —— 前半句基座数得出来
(`域_对象_gaps`),后半句才需要人。从前整条只读裁断,于是模型凭记忆写理由,
人填好的目标价它照样判「客户未提供」(复现的那单更离谱:两行年用量都填着,
它写「共 4 处选填缺口」,而 EAU 压根是必填)。现在谓词为真即达标、**那句相反的话一并丢掉**;
谓词为假才轮到裁量。同批:验收卡的判据改为**读时现算**(`container.checks.of`,
与提交门同一段 `criterionCheck`)—— 人在成果件上补一格,判据跟着变;
`remark` 不再算选填缺口(它是我方写的注,不是客户该给而没给的)。
- **作业指导书与验收判据同一套版面**(2026-08-02 用户定):从前指导书是一串松散的圆点、
判据是一摞带章的行,同一张卡上两套版面语言。差别只留一处:**指导书不画对勾** ——
它是要办的事,系统并不知道人做没做。执行卡那一钮也改称「查看工单」。
连带挖出:**引擎压根不往下传 `steps` / `standard`** —— 活动照骨架写了,发卡时一个字
都没到卡面,人拿到的只有一句「请核对确认」。空着不是简洁,是把交代省掉了。
- **建客户要公司与联系人都经人确认**(2026-08-02 用户定):录入卡加 `also` 段 ——
一张卡两段(公司档 + 联系人档),确认一次落两行,值按 `段号.列名` 隔开
(两张表都有 `name`,平铺会互相盖掉而没人看得出来)。从前联系人由 AI 自己写,
而 `contact_code` 恰是它编出来的那一个。
- **该问人的问人,人答不上来的别摆到他面前**(2026-08-02 用户两条):
①卡面摆的是台账登记的**表人读名**(「客户档案」),不是 `customer.profile`;
主键行只摆表单里没有的那几格、用中文列名 —— 从前一句「主键 customer_code=待定」
既是英文列名,又在替一件他马上就要做的事做旁白。
②**自增列不问人**:声明加 `FieldDeclaration.auto`,标了的列压根不进表单,
写入那一刻由基座按「同组其余主键值-两位序号」生成(`CU-9001-01`,序号数正式版 + 本单草稿,
同一单连加两位也不撞);卡上另摆一句「由系统按顺序生成,不用你填」——
**不能一声不吭地拿掉**,那样人会以为这张档少了一格。
- **放行卡砍掉四条判据,办结后换成落地结果**(2026-08-02 用户定):
`downgrade-safe` · `route-alt` · `route-rfq` · `typed-on-record` 四条都是**内部一致性**
(打标依据对不对、几类料开了几张单、两张表行数齐不齐)—— 该由引擎自己看住,
而放行卡是给签字的人看的:一屏九条,真正要他过目的那几条反而淹了。
落地那一侧不因此变松:同一批基座读数仍在 S5/S6 的收步判据里。
**办结之后那一屏换成「这一签下去发生了什么」**:进了哪几张表各几行(摆表的人读名)、
转去哪儿了(摆出口的 description)、试跑挡下几行 —— 判据说的是签之前要核什么,
签完再回看,那一摞对勾答不了这个问题。事实取自放行那一刻的**结构化留痕**
(`ledger-write` / `release-verdict` 的 detail),不解析日志句子。
- **判据措辞写全,两张卡的按钮统一**(2026-08-02 用户定):
「客户已确认(认出或已建档)」→「客户已确认:发件邮箱认出为老客户,或已为新客户建好档」,
五条同批改写;执行卡与验收卡那一钮改成同一形状 —— 图标一格、**四字粗体**
(执行工单 / 验收工单)、小字说明、右侧箭头,且四字在上小字在下(从前是反的)。
- **执行工单说的是「哪几格必须有、哪几格值得追」**(2026-08-02 用户定):
A1 的作业指导书从「怎么核表」改成逐项建议 —— PN/年用量必须有(缺一条走不到放行)、
目标价尽量试探出来、客户料号对齐回价单、品类与制造商能填就填;
收口标准写明「问不到的留空并在备注里写明,放行时由你决定先受理还是退回」。
- **A1 不再开请求单**(2026-08-02 用户当场定):`alt_request` / `rfq_request` 两张表
连同 S6 的开单动作、两个派单计数列、报告里那两张明细表一并退休。原话:
「这两项数据不在这里产出;随令牌流向下一个节点的只有工作成果验收内的内容;
进入选型替代后,活动会自己归一需要的数据」。从前 A1 逐条开单交给 A2/A3 ——
那是**替下游把它的输入先摆好**,而下游本来就要照自己口径归一一遍:
同一份事实两处各存一份,改一处就分叉而没人看得出以哪份为准。
S6 的收步判据改读 `route_decided_total`(旗是布尔,分不清「没写」与「写了 false」)。
报告同批瘦身三处:两张请求单表 + 那条对账说明、「受理结论」四格表、
「本轮不报 0 行」横幅 —— 后两者要么与别处重复,要么九成时候在说「没有」。
- **消息不再被内部事件刷屏**(2026-08-02 用户:「消息怎么总莫名其妙的出内容」):
「无主入站待认领」从前只看「有没有主 + 有没有人接住」,于是**台账写一行发的
`data` 事件**也进兜底 —— 装一次活动包就往三个人收件箱塞十几条
「无主入站待认领:(无主题) … 原件:无」。判据加一刀认**来源**不认类型:
同样是 `data`,从通道进来的是件、台账写出来的是事实;只有 `source.kind === 'channel'`
才谈得上「无人认领」。顺带:顺利收尾那条 `终态:released` 不再进对话区
(落地结果那一屏已经说全了,且它摆的是英文状态名);没顺利收尾的仍出声,措辞取
`TERMINAL_STATE_LABEL`。
- **一道只认「有人写过」的门等于没有门**(2026-08-02,用户送来一单熔断的实测):
那一单跳过 S4/S5/S6 直接提交放行 —— 受理记录三行一个标没打、分类表一行没写,
却进得了放行门。查出来三个洞:
①**放行门的入场哨兵 `s_routed` 只有 onPart 没有 ifPart** —— 「往 need_sourcing 写过一笔
就开门」,模型顺手写了个 `false` 就把门推开了。现在认**办完了没有**,
且三个数全由基座现数(打了标的条数 = 记录行数、去向定过了)。
②「每条都已打标」这条 L2 读的还是活动自报的 `untyped_total` ——
「机检只许读基座数得出来的数」**第三次**被违反(前两次:missing_key_total /
missing_minor_total)。改读 `_type_tag_a + _b + _c = _rows`,两边都是基座出的数。
③**拒回把「活没干完」说成了「数或行对不上」** —— 那一单数是对的(诚实报了 3 条没打标)、
行也是对的,而话术只给「改数 / 改行」两条路,还明写「别为了过判据去改那个数」,
正好堵死它唯一想走的门,于是原样重提五拍熔断。现在判据点名的表若**这一单一行都没写**
(基座 `_rows` = 0),就直说「那一步还没办,回去办了再来」。
**指向两扇打不开的门,比不指还糟。**
- **验收那一屏是活动的收口,答两件事**(2026-08-02 用户定):①落了什么 —— 按**交付物**点名
(`RequiredDeliverable.ledgers` 说清一份成果由哪几张表承载:A1 的受理记录 / 分类表 / 结论
是**同一份**询价受理记录的内部结构,从前各占一条,人在成果面上看到三样东西);
②往哪儿去 —— 转出哪一口、**带过去哪些字段**(载荷即已落地的事实,摆列名不摆值),
一个口都没发就直说「到此为止」。同批:`统一受理记录` 全仓改称 `询价受理记录`;
成果列表执行蓝 / 验收绿两色;办结卡那一钮改称「打开报告」。
- **签完到收尾之间有自己的话**(2026-08-02 用户:「点完验收按钮后会闪一下中间态」):
那不是渲染毛病,是**真的中间态**(合并 / 发口 / 落终态还在跑)。从前它落在通用四态里 ——
待办清零先闪一句「都办完了」再跳「已收尾」;那句话在那一刻是对的,可它说的是另一件事。
现在这一段说「字已签下,正在落地」。**中间态本来就该说出来,只是要说对。**
- **进度条漏了一格,和一条已经不存在的路**(2026-08-02 用户送来一条实测日志):
①`INTAKE_PHASES` 漏了 `S3_confirm`(它是 08-01 才补回成一项的)—— 计划项六个、名单里五个,
于是 S2 一收进度条当场跳到「判定去向」,而人这会儿正对着受理需求审定那张卡:
**他手上办的那件事在条上没有格子**,条却已经走过去了。补成四格
(定位客户 / 归一受理 / 交你审定 / 判定去向 + 基座统一加的放行收口),
包内自测钉死「除放行外每一项恰好属于一个阶段」。
②说明书里还留着「人交回来还缺必填,就再发一张卡」—— **提交闸上线后那条路已经不存在**
(缺必填按不下提交),模型照它办,每次都撞在「这件事刚问过,人也答过了」上,连烧四拍。
改成「这张卡一单只发一次」;同时把提交闸补到**服务端**(收下回传之前把住)——
说明书向模型承诺「卡回来时必填一定是齐的」,那句承诺只有服务端拦得住才算数。
- **话说的范围要盖住门拦的范围**(2026-08-02 用户问「为什么会少了 start」查出来的):
提示词那条规矩写的是「标了『须你启动』的项要先 start **再调工具**」——只说了调工具;
而拦截那一侧(`readyToWork`)管的是 tool / ask / human / decide / entry / finish 一整片。
模型那一拍要发的是 `human`(派工单),照字面读这条规矩管不着它,于是漏了 start,
撞上「S3_confirm 标了人工激活,要先 start 再干活」白烧一拍。**话窄一格,模型就正好漏在那一格上。**
写全之后三案例复跑 **全部被拒 0**(案例三从 14 拍 126k / 被拒 2 → 11 拍 97k / 被拒 0)。
同批两处呈现:目标价改左对齐(右对齐是给要竖着相加的数用的,这张表一行一个料、彼此不相加);
待处理那一屏表上方加**缺项红带**,点名还差几格、差在哪一行哪一列 —— 两个数由基座现算
(`_missing` / `_missing_keys`,与提交闸、放行门 L1 同源),「一格不缺就别出这条带」
交给样式表(`data-class-of` → `v-0` 那档 display:none),模版仍不算也不判。
- **A1 三案例常备**(2026-08-02):全 A 类直通 / 客户点名跳一条 / 新客户中文正文列料缺必填 ——
三条来件形状真不同(俄文 BOM 附件、正文点名跳料、中文正文列料无附件),
末次复跑 **3/3 released、全部被拒 0**(11 / 10 / 11 拍)。
- **A2/A3 按复杂活动 MVP 简化形完整重写**(2026-08-02 用户改盘:「MVP 期间只做精美验收报告 +
一张执行单,提交就是输出」):`quote-alternative@3.0.0` / `quote-sourcing@3.0.0`,各四项扁平
(归一 → 一张执行单交人 → AI 判稳/齐检 → 放行)。**A2**:挑 C 类组单交 FAE 系统外选型填回,
替代料查库行情**判稳定标**(≤90 天且稳转 A,否则转 B;尺与 P-03 的 A/B 行同一把),
询价受理记录就此转成**询价受理清单**;出口 `alt-route` 两口带 when(还有 B → to-sourcing,
全 A → to-pricing),verdict 落 `need_sourcing` —— **E5 自此第一次真正成立**(从前 A2 台账
没有承载列,那条边恒假)。**A3**:归一**目标报价清单**、A 类行按库内历史价预填
(`price_basis` tally HIST/SOURCED)、PRM 执行单补货源价 —— `base_price` 标 `required`,
件上红带 / 执行卡提交闸 / 放行门 L1 三处同源,实测闸真拦(单飞两颗料只填一颗,
交卷被点名「缺底价」)。判据全读基座读数(旧版两活动各两条 L2 读自报数,全部置换);
GRADE_DMN / STRATEGY_DMN 两张零求值器判定表、shortlist/benchmark/supplier_quote/compare_table
四张不再产出的表、两个死 `run()` 全部退役留墓志铭。报告各一张件贯穿在办与归档
(`alt-roster` / `sourcing-roster`,PRD 版面语言拷自 A1;A2/A3 无 PRD 目标件,用户定沿用自造)。
**验收:A2 3/3、A3 3/3 全部 `released`、行动被拒 0**(6-7 拍 / 38-47k token),
三案例形状真不同(流内混行载荷 / 免寻源转 A / 单飞宽进自造案号)。
`contract.input.required` 一律空(用户定:宽进严出,输入契约在活动内归一+补全)。
同批:A1@43 出口撤空壳 `altRequests`/`rfqRequests`(表已退休,数组通配让它装的与 records
完全相同);e2e 脚本落成 `tools/e2e-a2.mjs`(登录 AI → testbed 起单 → 件上按地址保存 →
答卡 → 断言 released/被拒 0/发口)。
- **「算出来的口」改为服务端算数**(2026-08-02,A2 e2e 逼出来的 harness 修死):放行卡的
`routedPort` 从前只在**前端回传**时顶上 `selectedPorts`(chat-bubbles 里那段),而放行落地
读的是**人事件载荷**(原始 reply)—— 换个客户端(脚本/API)就死在「选择组未选出口」,
台账已合并、单落 `blocked`。现 `human-tool-service.replyWorkOrder` 在发事件前算好**有效口**
(routedPort 优先,算不出才认人选),事件与返回值同一份 —— 服务端说了算的事,
不靠每个客户端自觉。顺带:执行卡 `fields` 缺席时基座兜底加必填「结果」回执字段,
代答脚本交卷要带 `values.result`。
- **A2 浏览器真人路走查通过并逮住一个洞**(2026-08-02):锁定 → 编辑 → 填错取消(还原)→
重填 → 保存(痕「改了 1 行」不撒谎)→ 交执行卡 → AI 判稳(原标 C 现标 B,依据逐行留痕)→
验收签字 → **released、7 拍/51k、被拒 0**;归档件零输入框、闸与红带都收、去向命中留在定稿。
逮住的洞:**模版主键格没挂 `data-col`,人保存的行没有钥匙**,服务端按「全表一致列」补键,
两行对到同一行上、后者盖前者(BBPY 的 C 标被隔壁行的 A 盖掉)—— e2e 走 API 自带主键测不出,
只有件上真按保存才现形。修:主键列必挂 `data-col`(它不是编辑面,是行的钥匙;A1 从头就带),
两包自测钉死,`quote-alternative@3.1.0` / `quote-sourcing@3.2.0`。
A3 另修一处时序:第一拍禁写 verdict(凭据列提前落会让引擎提前收步,预填从此不发生 ——
实测嘴上说预填了、台账里没有)。
- **A2 执行件重做成替代选型工作单**(2026-08-02 用户:「执行工单的 HTML 怎么是按验收单做的?
替代选型要为选型高度定制一个模版」):`quote-alternative@3.4.0` 两个局面各一张 ——
`alt-worksheet` 选型工作单(S1/S2 摆):逐颗料一张**选型档案卡**(题面:要素/为什么要替代/
客户约束与预授权;定案回显带待填胶囊;A/B 行收成「原样承继」一行)+ **替代等级判据表**
(P2P 直换 / FUNC 功能兼容 / OTHER 须验证,附 pin-to-pin 五项核对与「同封装不等于同引脚」警示)+
三层筛指引(参数硬指标 → 认证合规 → 供应价格)+ 填回工作表;`alt-roster` 清单(S3/放行/归档)。
台账补齐**对标维度**:`alt_grade`(tally P2P/FUNC/OTHER)/`alt_diff`/`alt_risk`/`alt_verify` +
承继 `remark`(预授权/约束);执行卡指导书按等级写死核对深度。复跑 3/3 released、被拒 0。
连带逮住一个渲染器约束并记进陷阱表:**行展开按第一个同名闭合标签截行内容** ——
`<div data-rows>` 的行模版里嵌 `<div>` 会把行截成套娃(第二张卡长进第一张的表头里),
行容器要用行内不会再出现的标签(`<section>`/`<tbody>`)。
- **A2 选型工作单精专一颗 + 逐颗按序派单**(2026-08-02 用户两条:「选型 HTML 里为啥出现
ABC 类描述的表?这个报告就精专一个芯片的选型」「多个芯片按顺序派选型单」):
`quote-alternative@3.8.0`。台账加**排程列 `sel_stage`(tally NOW/WAIT/DONE)**:
S1 给每颗待选型料标 WAIT;S2 只 start 一次、一串卡都发在它名下 —— 每轮把一颗置 NOW、
发**这一颗**的选型单(标题带 PN 与第 k/n 颗,互不撞「一单一卡」闸;卡=七格表单,
选填显式 `required:false` 留「替代未果」通道),人交回 → 定案照抄落行、置 DONE → 下一颗;
全部 DONE 记 filled_total 才 finish。工作单随排程列演**当前这一颗**:顶部选型队列丸
(当前蓝/办结绿/排队灰,非选型行一枚不出)、替代关系图(芯片→芯片内联 SVG,未定案「待选定」红)、
题面/定案两栏档案、等级判据三档配示意图(P2P 引脚一一对应/FUNC 芯片+外围件/OTHER 打样烧瓶)、
pin-to-pin 五项核对图标带(封装尺寸/引脚/电气/温度/认证)、三层筛漏斗;填回表只显当前行;
已定案收一行摘要 —— **ABC 分类语言全部归收口清单**(自测钉死工作单正文不含原标/分布条/判稳)。
验收:3/3 released、被拒 0(双卡案例 8 拍/69k,第 1/2 → 第 2/2 依序)。
路上逼掉三类抢跑(guide 写死):S2/S3 收步后「这一拍到此为止」、第一轮 start 提成显式第一步、
被拒重试不重写已生效的值(空转写也是拒)。
- **A3 执行件同款重做成寻源询价工作单**(2026-08-02 用户定,素材取 MVP 示例工作流 §1.7
**只作文字参考、不作实现逻辑参照**):`quote-sourcing@3.4.0` 两个局面各一张 ——
`sourcing-worksheet`(S1/S2 摆):逐颗待询料一张**询价档案卡**(题面含**取价对象**
「替代料有值取替代料」/客户约束;A 类收成「已按历史价预填 · 可校可改」一行)+
**按场景圈渠道**规则(BOM早期可放宽 / 后期主→备选→贸易商圈两三家贸易商尽量不用 /
现货只认库存实拍无库存转单商不可选 / 样品量小求快)+ **价格验证的尺**(早期首报即用 /
后期按历史最低降两成两轮核 / 现货多重校验 / 样品低于线上即用)+ 发询纪律与时限带 +
填回工作表(缺价红带与提交闸同源);`sourcing-roster`(S3/放行/归档)。
`quote_list` 补承继列 `remark`(认证/预授权/急料)。复跑 3/3 released、被拒 0。
同批堵一条自造案号的口子(A2@3.5.0 同款):单飞造号**只从本单来件取材,
不许从台账里已有的别单单号里挑** —— 实测一轮借走了正式表里的 MD14.1。
- **执行卡零输入**(2026-08-02 用户定:「执行卡片不要有任何填写的了,填写全去工作区,
包括A1的补全信息,那个『结果』输入框没任何作用」):基座兜底的必填「结果」textarea 删掉
(`fields = declaredFields ?? []`);三活动卡骨架撤 `blocks`/`fields` —— 填报全在
工作区的件上(editGate + 孪生件,保存即落草稿层,模型**不许再 write 一遍**)。
**提交闸回落**:卡不绑表时改看必交付物声明的 `ledgers`/`ledger`(纯函数
`gateAddressesOf`,有测),与放行门 L1 仍同一个数;服务端收回传前同一段把关。
连带删「执行工单 = 指导书 + 空表单,表单不得为空」的拒发 —— 通道换到件上之后,
那道机检让活动照新规矩发卡、基座按旧规矩连拒到熔断(实测 A1 五拍)。
- **A2 选型件升格「一页汇报」**(2026-08-02 用户:「还是不够华丽,要设计成强交互的
汇报形式,直接拿去当一页 PPT 的程度」):深空电路底 hero(队列信标呼吸 /
原厂芯片 → 流光走线 → 替代定案 / 四格账)+ 编号 slide 小节推进(题面七格 ·
等级三卡悬停展开口径 · 五项核对徽章 · 三层筛 · 填回表 · 已定案摘要,空节 `:has` 自折)。
「强交互」全是纯 CSS(hover 浮起 / focus 展开 / reduced-motion 全静),沙箱仍零脚本、
模版仍不算不判。规范新增 §8.5 立此语言;踩了「媒体查询写在基础规则之前被盖掉」
的层叠坑(竖排下走线该藏未藏,排障入册)。
- **start 墙拆除 + JSON 括号栈 + 空转拒回带指南**(2026-08-02,零输入改造连跑逼出):
①**人工激活「先 start」不再是墙**(`readyToWork`):措辞写全(话与门同宽)之后 A1
仍连拒五拍熔断,五次全是「要先 start」—— 那墙保护不了任何东西(start 是模型自己的
动作,同一串连发即过),学不稳的礼仪就是死法;现在**动它就算启动**,人工激活真正
要保的两条(引擎不因哨兵替启、不给 doneWhen 替收)原样有测。三活动剧本的 start
礼仪同批删除。②关思考的模型偶发多吐一个 `}`,单数花括号的配平切出半截非法片段,
整拍六个动作全对却退化成「需要你判断下一步」兜底卡;`parseJsonLoose` 改**括号栈**、
不配对的闭括号当噪声丢(7 测)。③「写了等于没写」拒回补行动指南(值已在台账 →
该办下一件事),治 A2 收步时连拒四拍的重写循环;A2 判稳同批堵死「拿上游原 PN 的
9999 顶替、不亲查 alt_pn」的近路(实测走岔过一单去向)。
**e2e 三套七案例 7/7 released、全部被拒 0**(6-11 拍):a1 闸拦空手交卷→件补年用量;
a2 to-sourcing / to-pricing / to-sourcing;a3 quotation×3(案例 3 闸拦真拦)。
浏览器全链走查:hero 呈现、编辑→保存→落草稿→队列推进(办结绿/当前信标)→
零输入卡提交→released。A1@45.0.0 / A2@4.5.0 / A3@3.6.0。
- **一天里连挨三炸后的返工账**(2026-08-02 下午,全部用户实测逼出):
①**工作区滚轴拉不到填写区** —— ViewContainer 量高在 `editable` class 落下**之前**
(闸/红带现身把内容撑高 122px 没人再量),且 ResizeObserver 挂在 srcdoc 之前那份
空白文档的 body 上(盯着一具尸体);修:先 bind 再量 + observer 每次有机会重挂真 body。
②**「稳定的活动又开始出错」** —— 零输入改造时我往**全局提示词**塞了一句
「执行工单…别再 write 一遍」,把 A1 说明书「人交回确认卡后写 confirmed_total 记账」
顶翻:模型收到答复不记账不收步、把确认卡当没答成,重发同一张卡连拒五拍熔断。
改回通用真理(「人答回的东西在轨迹里,照说明书处理,别当没答过再发一张」);
**全局提示词只说通用真理,活动级细节归说明书** —— 此为铁训。
同批把「重发已答过的卡」从拒改为**头两次无事发生 + 观察指路**(第三次起才算被拒,
熔断兜底仍在),空答复落痕带「人已办完并交回」一句(空 values 在模型眼里像没答)。
③**「啥都没干就能提交」** —— A2 定案列当时全标选填(想保「未果留空」通道),
闸回落后成了没牙的闸。新增**行级必填 `requiredWhen`**(`{column:'sel_stage',
value:'NOW'}`:该轮到的那一行才算必填,排队的颗不拦当前的卡 —— 表级 required
在逐颗派单下会被第二颗的空格拦死成死锁);未果通道改「备注写缘由 + 行首 × 撤行」。
`_missing`/红带/提交闸/放行门同源生效,e2e 三案例空手交卷全部 400 真拦。
④**「输入区和汇报内容为啥分开?一屏都看不完算什么一页 PPT」** —— A2 工作单改
**看与改同一块**:01 区平时是汇报稿(题面七格+定案摘要+档案行),按「编辑」同一块
换成表单(`:has` 切换),保存/取消回稿;方法论(等级三卡/五项核对/三层筛)收进
原生 `<details>` 折叠条(零脚本);页高 2528 → 1285。A2@4.7.0。
⑤**遗留(记 debt):A2 单飞判稳连续两轮「不查工具直接编」**转 A 走岔去向 ——
说明书措辞已到头,结构性根治 = 判稳 decisionTask 化 / 工具出参带标(见 debt.md);
现状兜底:验收页 type_tag 可改、去向跟着变。
⑥契约变更:`FieldDeclaration.requiredWhen`(api-report 已刷新,随本轮一并提交后
api:check 门才绿 —— 它拦的就是「契约变了没入库」)。
- **A1「又出补全卡」的病根:入场哨兵读自报列**(2026-08-02 用户送来 exhausted 单):
`s_parsed` 读模型自报的 `line_total`,模型把 record 三行在 S1 拍写完、没记这个数,
S2 空手收步 —— 门永不开,引擎报「依赖断点」,提示词「断点请调人」把模型推去发
补全卡绕路(两张标题只差尾巴的卡把 humanCalls 4/4 烧光)。
**「机检只读基座数」第四次违反现形,这次是哨兵**。修:s_parsed 改读
`quote_intake_record_rows > 0`(行落了门就开,不等模型记账);`sameQuestion`
补前缀比对(≥6 字前缀 = 同一问)。复跑新客户空手确认路:**released、被拒 0、
断点 0、补全卡 0**(11 拍,回稳定基线)。A2/A3 哨兵同缝记 debt。
- **补全卡(ask)全局退役**(2026-08-02 用户定:「彻底全局退役补全卡,执行卡完全
就是包含补全语义的人类工具」):缺信息 = 发**零输入执行工单**(指导书写清缺什么,
人在工作区的件上补)。归一层把旧输出的 `ask` **原地转成执行工单**(字段名并进
指导书;拒回只会让模型换花样再发,归一才是铺路);引擎侧直发 `ask` 如实拒并指路;
提示词④段改写、handsOff 去 ask;A2/A3 剧本里「未果问人」改用决策卡(二选本就是
处置);规范 §3.4 五类卡 → 四类。历史卡回放兼容件(契约类型/前端渲染/起单老路)
留着,清理记 debt。A1@47.0.0 / A2@4.8.0 / A3@3.7.0。
- **A2 工作单第三版:对决卡 + 一张贯穿 + 占位三级**(2026-08-02 用户四条连发):
①「01 重构成渲染态就是结构,编辑就是写组件内的值;顶栏与 01 合并:左静态原厂
SVG 卡、右替换卡、等级直接选择(正确性全由人控)」→ **对决区**:深空 hero 里
左卡(原厂题面规格)→ 流光走线 → 右卡(替代定案就地编辑);**等级 = 三枚自绘
radio**(不写 checked,当前值 data-class-of 投影描虚线;基座 collect 对未选中
radio 整列不交 ——「没点」是「不改」;快照/取消按 checked 存取)。
收值铁律:**一张卡里所有输入格的祖父必须同一元素**(collect 按祖父归行)。
②02 指引铺开、不写类型(口径贴在三枚选择钮上);③**空占位三级全局统一**:
必填红 / 建议填橘 / 选填灰 = required / expect / 其余(A2 已上,A1/A3 记 debt);
④**一张模版贯穿到底**:「待处理的 HTML 报告完成后直接转变为静态的工作成果」——
alt-roster 退役,收口内容(清单总览三态丸、去向判定)长在同一张尾部有值才现身;
规范 §1 硬规矩收紧,A1/A3 旧制记 debt。基座陪三小刀:`setOpen` 对非表格容器把
`.on` 落在 `data-edit` 元素自身;collect/快照/取消的 radio 特判。
验收:e2e 3/3 released 被拒 0(闸拦三案例全 400);浏览器实证 radio 选 P2P →
保存落草稿 → 徽变绿 → 取消还原(含 radio uncheck)。A2@4.9.0。
- **A2 工作单定稿为 One Pager + 单卡多页 + 成果 1:1 快照**(2026-08-02/03 用户连定):
①「这份报告就是一颗芯片的替代选型」—— 队列丸/清单总览/去向段全撤(收口整合的
东西不在这份),版面 = 深空 hero 对决卡(左原厂静态 SVG 卡 · 流光 · 右替换卡)+
选型指引(不分段);「待选定」与必填同风格红胶囊左对齐;编辑钮做进替换卡右上角
(cardbtn 三件套仍是 data-edit-open/cancel/save);等级口径贴在三枚选择钮上。
②「一个执行单可以派多个 HTML 待执行报告,合理利用右上角的翻页」——
**逐颗派单退役**:一张执行单,件里一颗待选型芯片一页(行挂 `data-page`,
orig_type=C 成页),右上角箭头翻页;`sel_stage` 排程列整个退休;
requiredWhen 改钉 `orig_type=C`;双 C 案例 7 拍(比逐颗省)。
基座配套:渲染器**行内表单组名唯一化**(radio 组按行号缀名,页间不互斥);
ViewContainer 通用分页(`[data-page]` 可见段,`page`/`onPages`,不传 page 不分页)。
③「工作成果要 HTML/UI/数据/内容/布局 1:1 从待处理转成静态报告」(反复强调)——
病根:执行单定稿走 WorkOrderReport 卡壳、验收单渲「当下」视图,都不是办结时那份。
修:**回执收下那一刻把渲好的件存进工单**(`WorkOrder.finalHtml`),成果页
1:1 静态渲快照(零编辑钮、数据定格);旧单无快照退最近视图再退卡壳(历史兼容)。
e2e 3/3 released 被拒 0;浏览器实证:1/2↔2/2 翻页、两页一次保存全落库、
成果点开即对决卡静态版。A2@4.10.0。
- **A2 逻辑收口:两件各归各位**(2026-08-03 用户:「验收工单怎么又变成选型了?」):
「一张贯穿」被我执行过头 —— 验收阶段摆的还是选型 One Pager。校准后的口径
(规范 §1 已改):**「1:1」的落点是每份件与它的办结快照**(在办可编辑 ↔ finalHtml
静态归档),**不同工作各有各的件** —— 选型 One Pager 归执行单(S1/S2),
**收口整合清单归验收**(S3/放行/归档,`alt-roster` 恢复:整份清单
原标/替代/等级/现标/依据 + 按分类算出的去向判定,只读 —— 就地改走验收卡的
editableAtRelease 表)。浏览器全链实证:验收阶段工作区 = 收口清单(判稳这轮
也真查了工具:43 天·稳 → 转 A);成果两份定稿各是各的快照(执行单=One Pager
静态、验收单=清单静态)。e2e released 被拒 0。A2@4.11.0。
同批沉淀:活动开发规范新增 **§6.5 设计律八条**(墙要配路 / 学不稳的礼仪就是死法 /
拒回喂对抗观察喂事实 / 机检只读基座数管一整片 / 提示词分层 / 措辞治不了的结构治 /
改共享面全量回归 / 用户重复提的要求说明没打中病根);HTML 规范补「概念图形是
第一语言」与「收值三铁律」。
- **A2 两张报告第四版(用户 /brand 推倒重设计)**(2026-08-03):
①**选型执行工单**重单颗芯片:白纸文件基底 + 身份条(眉头式,客户在条内不占右上角),
深空只留「对决 Stage」(原厂芯片 →流光→ 替代芯片,PN 大字,**编辑钮组在 Stage 右上**);
定案面板白纸双栏(左题面灰底/右定案,输入全在右栏);指引脚注化(五徽一行+三层筛横条)。
②**选型验收报告**重列表与落边:汇总带(条数/A/B/C)→ 受理记录大表 →
**落边图**(SVG 流程:清单 → 菱形「还有 B 类?」→ A3 寻源/A4 定价,命中边实线亮+流光、
未命中灰虚,`case:routeKey` 投影 —— 不冒充判过)。
③占位三种定稿:**必填(红)/选填(灰)/建议(橘)**(`ph-req/ph-opt/ph-sug`);
**等级空位归「必填」**(不再写「待选定」),打开编辑即三枚选择。
e2e released 被拒 0;浏览器实证:Stage 空位红胶囊呼吸、落边图 v-r1 命中亮线带真实计数。
A2@4.12.0。
- **兜底卡不再摆模型原话:输出不成形先就地重问**(2026-08-03,用户送来一单:
「正常派工单为啥不是作业指导书,卡片里又是乱七八糟的东西」):关思考的模型偶发把
整拍输出写坏(一串行动一个都不认识 —— 多闭括号那形已由括号栈自修,这次是另一形),
从前一次没认出就发「需要你判断下一步」兜底卡,还把 JSON 原话整段摆卡面。
现在 `normalizeTurn` 标 `unrecognized` → decide **就地重问一次**(原文经 `note`
存工作日志内部痕,附「只输出 JSON」硬提示);第二次仍不成形才交人,卡面只说人话
(原话在日志,不上卡)。假网关三测钉死:重问只一次、原文进痕、好拍不白重问。
复测 e2e a1:released、被拒 0(11 拍/102k)。
- **提交钮靠右 + A1 占位补齐三级**(2026-08-03 用户两条):①执行工单的提交钮从卡脚
左侧移到右侧(`jc-fc-ft` 加 flex-end;验收卡「重做|通过」有 `jc-fc-sp` 撑着不受影响;
旧版报告页脚 space-between 同批)。②A1 报告里品类/制造商/目标价三列的空占位从灰
「选填」改橘「**建议**」(用户点的是目标价)—— 档位跟台账声明走:required→必填红、
expect→建议橘、其余→选填灰,颜色与 A2 同套;备注仍选填;「分级依据」那段话同步改口。
跟着一条(用户:「没有和数字对齐」):裸 inline-flex 胶囊按 baseline 挂,盒子比字的
基线深几像素,整枚往下坠、行高忽高忽低 —— 空格子(`:empty`)转 flex 居中 +
`min-height` 撑住文字那份盒高,胶囊中线对数字中线(陷阱表入册)。
再跟一条(用户:「编辑态太拥挤」):那条 flex 规则比「编辑态藏只读份」的 display:none
**更特异**,编辑态里胶囊盖过隐藏冒了出来,54 个输入框旁边各站一枚 —— 圈上
`:not(.on)`:胶囊只属于看的那份,编辑态里该不该填由闸与红带说。
quote-intake@48.2.0 已装,62 测绿。A3 的占位三级仍欠着(debt)。
- **保存不再闪:就地换内容的第二层是逐节点 morph**(2026-08-03 用户:「保存的时候
HTML 会闪一下,之前都修过怎么又来了」):08-02 那刀把 srcDoc 重载换成
`body.innerHTML`,文档不再重载 —— 可整树仍是**推倒重建**:47KB 样式表在 body
再解析一遍(head 那份还在,从此一文档两份同文样式,实测拿探针在真单上量出来的)、
二十来个 SVG 全部重建、CSS 动画回第 0 帧重起跳 —— 同一个症状,病根在下一层。
现 `ViewContainer.replaceInPlace`:顶层样式归位 head 去重(注意 `:scope > style`
在 DocumentFragment 上**实测不命中**,要用 children 过滤 —— 不然新旧顶层错一位
全树失配,浏览器独立三轮验证逮出来的)+ `morphNode` 新旧逐节点对齐,一样的不碰,
输入件活值只在拟值真变时跟上(人敲了一半的字不因无关重推被擦);任何一步栽了
退回整树重建(闪但不错)。验证:浏览器独立三轮(改值保identity/加行保敲字/
遗留双样式自愈)全过;1103 测、typecheck/lint 绿。真单上的探针账:save 后
probe alive、loads 0、无 remount —— 闪的确不是重载,是重建。
- **「保存后旧值还持续一会儿」才是人看见的那件事**(2026-08-03 用户第三次指出同一处):
上面两刀治的都是**重绘**,而人说的是**内容**:保存要跑个来回(POST 落草稿 → 失效缓存 →
重取详情 → 新件推回),闸却在按下那一刻就关了 —— 这几百毫秒里屏上摆的是只读那份的
**旧值**,人刚敲完的数当场消失,看着像这一下没生效(会再改一遍、再按一次)。
值本来就在手上,不必等服务端告诉我们:按下保存**先把新值写进只读孪生件**再关闸
(`mirrorTwins`),回声到达时 morph 一比已经一样,一次重绘都没有。
只镜像格子自己的值 —— 红带缺几格 / 分布条 / 去向是**基座算的数**,一律等回声(界面不撒谎)。
途中逮住一条会让这一段静默失效的事实:**渲染那一遍把 `data-slot` 连同槽位一起消费掉**,
活 DOM 里只读那份与 input 都没有这个属性;认孪生件要**按位置**(`previousElementSibling`)。
第一版按 `data-slot` 找,在我自己搭的合成 fixture 上全绿、在真单上一格都不动 ——
**验证要在真单的 DOM 上做**。实测:显示 1ms(点击同步内完成)、20 秒 663 帧零抖动、
值真落库(服务端详情里就是新值)。
- **A4 成本定价补齐到验收线**(2026-08-03,`quote-pricing@3.5.0`):契约宽进(input.required 清空,
原本 required `customerCode`+`records` 而上游 A3 发的是 `rows` —— 这条边真跑会断)、
`draft` 口载荷对齐 A6、哨兵与判据全改基座读数(`draft_total` 自报数是第 5 类同款违反)、
两份件(pricing-worksheet / pricing-roster)、78 条包内自测、e2e 加 `a4` 套件
(含**决策卡代答** answerDecisions / expectDecision)。**e2e a4 3/3 released、被拒 0**
(7-9 拍 / 54-74k),闸每单真拦,超限那单真发决策卡。三处踩坑各留一条账:
①**只有一列价时 AI 会编价**(库里查不到的料它照样填一个,交代还说「价空着等你定」)——
结构治:拆 `suggested_price`(AI 算)/ `quoted_price`(人填,`required`),
闸从此每单有牙,不靠模型分辨「这行算得出没有」;②门禁三列没人写、放行门只说
「数不对/行不对」→ 底价自检独立成项 `S3_gate`,`doneWhen` = 三档守恒(与验收 L2 同源);
③人点完决策卡后那一步被重念、guide 头一段写着「发一张决策卡」→ 连发四张烧光调人预算,
改成**先分岔(轨迹里人选了没有)再谈动作**。
- **决策卡也有了幂等兜底**(2026-08-03,A4 逼出):`resendVerdict` 抽成纯函数,
执行工单与决策卡**同一把尺** —— 人已答过的同一问,头两次「无事发生」(卡不真发、
humanCalls 不烧,只把事实摆回轨迹),第三次起才算被拒(熔断仍看得见)。
从前只有执行工单那一路有,决策卡一道都没有:同一个岔路口连发四张,四次调人预算
烧光落 `exhausted`。**按钮按两下不该变成墙,也不该变成四张卡**;6 测钉死三档。
- **重发判断要走在站上场之前**(2026-08-03,**A1 基线当场熔断**逼出来的顺序):
人答完之后那一步常常已经收掉,而 `readyToWork` 走在前面 —— 对 Completed 项直接抛
「这一步已经办完,不能再往它上面挂活」,于是「重发已答过的卡 = 无事发生」这条**唯一的活路
在最需要它的时候够不着**:同一条拒回重复五遍熔断(实测 13 拍 124k、发口一个都没有,
而数据本身合规)。重发一张已答过的卡本就不需要那一项在场 —— 它什么也不做。
两族(human / decide)同批换序,无事发生那一路**原样交回局面**(不顺手把项推上场)。
这是设计律第一条「墙要配路」的第三次现形。复跑 A1 四轮:三轮 released 被拒 0、
一轮 released 被拒 4,**熔断不再出现**。
同批修 e2e 脚本一处误判:**「已回传」不是「闸拦着」** —— 两种 400 长得一样而处置正相反,
当成闸拦着就原样再交一遍、三次判失败,把一单 released 的 A1 记成了失败。
- **A6 报价议价补齐到验收线**(2026-08-03,`quote-negotiate@3.5.0`):五项
(排版报价函 → 交人发出并落客户回音 → 逐条定案 → **还价才叫人拍板** → 放行),
四道哨兵全读基座读数,两张判定表(N-01 议价结果 / N-02 让步梯度),三口带 `when`
(won / revise / lost),两份件(negotiate-worksheet 可编辑 + negotiate-roster 收口含落边图),
90 条包内自测,e2e 加 `a6` 套件。**连跑两轮 3/3 released、被拒 0**(6-8 拍 / 44-65k),
三口各覆盖一条,闸每单真拦,还价那单真发决策卡。三个结构账各修死并有测:
①**同一张决策卡连发六次** —— `revise` 那条路原写「定案不动」,人点完哨兵照旧成立;
改:`deal_status` 加第四档 `REVISE`,拍板三条路都必须动它,「办完了」在数上看得见。
②**模型自己写 REVISE 绕过拍板**(一轮 released 而决策卡 0 张,让步梯度成摆设)——
病根:哨兵读模型判出来的 `deal_status`;改读**客户自己填的那一格**(`_reply_type_counter`,
基座现数)。**「该不该叫人」不能由被叫的那一方说了算**。
③断点那几拍模型自编决策卡(拿计划项中文名当 itemId / 换问法发出两张)——
itemId / ask / 选项值写进**说明书**(说明书每拍都在提示词里,而 step guide 在断点时没摊开)。
**等外部回音落在执行工单上**(人收到信把回音填进件里),不用 `listen` ——
引擎的 `listen` 恒挂起而 desk 侧没有投递 data 事件的入口(记 debt)。
- **五套十三案例一次全绿**(2026-08-03,第三阶段主体达成):A1 1 + A2 3 + A3 3 + A4 3 + A6 3
= **13/13 released、行动被拒 0、发口全对、提交闸每单真拦**(6-11 拍 / 45-108k token;
两张决策卡分别落在 A4 超限拍板与 A6 让幅超授权)。门禁 1278 测、typecheck / lint 全绿。
这一轮同时是**共享面改动的回归证据**(agent-runner 重问 / turn-runner 重发换序 +
决策卡幂等 / ViewContainer morph 与保存镜像)。A7 归档同法补齐中。
- **「机检只读基座数」第一次覆盖到工具**(2026-08-03,治 A2 判稳偶发走岔):
新读数 `tool_<工具名去符号>_calls`(`toolCallReadings` 按留痕数**成功返回**的次数,
声明过的工具一律先铺 0;调失败不算查过 —— 调不通等于没拿到行情)。
病根:判稳的行情只有 `crm.history-price-read` 一条来路,而模型偶发压根没调工具
就把料判成「稳」转 A,**自报的依据列写得漂漂亮亮**,去向从寻源走成定价(约十次一次)。
说明书已写到头,**措辞治不了的结构治**(设计律第六条)。A2@4.14.0 立 L2:
`quote_alternative_list_type_tag_a = 0 or tool_crm_history_price_read_calls > 0`
—— **写成析取**:一颗都没转 A 就无需查行情(全 B 那条路合法),有 A 才必须亲查过。
静态审(`static-audit.boundNames`)与包内自测的「谓词绑得上」名单同批扩到这一类
(`declarations.tools` 在审计入参里做可选 —— 老调用方只传 ledger,别掀翻整份审计)。
判据锚在 `orig_type_c`(原标)而非现标 `type_tag_a`:清单里的 A 多半是**上游原样承继**的,
拿现标当锚会把「全是承继的 A、一颗 C 都没有」这条合法路径也拦下。
- **「闸没拦」与「压根没东西可拦」是两件事**(2026-08-03,一次假失败逼出来的):
`expectGateBlock` 从前写成「空手交卷必须吃 400」,于是模型碰巧把该填的格子全填上的那些轮
(A1 补齐了缺的年用量、A2 客户点名的替代料型号本来就在来件里)一律被判成「提交闸失效」。
**而闸好端端的** —— 拿一单直接空手交卷实测吃的就是 400,还点名了缺哪一行哪一格。
现在断言分三档:blocked / nothing-missing(该填的全填上了,闸无需出手)/ leaked(缺着还放过去,真失效),
用**与 buildEdits 同一份草稿、同一个列名**去数。断言报的失败是假的,真失效那天反而没人信它。
- **A7 情报归档补齐到验收线**(2026-08-03,`quote-archive@3.0.0`):归一情报卡 →
一张零输入执行单(逐条落**输赢归因** + 竞对价)→ 按败价幅度算档 → **入库口径决策卡**
拍板(全量/脱敏/仅内部)→ 放行,一口 `archived`。哨兵读**人填的那一格**、
6 条 L1/L2 全读基座数、`competitor_price` 用 `requiredWhen{cause_tag:PRICE}`
(交期/认证败的行不被拦成死锁)、82 条包内自测。**e2e a7 3/3 released、被拒 0**(各 7 拍/54k)。
同批退役三张共享域表并留墓志铭(单案例算不出月度落地率、客户档案 A1 已持有、
行情历史与情报卡是同一份事实)。
- **A2 常路会跳过派给 FAE 那一步**(2026-08-03 发现,**未修**,已写 debt):
案例①连续三轮 6 拍收口、一张执行工单都没发 —— 模型自己把替代料填了,
而 S2 的 `doneWhen` 认的正是那几格填没填,于是收步条件当场成立、**人环整个消失**。
这是「触达世界的项不给 doneWhen」的反面教材:「把清单交给 FAE 选型」触达的是人,
完成与否不该由数据形状推出来。治法与 T_release 同款(人工激活 + 不给 doneWhen)。
**排除项**:撤掉当日新加的工具留痕判据(@4.15.0)后原样复现 —— 不是它引起的。
- **A1 的话与工单说的不是一回事**(2026-08-03 用户四连指出:「这个工单是让员工填必填,
建议追问目标价,其他选填,你这条日志的表述就完全变了」):件与卡早已是**三档**
(必填红 / 建议橘 / 选填灰),而 A1 的说明书还在教**两档** —— 目标价被明写成「选填」,
于是交代里说成「缺的选填项你看着补」;更糟的是同一句里「NE555P 我先照历史价估」:
**它把 S4 查来的历史价当成了客户的目标价填进去** —— 那是替客户表了态,
下游定价议价全建在这个假数上。三处同批改齐(`quote-intake@49.2.0`):
①说明书「两种分量」改「三种分量」,逐列点名哪几格是建议档,并写死
**目标价客户没给就留空、不许用历史价或经验价估**;②say 口径写明「用件上那三个词、
只说事实」;③S3 卡骨架的 steps/standard/basis 与验收判据 label 一并换成「建议追问」
(judge 按整句对名,说明书那一处同字改)。实测交代已改成
「DAG… 缺年用量(必填),UMW… 缺制造商、NE555P 客户没给目标价(这两条建议追问,不拦单)」。
- **反例引了原话,模型照抄反例**(2026-08-03 用户送来 10:40 的单:「还是老样子啊,
派工单的时候为什么会查历史价?」):上一轮治措辞时,我把那句错话**原文**引进说明书
当反例(「别说『我先照历史价估』」)—— 关思考的模型不读「别说」的否定框,
只认框里现成的句子,又原样说了一遍。台账数据其实全对(信里给了 8.0/22,NE555P 留空,
一个假数没写),错的只有这句被我喂进去的叙事 —— 且它谈的历史价那一拍**根本还没查**
(S4 未跑,轨迹里零工具调用):纯编造。治法(`quote-intake@49.3.0`):
①**反例一律不引原话**(描述失败,不给可照抄的句子),A1 三处清扫,其余五包 grep 无同类;
②**要引原话就引正例** —— S3 派卡拍给了一句完整交代模版(三档词 + 只说事实);
③叙事纪律:历史价/分类/去向是审定之后那几步的事,派卡拍一个字不提。
验证:同一封信两轮 —— 一轮平实无编造、一轮逐字命中正例模版,台账两轮全对。
**提示词里唯一该出现的原话,是你想听到的那句。**
连带一笔:复现时我起的试跑单把用户 10:40 那单顶掉了(试跑台一次只挂一单,已有 debt)——
**用户正在测试台上测的时候,别起自己的试跑单**。
- **执行卡的指导书空了:卡骨架住错了地方**(2026-08-03 用户:「作业指导书展示不对了」):
受理需求审定卡的骨架(steps/standard/basis)写在 S3 那一步的**剧本**里,而模型把
「建档→落表→收步→派卡」压成一拍连做(被鼓励的省拍打法)—— 那一拍摊开的是 S1 的剧本,
S3 的骨架看不见,模型凭记忆拼出一张裸卡,基座兜底 basis 又摆上「当下可为(空)/目标缺口」
这类内部家具。**卡内容不该取决于它在哪一拍被发出**。两处修:
①骨架搬进**说明书**(每拍都在;A6 决策卡先立此法 —— 断点拍自编决策卡同一个坑),
剧本留一句指路;第一版误插进 S1 剧本(录入卡骨架就住在那儿,被我当成了说明书),
测试逮住后挪进 NARRATIVE 本体。②`steps`/`standard` **补进出参 schema** ——
它们从前不在 schema 里,能到卡面纯靠厂商 JSON 模式宽松放行,而本仓早有纪律
「结构化出参只吐 schema 里声明过的键」(ai/ledger 当年就是这么丢的)。
`quote-intake@49.5.0` 已装;1366 测、typecheck/lint/depcruise 绿。
用户在途那单已见到全指导书;e2e 复跑等测试台空出来再补(他的单还开着,不顶)。
- **工作日志:一行摆首句,展开才看细节**(2026-08-03 用户:「细节展开不够好」):
从前一条只有一行标题,而留痕里那些人真想回看的东西 —— 凭什么算这一步办完了
(`rationale`)、那一笔写了哪几行(主键名单)、被拒到底拒在哪儿(`reason`+`hint`)、
发的是哪种卡送到哪儿 —— **一个字都没露过面**。现在 `detailOf` 把它们摘成
**人读键值对**(与 title 同一条纪律:不摆内部英文名、认不出的不摆),
折叠不占地方、展开才现身;**摘不出就是空数组,前端据此不给展开钮** ——
点开是空的抽屉比不给还糟。
连带修一处**文档与实现不符**:「一轮一句」口径说埋头办事那几拍的交代
「留进工作日志」,而实现把 `internal` 整类滤掉了 —— 那几句**哪儿都看不到**。
现在带 `say` 的放行(它是人话),章写「交代进展」、记在 AI 名下;
排障用的内部痕(重问原文)照旧不摆。
两种交代统一「首句上行、全文进抽屉」(一句话说完的不重复摆,免得点开发现一模一样);
截了才加省略号 —— 加了等于说「后面还有」。
实测:一单 8 行、6 行有抽屉、行高 34-36px 齐平,展开那两行 141/103px。
14 条新测(detailOf 五类 + 压下交代放行 + 首句去重)。
- **E04 关系覆盖与关键人经营修到验收线并全流程跑通**(2026-08-22,
`crm-relationship-coverage@2.0.5`,用户:「实现完成了但做的不好」)。接手时两天 18 次
试跑只 2 次 released、活单正熔断;收尾:**e2e 三案例(点名/月度/驳回循环)+ 浏览器
新客户建档路全部 released**,新客户路被拒 0(18 拍/216k/5 人环)。修死的账,harness 四刀:
①**finish 的 doneWhen 按写完后的草稿算**(从前拍首快照,「先写后 finish」这个被鼓励的
省拍打法被误拒,下一拍引擎又用同一份数据自动收步 —— 同一份数据两个裁决);
②**空转写身后还有行动就不废串**(「被拒停在谁那儿」把「写记账旗+发卡」整串弃权,
排在后面的发卡从没执行过,连拒五拍熔断 —— 值没变的写什么也没改,后面行动不该陪葬;
串尾/独苗仍拒,熔断检测靠它);③**调工具挂不上项不拦调**(授权面是工具白名单,
与「写的授权面是台账声明」同款);④**读工具同一份入参重调:第 2 次起出参标题带点名
警告(不算被拒),期间没写过东西的第 5 次才拒**(实测模型把 recompute-score 连调 10 次
赌分数变卦 —— 26 次调用烧穿预算的前科在案而 stalledTurns 只数被拒,成功的重调无兜底)。
活动包三处结构治:⑤**S5 记账旗退役**(receipt_confirmed_total 是模型写的「人环凭据」,
S4 一过它顺手写旗就坚信 S5 办完,[写旗+finish 被拒]×5 熔断两轮;门改读基座数
receipt _rows/_missing —— 回执四列全是人在件上填的,被叫的那一方无账可记);
⑥**收口拆两项**(S6_writeback 写回主数据 / S6_ledger_update 只写明细+结论 ——
三拍纪律写得再明白,模型照样把四张表挤一串,串尾最费字数的明细表被截成空数组;
拆开后剧本只摊自己那几张表,串想长也长不起来);⑦**case:openedAt 真的进 Agent 作用域**
(说明书让拿它铸 round_ref 而这个键从前只注给视图渲染 —— 模型只能编,正式表里一有旧号
就照抄,测试台里所有单共用同一个案号、跨单主键相撞;现注真实开案时刻含年秒,跨单唯一)。
S5 指南改「唯引擎 worldTouched 事实行是从,别自己数 card-reply」——轨迹里躺着 S2/S4 的
card-reply,模型对不准归属,连续三拍幻觉「回执已交回」(措辞治不了的结构治第 N 课:
**指南让模型判的事,引擎已有现成事实的,一律改成读事实**)。视图照目标件 §6.2 补齐:
关联任务(engines 注入 case:taskId)、步骤行、页脚案号、执行工单1 编辑闸措辞
「AI 已识别 N 个客户」(绑基座读数)、计划表补时间点列(判据③指向的东西must在卡面)、
回执对象列「客户 · 关键人」、结果摘要/客户反馈照目标件换 **textarea**(渲染器补
textarea 孪生:值进正文、collect/镜像/增删行全链)、台账更新确认补「依据/编码」次行
(三条 L4 从前让人判他看不见的东西)。verdict.trigger 改名 trigger_label(与入参同名,
首帧摆英文码);plan.status 死列退役;建档卡写的六列补进声明(授权面);两条 L1 谓词
各钉一半基座数(旗单独成谓词是「机检只读基座数」的伪装形)。e2e 加 `e04` 套件
(`stages` 按卡名对号 —— 一单两张不同表的执行单;`fillAllBlank` 整行扫空;
`decideSeq` 驳回→通过按张走;buildEdits 泛化 rowKey,不再钉死 pn)。
新测:turn-runner +6、包内 76(补 steps.test.ts:count(customers) 三形状真 @sfeel 钉死 ——
未绑定名 flatten 成 [undefined] 长度 1 不是 0)、view-render textarea 3、ui-kit 2。
- **验收「重做」第一次真的能退回重做**(2026-08-22,柴浩实测:点了重做,单子卡死):
从前非 pass 裁决也走 `finished` 分支 —— runTurn 把在途验收消费成 null、返回
「finished 未放行」,task 层把它重新挂成 awaiting-human;**人已经说了话,却再没有
任何事件会叫醒它**(A 系列 e2e 从来只点通过,这条路第一次被真人踩到)。
修死(turn-runner + port.ts + CONTRACT.md,3 测):非 pass = **打回重做,不是终局** ——
意见(`PendingAcceptance.comment`,onEvent 从裁决载荷捕入信封)以
「验收被打回重做:<意见>」进轨迹(没写意见就明说「自己复核一遍」),在途验收清掉,
**同一拍照常问模型**;刚被打回的那一拍不走判齐快道(判齐恒真的活动会在意见没人读时
原样再发一张卡)。模型修订后重新 submit,新发的验收卡才是下一次裁决的对象。
卡死的那单以「把消费掉的在途验收原样放回信封 + 拨回 running」救活
(不手插记忆行 —— task_memory 有封链,留痕必须走正规通道),实测:重做意见进轨迹 →
模型复核三条裁量 → 重新提交 → 新验收卡已回到负责人工作台。
- **「重做」得真的退回去改,不是原样再递一次**(2026-08-23,柴浩连点两次重做的实测账):
上一条修好了「重做后单子卡死」,但没治**空转重做** —— 打回那一刻案例模型的项全是
`Completed`,模型除了重新 submit 无事可做:两次都是 6 秒内把三条裁量判据重判一遍、
台账一个字没动就把同一份成果递回来,人看见的是「我说了重做,它当没听见」。两手一起治:
①**基座侧结构闸**(`raiseAcceptance` 一个出口管住模型 submit 与判齐快道两条路,6 测):
打回之后台账没动过(写/撤都算)就不许再提交;软硬两段 —— 头一次拒并指路
(改台账 / 或发卡问清楚要改什么),已因此拒过一次再提交就放行(墙要配路,不锁死单子)。
②**活动侧指路**(`quote-…` 同理,E04@2.0.7 的 T_release 剧本加「被打回重做」分支):
闸只知道「没改」,**改哪一张表是活动自己的知识** —— 理由空改 `plan.rationale`、
依据虚改 `ledger_update.evidence_ref`、结论糊改 `verdict.summary`;没写具体意见就
自己挑最站不住的那处改实,一律同 PK 覆盖写(新开行会把收步判据弄假)。
T_release 的 `writes` 同批补上这三张表 —— 不声明就写不进去(写的授权面是台账声明)。
- **「取不到」不是「还活着」:测试台钉着死号说在跑**(2026-08-23 用户:「推进完成了,
但测试台还在运行中,没有停下来」—— 当场复现):面板钉着一个**已被别处清掉**的任务
(reset-runs / 另一台起单会先销毁上一单),屏上同时说两句相反的话 ——
上面「AWAITING-EVENT · 自动刷新 2s」灯亮着、钮写「停止仿真」,下面一条橙带
「取数失败 —— 任务不存在」。两处一起修:
①**后端状态码说错了一格**:「任务不存在」抛的是普通 Error → 兜底成 `500 internal`,
而 500 的意思是「服务器出毛病了,等会儿再来」—— 面板据此举着上一次的状态每 2 秒重试。
现在这条路由如实回 **404 not-found**(「这一单已经不在了」);
②**前端把「取不到」当成了「在跑」**:`q.data` 在取数失败后保留上一次成功的那份、
其 `terminal` 恒 undefined → `live` 恒真;`s === undefined ? 'live'` 那个兜底更是直接
在撒谎。抽出纯函数 `observeFace`(6 测)分三种局面说话:**没了**(404 → 停轮询、
灯灭、说「这一单已不在了」、当场松手回装配台)、**取数失败**(断网/500 → 不说在跑,
轮询留着等它回来)、**取到了**(照实说)。浏览器实证:起单 → 面板盯着 → 别处清掉 →
6 秒内自己回到装配台,鬼卡片不再出现。
- **立监听的授权面是清单声明 —— 立了没人叫醒的监听不是等待,是失联**(2026-08-23,
验重做那一单当场撞出来的第三个洞):S4 审批过后模型**漏写了 `plan_approved_total` 那面旗**
(人工激活的项没有 doneWhen 兜底,finish 拦不住),S5 的入场哨兵永不成立 → 依赖断点 →
它临场「立一个 data 监听等执行回执」,而 E04 的 `declarations.listeners` 是**空的**、
这一单也不会有任何 data 事件进来(全仓没有一处消费静态监听声明,desk 侧更没有投递 data
的入口 —— 老 debt),单子就此挂在 `awaiting-event` 15 分钟一动不动。
修:`ListenerRegistrar` 补 `declared(taskId)`(engines 从清单取),`listen` 只放行
**声明过的那几种**,没声明的当场拒;拒回把两条真路一起指出来 ——
「要等人办事就发执行工单(人在件上把回音填回来);卡在断点多半是某个入场前提的数
还没写(常见是某面记账旗漏了),回去补那一笔,门自己就开」。3 测 + CONTRACT.md 已记。
- **步数是活动自己声明的预算,记的是 tick 不是模型拍**(2026-08-23 用户问):
测试台那三格读的是 `task.caps` ← 清单 `contract.resources.budget`(E04 声明
80 步 / 50 万 token / 12 次调人,A 系列 50-60 步 —— E04 高是因为四道人环 + 审批循环)。
**一步 = 一次 `task.tick()`**,而不是一次模型决策:实测一单 19 步里只有 12 拍真跑了模型,
另外 7 次是人回卡后「看一眼在途验收就返回」的空转 tick。挂起等人期间不烧步数
(推进器只捡 `runtime='running'` 的单),所以这笔账不会随人拖延而涨。
- **起单入参要预填满**(2026-08-23 用户:「询价受理起单时左边都有预填好的输入,E04 也要」):
测试台落到一个活动上自动铺的是 `samples[0]`,而 E04 的第一条样例只有
`{trigger:'monthly'}` 一个键 —— 表单除了那个下拉全空,看着像没预填(A1 两条样例都是
满载的一封信,所以那边没问题)。E04@2.0.6 把**满载的那条**(重大商机 · 点名 CU-0142,
四字段全有值)挪到第一位、月度例行补上真实背景说明,并把五条样例名收到 **≤14 字** ——
超过 14 字测试台只显示「样例 N」(activity-run.tsx),那等于没名字。
包内测试钉死这三条;e2e 的 e04 套件样例序号同批对调。
- **I01 品牌形象与销售工具包管理按 E04 标准审完并全流程跑通**(2026-08-23,
`brand-content-toolkit@1.1.1`):**e2e 三案例 3/3 released、被拒 0**(9-10 拍 / 66-82k),
浏览器真人路(件上加一行 → 提交 → 初稿审核 → 发布放行)**released、被拒 0**。
审出并修死的问题,与 E04 那一轮同族:
①**两条 L1 只读模型自写旗**(`requirement_confirmed_total`/`draft_approved_total`)——
各钉一半基座数(`_rows > 0 and _missing = 0`);
②**判据指向的东西不在卡面上**:L4「场景与 BT 标签是否登记完整」而 `content.asset`
压根没有 BT 列(剧本拿 `brand_tone` 顶替)—— 补 `bt_tag`(**人读值不带 tally**:
件上是普通格子、没有翻译层,存 ASCII 人看到的就是 ASCII,这是 `scene` 踩过的坑),
两份验收件都摆出来;
③**「发布前场景必须登记」只写在剧本里、机器数不出来** —— `scene`/`bt_tag` 加
`requiredWhen: {content_status: published}`,红带/提交闸/放行门 L2 三处同源;
④卡头/页脚缺说明书 §6.2 的四个共用动态位 —— 补关联任务(`case:taskId`)、步骤行、
页脚单号(最迟交回无真数据源,照 E04 口径不摆);编辑闸措辞改回目标件
「AI 已识别 N 个内容需求」(N 绑基座读数);触发口径并进【做什么】;
⑤样例名超 14 字全退成「样例 N」+ 样例 0 只有两个键 —— 收短名、把满载的那条挪到第一位;
⑥e2e 加 `i01` 套件(一张执行单 + 初稿审核决策卡 + 发布放行,含驳回循环案例)。
包内测试 29 → 44(补 steps.test.ts,把上面每条口径钉死)。
- **人在件上「加一行」会被静默丢掉:序号型主键没人给它续号**(2026-08-23,审 I01 时
逮到、浏览器实测复现):`content_brand.requirement` 的主键是 `round_ref + req_seq`,
而「加一行」那一下所有 `data-col` 都被清空(`ViewContainer.addRow` 如此)——
`req_seq` 空着,而各行序号本就互不相同,「全表一致」那条补法永远取不出 →
`writeEditedRows` 一 continue 就没了:**屏上两行、库里一行,还不报错**。
修:凑主键那一段抽成纯函数 `resolveRowKey`(9 测),三类主键三种凑法 ——
件上给了的用他填的 / 件上没摆的按行认或全表一致 / **整数型主键由基座续号(现有最大 + 1)**。
途中自己踩了一脚并当场修回:一度把序号列的 `data-col` 拿掉「让它只读」,
结果**老行也没了钥匙**,服务端把它当新增行、又拿「只有一行时的全表一致」猜出个 1,
**当场覆盖掉原来那一行** —— **主键列必挂 `data-col`**(它不是编辑面,是行的钥匙),
且序号型主键不走「全表一致」那条路(一致只是行数太少的假象)。
- **兜底卡自己被门拦住:最后的活路砌了墙**(2026-08-23,E04 回归实测):依赖断点那一拍
「当下可为」是空的,归一层给兜底卡兜出来的 `itemId` 就是空串,于是引擎自己造的那张
「需要你判断下一步」被 `readyToWork` 拒 —— 人连被问一句的机会都没有。
修两处:①归一层的项号兜底连**进行中**的项一起看;②**发卡的授权面是调人预算,不是计划项**
——项号挂不上照发、留痕注明(与「写看台账声明」「调工具看白名单」同族);
「这一步已经办完/停用」仍是真墙(既有测钉着),用 `ItemUnattachableError` 把两件事分开。
- **枚举列上下两态得说同一个字**(2026-08-23 用户:「BT 层级下拉框显示不全,
都看不到具体选了哪个」,`quote-…` E04@2.0.8):覆盖范围确认那张件的 BT 层级一格两处错 ——
①**列宽只有 80px**,而选项文字是「BT-01 · 采购/供应链」,下拉被挤扁,选了什么看不见
(覆盖深度那列因为选项只有两个字,同样的窄列一直没暴露);
②**只读那一份是 `data-slot` 直显**,存的是 ASCII `bt-02`,人看到的就是 `bt-02` ——
与编辑态下拉里的「BT-02 · 技术」对不上。**覆盖深度当初专门修过这个坑,BT 层级漏了**。
改:列宽 80 → 150,只读态换成 `data-class-of` 徽标、人读名由样式表出(值仍是 ASCII ——
台账与 recompute-score 的 `btLevel` 入参认它),选项文字统一成人读大写。
两条包内测试钉死:枚举列不许 `data-slot` 直显机器码、BT 列宽 ≥140px。
- **画面挑的是拍首那一步,而卡发的是下一步的**(2026-08-23,走查 E04 S4→S5 撞上):
那一拍收掉 S4(经营计划审批)、当场发出 S5 的回执执行卡,而工作区推的仍是 S4 声明的
**只读审批件** —— 人拿到的卡写着「把回执填到件上」,屏上一个可填的格子都没有;
提交闸如实拦住「缺完成状态、结果摘要、关键人变动」,他无处可填,整单挂死在那儿。
病根与 `liveScope` 那条同源:**拿拍首的局面去决定拍尾的事**(`liveStep` 在行动串跑完
之前就算好了)。修:推帧前按 `currentRuntime` 重算一次在办的那一步,算得出就以它为准;
算不出(活步都收完)照旧走老路,免得把人刚签过的放行页冲掉。设计律第一条
「墙要配路」的第四次现形。测钉死(拿掉修复就退回推 step1)。
- **表宽超出就得能横着滑**(2026-08-23 用户:「覆盖范围确认这个表格显示不全,
不能左右滑动」):E04/I01 抄 quote-* 版式时把 `.jc-tbl-wrap` 的 `overflow-x: auto`
抄成了 `overflow: hidden`(本意是圆角裁表头)—— 列一多、或某列为放下 BT 下拉框加宽,
右边那几列**直接被裁掉且滑不动**。两包改回 `overflow-x: auto; overflow-y: hidden`
(竖向仍关:件是整篇跟着外层滚的)。实证:950px 的表在 586px 容器里滑得动,
编辑态(958px)同样。E04@2.0.9 / I01@1.1.2。
- **翻件与翻页各归各位,没得翻就别摆数字**(2026-08-23 用户两条:「一次叫人不一定只有
一个 HTML 模板所以需要翻页,现在这个 0/0 显示的不正常」「工作成果点进一个工作成果
也需要这个东西」):右上角那对箭头从前**三处各写一遍、两组二选一**
(`docPages > 1 && openList.length <= 1`)—— 多张卡各自多页时**页就翻不动了**,
人只看得见每张卡的第一页。三处收成一个 `Pager`,两组同时在场时各带一个字(件/页)。
0/0 有两个来源,都治了:①`ViewContainer.paginate` 对没写 `data-page` 的件如实回报
0 页 —— **件在手上,再少也是一页**,改 `Math.max(1, …)`;②一件都没有时(在跑 /
等对话区那张卡 / 已收尾)摆的是 `0/0`,**0 分之 0 不是一个数**,改写「—」并禁用两枚箭头。
成果详情补**翻份**:一单常有三五份定稿(执行单快照 / 验收单快照 / 决策卡快照),
从前想看下一份得退出去再点一次;换份时页码归零(上一份翻到第 3 页,下一份可能只有一页)。
判断抽成纯函数 `pagerFace`/`pagerText`(9 测)。浏览器实证:决策卡那一屏「—」、
回执卡「1/1」、办结后四份成果 1/4→4/4 逐份翻过、末份下一枚变灰。
改共享面照例全量回归:1573 测 / typecheck / lint / depcruise 绿,
**e2e e04 三案例全部 released、发口 coverage-map 全对**(16-20 拍);
两案例各有 1-2 次被拒,都是既有的模型空转被墙拦住(recompute-score 同参连调第 5 次、
S6_writeback 少写一行就 finish),非本轮改动引入 —— E04 的 `被拒 0` 仍欠着。
- **I01 的「审核资料」第一次真产出资料文件**(2026-08-23 用户定:「格式可以是 word、excel、
md、html,文件需要能在前端渲染,在表格中点击资料名可以跳转到一个新的页面来渲染这些文件」):
接手时这一步**一个文件都产不出来** —— S3 的剧本白纸黑字写着「file_ref 选填,本 MVP 阶段
可留空」,台账里只有一行标题,人要审的那份初稿根本不在系统里(点不开、下不来)。
**文件是台账那一行的投影,不另存一份**(另存 = 同一份事实两处各存一份,改一处就分叉):
①**声明**:台账对象声明加 `file: {titleColumn, bodyColumn, formatColumn}`(契约变更),
它同时是授权面 —— 没声明的表点不开(403),与「写看台账声明」「立监听看清单声明」同款;
②**现造**:`file-compose.ts` 进「标题 + Markdown 正文 + 格式」出真字节 ——
docx / xlsx 是**自己打的 OOXML 包**(`zip-write.ts`:store + CRC32,不引依赖,
与 `upload-extract.ts` 读 xlsx 同一条路);md 出原文、html 出整份自带样式的文档;
③**读回来渲**:`file-doc.ts` 解**造出来的那份字节** → `FileDoc`(docx→段落 / xlsx→行列)
—— 屏上渲的与下载到的是同一份东西,渲得出来才证明文件是真的;
④**点得开**:视图新增绑定 `data-file-of="主键列"` → 渲成 `data-file="域.对象/主键值"`,
ViewContainer 接住 → 工作区二级界面 `FileViewer`(Excel 网格 / Word 纸面 / 渲好的 Markdown /
沙箱 HTML)+「下载原件」(`?raw=1`,RFC 5987 中文名)。
**Markdown 富文本渲染顺带销账**:`markdownBody` 一个依赖都没引(标题/列表/GFM 表格/
分隔线/粗体/行内码),全程转义、走同一个沙箱 —— 与下载到的 .html 是同一段函数出的。
I01 侧:`content.asset` 加 `body_md`(正文,必填)+ `file_format`(tally 四档,必填),
S3 剧本教它按内容形态挑格式(表→xlsx / 正式文档→docx / 网页→html / 短要点→md),
新增 L2 判据「每份内容都产出了资料文件」(四档计数之和 = 行数,两边都是基座数),
两份验收件的资料名都挂上链接 + 格式徽;新增第 4 条样例「对照表与落地页」——
一封需求里三种形态,专治「一律 docx」那条走不到的路。
**验收**:e2e i01 四案例(含驳回循环)**4/4 released、被拒 0**(8-9 拍 / 68-89k),
资料文件逐份取得回渲得出,末条实测 `xlsx / html / md` 三种格式各出各的;浏览器在**审核那一屏**逐份点开
(Word 纸面出四节标题与要点 / Excel 网格出参数对照表 / md 渲成标题+要点 / html 出纸面),
「下载原件」拿到的 .docx 落盘后 `file` 认作 **Microsoft Word 2007+**、
macOS `textutil` 逐段读得出正文。新测 47 条(现造+读回 22 · `data-file-of` 绑定 4 ·
fileRefOf 4 · 主键解析 6 · 包内 11);全仓 1573 → 1620。I01@1.2.2。
连带治掉一处每单白吃一次的被拒:**「提交前先裁三条 L4」原本只写在 T_release 的剧本里**,
而拟发布与提交常被模型压成同一拍 —— 那一拍摊开的是拟发布那一步的做法,T_release 的
剧本这时**根本不在上下文里**,于是照着 S5 写完就 submit,被门点名「三条还没裁过」。
规矩搬进**说明书**(每拍都在),与 A1 的卡骨架、A6 的决策卡同一课:
**模型会压拍,压过之后只有说明书还在**。
改了共享面(view-render / ViewContainer / desk 路由)照例全量回归:**e2e e04 3/3 released**、
发口全对(两例被拒 0,余一例是 E04 既有的模型空转)。
一处边界记进 debt:资料这一行落在**主数据**上,而试跑单放行时主数据只留在活动缓存、
不落正式表 —— 于是**试跑单放行之后**那份资料点不开(正式单不受此限);
404 的话已分两种说法,不拿「可能已被撤掉」把人支去翻一行根本不会在的东西。
- **产出的资料存了档,工作成果里点得开;查看面的灰底不再半路变白**(2026-08-23 用户两条):
①「渲染页面向下翻的时候背景的灰色在下半截会变成白色」—— **修了两刀,第一刀没打中**。
第一刀治的是走沙箱那两档(markdown / html):外层 `.fileview-body` 在 markdown 那一档
写死 `background:#fff`(它还是一整块 `<pre>` 铺满时的写法),与里面那份自带灰底的文档
不同色;改成同色 `#f4f5f7` + 去内边距,html 那一档一并(它套的是「渐变书桌 + 26px 边距」,
而那份文档自带书桌)。**但用户报的不是这两档** —— 他截图里那份是 docx,
走的是 word / excel 那条**父文档直接渲**的路(不进 iframe)。
真病根:`.fileview-body` 是 `.fileview`(`height:100%`)的弹性子项,默认 `flex:0 1 auto`
**不长个** —— 盒子高度被「看得见的那一屏」封住,而里面那张纸比一屏长时溢出盒子继续排,
**背景只画在盒子里**:滚过一屏,纸两侧的灰书桌就没了,底下是面板自己的白。
改 `flex: 1 0 auto`(不许被压 → 盒子至少和纸一样高;内容短时又能长满 → 下方不留白边)。
实证(同一单来回切):撤掉这一改盒子 529px、屏底取到 `rgb(255,255,255)`;改在盒子 1399px、
屏底取到书桌渐变。四种格式滚到底逐一取色:docx/xlsx 两侧是书桌灰,md/html 纸铺满且外层同色、
无空隙。**教训:同一个症状可能有两条独立的路,治完一条要把另一条也走一遍**。
②「检查当前产出的附件是否存档,在工作成果里也需要有产出的附件,点击后可以预览」——
**查出来的实情是没存**:文件一直是台账那一行**现造**的,而资料落在**主数据**上,
试跑单放行时主数据只留在活动缓存、不落正式表 ——「放行之后再点开」实测 404,
而工作成果恰恰是收工才去看的地方。现在**放行落地之前**(人的修订刚落回草稿层)
把每一份造成字节冻进 `sys.task_asset_file`(迁移 0029,一单一行一份、重复放行覆盖);
取文件那条路**存档优先** —— 归档件上点开的必须是他签字那一刻的那一份,
不是台账后来被下一单改成的样子。工作成果里「产出的资料」自成一摞(与定稿报告分开:
报告是「叫人办的那件事办完长什么样」,资料是**办出来的东西本身**),按格式上色、
带存档时刻,点开即预览、可下载原件;件上与归档报告里的资料名照旧点得开(同一条路)。
路上逮住一个只在存档那条路上出现的坑:**pg 取回来的 `Buffer` 挂在共享的 64KB 内存池上**,
`buf.slice().buffer` 是视图不是拷贝 —— 三份资料下载下来都是 65536 字节
(后面全是别人的残渣);改 `Uint8Array.from` 按元素拷。
验收:e2e i01 断言加了「放行之后逐份仍取得回、原件仍是 ZIP」这一条,
**四案例 4/4 released、被拒 0,每单都是「在办中渲得出 + 放行后存了档点得开」**;
浏览器实证两屏(审核那一屏、工作成果那一屏)都点得开,归档件里的资料名同样点得开,
归档的 .xlsx 落盘后 `file` 认作 **Microsoft Excel 2007+**、python `zipfile` 读得出
整张对照表。新测 8 条(存哪些不存哪些 + 主键拼法);`reset-runs` 一并清这张表。
- **两个后端连同一个库,把同一张单推坏了**(2026-08-24 柴浩实测:E04 一单五拍熔断;
用户中途提示「本机和局域网另一台机器的同一个后端都连着这个库」——最后一块拼图):
症状是**两堵墙对着撞** —— `finish S2` 被拒「从没给它发过卡」,而重发那张卡又被拒
「这件事刚问过,人也答过了」。查下来:卡确实发过(11:17:53 发、11:18:01 人答的),
可局面里 **8 个计划项的 `worldTouched` 全是空**;同一步 S1 被收了两遍
(两条 rationale 只差一个标点 —— 是两次独立采样,不是重放)。
根因:两边的推进器各自 2 秒扫一次「running 的单」,**同时推同一张**,
两拍并发写同一份 `sys.loop_state`,**后写的整份覆盖先写的** —— 发过卡这个事实就此消失。
而互斥只在进程内(`task-lock.ts` 开头自己写着「MVP 单进程…多进程部署时再叠一层」)。
**修**:`workers/task-claim.ts` —— 库里一列 `advancing_until`(迁移 0030)当跨进程租约,
推之前一条 SQL 判+占(判与占分两句写就是经典竞态),推完就还,带 5 分钟过期
(进程崩了不锁死);推进器与派发器两条推进路径都接上。
实测:两条真连接对着真库抢 20 轮,**每轮恰好一个赢**;租约过期后另一方接得上。
**还欠**(记 debt):`loop_state` 本身没有乐观并发(版本号 / CAS)——
租约挡住了主路,但绕过它的第三条路仍会**悄无声息**地整份覆盖。
排查法留一条:`worldTouched` 全空 + 同一步收两遍 = 并发覆盖的指纹。
- **点了要有反应,在办事要说出来**(2026-08-24 用户:「点击了都不知道点没点上」):
两件事各缺一半。①**键感**:治理台整套 `g-*` 控件一条 `:active` 都没有,工作台只有零星几个;
更糟的是有 `:active` 的那几个把 transform 一起塞进了 0.16s 的过渡里 ——
一次点击常常比这还短,手抬起来时键帽才刚下去一半。新增 `styles/press.css`
(三面共用、**装在最后**):按下 `scale(.97)`(整行整卡这类大件收到 `.995`,同样幅度会晃)、
**按下这一刻不过渡**(松开仍走控件自己的过渡,回弹是软的)、`:focus-visible` 描圈。
②**在办**:请求在路上的那几百毫秒屏上从前一动不动 —— 新增 `shared/Btn.tsx`,
`busy`(递 `mutation.isPending`)或 `onClick` 返回的 Promise 一亮,按钮脚下走一道
不定长进度条。**不给 `disabled`**:那会把按钮画成灰的,而它此刻正在**做**这件事,
不是做不了(界面不撒谎)。全仓 40 余处会去请求服务端的钮都换成了它;
勾选与下拉给不了键感,改成把**那一行**点亮(认 `mutation.variables`,只亮真正在路上的那一条)。
途中两个坑各留一条账:**条不能画进按钮自己的 background** —— 第一版用 background-image,
在真页面上量出来根本不存在:`.tbtn` 这类皮肤用 `background:` 简写上色,
特异度压过 `[aria-busy]`,图片当场被顶回 none(动画照跑,条却没有);改用 `::after`
(全仓按钮类没有一条定义过伪元素,审过)。**`<select>` 一律不挂 `aria-busy`** ——
替换元素画不出伪元素,且它的下拉箭头本身就是 background-image。
③**防抖按在唯一通道上**(`typed-fetch.call`):在途去重(同一笔还在路上,第二次点击
拿到同一个 Promise)+ 落地后 450ms 的双击窗(**只管写请求**:读请求写完立刻重取的
那一下不能被当成余震压掉);失败的不进窗 —— 那时候再点是重试,重试必须真的重试。
按在这里,所有点击路径一次盖全,不必指望每个调用点自己记得。
④顺手修一个**没接线的钮**:对话区空态那枚「发送」从来没有 `onClick`,
只有文本框里按 Enter 才发得出去 ——「点了都不知道点没点上」在那儿是字面意思。
实证:浏览器里量了层叠(探针类复制 `:active` 规则,`.tbtn`/`.jc-tnav-tab`/`.jc-topbar-logout`
都真到 `scale(.97)`、`transition-duration: 0s`)、真点了会走网络的钮(条真现身真收掉)、
连点三下只发出**一个**请求。新测 9 条(callKey / 在途去重 / 双击窗 / 读写分野 / 失败不进窗)。
- **四件事一起收**(2026-08-24 用户连报):
①**进度条的刻度与业务步数对不上**(「E04 应该是有 7 步、给人确认是 4 步,这里要是 x/7 才对」):
`COVERAGE_PHASES` 从前按归口粗分三段 → 屏上 x/4,而文档开篇写的是「整体流程(7 步)」——
同一件事两个数。改成一段一步(6 段 + 基座那格「放行收口」= 7),与文档那张表逐行对齐;
四张卡就是那 4 个「给人确认」的刻度。实测:`4/7 · 经营计划审批`。
(踩了一脚:注释里写 `x/7` 那个星斜杠就是块注释的结束符,esbuild 当场报在几行之外。)
②**件上新增的行被静默丢掉**(「新增了一个客户,推进到下一步直接就把这一行遗漏掉了」):
主键那几格空着就凑不出钥匙,基座一句 `continue` 跳过,而接口照回 `{ok:true}` ——
**保存说成功,东西却不在**。查的时候又逮出更凶的一面:表里恰好只有一行时,
「全表一致」把那一行的客户编码当成常量补给新行,**当场把老行覆盖掉**
(与 2026-08-23 序号型主键那次同一条规律,当时只按「是不是整数列」绕开了)。
现按**他填得了吗**统一判:件上摆着的主键格,空着就不许基座替他编值;
没落下的行点名回给前端(只点他填得了的那几列),件上方红字说清。
I01 的序号型主键照旧由基座续号,不受影响。
③**界面停在「AI 推进中」,刷新才发现已经在等人**:`createBroadcaster()` 是**进程内**的
一个 Set —— 那会儿两个后端连同一个库,单子被另一台推着走,这一台的浏览器一个字没收到。
加 `broadcast-bridge.ts`:Postgres `LISTEN/NOTIFY` 当桥(不引消息队列),自己发的自己不收,
形状不对的载荷丢掉。实测:另一台 NOTIFY 一条,本机 SSE 立刻收到。
④**数据域按活动重写**(用户定):从前按性质分组(主数据/单据/派生)——那是治理这张表的人的分法;
而人跑完一单来这儿问的是「我这个活动写了哪几张表、现在各有几行、刚那一单落下了什么」。
新增 `/api/gov/data/by-activity`:每个活动 → 它声明的表 + **正式行数** + **在办草稿行数** +
最近三单。三个数各说各的:没物化就不给数(「声明了没写过」与「写过又空了」是两件事)。
实测 E04 一单跑完,那一屏从「正式 18 行」变成「正式 24 行」、最近的单标「已放行」。
- **试跑单也能「落真库」了**(2026-08-24 用户:「活动执行后数据并没有真实入到后台数据库里面」):
实情是一半 —— **单据真落了**(`crm_coverage.*` 有行、有值),**主数据被挡在活动缓存里**
(`ledger-service` 那道门:试跑往 `customer.profile` 建一位客户,那位客户就永久留在库里,
「新客户来函」样例第二次跑就成了老客户)。可这条保护在演示时正好拦住要看的东西:
台账更新明细白纸黑字写着「亲密度 3 → 10」,而 `customer.contact` 里还是 3 ——
**单据说改了、主数据没改,两份事实对不上**。
现给试跑一个开关:`sys.task.land_master`(迁移 0031)+ 起单入参 `landMaster` +
试跑台上一个复选框;`isSimulated` 认这一列。
**默认打开**(用户当场定:「那你就默认给它打开」)—— 跑一遍活动就该看见数据真的变了,
这是本分;保护没取消,只是**换了落点**:要它的那个调用方自己关
(`tools/e2e-a2.mjs` 显式传 `false` —— 只能测一次的样例归它管)。
**默认值服务于人手点的那条路;脚本要什么,脚本自己说。**
实测(不传任何参数起一单 E04):`land_master = t` → 放行写合并 16 行、**没有**「只留在活动缓存」,
活动自己新建了两位关键人(CU-0142-02/03)、覆盖度 17 → 33。
- **人加的候选客户被整单无视:覆盖闭合成为机检**(2026-08-24 柴浩实测:「覆盖范围确认
步骤我新增了一行要覆盖的用户,后面推进直接无视了」):行**落了**台账(candidate 两行、
focus 段模型看得见、`_rows = 2` 也在),而 plan/receipt/收口全是 CU-0142 的 ——
模型锚在轨迹「识别出 1 家」上;S3 收步判据只数 `plan_rows > 0`、放行也没有一条钉
「盖没盖住每一家」,一路绿灯 released。三处合谋,三处一起修:
①**基座新增 `distinct` 读数**(声明列标 `distinct: true` → `域_对象_distinct_<列>`,
空值不算一种、零行铺 0,静态审计认它)—— 「计划盖住几家客户」从此是基座数得出来的数
(计划行数 ≠ 客户数,一家几位关键人就几行);E04@2.1.1 把闭合
`plan_distinct_customer_code = candidate_rows` 钉在 **S3 收步 / S4 入场哨兵 /
放行 L2** 三处。②**「就地修订」痕点名新增的行**(从前只说「新增 1 行」,哪张表、
哪家客户都不说;撤行 2026-08-02 就点名了,加行是同一条道理的另一半)+ 行动指南
「人加的行同等作数,按台账现读全表办」;说明书立「人核对过的候选清单是每一步的
输入契约」。③**墙要配路**:人加的客户常在主数据里零联系人,S3 给「首访建档」的路
(计划行 contact_code 用 `-00` 占位引用、缺口按默认尺算、不往主数据建假号),
S6 补写它的客户档案、回执带回真人再建真档。
**验收**:e2e e04 复刻案例(件上加 CU-E2E-ADD)—— 决策卡改口「共4条,覆盖2家客户」、
**released、被拒 0**,正式表里那行计划就是 `CU-E2E-ADD-00 · 本月内首访识别关键人并建档`;
痕也点了名(「新增 1 行(CU-E2E-ADD/COV-…)」)。另两案例 released、被拒 11/1 ——
全是 08-23 已记档的既有空转(S6 少写就 finish · no-missed-update 先写 2 条),
没有一次撞在新闭合上;「E04 被拒 0」仍欠着(debt)。1663 测 / typecheck / lint /
depcruise 绿;契约变更(`FieldDeclaration.distinct`)api-report 已刷新待提交。
小尾巴:人加的候选行 S6 忘置 status(状态徽空着,不拦单),随「被拒 0」一并欠着。
- **驳回意见点名「测试111」,改动落到了 Itelma 头上:归属交给基座比对**(2026-08-24
柴浩实测第二发):意见原话「测试111建议动作改成拜访CTO」,计划表里明明有一行
`customer_name=测试111`,模型复述时把「测试111」当杂音丢了,按「谁有CTO」的自我
推理挑了 CU-0142-01 改。与 E04 worldTouched 同一课:**指南让模型判的事,引擎有
现成事实的,一律改成读事实** —— 归属是纯字符串包含。两手:①基座 `note-anchors.ts`:
决策卡带意见回来那一刻,意见与本单草稿逐格字面比对(值 ≥3 字、非纯数字、命中 >5 行
当没命中),命中的行以观察落在 card-reply 旁(「意见按字面点名对上了…先认归属;
点名的行缺什么,改这一行自己的内容,不是挪到别的行头上」)—— harness 侧,在途单
立即受益;②E04@2.1.2 S4 剧本立归属纪律(照观察认、四列逐行比、认不出唯一就重发卡
把「你理解改哪一行」写进 ask 请人确认、重发卡的 ask 用人读名点名改了哪家哪位)。
e2e 案例①升级:点名意见驳回 → 断言改动落在被点名那一行(`expectRevised`)。
7 测(matcher)+ 1 测(guide 钉死);1671 测全绿。
- **落库的台账要摆全给签字的人,AI 填不出的字段在确认屏上就能补**(2026-08-24 柴浩
连报四件:联系人没建上 · 新客户档案一堆空字段 · 两条无名联系人 · 确认屏没摆全):
勘出两类病:①**模型替「计划要经营的岗位」凭空建联系人档**(人名职务全空、却标着
关键人/亲密度3 —— 把计划冒充成档案;两条已人工删掉,CU-0142 覆盖度 100→17 改老实);
②新客户档案连 name 都没抄(候选行里明明有)。修四层(E04@2.1.3):
①声明:`customer.profile.name` / `customer.contact.name` 升必填 ——
`_missing` 本就在 S6 收步与放行哨兵里,**无名档案从此进不了正式表**;
industry/region 标建议档(AI 从来件/note 推得出才写,不许编造;推不出橘胶囊留给人);
②**台账更新确认那份件补两张「落库预览」表**(将写入的客户档案/联系人档案,
即签字后进正式表的行本身,不是摘要):可就地补改、联系人可**加行**,红带与放行哨兵
同源(`customer_*_missing`);③基座:件上「加一行」遇声明 `auto` 的主键由基座续号
(`writeEditedRows` 接 `autoKeys`,与录入卡同一段 —— 「自增列不问人」管到件上;
拒回不再点名人填不了的 auto 列);④剧本:碰过的行把 name 照现值带上、
没有真实姓名不建联系人行、新客户档案 name/cust_type 照候选行抄。
1672 测全绿;e2e 案例 0 再扩:确认屏补一行联系人(编码留空)→ 断言基座续出
`CU-E2E-ADD-01`。**验收(@2.1.4):三案例 3/3 released、全部被拒 0** ——
E04 第一次到零被拒线(08-23 起欠着的那条就此销掉);案例 0 一单连过四关
(加行进计划 / 点名驳回改在被点名行 / 确认屏补录联系人续号 CU-E2E-ADD-01 /
名字必填的新墙零摩擦)。途中顺手治掉一条 guide 自招的空转:S3 ④「顺手补写
cust_type/bt_level」没写「还空着」三个字,模型把有值的行照抄一遍白吃一拒 ——
补上三个字(@2.1.4)。数据侧同批手术:两条无名联系人已删、CU-0142 覆盖度
100→17 改老实、CU-2039 档案回填人给过的 name/cust_type。
- **落库预览要回显「签下去之后这一行长什么样」,不是草稿那半截**(2026-08-24 柴浩:
「Itelma 的字段没回显,点编辑变空白输入框」):两层病 ——
①预览绑的 `mine:` 只有模型本轮写过的列,Itelma 既有的客户类型/行业/区域、联系人的
职务/角色全不在;②文本格用了手写 `<input>`,渲染器只给自动孪生件(`data-slot`+
`data-col` 空 span)填值,手写的一开编辑就是白框。修(E04@2.1.5 + 基座):
①新数据源 `touched:域.对象` = 正式现值 + 本单草稿叠加、按草稿键只取本轮碰过的行
(engines `touchedRows` 纯函数;不进提示词,restPart 滤掉);②预览两表改绑 touched、
文本格全部换自动孪生(select/textarea 本就有 current 填值);③**保存的「真改了吗」
也对着叠加行比**(从前只对草稿:回显值一保存全算「改了」,痕写「改了 2 行」而人
一格没动,日志撒谎)——「是不是新增」同理改判。
连带逮出并修死一个**新增变覆盖**:人在确认屏加联系人,编码空着(自增列本分),
而 `resolveRowKey` 的 findKnownRow 拿半把钥匙(只有 customer_code)把新行错配到
该客户已有的草稿联系人行上 —— 编码从那行借来,模型刚建的那位被顶掉,痕还写
「改了 1 行」。立规:**空着的自增列不是身份线索,是「给我续个号」**——声明 auto
的列件上摆着却空着,一律不走 findKnownRow/全表一致,直进续号(2 测钉死);
e2e 断言同批收紧(按填的姓名找行,防覆盖冒充新增再骗过一次)。
**验收**:案例 0 released、被拒 0;定格的确认屏 HTML 六探针全中(Tier1 OEM /
车规电子 / value="Itelma" / value="Ekaterina Volkova" / 测试CTO王工 /
CU-E2E-ADD-01);痕三条全部老实(新增记新增)。1676 测 / 五门禁绿。
- **括号少一个,一拍全对也白跑:括号栈补上「补」这一档**(2026-08-24 柴浩:「怎么又
推不动了」):卡在 S6 收口拍 —— 全流程括号最深的输出(decision_chain +
interaction_timeline 两个嵌套 JSON 列),关思考的模型在 profile 行上**少吐一个 `}`**;
drop 档(08-02 治「多括号」)把后面本该关 rows 的 `]` 当噪声丢掉,整段错位到尾,
重问一次(温度 0.2)几乎原样复现,两连败 → 兜底卡「需要你判断下一步」交人,
单子看着像卡死。修:`parseJsonLoose` 两档**有序**修复 —— 先 drop(多括号当噪声),
失败再 close(闭括号对不上但栈更深处有它 → 把欠的补上;文本截断收尾 → 全补)。
顺序不能反:close 先跑会把多括号那形的外层提前关掉、行动串截半(测钉死)。
仍只合成闭括号,不发明内容。事故原文实测:三个 write 全解出。1679 测绿。
**同夜第二形**(e2e 逼出):行对象没关、后面直接跟 `,{"key":…`(下一行)——括号到尾
能配平、strict 与两档全看不出;close 档补第三条:**对象里逗号后面冒出 `{`/`[`,就是
上一个对象没关**,把欠的 `}` 补在那个逗号之前(逗号其实属于外层数组)。两起原文
全解出(11 测)。e2e 同批:认出「需要你判断下一步」兜底卡当场判失败收工,
不再空转到 20 分钟超时。
- **数据域记录浏览的 JSON 列不再是 `[object Object]`**(2026-08-24 用户报):
格子文本 `String(row[col])` 对对象一律糊成那七个字 —— 决策链地图 / 互动时间线两列
整列不可读。补 `cellText`:对象/数组 stringify 原样摆,超 120 字截断加省略号、
全文进 title(悬停可读)。别处早就对了(试跑草稿面 JSON.stringify、视图 displayValue),
只有这张表漏了。浏览器实证:决策链格摆出 `{"nodes":[…` 真内容,全页无 [object Object]。
- **「关键人待识别」从计划渗进主数据又渗回来:占位句式全链退役 + 引用墙**(2026-08-24
柴浩:「审批里怎么会有关键人待识别的项目」):三层病 ——
①模型把 2.1.1 的占位句式(查无联系人客户的 -00 行)**泛化到缺口节点**,给 Itelma
编 CU-0142-02/03 引用码 + 占位人名(措辞三连拦不住:反例描述/说明书纪律/禁令);
②某单落库后这些占位行**以「关键人待识别」为姓名进了 customer.contact 主数据**,
下一单从主数据读到它们照常规划 —— 污染自我强化;③一次 e2e 集合共用 bug
(录入卡与决策卡共用已答名单,decideSeq 序号被顶,点名驳回被跳过)。
修四层(E04@2.1.7 + 基座):①**占位句式全链退役** —— 查无联系人的候选客户改走
**数据录入卡**先收第一位关键人(该问人的问人;骨架进 S3 剧本),真人建档后再排计划;
一位联系人一行,缺口节点动作并进已知联系人那一行;②**契约新增 `refersTo`**
('域.对象.列'):声明引用关系,基座 draftWrite 那一刻查引用表(正式+草稿叠加),
查无此值当场拒、拒回指路;安装静态审核 refersTo 目标真实存在
(`reference-target-unbound`,写错地址=永远查无此值的死墙);plan/receipt 的
contact_code 都钉上;③主数据两次清污(占位联系人删除);④e2e:录入卡代答
(entryValues)+ 计划违禁字样断言(forbidInPlan)+ 已答名单分家。
**验收(@2.1.7,主数据清污后)**:三案例 3/3 released、全部被拒 0(16-18 拍);
案例 0 计划恰 2 行全是真人(Ekaterina 那行把两个缺口节点的动作并进她名下、
王工按点名改成约见CTO),录入卡先收人 → 确认屏再补一位续号 -02;案例 2 单人单行。
注意:refersTo 墙在这轮从没响 —— 主数据干净时模型照 2.1.7 的「一位联系人一行」
就不再编码了;墙是备份,不是主路。**清污是前提**:主数据里躺着占位联系人时,
引用检查会「合法」放行它们(引用的确存在),病就从主数据渗回来。
- **报价链 A1–A7 从系统卸载,只留 E04 / I01**(2026-08-24 用户定,**只卸不删源码**):
六个 quote-* 包在库里置 `uninstalled` + 禁用(registry.uninstall),两个 RFQ 触发器
(trg-rfq / trg-rfq-manual)停用 —— 触发器对着已卸载的活动起单只会生出坏任务;
种子同步:`REAL_PACKAGES` 只剩 E04/I01,`seedMvpFlow` 以 `SEED_QUOTE_FLOW=false`
整段不播(统一报价流程包 / 触发器 / 询价邮箱 —— 装不上的活动激活流程包会被闭合
校验拦下)。源码、e2e 套件、包内测试原样保留;`MVP_PACKAGE` 常量仍是流程编译与
触发装配那几组测试的夹具。**库里 `unified-quote` 流程包仍在**(active,节点指向已卸载
的活动 —— 蓝图待补清单会点它),等用户定要不要连流程包一起退。要装回:名字加回
`REAL_PACKAGES` + 拨回 `SEED_QUOTE_FLOW`,跑 activities:install。
- **台账更新确认四件小账**(2026-08-24 柴浩连报,E04@2.1.8):①**重做后旧明细留在表里**
(SQ-0031 的覆盖度同时挂着 50→50 与 50→100):主键是序号,重做时模型新开一行而不是
同 seq 覆盖。结构治:明细表加 `update_key`(台账地址|客户|联系人|字段,必填,
`distinct`),S6 收步 + 新 L2「同一处字段只留一条更新」钉 distinct = rows;
T_release 重做分支写明过期行 `drop` 撤掉。②**依据列带机器键前缀**
(「回执 contact_code=CU-0087-02:…」):说明书与技能改教人话(客户名·人名的回执:…),
不写编码、不带前缀。③**标题旁的单号不摆**:`doc()` 的 `titleRef` 改可选,四份件全去掉
(页脚单号仍在)。④**验收判据与「AI 已完成」文案夹着 `coverage_score`/`decision_chain`**
→ 全改人读名。当前那单的草稿当场手术:删过期行、去六条前缀。包内测试 91 条钉死四条口径。
- **计划 7 行回执 6 行照样交卷、两堵墙对撞熔断、对话区偶发乱序**(2026-08-24 柴浩三连):
①**多行 write 不是原子的** —— 第 2 行撞 refersTo 墙被拒时第 1 行已落草稿,轨迹只记
「被拒」,模型与人都以为一行没写,回执骨架从此少一行;提交闸只数已有行缺不缺必填,
数不出「少了一行」;放行门「每条计划都有回执」拒 → 模型删计划凑数 → 「每家候选都进了
计划」拒 → 加回来 → 循环五拍熔断,而缺的那行回执只有人能填。修:loop 的 write
**整批先验后写**(`draftWrite` 加 `dryRun`,两遍),被拒 = 一行都没落;E04@2.1.9
把「回执行数 = 计划行数」钉进 S3 收步与 S4 入场哨兵(派回执单前就得齐),S4 剧本
加/撤计划行同步骨架,T_release 写明回执少行 → 补骨架重派执行单、**不许删计划凑数**;
e2e 回执单派出那一刻断言骨架 = 计划。②**对话区按任务内序号排,不按墙上时钟**
(`chat-order.ts`):合并从前按 `at` 字符串排,两台后端交替推同一单、时钟一偏,
上一拍的话就排到下一拍后面;记忆 `seq` 与时钟无关,AI/系统项本身是记忆条目、
卡对 card-sent、自由输入对 human-input(`say` 现在把消息 id 记进 detail),
找不到落点的老数据按时刻插位。3 测。
**验收**:脚本 e2e 案例 0 released、被拒 0、回执骨架 = 计划;浏览器全链(AI 账号,
不落主数据):件上加客户 → 录入卡收 CTO → 点名驳回改对行 → 回执单待回执 2/2、
闸拦空手交卷、件上填两行保存即落库 → 验收判据全中文、落库预览回显 → **released**
(17 拍、被拒 1 —— 模型在 S3 先写了计划再写回执骨架、中间撞了一次 doneWhen 收步,
下一拍补齐);对话区 AI 气泡 23:52 → 23:55 → 23:57 单调;更新明细依据人话、位置键唯一。
- **摆给人看的行标识去掉单号那一段**(2026-08-25 柴浩:「COV-…/CU-0142-01 只保留斜杠右边」):
缺项红带 / 执行卡提交闸 / 拒回主键名单 / 就地修订痕从前把主键各列全拼上 ——
可人正在这一单里看件,单号是脚下的地面,不是区分行的信息。基座 `rowLabel(id, caseKey)`
按声明的单标识(`caseKey`)去掉那一段,四处同源同改;去完一段都不剩(主键只有单号)
退回整段。`missingReadings` 入参补 `caseKey`。4 测;在途单 `views.repush` 一帧即见。
- **点击后两块同一帧变脸:「在办事」写在回传返回之前**(2026-08-25 柴浩:「右边聊天框
先有反应,中间的 html 过一会儿才变成 AI 正在推进中,看上去很不流畅」):人回传落库后
runtime 要等派发器投递、推进器抢到租约、开跑前那一刻才翻成 `running` ——
前端 onSuccess 那一次重取抓到的还是 `awaiting-event`:对话区(卡状态已落)先变,
工作区(读 runtime)要等下一次推送。修:`TaskService.wake(taskId)` —— 只对
awaiting-event / awaiting-human 翻 running 并 setPhase('active')(顺带广播),
两条回传路由(工单 / 对话卡)在返回之前调它。浏览器探针实测(100ms 采样):
点「通过」后 **401ms** 中间已是「AI 正在推进这单」、对话区同帧「你选了:通过 ·
持续推进中」;8.2s 推进完成两块同帧换成回执件 + 下一张卡。3 测;CONTRACT.md 已记。
- **对话区「上一步的卡跑到这一步下面」的真病根:并卡判紧邻只看对话项**(2026-08-25
柴浩第二次报):08-24 那刀(按记忆 seq 排序)治的是**跨机器时钟偏**,而这次时钟没偏 ——
I01 一单:「两份初稿…请审核」→ 发决策卡 → 人答 → 收口 → 发验收卡;`projectChat`
的「一个气泡 = 交代 + 卡」只看 `out` 末项是不是还没挂卡的 AI 发言,而决策卡 / 录入卡
的 card-sent、人的答复、内部观察都**不进 out**,那句话在它眼里一直「空着」——
41 秒后的验收卡被挂到了上一步那句话上,以它的时刻排到决策卡前面。修:「刚说过话」
按**记忆序列**判(话与工单之间不许隔任何条目;装配戳这类信封件除外;跨人卡 / 决策卡
的 card-sent 也算隔开),一句话只领一张卡。3 测(26 → 全绿)。**同一症状两条独立的路**
(时钟偏 / 并卡误认),治完一条要把另一条也走一遍 —— 这是 08-23 灰底那课的第二次。
- **工作成果里摆着别单的资料:「这一单产出的」被算成了「这张表里所有的行」**(2026-08-25
柴浩:「这个工作成果怎么有 4 个资料,这单的需求只会产出一个」):那一单只写了
`CT-2026-0004` 一行(三笔留痕全指着它、放行合并 3 行),而工作成果里摆着四份 ——
另外三份是**品牌内容库里历次跑出来的资产**。病根一处、抄了两遍:放行存档
(`archiveAssetFiles`)与在办列单(`assetFilesOf`)取行都用 `taskView(where:{})` ——
那是「正式版全表 + 本单草稿」的合并视图,而资料常落在**主数据**上(`content.asset`),
整表里躺着别单放行过的行。台账契约本就把这两件事分得清清楚楚(`taskDrafts` 的注释:
「引擎求值要区分『这一单的事实』与『别人放行后的事实』」),视图模版也一律绑 `mine:`
——只有资料这两处忘了。修:抽一段 `assetRowsOf` 存档与列单同用,认**本单碰过的行**
(草稿键),值仍取叠加行(改过一格的行按落库后的样子造文件);`touched` 是必填入参 ——
「哪几行是这一单的」每个调用方都得回答得出来。e2e 补**份数断言**(存档份数 =
本单写下的资产行数,多一份也判失败 —— 从前只断「取得回、渲得出」,多摆几份照样全绿)。
用户那一单误存的三份已删,工作成果现摆 1 份、点开即那份 .docx。5 测。
顺手清两笔:`wake.test.ts` 的 `as unknown as`(§12.5 禁止清单,lint 红)、
`wake` 契约的 api-report 快照(上一轮没入库,api:check 一直红)。
- **统一鉴权中心(Keycloak)接入,只做后端**(2026-08-25,ADR-012):资源服务器 —— 后端只验 Bearer JWT
(`jose`,RS256 / iss / aud 本地验,不回源);`Staff.id` = `sub`,首登即建、Admin API 同步名册;
**权限只到端**:`sys.role_access` 一行一个 realm 角色,运营中心可改(锁死不变量:改完得有人还能进运营中心);
路由归属写在契约 `access` 上,app 层一处中间件统一判 401/403,治理路由里 59 处守卫整体删除,
覆盖测试 fail-closed;SSE 与下载走 60 秒票据;口令 / 会话表 / 岗位授权退役(八条路由回 410,契约留一轮)。
web 待按前端手册接入,接入前登不进。
- **邮件收发模块接上腾讯企业邮箱,两条路**(2026-08-25,ADR-013,`apps/api/src/modules/mail` L1):IMAP/SMTP(任意信箱 + 客户端专用密码)与
企业微信邮件 API(应用邮箱);腾讯没有带内容的推送,收信是**轮询拉**(每账号自己的间隔,跨进程租约 `polling_until`)→ postal-mime 解析 →
`sys.mail_inbound` 两把唯一键去重 → 分发给订阅方(`channel` 是第一个:来信归一进事件流,活动经触发器 / `listen` 收到)。
分发**自动只投一次**(channel → event 按 cause.ref 不幂等,重投会起两单),失败在运营面可见,「重新投递」是人按的钮。
发信:`mail.send` 工具 2.0.0 真发(放行时经 ToolInvoker;`dryRun` 只校验 —— 注册的试运行会真调处理器)、channel 出站经 `mail.send`、
运营面试发;先落 `sending` 再发,厂商失败不抛(`state:'failed'` + 原话脱敏);带幂等键的不发两封。凭证密封,视图只回 `secretBound`。
15 条 `/api/gov/mail/*` 路由**全部归运营中心 `ops`**(读写都不给设计端 —— 邮箱那一屏没有设计端消费方,入站正文是客户来往内容,
见 ADR-013 决策 10);前端未做,照 `docs/前端对接说明-邮件收发.md`。新依赖 imapflow / nodemailer@8 / postal-mime。
欠账(debt):event 按 cause.ref 幂等、IDLE、wecom 无 Message-ID、channel 无 upsert 路由(共十五笔见 debt.md)。
- **「工作台疯狂轮询三个接口」= 两台后端互桥回弹的广播风暴**(2026-08-26 用户报):前端没有任何轮询
(`refetchInterval` 全仓只在测试台),是 SSE 在以每秒几千条的速度推 `system` touch —— 挂在库的
`jcai_touch` 频道上实测 **45 秒 192,270 条**,全是同一条 `POST /api/gov/process/validate`,
在 8787 与 8790 两个进程之间严格交替、条数相等。病根 `broadcast-bridge.ts`:收到别人的 NOTIFY 就
`broadcaster.publish` 到本地,而桥自己也订阅着这个 broadcaster,那条转发被当成「自己推的」再 NOTIFY
一遍(from 换成自己)→ 对面不是它发的、再转发、再 NOTIFY……「自己发的自己不收」只挡一跳,两台接力
就是永动机;08-24 验桥时只有一台在跑,没有第二方回弹。修:转发进来的那条打记号(WeakSet,publish
同步派发),「本地 → 库」那一侧认出记号就不发;`bridgeBroadcaster` 第三参 `self` 可注入(同进程两座桥
才模拟得出两台机器)。2 测:转发不再 NOTIFY 出去 · 两台互桥一条广播各到一次就停(假频道封顶 50 条,
让用例失败而不是把测试进程撑爆 —— 第一版真·无限递归 OOM 了)。两侧任一打上补丁回弹即断。
连带看见但未动:`task-service.tick` 每拍无条件 `setPhase` 广播 + 每拍推帧 + 推进器 `advanced`,一拍
3-4 条 `task` touch,前端 `invalidateFor` 无合并 —— 推送有多密请求就有多密(记 debt)。
- **工作台任务界面给 SSE 配了 10 秒兜底轮询**(2026-08-28 用户定):`app/fallback-poll.ts` ——
任务界面开着时每 10 秒把 `desk` 下**在用的**查询(清单 / 这一单 / 角标,`type:'active'`)各重取一次,
推送漏了画面最多旧 10 秒;**不取消在途**(`cancelRefetch:false`,慢接口不被兜底打成永远取不回)、
页签藏起不打、回前台先补一趟;壳层 `useEffect` 起停,切模块 / 卸载即 `stop()`(定时器与可见性监听一起摘)。
`doc` 可注入,4 测钉死(周期 / 停止 / 可见性 / 在途去重,第四条做过变异验证)。
§9.2「组件禁止自行轮询」照旧:兜底只此一处、由壳层起停。`queryKeys.desk` 新增作整支前缀。
- **录入卡在等人时,工作区摆占位页,不摆件**(2026-08-28 用户看柴浩的差异评估单定的):建档那一步
(「客户 123 不在客户档案里,请核对建档」)要人做的事全在对话区那张录入卡上,而工作区里躺着的是
**上一拍**推的 HTML 件,人以为要在那份工单上办点什么。前端判:`pendingCardsOf(detail.chat)`
(纯函数,5 测)认出未确认的录入卡 → `ViewRegion` 在 running 之后、viewHtml 之前插一支占位
`EmptyState`(点名那张表的人读名,指向对话区);决策卡**不走**这一支 —— 人要决定的常常就是件上那份稿。
- **第三个活动 ACT-WORK-05 差异评估已入库并全流程走查**(2026-08-27,`part-substitution-assessment@1.2.6`):
原 PN 与候选替代料**逐项差异评估** —— 比参数、判四态(MATCH / MISMATCH / UNKNOWN / CONDITIONAL)、
定推荐等级(推荐 / 条件推荐 / 备选 / 不推荐)、留证据与验证任务,落 P-11(替代关系 + 差异明细)、
回写 P-01,发一口 `assessment-released` 交 ACT-GATE-03。
**九个计划项**(五处不给 doneWhen):S0_bind → S0d_p08_master / S0d_p10_document(两张数据工单各一份件 ——
一个计划项只能绑一份画面,不能共用)→ S1_input_confirm(唯一的执行工单,零输入)→ S2_normalize →
S3_assess(两枚纯函数工具:`compare-parameters` / `recommend`)→ S4_review(决策卡循环)→
S5_prepare_landing → T_release。
**新建 4 域 7 张主数据表**(`parts.profile` / **`parts.parameter` 子表** / `parts.document` / `demand.request` /
`substitution.relation` / `substitution.difference_item` / `validation.record`),主数据域 4 → 8。
五张模版**逐字节搬自目标件**(`views/target-style.ts` 是抽取的原样式表,不用 E04/I01 的外壳)。
**六轮浏览器走查全部 `released`**(都在库常路 / 候选缺库 / 三候选含硬约束不推荐 / 原PN缺库硬阻塞 /
新客户建档 / 录入卡复验),覆盖决策卡、审核驳回循环、终局重做循环、数据录入卡四条人环分支;
逐单 SQL 复核落账(`customer_approval_status` 每单留空 —— 只读边界守住,`rule_version` 随结论落账)。
逐轮结论与 A–K 十一条发现见 `docs/ACT-WORK-05-端到端测试记录.md`,字段口径见 `docs/数据域字段说明-W05.md`。
**三条值得记住的**:①**「机检只读基座数」第六次现形,这次是存在性不是计数** ——
原 PN 根本不在库而模型判「在库」,剧本已写到头;治法是 `pn_check.found_pn_ref`
(`refersTo: parts.profile.internal_pn` + `requiredWhen: {exists_status: found}`)——
**判在库就必须拿得出一个基座查得到的料号**,查无此值当场拒、填不出则收不了步。
②**模型会压拍,压过之后只有说明书还在**(第四次):S1 的「先写清单再发卡」只在剧本里,
压拍那一拍卡发出去而清单一行没有,人对着空表;规矩搬进说明书。
③**措辞治不了的结构治,但先分清「已经说过」与「从没说过」**:同一天的发现 I 是前者(该上结构),
发现 J(数据工单派给了在库的那颗)是后者 —— 剧本从没写过「found 的不建」,补一句话就够。
平台侧四条欠账已记 debt(`disable` 无路可走 · 前一项不收掉后一项的件推不出来 ·
拒回数不出「缺的是一次工具调用」· 零行台账的提交闸无牙)。
- **脚本 e2e 逼出的八条:两条线逮到的缺陷不重合**(2026-08-27,`w05` 五案例连跑六轮):
浏览器走查逮**人看见什么、点得动什么**;脚本逮**机制** —— 它每张卡都先空手交一次、
每个岔路口按序代答,而人手点的时候永远不会去试「空着交上去会怎样」。**发现 L–S 八条,
没有一条是浏览器那六轮逮到的**。末轮:跑到的四例全部 released、三例被拒 0
(第五例停在大模型账户 `Insufficient Balance`,不是代码问题)。
平台侧六条(全部有测):①**闸看错了表** —— 卡没绑表就回落到必交付物,而数据工单要人补的是
`parts.*` 主数据、不在交付物名单里:闸盯着一堆无关的表、一格不缺,空手交卷一路放行。
契约新增 `ExecutionWorkOrder.gateLedgers`(**这张卡该拦哪几张表,发卡的人说了算**),
`gateAddressesOf` 变三级取一(绑的表 > 卡自报 > 交付物);②**拒回数不出「缺的是一次工具调用」** ——
`finish` 撞 doneWhen 为假时只谈「行与列」,现在摆判据原文 + 那几个名字此刻的读数,
`tool_*_calls` 读到 0 的单独点名;③**拒回喂指针没用**:人点了决策卡、模型每拍再发一张,
把「他选的是 approve」写进拒回**照发不误** —— 下一拍它又从头翻一次会滚走的窗口;
改结构 `answeredCardFact`,把「这张卡已答过 → 他选的是什么」做成**每拍都在的事实行**
(worldTouched 2026-08-21、E04 事实行 2026-08-24 之后同一条道理的第三次);
④模型传 `requirement: null` 把工具打崩(边界上一律经 `text()` 归一);
⑤拒回里的 `count=(没写过)` 是 S-FEEL 函数名被当成台账名 —— **假线索模型会去追**;
⑥**零行 = 零缺**:模型压拍没写骨架就发数据工单,人打开是空表,闸与哨兵一起放过
(`emptyGate`:卡自报的表一行都没有 = 没完成);⑦**「早收」不该算撞墙** ——
工具还没轮到调 `finish` 先到了,那是计划次序的小错,头一次只落观察、第二次起才算被拒
(与「重发已答过的卡」同一把尺)。
活动侧 1.2.9:三张执行工单各自声明 `gateLedgers`;说明书补「发卡前骨架必须先有行」与
S1 那张卡的前提(一颗 absent 都不剩);哨兵 `parts_profile_rows >= created` 逐颗对账。
e2e 脚本加 `JCAI_E2E_BEARER` 直供旁路(卡会落到 token 主人的工作台、不续期;
服务账号 `client_credentials` 仍是正路)。
- **数据工单确认即入库**(2026-08-27 下午,用户:「数据工单里面填的数据应该是确认这个数据工单后
这些数据就应该入库了」):查下来草稿层通往正式表只有整单放行一道口子(`releaseWrite(taskId)`)——
W05 的 P-08/P-10 卡上写着「确认后即入库」,而人建好的主数据要等整条评估放行才进表,试跑单
(不落主数据)永远不进。**不能简单地「确认时 releaseWrite 那几张表再清草稿」**:引擎的 `mine:` /
`_rows` / 哨兵(`parts_profile_rows >= created`)、视图 `data-rows="mine:parts.profile"` 全靠草稿层
认「本单写下的行」,清掉就当场断。修法:`releaseWrite(taskId, { only, cause })` **范围放行** ——
只并这张卡提交闸盯的那几张表(`gateLedgers` / 绑的 `blocks`,与闸同一份名单),并过的行**留在
草稿层打 `landed` 记号**(`__draft.landed_at`):读面一字不变,整单放行不再写它、不抛事件、不做
冲突检查(`landedEarlierRows` 分开报);再写一笔记号擦掉、基线换成落地后的值。事件不指回本单
(它正等自己的人事件)。app 侧 `data-order-landing.ts` 在回传路由里、保存与回传落定后调它;
失败不拦人(痕上说清,放行时再并)。`createOnly` 与 `drop` 对本单已落地的行改口(别 drop ——
撤了读面少一行);数据域「在办草稿」不再数已落地的行。活动 1.4.8:两张数据工单的剧本改口
「已入正式表,别再写、别 drop」。测:ledger IT 3 条(范围/记号/再写/试跑)+ app 7 条 + 域 1 条 +
活动 1 条;e2e w05 数据工单交卷即验痕(`JCAI_E2E_LAND_MASTER=1` 时连正式表一起验)。
- **验收卡只许有一种样式;验收件题头改验收绿**(2026-08-27 下午,用户:「验收卡怎么有两种样式,
统一都使用评审放行与落账确认这一步派出的这个验收卡的样式;中央 html 模版区域如果是验收工单
把标题部分的红色改为和验收卡一样的绿色」):①审核卡(决策卡 `variant:'review'`)从前只换了头上
的字、身子还是 A/B 选项列表;现在照终局验收卡 `AcceptForm` 那一套摆(`ReviewForm`:请你验收 ·
验收工单入口 · 理由框 · [重做] … [确认通过]),机制不变 —— 通过交 approve 项,重做写了理由走
`custom:<理由>`(基座按字面点名对行)、没写走驳回项;判断抽成纯函数 `review-face.ts`(7 测)。
「验收工单」钮对没有工单行的审核卡也要有反应:`ViewRegion.locate` 找不到那张单就把待处理翻出来
(件在那一屏)。②W05 两张验收件(ACC1 差异评估结论审核 / ACC2 评审放行与落账确认)的 `--ledger`
由目标件的 #b23a2e 红改成对话区验收卡同一枚 #0aa294(`--st-collab`),题头渐变与徽章投影同改;
CONDITIONAL 状态徽标是语义色,保留原红。W05@1.4.9 已装;浏览器走查未做(需登录统一鉴权)。
- **S1 清单把人刚填的参数摆成缺口:示例引了原话,模型照抄示例**(2026-08-27 下午,用户:「第一步已经
补充了 XL2596S-5.0 使能阈值,当前这一步还要填一次?」):人在 P-08 件上填了使能阈值 2.5(已入库),
两分钟后 S1 清单上却有一行「XL2596S-5.0 使能阈值 · 原厂未披露」。查下来 S1 剧本写着
`input_item 如「XL2596S-5.0 使能阈值」`、说明书⑤卡骨架写着「原厂未披露的参数(如使能阈值)」——
模型按示例造行,不读现值(值就在 mine:/focus 里)。与 08-03「反例引了原话,模型照抄反例」同一课:
**示例也不引具体料号 + 参数名**。W05@1.4.10:示例改成占位形「<料号> <参数名>」,写明「先读现值,
人填了值的参数不是缺口、零行合法」;包内测钉死。顺带看见:压拍时 `focus:` 只带拍首那一步的 reads
(S0d_p10 那一拍连做 S1 的写与发卡,S1 声明的 parts.parameter 不在 focus 段,只靠 3000 字的 mine: 段)。
- **运营中心 · 活动模块接口落地(L1/L2/L3 十一条,全 `ops`)**(2026-08-27,`docs/API文档-活动模块.md` 已按契约回写):
契约 `packages/contracts/src/{activity-ops,api/activity-ops}.ts`;服务端住 app 层 `apps/api/src/app/activity-ops/*`
(纯函数:启动参数派生 / 五态映射 / 时间线 / 摘要 / 视图注入;raw SQL 存取;服务编排)+ `routes/activities.ts`,
写全走既有 port(`task.start` origin=ops / `task.control('terminate')` / `registry.setEnabled`)。
**设计端两条改名让位**:`GET/POST /api/gov/activities` → `/api/gov/activity-packages`(前端零改动,import 的是路由对象)。
迁移 0034(`sys.task.seq` 人读实例号 `INS-<seq>` + 按活动索引)/ 0035(`sys.activity_launch` 幂等键一句 SQL 判占、
`sys.activity_profile` 负责人/说明/图标/色相,seed 按岗位填三个真包,取不到留空)。
五态是对 task 的如实映射(`pending` = 建单未被推进器领到;`rejected` = 打回未重提交那一段)。
W05@1.5.0:四个启动字段加 `x-control`/`x-options`/`description`(combo 候选从正式台账现读),
全流程分支图作 `activity-overview` 沙箱视图(模版无脚本,报高脚本由出口注入,协议 `jcai:view-height`)。
前端 §10 对接另起一轮。测试:契约 7 + app 层 33 + W05 包内 +1。
- **差异评估结论审核件改版:一个候选一张表**(2026-08-27 傍晚,用户改了目标件
`docs/SS02-ACT-WORK-05-html/ACT-WORK-05-验收工单-01-差异评估结论审核.html`:「存在多个替代 PN 要对比
差异时看不清楚,现在将每个待选 PN 分开」):渲染器从前只认一层 `data-rows`,做不出「外层按候选复制、
里层只列它名下的明细」。补**嵌套行模版 + `data-by="子列[=父列]"` 父键过滤**(`view-render.ts`,里层先按
本行展开再填本行标量;4 测),它也能当查表用 —— 品牌不在 relation 上,`<span data-rows="parts.profile"
data-by="internal_pn=candidate_internal_pn">` 从整表挑那一颗料的行。件照目标件重搬:候选 PN 结论汇总
(一个候选一条;差异统计绑 `difference_summary`,S3 剧本本就让它写成「7 项比对:4 MATCH / …」)+
`<article data-rows>` 包 `<section class="cand">` 的分组明细(`<tbody data-by="substitution_relation_id">`);
判据四条照目标件改;ACC1_CSS 整段重搬(.cand*/.rec*/.stat*,CONDITIONAL 改蓝),主题色仍取卡的
#0aa294(目标件改版自己写的是 #16a34a)。W05@1.4.11。规范 §4 绑定表补 `data-by` 一行。
- **「库里明明有值,清单还要填一遍」第三次复现:根因不是措辞,是让模型宣布台账事实**(2026-08-27
傍晚,用户:「都已经出现几次这个问题了,自己找到根因并解决」):1.4.10 改了措辞照样复现 ——
这一单 XL2596S-5.0 已在库、三颗料 21 个参数全有值、说明书已是新版,模型仍写出
「使能阈值 · 原厂未披露」并在交代里说「原厂没披露」。三条线索:①S1 的「待确认」行是**模型对参数表
的一句断言**,基座没有任何读数核它;②说明书里「使能阈值」与「未披露 / UNKNOWN」同句出现三处,
其中一处是我 1.4.10 写的反例原话「使能阈值 · 原厂未披露」(08-03「反例一律不引原话」那课又犯一遍);
③S-FEEL 没有列表过滤,想拿判据核「gap 行数 = 未披露参数数」也写不出。修(W05@1.5.1):**S1 一行参数
都不写**(item_key 不许以 unknown_ 开头);件上加「候选参数现值」只读块 —— `<article data-rows=
"mine:sub_eval.pn_check">` 逐颗复制,里层 `parts.parameter` 按 `data-by="internal_pn"` 现读,人看得见
每个参数此刻的值;未披露的由 S3 判 UNKNOWN + 验证任务(本来就是它的活)。说明书全文不再出现
「使能阈值」(包内测钉死);S3 示例改「实测<参数名>」。设计律:**台账里有的事实,不许由模型在别处再宣布一遍。**
- **「你真的改好了吗」—— 改是改好了,库里没有**(2026-08-27 傍晚):新起的单 `loop_state` 里还是旧说明书。
查下来两条:①`sys.activity_package` 里 1.5.0 / 1.5.1 两行都是**另一个会话**在同一个 checkout 上
改出来的(activity-overview 视图 + 启动表单 x-control),各比我的安装早几分钟占了版本号 ——
我两次 `activities:install`(候选分组件 / S1 参数行退役)全是**同版重装 no-op**,脚本还打印
「活动包已装」;②`manifestOf` 每次读库,不是服务缓存。修:升 1.5.2 重装并**用 SQL 核库里的清单**
(查 JSON 文本别用 `\"` 手写转义 —— 第一次核出个假阴性);`InstallVerdict.stored`(契约,默认 true)
+ 安装脚本同版时改口「已是这一版,未重装」。规矩:**装完看库,不看脚本的话;两个会话同改一个包,
版本号先问库里最高的是几。**
- **「验收卡又变成需要你定」「差异明细两张表没渲染出来」—— 同一个根:稳定版后端跑的是早上的代码**
(2026-08-27 傍晚):`.stable/RELEASE` 是 `3171d8a`(11:53 构的),早于「审核卡摆成验收工单」那一提交,
更早于当天所有改动;它与开发后端(:8787)抢同一个库的租约,抢到哪一拍就用旧代码发那一拍的卡、
推那一拍的帧 —— 决策卡没 variant、帧里 `data-rows`/`data-by` 原样漏出(旧渲染器不认嵌套)。
修:`./stable.sh update`(稳定版现为 `7555337+未提交改动`,与开发一致);并把审核卡的面孔改成
**引擎按剧本定**(`faceOf`:点名的项优先,挂不到就按当下在办的那一步 → `cards.decide.variant`),
不再只靠模型给对 itemId(2 测)。排查法:先看 `.stable/RELEASE` 的 commit 与 `lsof -iTCP:8790` 的
进程启动时间 —— **两台后端一个库,先问另一台跑的是哪一版。**
- **「叫了人我都没填你就直接推进了」—— 两道结构闸**(2026-08-27 傍晚,用户:「不能再有叫了人又继续
自动推进的问题」):实测账 —— S1 的执行卡 17:48:00.2 发出,0.3 秒后投到的是**上一张(P-10)卡回传的
人事件**(回传落库那一刻已 wake、推进器读 card-reply 先跑了那一拍,事件晚 12 秒),`deliver` 照样
tick,再一拍模型读到事实行「这一步已经发过卡,人已经被问过了,照『人交回之后』办」,把没人答的 S1
收掉。①`task.deliver`:人事件带 `occurredAt`,任务在这条回传之后推进过就只记到达痕(stale)不推;
②`runTurn`:`cards.unanswered(taskId)` 非空这一拍不问模型(`human-tool.pendingCards` = 没办结工单 +
没作答且没被顶替的对话卡),谁叫醒都推不动 —— 这一条管住所有多余唤醒(另一台后端 / 手动 wake)。
5 测(task 3 + turn-runner 2)。两台后端都要装上:dev 自动重载,稳定版 `./stable.sh update`。
- **审核卡 = 终局验收卡的结构:判据表,不是参考信息**(2026-08-27 傍晚,用户:「给你说了要最后一个
评审放行与落账确认这个验收卡的样式和结构,没有参考信息这个东西,变成 L1、L2 这种东西」):
`decisionCardSchema.criteria`(可选)—— 任务详情读时对**没作答的 review 卡**现算同一摞判据
(`checks.of`,L5 不上卡,过契约 schema 归型),与终局验收卡同一段算法同一份读数;`ReviewForm` 摆
`Crit` 判据表 + 头上「n/m 达标」,卡上不再有参考信息 / AI 建议。答过的卡不带判据。
- **验收卡的条目 = 人工验收清单,人点「达标 / 不达标」,点全才能通过**(2026-08-27 傍晚,用户定,先只做
ACT-WORK-05):从前卡上摆的是系统判的判据(L1/L2…)让人签;用户定「不是系统判断的条目,是人要对这个
验收工单的内容进行审核需要的步骤,每份验收工单固定」。契约:`PlanStep.acceptanceChecklist`(剧本声明)→
`AcceptanceWorkOrder.checklist` / `DecisionCard.checklist`;回传 `checked`(落 `done.checked` /
`chosen.checked`);human-tool 回传校验:通过必须 `checked ⊇ checklist`(`checklist-incomplete`),审核卡只拦
「通过」选项。引擎:审核卡随面孔带清单(`faceOf`),终局验收卡在 submit 时从剧本取(声明了清单且不是审核步)。
前端 `Checklist`:序号格 + 右侧开关(**待确认灰 ↔ 已确认绿**,用户定;不叫「不达标」—— 没点过不是判了不合格),
头上「已确认 n/m」,确认通过灰到点全;答过的只读摆当时点的。W05@1.5.3:
S4_review 4 条、T_release 5 条(按两份目标件的【验收判据】写成人眼能核的动作)。E04 / I01 未动(用户定先不管)。
`decisionCardSchema.criteria`(上一轮加的)撤掉。测:card-rules 2 + turn-runner + review-face + 包内 1。
- **「标红的填了还是不让推进」:红带点的是「缺输入项」,不是补充内容**(2026-08-27 晚,用户实测):S1 清单
11 行全没有 `input_item`(必填的人读名列),模型这一拍只写了 status/detail/origin;件上红带的固定前缀写死
「补充内容没填」,人于是把 11 行的补充内容全填成「1」,闸照拦(它拦的是输入项)。病根:剧本只在括号里提过
一次「input_item 用人读名」,逐行做法里从没再说 —— 措辞的「从没说过」那一档。修(W05@1.5.5):剧本逐行写死
六列与每行的人读名(客户 / 客户需求 / 原 PN / 候选 N / 应用场景 / BOM 位 / 替代类型 / 规则版本 / 负责人期限 /
原 PN 资料版本)+ 发卡前自核 `_input_gap_missing = 0`;红带前缀改「必填格」不写死列名;包内测钉死。
顺带答用户「这些输入项库里拿不到吗」:输入项只是每行的名字(AI 该写),不是库里的数据;真要人填的只有
应用场景 / BOM 位两格 —— 它们不在任何表里(P-01 是本单新建的、P-09 BOM 没建模)。
- **进度条钉在 1/6 · 重做意见变成「驳回(不写具体意见)」**(2026-08-27 晚,用户实测两条):①`phaseProgress`
从前「一段里的项全收完才算过」,都在库时数据工单两项永远 Available,条钉死在第一段;改成「案子走到了哪一段」——
最后一个有项动过(Active / Completed / Terminated)的阶段,全收完就进下一段,没收完停那一段;一项没动过才退回
老规矩(3 测)。②模型把审核卡骨架里的 `allowCustom` 抄丢,引擎默认 false,前端写了意见的重做只能退回驳回项,
卡面摆的是选项原标签;现在审核卡一律收自定义意见(`allowCustom ?? reviewFace`),答过的卡摆**验收的话**
(确认通过 / 重做:<意见> / 重做(未写意见)),不摆选项标签。
- **「评审放行与落账确认」派了两次:先一张执行单,人答完才 submit 又一张验收单**(2026-08-27 晚,用户送来
5616e13d 那单):S5 在同一拍里被自动收步后模型接着被问,读到人工激活步的事实行「唯一合法的动作是先发那一张卡
(human/entry/decide)或立监听」,就给 T_release 发了一张执行工单;下一拍才 judge + submit。修三处:
①`isReleaseStep`(剧本声明了人工验收清单且不是审核步)—— `human` 挂到放行步当场拒并指向 submit;
②放行步的事实行只指向 submit(不再套执行步那句);③验收卡题目取案例模型里那一项的名字
(「评审放行与落账确认(ACT-GATE-03)」),「收口验收」只是兜底。W05@1.5.6 剧本补一句「不发执行工单」。
2 测 + 包内 1 测。
- **工作成果详情右上角只翻页,不翻份**(2026-08-27 晚,用户:「这个东西不是让你在整个工作成果里面切换,
是让你在单个工单有多个页面的情况下切换的」):08-23 加的「翻份」撤掉;右上角那对箭头只在这一份件里翻页
(一页也摆 1/1),换一份成果回列表点。
- **验收卡「又变成老的」:投影按标题里有没有「验收」二字挑面孔**(2026-08-27 晚,用户实测):
`chat-projection` 从前拿 `title.includes('验收')` 决定 card-sent 是判据卡(`criterion` → `AcceptForm`)
还是执行卡(`guidance` → 通用「派出工单」气泡),而同晚验收卡题目改成了案例模型项名
「评审放行与落账确认(ACT-GATE-03)」—— 四个字不在了,人工验收清单整张不见,摆出的是 11 条判据 +
「打开报告」。同文件上面几行早写过「标题措辞是给人看的、随时会改」。改认痕里的结构化键 `mode`
(发卡时随 payload 入痕),老痕没有它才退回标题。2 测;读时投影,在途单刷新即好;稳定版已更新。
- **「字已签下,正在落地」停住不动:迟到守卫把放行裁决也丢了**(2026-08-27 晚,用户送来 317c9124):
同晚加的「迟到的人事件不再推」(`lastProgressAt > occurredAt` → 只记痕不投)前提是**那一拍能从
留痕 / 卡库读到答复**(执行单填报、决策卡选项都如此);而放行裁决只走事件这一条路 —— loop 的
`onEvent` 把 verdict 落进在途验收信封。实测账:签字 04.129 落库 → `wake` → 推进器抢先一拍
(在途验收没裁决原地返回,但 lastProgressAt 挪到 04.483)→ 事件 05.774 才到 → 判 stale 丢掉,
再没有任何事件叫醒它。修:`payload.mode === 'acceptance'` 的人事件不进迟到守卫(认结构化键);
1 测。那一单以「删 event_consumption 行 + 投递行翻回 pending」让派发器按新路重投 → released、
合并 24 行、发口 assessment-released。**两台后端都装上再重投** —— 稳定版的派发器同样会抢这条。
- **P-10 的卡对着 P-08 的件:画面跟着这一拍发出去的卡走**(2026-08-27 晚,用户送来 3ef3fc3e:
「当前这一步不是应该给我推 P-10 的数据工单吗?怎么还是推送的芯片主数据创建」):模型没收掉
S0d_p08_master(剧本两处白纸黑字「先 finish 再发下一张」,措辞治不了)就发了 S0d_p10 的数据工单,
两步同时 Active,推帧按「第一步没干完的」取了 P-08 的件 —— 人拿着 P-10 的卡,屏上没有资料表可填,
提交闸拦「缺资料」。08-23 那刀(按 currentRuntime 重算)治不了两人环项相邻的形状(debt 早记了)。
结构治:`applyAction` 的 human / entry / decide 三条路把 `issuedFor`(卡是哪一步的)交回拍内,
推帧时那一步声明了画面就推它,压过别的规则;没发卡的拍照旧。1 测;debt 销账。
在途那单以「task_view.template 改成 p10-document-create + `views.repush`」救活(tsx 起容器跑脚本,
`-e` 不支持顶层 await,要写成 .mts 文件)。
**根治**(用户:「根因修了吗?不要只修表象」):病根是**这一步办完没办完是引擎手里现成的事实
(卡答了、数据入库了),却让模型去记得 finish**。①引擎:人工激活的项在 `worldTouched` 之后照常求
doneWhen(此前一律跳过,怕替人签字 —— 门槛保留:卡没发过不收),拍首扫一遍、**拍尾再扫一遍**
(人答卡那一拍模型写完东西 doneWhen 才真;刚发卡的项排除;submit 拍不扫免擦信封);
②W05@1.5.8:P-08 / P-10 各给一条只读入库事实的 doneWhen(要建的每颗料 = absent + created,
主数据/参数/资料都落了、必填不缺、逐颗对账),S1 哨兵不再等模型写 `created` 旗(那是「机检只读
基座数」的哨兵形);剧本里「顺序不能反」改口「引擎也会自己收」。现有 E04 / I01 / W05 没有任何
人工激活项声明过 doneWhen → 零回归。3 引擎测 + 包内 220 测;规范 §4.4 / 建模纪律 3、4 改口。
e2e w05 这轮没跑(用户的测试台占着,起单会顶掉他的单)。
- **工作区正文里的占位上下居中**(2026-08-27 晚,用户:「AI 推进中 / 这单已收尾 / 还没有往来记录 …居中显示」):
`.jc-empty` 早写了 `margin:auto`,可它住在自绘滚动区的视口 `.wf-body`(块级)里,纵向 auto 边距算 0,
全贴顶边。与 08-x 治五模块空态同一招:`.wf-body:has(> .jc-empty / > .jc-working)` 才切成纵向 flex,
件 / 日志 / 往来记录这些正文照旧从顶往下排。浏览器实证「这单已收尾」「还没有往来记录」两屏居中。
- **两颗一模一样的输入电压范围判成 MISMATCH:客户约束一票否决**(2026-08-27 晚,用户送来 0bddd862):
客户写「输入电压在 45V 以内」→ 模型译成 requirement `>= 45`,原 PN 与候选上限都是 40V;`judgePair` 只看候选
过不过客户线,不看原 PN 自己过不过 —— 需求边界与在用料的差距记在候选头上,硬约束 MISMATCH → 整颗不推荐。
差异评估比的是「换上去会不会比现在差」:工具 `compare-parameters` 升 1.1.0 —— 候选与原 PN 相等 / 盖住、
且客户线原 PN 也过不去 → 仍按比对结果判(MATCH,风险中),备注点名「需求边界,请回头核对需求」;
候选更窄且过不了线仍 MISMATCH(3 形有测)。工具注册一名一行、upsert 换版本,handler 在进程内按名绑,
装完稳定版重建即生效;在途单要人在审核卡上「重做」并写明意见才会重比。
- **差异比对的入参由基座从台账取,模型只报料号与客户约束**(2026-08-27 晚,用户:「这个做差异评估比对的
harness 肯定有问题,要让它认真比对每一条,然后再输出结论」):同一单痕里模型念出「输入上限 32V 低于客户 40V」——
那是 S3 剧本示例的原话,不是这单的数;工具入参只存哈希,喂了哪几对值事后查不到;写回时还把工具的 `equal`
改成 `less`。两头都靠模型抄、两头都没有基座核。改三层:①工具运行时把 `taskId / activityId` 交给处理器
(`ToolHandler` 入参加两个可选键);②`compare-parameters` 1.2.0:给 `originalInternalPn + candidates[].
candidateInternalPn(+ requirements)`,参数行从 `parts.parameter`、封装 / 生命周期从 `parts.profile`、证据引用从
`parts.document` 由工具现读任务视图(本单草稿也算),出参每项带原值与证据,写盘照抄;老形状(自带 pairs)照接,
试运行走它;container 用 `compareParametersWith(ledger)` 顶掉静态名单那份;③≤800 字的工具入参整份进 `result`
痕(审得了才谈得上认真);W05 S3 第一拍只报料号与约束、示例只留占位形,第三拍 compare_result 也照抄;
S4 重比只改 requirements。13 工具测 + 包内 89。**基座能读到的事实,不让模型转述给工具。**
- **「下限~上限」一律是范围:解析器补齐写法、出参摆出读法**(2026-08-28 用户:「4.5~40 / -40~+85 这种我怕模型
搞不清楚,harness 里强调一下是范围值」):实测解析器真有洞 —— 单位写进值里(`4.5V~40V` / `-40℃~+85℃`)被读成
单个数,Unicode 减号、`…`、`≥45 / 40 以内` 读成文本。工具 1.3.0:分隔符认 ~ ~ - – — … 至 到 to、单位可夹在值里、
单边界读成半开范围;出参每项 `readAs:{original,candidate}` 写明「范围 4.5~40 / 定值 5 / 下界 ≥ 45 / 文本」——
比对依据可见,模型照它写影响、不自己重新解释值;契约描述与 S3 / P-08 剧本明写读法(示例用中性数 1~10,
不用真数据里的 4.5~40 —— 模型会把示例当这单的值)。W05 升版装上。3 测(11+7 种写法)。
- **AI 把原 PN 的规格书填到了候选料号头上:人填的表要声明,判据不摆给还欠卡的那一步**(2026-08-28
柴浩实测单 6ddcecf8,连撞五拍熔断):P-10 资料记录的标题 / 版本 / 链接与台账里 `LM2596S-5.0` 那一行**逐字相同**
—— 不是幻觉,是「手边有一行看着对的就拿来用」(那一步 reads 摊开了 `parts.document`,视野里唯一一份真资料
就是原 PN 的)。三层合谋:①把 P-08 的回卡认成 P-10 的(P-10 的卡从没发过);②我 08-27 给这一步加的 doneWhen
把「资料必填不缺」摆成目标、后面还跟「成立了就 finish」,**与同一份提示词里「唯一合法的动作是先发那一张卡」
直接打架**;③它顺手把 `exists_status` 改成 created,按剧本发卡名单自己空了 —— 一个合法动作都不剩。
止血两刀:**①`PlanStep.humanWrites`**(契约)—— 声明的台账 `write` 当场拒并指路「去发那张卡,值由人填」,
`drop` 不拦(写错了得撤得掉);判法认点名的项、点不出退回当下在办的那一步(压拍时骨架写在上一步名下正好放行)。
**②还欠一张卡的那一步不摆 doneWhen** —— 判据同时是摆在模型眼前的目标,而它此刻只许发卡。
W05@1.6.5 声明 `humanWrites: ['parts.document']` 并从 writes 去掉。4 测(墙 / 放行 / drop / 声明)。
**一个闲着的模型 + 一个它够得着的判据 = 它一定会去凑那个判据。**
用户同时点出更大的一条(记 debt,未做):**存在性核对 + 派数据工单是确定性流程,根本不该交给模型** ——
平台缺「确定性步骤」(纯工具只读、判定表不写台账、doneWhen 只收步),所以只能写进 guide;
引擎三样能力都有(taskView / draftWrite / issueExecution),缺的只是声明面。
- **确定性步骤已出设计,未动代码**(2026-08-28,ADR-014):盘完 W05 九步 ——
**三步整个确定**(S0_bind / S0d_p10 / S5)、四步八成确定、只有 S3 是 agent 主场;一单十来拍里七八拍在做确定的活。
agent 真正不可替代的只有四类:自然语言→结构化 · 读人的意见落到具体行 · 写给人看的话 · 非结构化抽取(实跑中一次没发生)。
设计要点:**声明式配方进 manifest,不执行包代码**(ADR-004「不执行代码即知包为何物」;artifact 至今零执行,
不为这个功能开沙箱面);三个动词 `project` / `card` / `say`,条件复用 S-FEEL、聚合复用基座读数,不发明第二套求值;
`auto` 是「问模型之前先把确定的事做了」,作用域到交出控制权为止;**一步要么确定要么不是**(判断点先切出去,
不做「一半 auto」);出错交人不重试不退回模型;静态审把地址/列名/S-FEEL 在装的时候审死。
**回溯验算:已记录的八条事故落在会被 auto 掉的三步半上**(编号抄别单 / 判在库判错 / 派给在库的料 /
没写骨架就发卡 / 清单漏列 / 库里有值当缺口 / 抄别的料的资料 / 撞墙五拍熔断)。
立场要改口:**agent 只在真需要判断的地方出现,与「人只在责任点与放行点出现」是同一条原则。**
五条待定见 ADR §11(决策卡给不给配方 / 工具串接 / humanWrites 细到列 / S2 与比对工具的 join 重复 / T_release 第三条裁量该删)。
- **运营中心活动详情沙箱换成「关键台账数据」看板,数据接真台账**(2026-08-27 晚,用户定:只摆最近一次已放行
实例、替换掉全流程分支图):模版搬自 `docs/ss02-act-05/ACT-WORK-05-关键台账数据.html`(P-01 KV / P-08 逐颗 +
参数瓷贴 / P-11 主记录 + 差异明细 / P-10 / P-06 本单 + 同料号历史),徽标文案全由 `data-class-of` 投影。
**取数归活动声明、执行归基座**:契约新增 `viewTemplates[].data`(`case{ledger,key,prefix}` + `rows[{as,ledger,by,not,orderBy}]`,
`from` 只能指 `case` 或前面的 `<as>.<列>`),`view-scope.ts` 按声明逐表等值读正式表、摊成扁平作用域
(`<as>` / `<as>.<列>` / `_rows` / tally 计数 / `case:*` / `board:state` 三态)交 `renderView`,`/view` 出口照旧注入报高脚本。
案号 = 前缀 + 开案时刻 14 位(`case-stamp.ts`,与引擎注给模型铸主键的 `case:openedAt` 同一函数 —— 实测 INS-20
`13:51:03Z` ↔ `W05-20260827215103` 一字不差);放行后草稿层已清空,所以只能这么圈。`store.latestReleased`。
W05@1.6.0(库里核过带 `data` 11 条);`views/overview.ts` 删除(docs 里的源文件不动)。测:契约 3 + view-scope 9 +
service 3 + store 1 + 包内 4;真库渲染 `v-ready`、INS-21 / `W05-20260827215148`。欠账见 debt(挑单 / 行级来源 /
`vtok` 三份 / `data` 装包静态审)。
- **确定性步骤已落地**(2026-08-29,ADR-014):`PlanStep.auto` 声明式配方,五个动词
(`project` / `analyze` / `card` / `submit` / `say`)、四种地址、嵌套两层封顶;引擎在拍首跑,
**发了卡就收拍(零 token)**,有 `guide` 的照常问模型。`analyze` 是**一次结构化 AI 调用** ——
系统组装入参、声明出参 schema、系统落表,**不给工具不给记忆不多轮**。
三条纪律进了规范 §4.6:**行由确定的那一侧决定不由 AI 决定** / 判据不许编数不出来的数 /
每一笔之前刷读数。静态审在装包时把地址、列名、模型名、视图、submit 的验收清单逐条核死。
配套四件:`data-options`(下拉选项从台账现读)· 件上保存后 `wake`(「保存即铺格」)·
审核卡放宽到单选项 · 卡答复即收步。**E04 / I01 / W05 一个字没改** —— 它们的剧本里没有 `auto`。
- **ACT-WORK-05 从『什么都丢给 AI』重写成『系统确定性取数 → AI 只在真需要判断处出场一次』**
(2026-08-29/30,`part-substitution-assessment@2.1.6`,design spec
`docs/superpowers/specs/2026-08-29-act-work-05-rewrite-design.md`,用户原话立场:「不是把
所有东西都丢给 ai 来处理…一定是系统先确定性的从数据库中取出数据后交给 ai 分析」)。
九步砍成**四步**(S1_inputs 核对入参与补数据 → S2_assess **整个活动唯一一次** `analyze` →
S3_review 结论审核 → T_release 落账放行),**全程零 `guide`**,行为整体搬进 `PlanStep.auto`
声明式配方(ADR-014 第一个真实用户);零工具、零技能,两枚旧工具与两张 DMN 一并退役 ——
规则只许有一处真源,活在配方的 `when` 链里。新建两张类型字典
(`parts.chip_type`/`parts.type_param`):按芯片类型(不是按料号)标一次核心参数字段与
硬软约束,「两颗料必须用同一套参数名」从此是**结构保证**,原先靠测三次都没拦住的
自指引用墙退休。三张件(数据工单 · 结论审核 · 落账确认),数据工单按缺口条件发卡,
零卡直通是常态路径之一。
**e2e 五案例的真实战果**(2026-08-30,连续多轮真跑,详见
`.superpowers/sdd/2026-08-29-act-work-05-rewrite/task-11-report.md`):候选缺库·新建类型 /
都在库·零卡直分析 / 原PN缺库三例 `released`、**被拒 0**、**模型调用恰 1 次**、发口
`assessment-released` 全对——**「候选缺库·新建类型」这条记录后来被全分支终审推翻**
(见下方「全分支终审」条):那次 `released` 靠脚本走 API **显式传 `type_id:'90'`**,
没有走真人在浏览器里点「新建类型」那条路;`e2e-a2.mjs` 自己的注释原话是
「这条路径连真人在浏览器里都走不通」。**该走的那条路当时藏着 Critical 1**(见下方条目),
这里的「released」只证明了 API 直传能通,不证明「新建类型端到端通了」。
类型不一致·硬拦那例撞上**已记入 `docs/debt.md`** 的平台死锁
(`prune` 与「数据工单确认即入库」的架构性冲突:人先交一次、字段已落地,再改类型选择,
`prune` 想撤已落地的陈旧行被显式挡住,两条机制各自都对、合起来死锁);两颗都缺库那例
卡在「决策卡答完之后不再推进」,`advancing_until` 反复核过是空、租约与陈旧进程两种假说
均已排除,**真因未定位**,如实记录未解决,不强装成功。**`judgement_class` 逐行核对通过**
(7/7:使能阈值 / 工作温度 / 开关频率 / 输入电压范围 / 输出电压 / 输出电流 / 静态电流,
AI 判的 `difference_status` 与规则链算出的 `judgement_class` 逐行对上,`risk_level`
联动也对)—— 这条验证之所以要点名贴出来,是因为它曾经**逐行全错**。
**地基缺陷**:活动清单存进 `sys.activity_package.manifest` 这个 jsonb 列后,PostgreSQL
按「先短后长、同长字典序」重排了所有嵌套对象的键,而 `project`/`analyze` 的 `fields`
原来靠 `Object.entries` **声明顺序**求值(后一字段靠 `ctx.computed` 看前一字段已算出的
值)——「声明序 = 依赖序」这条从没写下来的假设一进数据库就被打破,且**不报错**、
隔离测试也复现不出来(它直接读 `dist/manifest.json`,不经数据库往返),只有真跑 e2e
才现形。W05 实证:合成列 `judgement_class` 被排到它依赖的 `difference_status` 前面,
读到 `undefined`,七行**全部**误判(`difference_status` 本身走 `lookup` 不依赖字段序,
所以是对的 ——「一个对一个全错」的怪现象由此而来)。**修法是把字段求值从『声明序』
改成『依赖拓扑排序』**(Kahn 算法,新增 `packages/utils` 的 `topoOrder`,契约纯新增);
真正的环在装包静态审当场拒装,不兜底、不静默放行。四条新纪律入规范 §4.6(六条→十条):
`fields` 顺序不可依赖拓扑排序之外的任何假设 / 跨笔顺序仍要人自己排(一笔读的是另一笔
写出来的数就得排在后面)/ 方向相反的依赖拆两笔写、中间夹子表 / `gateLedgers` 同时管
「闸要求非空」与「确认时并进正式表」两件事,漏想一半就会悬空引用或永久卡死。
`pnpm gates` 退出码 0(2447 passed | 34 skipped)。
- **W05 数据工单换版面已退回**(2026-08-31 用户:「改了 ui 之后这个版本我感觉有点问题」):
`report.ts` / `target-style.ts` / `activity.test.ts` 三个文件**逐字节恢复**到换版面之前
(45cec82 的样子),包版本 **2.3.0**(内容是旧版面 —— `store.manifest` 不传版本时取
**最近安装**的那一条,不是版本号最大的,所以退源码必须配一个新号装进去才真生效)。
**换版面那一版原样活在分支 `feat/w05-view-swap`**(HEAD `1373eb4`),随时切得回去;
下面这条记的是它的账,留着当索引 —— 里面三条渲染机制的实锚(宿主闭合标签 / 行内
class-of 只认行作用域 / data-by 回落)与平台侧探针测试**不随退回作废**,它们钉的是
平台行为,测试与目标件 html 都还在主支上。
- **(已退回,见上条)W05 数据工单换版面 + 两条渲染机制的实锚**(2026-08-30,`part-substitution-assessment@2.2.2`,
用户给了新目标件 `docs/ss02-act-05-new/ACT-WORK-05-数据工单-PN主数据创建.html`):
`input-supplement` 整张照它重排 —— **两条并列轨道**(每颗料一条:档案卡 + 主数据 + 类型选择)
+ `<details>` 新增类型面板(chip_type / type_param 两张表原样搬入,独立「核心参数字段」区退役)
+ 核心参数值**瓷贴单块平铺**;绑定面一列不差(四张台账 / 四道闸 / 两处加行 / 终审 C1 的
disabled type_id / 主键钥匙)。目标件脚本驱动的状态全部无脚本翻译:保存即铺格顶掉「选类型
即时加载」、details 顶掉 `.newtype.show`、步骤圆点按基座数点亮、gateprog 进度条如实退掉
(分母不是基座现有的数)。**三条机制账**,全有测钉死:
①**`data-rows` 宿主的闭合标签就是行模版的截刀** —— ROWS 正则按宿主自己的闭合标签非贪婪
截取,`<div class="lanes">` 被行模版里第一个 `</div>` 截半,第二行嵌进第一行没闭合的标签里
档案卡当场串行(A2 立的「行容器用行内不会再出现的标签」说的正是**宿主**,它自己就是
`<article>` 包 `<section>`);防再犯钉用**配平判法**(「不含闭合标签」是空话 —— 非贪婪截取
本来就停在闭合标签之前,那条断言永远不会红);
②**行内 `data-class-of` 只认行作用域**(renderRows 末段 renderTemplate 拿的是行对象),
作用域级读数在行内投不出 —— 圆点的投影挂在行外的 `.pj` 包裹层,后代选择器点亮;
③**`data-by` 行缺键落回外层同名字段**(终审 I3)真咬人:XL 没选类型,`sub_eval.case`
摊平的 `chip_type_id` 顶进来,查名 pill 摆出它没有的类型 —— 守卫认 `selectCurrent` 按
**这一行自己的值**写下的 `option[selected]`,行里没真选上名字不摆(判断全在样式表)。
同批逮到并修死:profile 的编辑闸在第一版 body 里**整个漏掉**(宿主在而闸不在,XL 必填
永远补不上 —— 「四道闸」旧断言只查 data-edit 宿主没查 [data-edit-for] 闸,补强)。
另一半探针钉进平台测试:嵌套 data-rows 在唯一 data-edit 宿主里**必然把一颗料的格子并成
一条记录**(rowOf 认宿主直接子元素;真实 renderView+collect 实测,
`view-container-collect-div-rows.test.ts`)—— 步骤③不按轨道分两栏是机制不是偏好。
**验收**:活动自测 62 → 74(新钉逐条变异验证);`pnpm gates` 退出码 0(2497 测);
2.2.0/2.2.1/2.2.2 三连装库 SQL 逐次核过;浏览器全流程真人路 —— 起单 → 两轨道核对 →
保存即铺格(XL 七格当场铺出)→ 填参数 → 确认写入办结 → S2 分析推进;新建类型走种子行
续号 `03`、DC-DC 原行未被覆盖、下拉即时长出;类型不一致护栏真亮 v-2 再熄灭。
终审评审 0 Critical / 0 Important / 1 Minor(注释漂移,已修)。跑完 reset-runs,
主数据与活动缓存零残留。
- **W05 三张工单件视图层按 C 端重设计**(2026-08-31 用户定:「不要后台管理端的样子,
要给客户用的 C 端界面;可加主题 SVG 与动画;只保留功能,视图层可以推翻重新设计」,
`part-substitution-assessment@2.6.0`):「精密检测报告」语言 —— 深色电路板夜景 hero
三张各一幕(建档台:两颗料的芯片铭牌由 `mine:sub_eval.part` 铺行、不在库虚线描边 /
对决量尺:原 PN→候选 PN + 推荐等级徽章 / 落账席:慢转印章环 + 一句话结论),正文瓷白
报告版面(丝印小标 / 比对光谱分布带 / 落账三卡大数);动画全 transform/opacity、
reduced-motion 全静;验收两件仍是验收绿 #0aa294。**功能绑定逐项保留**:可编辑表 DOM
结构逐字节不动(收值链路按结构认元素),机制规则(计数器/种子行显隐/gate-bar :has/
overflow-x)逐字保留仍被测试钉着。设计系统收进 `views/style.ts`,`target-style.ts`
退役(目标件时代的锚),report.ts 的 vtok/badgeCss 收归 badge.ts(销一笔 debt)。
离线预览自审(真 renderView + 造景数据,不碰测试台)逮到并修掉三洞:kv 占位破折号
连嵌套徽标一起吃(改只认直接子级)、光谱条里渗计数字、加行钮没 base display:none。
104 包内测 + 2516 全仓绿,两条新锚变异验证过,2.6.0 装库 SQL 核过。
(2.5.0 是同日另一会话的启动表单芯片类型联动 —— 两会话同 checkout,版本号先问库。)
- **W05 数据工单三病一改:档案卡上桌,prune 跳过已落地**(2026-08-31 用户实测三连 +
「设计只是头上加了动画」,`part-substitution-assessment@2.7.0`):
①「类型自己给上了」= data-by 行缺键落回外层(debt I3 原样咬人)—— 查名 pill 摆出案卷锚
(原 PN)的类型;治:守卫认 `selectCurrent` 按**行作用域**写的 `option[selected]`,
真选上才摆名、没选摆「待选择」胶囊。**守卫必须单层 `:has`** —— `:has()` 里嵌 `:has()`
是非法选择器,整条被浏览器静默丢弃(第一版就栽在这,预览截图逮回),挂共同祖先上写。
②「品牌…点保存根本不会保存」= 块① 行源是 `sub_eval.part` 而那张案卷表没有主数据列,
`renderTemplate` 只认行作用域 —— 保存真落草稿、显示与孪生件永远空白(四步重写后的潜伏缺陷,
真人一填才现形;e2e 走 API、旧浏览器走查在 swap 版上,两条线都照不到)。治:行源改
`mine:parts.profile` 本身(S1 ④ prune:true 恒有两行),行里天生有全部列。
③「改回同一类型,下面还是两个类型」= ②③ 自投影为绕「已落地行撤不掉」的死锁特意不带
prune,没落地的陈旧行也跟着积。治在平台:`draftDrop` 加配方专用旗 `skipLanded`
(跳过并出声「N 行已随数据工单入库、这一笔不清它」,不炸),②③ 恢复 prune:true ——
H35 案例 2 不再死锁,debt「prune 与确认即入库的架构性冲突」销账。quiet 拍仍不撤行(F3),
清理落在每次确认工单那一拍。
④设计:块① 从 11 列横滑表推翻成**电路板工作台** —— 深色板底上两张可就地编辑的芯片
档案卡(SOIC 封装 SVG + 角色/在库徽 + 类型选择行 + 双栏主数据格),编辑态整卡变表单;
三级占位(必填红/建议橘)上卡与参数值表(徽标包装的必填格用单层 `:has` 认裸 class 补胶囊);
参数值表所属料号列加角色徽。测:107 包内(守卫/行源/嵌套零 data-col 三锚变异验证)+
auto-runner skipLanded(变异验证)+ 2520 全仓;2.7.0 装库 SQL 核过。
另:1838474「在库」是真的 —— 用户此前某单 land_master 落过它(正式表 chip_type_id 为空)。
## 文档权威地图
| 层 | 文件 | 说明 |
|---|---|---|
| **活文档**(冲突时以代码现状为准) | `docs/编码规范.md` | 工程结构权威:模块层级 L1-L8、依赖门禁、AI 协作协议 §12 |
| | `docs/产品设计.md` | 三面一体的产品形态与决策记录 |
| | `docs/活动开发规范.md` | **开发活动照这份**(2026-08-02 第三版,按四轴重组:解耦机制/Harness 契约/Loop/活动怎么写):基座读数与机检纪律、门与闸、五类卡、剧本 steps、建模十纪律、三常备案例与验收口径(released+被拒0)、**排障速查表**;§8 = 待实现 |
| | `docs/HTML报告生成规范.md` | **报告模版照这份**(2026-08-02 从开发规范拆出):一份 HTML 三个身份(件/表单/归档件)、**报告与卡的关系与同源纪律**、绑定语言全表、编辑态(闸/孪生件/增删行/红带)、PRD 平移法、陷阱表 |
| | `docs/前端对接说明-统一鉴权中心.md` | **前端接统一鉴权中心照这份**(ADR-012):要改哪些文件、`/api/me` 与端、401/403/410、SSE 与下载的票据 |
| | `docs/前端对接说明-邮件收发.md` | **前端接邮箱配置 / 来信 / 发信记录照这份**(ADR-013):账号表单两形、四个动作、投递状态、附件与原件的票据下载、SSE 失效、腾讯侧前置 |
| | `docs/API文档-邮件收发.md` | 邮件收发 15 条接口的人话版 + schema 附录 + curl;活动怎么收(事件链)怎么发(`mail.send` 2.0.0) |
| | `docs/API文档-鉴权与人员.md` | 鉴权 / 人员 / 角色→端接口的人话版 + 全部路由归属总表;契约不一致时以 `packages/contracts` 为准 |
| | `docs/ACT-WORK-05-端到端测试记录.md` | **历史记录,已停止更新**(2026-08-30 标注):旧九步设计从零到 released 的走查账,六轮逐轮结论 + A–Z 二十六条发现总表(现象 / 病根 / 治法 / 层);四步重写(2026-08-29)之后的发现不再往里追加,散落在源码注释与 `docs/debt.md` |
| | `docs/数据域字段说明-W05.md` | ACT-WORK-05 重写后九张台账 / 66 列 / 人填列 20 —— 建活动时照它对字段 |
| | `docs/adr/ADR-014-deterministic-steps.md` | **确定性步骤(已实现,2026-08-29)**:W05 九步的确定/判断盘点、`PlanStep.auto` 声明式配方(五动词:`project`/`analyze`/`card`/`submit`/`say`)、引擎拍内次序、回溯验算、迁移次序、§11 待定前两条已定(决策卡给了 / 工具串接换成 `analyze`) |
| | `docs/debt.md` | 欠账台账(只增,销账划线) |
| | `docs/adr/` · 各模块 `CONTRACT.md` | 架构决策与模块级不变量 |
| 业务样例(活) | `docs/MVP示例工作流.html` | 七节点 SOP + 判定表 + 台账域 —— 开发活动的业务素材 |
| 前端语义权威 | `~/coding/JCAI_PRD/workbench` `~/coding/JCAI_PRD/governance` | 原型 1:1 平移(只平移不 import);工作台视图逻辑以 `workbench/.../\_data/model.ts` 统一建模为准 |
| 归档 | `docs/archive/` | 已完成使命的文档(**操作系统/活动模型两卷语义源**、旧 README 规格包、PROGRESS、旧计划),只读;代码注释里的 OS x.x / AM x.x 编号指向归档卷章节 |
## 铁规矩(违者返工)
1. **五道门禁以退出码验**,不许以 echo 验:`pnpm -s typecheck && pnpm -s lint &&
pnpm -s depcruise && pnpm -s api:check && pnpm -s test`(或 `pnpm gates`)。
2. **契约变更四步**(§12.4):depcruise 反查下游 → 同步 CONTRACT.md →
`pnpm api:check --update && git add api-report` → 破坏性走三步弃用。
3. **§12.5 禁止清单**:no `any` / `as unknown as` / `@ts-ignore`;domain 零 IO;
不删测试;不动门禁配置;不绕写三分/两缝。
4. **mock 只许出现在外界**(邮件通道、外部系统的录制回放替身);系统内部机制不得 mock。
5. **密钥只从环境读**:`JCAI_DEEPSEEK_API_KEY`(模型)、`JCAI_SECRET_KEY`(凭证密封 + 票据派生)、
`KEYCLOAK_URL` / `KEYCLOAK_REALM` / `KEYCLOAK_CLIENT_ID`(启动必填)、`KEYCLOAK_PROVISIONING_CLIENT_*`(名册同步,可选);
不入源码、不入包、不入留痕;E2E 永不回退开发库。
6. **试跑一律用 AI 服务账号**(Keycloak 里 `bpos-e2e` 的服务账号,client_credentials 拿 token;`JCAI_TEST_ACCOUNTS` 列上它的用户名),
绝不派到用户工作台;测完 `pnpm --filter @app/api reset-runs` 清运行数据(清跑出来的,留配置好的)。
7. **安装恒新增**:活动/工具改了内容必须升版本号,同版重装是 no-op(静默丢失,踩过)。
8. **界面不撒谎**:状态如实(未绑就写未绑)、错误带厂商原话、不可用不摆假数字。
## 常用命令
```bash
pnpm gates # 五道门禁(gen:tiers → typecheck → lint → depcruise → api:check → test)
pnpm db:up # docker compose 起 PG16
pnpm db:migrate # 应用迁移(新迁移写 db/migrations/ 并登记 meta/_journal.json)
pnpm db:seed # 播种(五员工 + AI 账号;登录者 = 冯兵)
pnpm dev:api # :8787 pnpm dev:web # :5173(/api 反代)
pnpm --filter @app/api reset-runs # 清运行数据,留配置
pnpm activities:install # 只装活动包(不碰治理台配置)—— 开发活动时用这个,别用 db:seed
```
## 结构速查
```
apps/api/src/modules/<m>/{index,contract,port,CONTRACT.md,internal/{domain,usecase,adapter}}
apps/api/src/app/ # 唯一组装层:container / wiring/engines / routes / workers / seed
apps/web/src/features/ # desk-*(工作台)· gov-*(设计+运营)· auth
packages/{contracts,activity-sdk,sfeel,ui-kit,testing}
activities/<id>/src/{index,manifest,case-model,skills,views/} # 活动包(只准 import @sdk/@contracts)
```