Archived
评审指出 ADR-014 被标「已实现」后,正文 §3.2/§4/§5 仍是实施前的三动词提案, 与真实 schema(auto-recipe.ts)和 turn-runner.ts 的拍内次序对不上,会误导 下一个直接翻开这份 ADR 的读者(W05 重写实现者)。逐条对代码核过后分两档改: §3.2 动词表与 §5 拍内次序按代码改对(含之前遗漏的「有卡未答就静默重跑配方」 那道前置门);§4 的两个例子不逐行改,改成开头一段按语指出三处已知出入 (workOrder→as、view 挪到 PlanStep、self/joinRows 未实现)。顺带把 §11 待定的前两条标成已定并指回销账位置。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
394 lines
25 KiB
Markdown
394 lines
25 KiB
Markdown
# ADR-014 确定性步骤:确定的活由引擎按声明做,不问模型
|
||
|
||
状态:**已实现**(2026-08-29;设计见 `docs/superpowers/specs/2026-08-29-act-work-05-rewrite-design.md` §5)
|
||
背景出处:ACT-WORK-05 差异评估九步流程盘点(§2)、`docs/ACT-WORK-05-端到端测试记录.md` 发现表 A–AE。
|
||
关联:ADR-004(活动包 ABI:**系统不执行代码即知包为何物**)、`docs/活动开发规范.md` §4.4(自动收步)、
|
||
`PlanStep.humanWrites`(2026-08-28 立的墙)、ADR-005(工具契约与落地预检)。
|
||
|
||
---
|
||
|
||
## 1. 问题
|
||
|
||
用户 2026-08-28 的原话:
|
||
|
||
> 「这个不是一个确定的流程吗?根本不需要交给 ai,你直接查库不就知道有没有了吗?」
|
||
|
||
指的是 W05 的「逐个料号查库 → 不在库就铺骨架、发数据工单」。这一段没有任何判断余地,却写成了模型的 guide。
|
||
不是活动作者偷懒 —— **平台里没有别的落点**:
|
||
|
||
| 现有机制 | 能做 | 不能做 |
|
||
|---|---|---|
|
||
| 纯工具(`pure`) | 算、读台账(1.2.0 起) | 写台账、发卡 |
|
||
| 判定表(DMN) | 出结论 | 写台账、发卡 |
|
||
| `doneWhen` | 判「办完没有」,引擎自己收步 | **做事** |
|
||
| 哨兵(`entryCriteria`) | 判「能不能进这一步」 | **做事** |
|
||
| 视图绑定语言 | 把台账取出来**摆到屏上** | 写回去 |
|
||
|
||
「读台账 + 写草稿 + 发人卡」跨了三样,没有一个机制能整段承接。而引擎这三样能力**全有**
|
||
(`data.view` / `data.draftWrite` / `humanTool.issueExecution`)—— 缺的只是**声明面**。
|
||
|
||
`packages/activity-sdk/src/define.ts` 里 `run?` 的注释早就写着:
|
||
|
||
> 留着它是为**确定性子序列(结晶片段)**将来有个落点;不写就是不写,不是缺件。
|
||
|
||
这份 ADR 就是给那个落点定形。
|
||
|
||
**代价已经付过。** W05 的事故里,至少八条落在「本来就该是确定的」那几步上(§7 逐条验算)。
|
||
|
||
---
|
||
|
||
## 2. 盘点:W05 九步里哪些是确定的
|
||
|
||
| 步 | 确定的部分 | 需判断的部分 |
|
||
|---|---|---|
|
||
| **S0_bind** 建上下文 | 铸案号 · 查客户在不在库 · 写需求单(入参搬运+常量)· 逐料号查库写核对表 · 写结论行 | **零** |
|
||
| **S0d_p08** 派主数据单 | 定名单 · 铺三张表骨架 · 发卡 · 人交回后改旗 | 有 datasheet 附件时从原文抽参数值 |
|
||
| **S0d_p10** 派资料单 | 定名单 · 发卡 · 人交回后改旗 | **零** |
|
||
| **S1** 评估输入清单 | 清单九行(四行绑定投影 + 两行固定缺口 + 三行常量默认)· 发执行单 · 把 supplement 抄进需求单 | 人补的自由文本**归纳**成技术约束 |
|
||
| **S2** 标准化对照表 | 关系骨架 · 逐参数对照行(原 PN 参数集 × 候选同名行的 join)· 补封装/生命周期两行 | 单位换算;`constraint_type` 未标时归类(**应进 DMN,不进配方**) |
|
||
| **S3** 逐项差异评估 | 工具串接 · 四态照抄 · 计数 · `difference_summary` · 置信取最小 | **客户原话 → 约束式** · 影响陈述 · UNKNOWN 去向与验证条件 · 推荐理由扩写 |
|
||
| **S4** 结论审核 | 发决策卡(内容是计数投影)· approve 收步 | **读人的自由文本意见 → 定位到具体行 → 改实** |
|
||
| **S5** 拟落账 | 分析状态推 FAE 确认 · 回写需求单五项(风险取最高档、VAL 号拼接、编号、常量三项) | 只有 summary 一句人话(可模板化) |
|
||
| **T_release** 放行 | submit · 无分支去向 | 两条裁量判据 · 打回后修订 |
|
||
|
||
**agent 真正不可替代的只有四类**:①自然语言 → 结构化;②读人的意见并落到具体行;③写给人看的话;
|
||
④非结构化来源抽取(datasheet 抽值、单位换算)。第四类在实跑中一次都没发生过(没传附件)。
|
||
|
||
**结论:九步里三步整个确定(S0_bind / S0d_p10 / S5),四步八成确定,只有 S3 是 agent 的主场。**
|
||
按拍数算,一单十来拍里有七八拍在做确定性的活 —— 而每一拍都是一次采样,都有编错号、抄错行、漏一列的机会。
|
||
|
||
---
|
||
|
||
## 3. 决策
|
||
|
||
### 3.1 声明式配方,**不执行活动包代码**
|
||
|
||
`sys.activity_package.artifact`(包的 `index.js`)存了库,但**至今一次都没被执行过**。这份设计**不开这条路**:
|
||
|
||
- ADR-004 的立场是「系统不执行代码即知包为何物」;配方是**数据**,装进来仍然只是数据,
|
||
可静态审、可回放、可在治理台上摆出「这一步系统会做什么」。执行代码则相反。
|
||
- 执行第三方包要配沙箱、超时、内存墙,而 `scanArtifact` 只是文本扫描,拦不住混淆。
|
||
- 配方要表达的形状**很窄**(§3.2 五个动词),不值得为它开一个能跑任意代码的面。
|
||
|
||
**代价**:表达力有上限。上限之外的**不要硬塞** —— 退回模型,或者把那一段切成独立的 agent 步(§3.4)。
|
||
|
||
### 3.2 五个动词,复用已有的两套求值
|
||
|
||
**改口**(2026-08-29,落地时定):设计之初只列了三个,实现时补了 `analyze` 与 `submit`
|
||
(§11 待定①②随之销账,见该节按语)。配方有五个动词:
|
||
|
||
| 动词 | 做什么 |
|
||
|---|---|
|
||
| `project` | 从「某个来源的每一行」投影出台账行,`draftWrite` 落草稿层 |
|
||
| `analyze` | 一次结构化 AI 调用:系统组装入参、声明出参 JSON Schema,出参落拍内作用域供后续 `project` 消费。不给工具、不给记忆、不多轮 |
|
||
| `card` | 发一张人类工具的卡(执行工单 / 数据工单 / 决策卡),**至多一张** |
|
||
| `submit` | 提交放行,发验收卡挂起(走与模型 `submit` 同一条 `raiseAcceptance`) |
|
||
| `say` | 一句给人看的交代(模板串,不是模型生成) |
|
||
|
||
条件与聚合**不发明第二套求值**:
|
||
- 条件用 **S-FEEL**(`when`,对任务视图求值)—— 与哨兵、`doneWhen` 同一个求值器;
|
||
- 计数/聚合用**基座读数**(`_rows` / `_missing` / `_distinct_x` / tally 计数)—— 本来就在作用域里。
|
||
|
||
### 3.3 `auto` 是「问模型之前先把确定的事做了」,不是「整步替代」
|
||
|
||
`PlanStep.auto` 是一个属性。引擎在这一步的**每一拍拍首**先跑配方,然后:
|
||
|
||
- 配方发了卡 → 这一拍到此为止(**零 token**,不问模型);
|
||
- 没发卡且这一步**没有 `guide`** → 求 `doneWhen`,真了收步、进下一步(下一步若也是 auto 就接着跑);
|
||
- 没发卡且这一步**有 `guide`** → 照常问模型(半 auto:确定的已经做完,模型只面对剩下的判断)。
|
||
|
||
这样老步骤一个字不改,可以一步一步搬。
|
||
|
||
### 3.4 作用域:**一个计划项内,到交出控制权为止**
|
||
|
||
配方跑到「发卡」就结束 —— 与现有 `handsOff` 语义(ask/human/decide/listen/submit 是交出控制权)对齐。
|
||
人答回来之后,那一步若还有活,归 `guide`。
|
||
|
||
**推论(重要)**:一步要么确定,要么不是。**不做「一半 auto」的复杂机制** —— 判断点要先从那一步里切出去。
|
||
例:S0d_p08 的「datasheet 抽值」应当移出这一步(归到起单读来件),这一步才变成纯 auto。
|
||
**这条逼着活动作者把判断点想清楚,是特性不是限制。**
|
||
|
||
### 3.5 幂等
|
||
|
||
配方会被反复进入(人答卡后再 tick),必须幂等:
|
||
|
||
- **写**:`draftWrite` 本来就是同 PK 覆盖。值没变 → **静默跳过,不留痕、不算空转被拒**
|
||
(「写了等于没写」那条判据是拦模型空转的,配方不是模型);
|
||
- **发卡**:先看 `worldTouched` —— 发过就不再发。人工激活的 auto 步,**配方发卡就是启动**。
|
||
|
||
### 3.6 出错 = 交人,不重试、不退回模型
|
||
|
||
配方抛错(地址不存在、S-FEEL 算不出、卡骨架不合契约)是**活动包的 bug**:如实留痕 + 交人。
|
||
**不重试五遍,也不退回模型** —— 退回模型就是让它去凑,那正是这份 ADR 要消灭的东西。
|
||
|
||
### 3.7 静态审在装的时候把住
|
||
|
||
`staticAudit` 扩到配方(与 `refersTo` 目标检查同款,写错地址 = 每一单都错):
|
||
|
||
- `into` / `each` / `lookup` / `joinRows` 的台账地址必须在 `declarations.ledger` 里(与写的授权面同一份名单);
|
||
- `fields` 的列名必须在该对象的列声明里;
|
||
- `when` 的 S-FEEL 必须能解析,引用的名字要绑得上(`boundNames`,已有);
|
||
- 卡骨架的 `view` 必须在 `viewTemplates` 里;
|
||
- 同一张表既在 `auto.project` 里又在 `humanWrites` 里 → **警告**(铺骨架合法,但要作者确认列不重叠)。
|
||
|
||
### 3.8 观测与度量
|
||
|
||
- 配方的每一笔照常进 `sys.task_memory`,`detail.auto = '<步名>#<第几笔>'`;
|
||
工作日志三色里归**系统灰**(已有档,不必新增);
|
||
- 治理台的活动详情能摆出「这一步系统会做什么」(配方是数据,渲染得出来)—— 这是相对提示词的一大好处;
|
||
- **自主率的分法要认第三档**:现在两档(AI / 人),配方做的事既不是 AI 判的也不是人办的,是系统做的。
|
||
|
||
**改口**(2026-08-29,实现时踩出来的):`docs/superpowers/specs/2026-08-29-act-work-05-rewrite-design.md`
|
||
§5.9 写的是「`analyze` 那一笔归 AI 蓝」—— 那句要改口,**它也归系统灰**。理由:那一行记的是
|
||
「系统把 N 条参数交给模型、拿回 M 条结论」,发起与落表都是系统做的,模型只提供内容;
|
||
内容本身的归属在它落下的台账行上看得见,不必让日志行冒充成「AI 判的」。
|
||
连带修了一处会让整条留痕**静默消失**的坑:配方留痕最初用的是 `kind: 'result'` —— 那不在工作日志
|
||
的骨架集合里(`result` 是进模型叙事轨迹那一类,不是给人看的那一类);`project` / `analyze` /
|
||
「自动收步」那几笔当时又都标了 `internal: true`,会被 `machinery()` 再滤掉一道 ——
|
||
**三段各自「正确」,合起来一笔都进不了工作日志**,人打开日志想知道「系统刚做了什么」,
|
||
看到的是空的。现在统一改成 `kind: 'observation'` 且不标 `internal`(「已发过卡,不再发第二张」
|
||
这一笔仍保留 `internal` —— 它每拍都打一遍,是排障痕,不是给人看的交代)。
|
||
|
||
---
|
||
|
||
## 4. 声明形状
|
||
|
||
> **这一节是 2026-08-28 的原始提案,落地时有出入。精确语法以
|
||
> `packages/contracts/src/auto-recipe.ts` 与《活动开发规范》§4.6 为准。**
|
||
> 已知的三处差异(下面 §4.1/§4.2 的例子按原始提案写,未逐行改过,读的时候按这三条心里默认翻译):
|
||
> `workOrder` → `as`(且没有 `entry`,只有 `execution` / `decide`);**卡上不写 `view`** ——
|
||
> 画面归 `PlanStep.view`(已有机制,一处声明,§3 没提是因为原提案漏写了这条,不是后来删的);
|
||
> `{ self: true }` 与 `{ joinRows: … }` **未实现** ——`each: 'in:candidateInternalPns'` 这种
|
||
> **扁平数组**(元素不是对象、是原始值)的本项,实现里是 `rowsAt` 把每个元素包成 `{ value: 原值 }`
|
||
> 再取 `{ col: 'value' }`,不是 `self`;`joinRows`(多行一列拼成串)没有对应写法,真要拼多行,
|
||
> 目前得退回模型或切成独立步骤。
|
||
|
||
```ts
|
||
// PlanStep 新增(可选,老活动一个字不改)
|
||
auto?: AutoRecipe;
|
||
|
||
type AutoRecipe = {
|
||
/** 配方级局部值:先算一遍,后面所有表达式都能引用({in:'evalRef'})—— 整单只有一个案号,靠它 */
|
||
readonly let?: Record<string, AutoExpr>;
|
||
/** 按序执行;每一笔可带 when(S-FEEL),假就跳过这一笔 */
|
||
readonly do: ReadonlyArray<AutoAction>;
|
||
};
|
||
|
||
type AutoAction =
|
||
| { kind: 'project'; when?: string; into: string; from: AutoSource; fields: Record<string, AutoExpr> }
|
||
| { kind: 'card'; when?: string; workOrder: 'execution' | 'entry'; variant?: 'data';
|
||
title: AutoExpr; gateLedgers?: string[]; view?: string; /* 指导书等静态文本直接写 */ }
|
||
| { kind: 'say'; when?: string; text: AutoExpr };
|
||
|
||
type AutoSource =
|
||
| { once: true } // 一行
|
||
| { rows: ReadonlyArray<Record<string, AutoExpr>> } // 固定几行(S1 的默认三项)
|
||
| { each: string; where?: Record<string, AutoExpr>; // 'in:candidateInternalPns' | 'mine:域.对象' | 'ledger:域.对象'
|
||
then?: { each: string; where?: Record<string, AutoExpr> } }; // 第二层,**最多两层**
|
||
|
||
type AutoExpr =
|
||
| string | number | boolean // 常量
|
||
| { in: string } // 入参 / case:* / 基座读数 / let
|
||
| { self: true } // each 是数组时的本项
|
||
| { col: string } | { outer: string } // 本行的列 / 外层那一行的列
|
||
| { cat: AutoExpr[] } // 拼接
|
||
| { fmt: AutoExpr; as: 'digits' } // 只留数字(铸号)
|
||
| { lookup: string; by: Record<string, AutoExpr>; take: string; else?: AutoExpr } // 查另一张表的一列
|
||
| { joinRows: string; where?: Record<string, AutoExpr>; take: string; sep?: string } // 多行一列拼成串
|
||
| { when: string; then: AutoExpr; else: AutoExpr }; // S-FEEL 条件(可嵌套)
|
||
```
|
||
|
||
**字段按声明顺序求值,已算出的字段进同一行的 S-FEEL 作用域** —— 「先 lookup 出依据,再按依据判 found/absent」
|
||
这种写法靠它成立。
|
||
|
||
### 4.1 例:S0d_p10_document(整步确定,最小的那个)
|
||
|
||
```ts
|
||
auto: {
|
||
do: [
|
||
{ kind: 'card',
|
||
when: 'sub_eval_pn_check_exists_status_absent > 0',
|
||
workOrder: 'execution', variant: 'data', view: 'p10-document-create',
|
||
gateLedgers: ['parts.document'],
|
||
title: { cat: ['数据工单 · 原厂技术资料创建(P-10):',
|
||
{ joinRows: 'mine:sub_eval.pn_check', where: { exists_status: 'absent' },
|
||
take: 'internal_pn', sep: '、' }] } },
|
||
{ kind: 'say', text: '这几颗料的原厂技术资料库里查无记录,已派数据工单请你登记。' },
|
||
],
|
||
}
|
||
// guide 不写。doneWhen 照旧:parts_document_rows >= parts_profile_rows and parts_document_missing = 0
|
||
// 人在件上填完确认 → 数据即入库 → 下一拍 doneWhen 成立 → 引擎收步。**模型在这一步一次都不出现。**
|
||
```
|
||
|
||
### 4.2 例:S0_bind 的铸号与存在性核对
|
||
|
||
```ts
|
||
auto: {
|
||
let: {
|
||
digits: { fmt: { in: 'case:openedAt' }, as: 'digits' },
|
||
evalRef: { cat: ['W05-', { in: 'digits' }] },
|
||
requestId:{ cat: ['REQ-', { in: 'digits' }] },
|
||
},
|
||
do: [
|
||
// 客户不在库 → 发数据录入卡,这一拍到此为止
|
||
{ kind: 'card', when: 'customer_profile_rows = 0', workOrder: 'entry', /* … */ },
|
||
{ kind: 'project', into: 'demand.request', from: { once: true },
|
||
fields: { request_id: { in: 'requestId' }, customer_code: { in: 'customerCode' },
|
||
requirement_version: 'V1', request_type: '技术需求',
|
||
request_description: { in: 'requestDescription' },
|
||
input_snapshot_ref: { cat: ['SNAP-', { in: 'evalRef' }] },
|
||
original_internal_pn: { in: 'originalInternalPn' },
|
||
request_status: 'pending', current_activity: 'ACT-WORK-05', current_stage: 'assessing' } },
|
||
{ kind: 'project', into: 'sub_eval.pn_check', from: { each: 'in:candidateInternalPns' },
|
||
fields: { eval_ref: { in: 'evalRef' }, internal_pn: { self: true }, role: 'candidate',
|
||
found_pn_ref: { lookup: 'ledger:parts.profile', by: { internal_pn: { self: true } },
|
||
take: 'internal_pn', else: '' },
|
||
exists_status: { when: 'found_pn_ref != ""', then: 'found', else: 'absent' } } },
|
||
// 原 PN 那一行同理(from: { once: true },role: 'original')
|
||
{ kind: 'project', into: 'sub_eval.verdict', from: { once: true }, fields: { /* … */ } },
|
||
],
|
||
}
|
||
```
|
||
|
||
「在不在库」从此是一次 `lookup`,不是模型的一句断言 —— 08-27 那条「原 PN 不在库却判在库」结构性消失。
|
||
|
||
---
|
||
|
||
## 5. 引擎行为(拍内次序)
|
||
|
||
**改口**(2026-08-29,与 `turn-runner.ts` 实际次序对齐 —— 落地时多了 `analyze`/`submit`
|
||
两个动词,分支也比原提案细):
|
||
|
||
```
|
||
tick 开始
|
||
├─ ⓪ 这一单还有任何卡没交回(不论哪一步发的)→ 这一拍不问模型;
|
||
│ 若当下这一步声明了 auto → 静默跑一遍它的配方(quiet:只跑 project / say,
|
||
│ 「保存即铺格」——人在件上按了保存,系统按最新草稿把该铺的行铺出来)→
|
||
│ 记痕「等人交回」→ status awaiting,这一拍到此为止,不进入下面任何一步
|
||
├─ ① 拍首自动收步(现有:doneWhen 为真的项,人工激活项需 worldTouched)
|
||
├─ ② 算 current(当下在办的那一步)
|
||
├─ ③ current.auto 存在 → 跑配方(走到这里已经过了 ⓪ 那道门,`quiet` 恒为 false;
|
||
│ `do` 数组按声明顺序逐笔执行,五个动词可任意穿插)
|
||
│ ├─ 求 let
|
||
│ ├─ 按序执行每一笔(when 假则跳过;project 写/撤过东西后,下一笔重新取一次读数)
|
||
│ │ · project → 逐行 draftWrite(同 PK 覆盖;值没变静默跳过)
|
||
│ │ · analyze → 一次结构化 AI 调用,出参落拍内作用域 `result:<into>`,供后续 project 消费
|
||
│ │ · card → 先看 worldTouched,发过就当这一笔已完成、跳过(不当被拒);
|
||
│ │ 发了标 worldTouched、烧 humanCalls,这一笔之后停(交出控制权)
|
||
│ │ · submit → 记下 rationale,这一笔之后停(交出控制权)
|
||
│ │ · say → 进对话区
|
||
│ ├─ 每一笔留痕(by=系统,detail.auto)
|
||
│ └─ 抛错 → 留痕 + 交人(不重试、不退回模型),这一拍到此为止
|
||
├─ ④ 配方发了卡 → 标 worldTouched、按声明推画面,status awaiting,收拍(零 token)
|
||
├─ ⑤ 配方 submit → 发验收卡挂起(走与模型 `submit` 同一条 `raiseAcceptance`),status awaiting,收拍
|
||
├─ ⑥ 没发卡也没 submit,但配方写过东西(project 落了行/撤了行)→ 重求 doneWhen;
|
||
│ 真了收步,下一拍重新导航(封顶 8 轮,与现有自动收步同款)
|
||
├─ ⑦ 卡答过了就收步(近道):doneWhen 未声明 · 卡已发过(worldTouched)· 配方会发卡
|
||
│ · 这一步**没有** `guide`(全 auto)→ 引擎直接把这一项收掉,不问模型
|
||
│ (**半 auto 的步 —— 声明了非空 `guide` —— 不走这条**,R9,见 §3.3)
|
||
├─ ⑧ 这一步有 guide → 照常问模型(半 auto)
|
||
└─ ⑨ 无 guide、doneWhen 不成立、也没有卡在等 → **交人**(配方没做到位,是包的 bug)
|
||
```
|
||
|
||
**预算**:配方不烧 token(`analyze` 是例外 —— 它是一次真实的模型调用,烧 token、计入预算,
|
||
但不计入 `stalledTurns` 熔断计数,见 debt.md);发卡烧 `humanCalls`;配方段在同一 tick 内,不额外计 step。
|
||
|
||
---
|
||
|
||
## 6. 与现有机制的衔接
|
||
|
||
| 机制 | 处置 |
|
||
|---|---|
|
||
| `doneWhen` | 不变。auto 步几乎都该有 —— 它做的事是可验的 |
|
||
| 哨兵 `entryCriteria` | 不变。auto 步照样要满足入场前提才在场 |
|
||
| `worldTouched` | 配方发的卡同样标 —— 它是真发了 |
|
||
| `humanWrites`(2026-08-28) | **配方豁免**:那道墙防的是模型即兴,配方是审过的声明。铺骨架合法,人填内容不冲突(静态审提示列不要重叠) |
|
||
| 写三分 | 不变:配方只写**草稿层**,落正式表仍靠放行 / 数据工单确认入库 |
|
||
| 「一单一卡」 | 不变:配方至多一张卡 |
|
||
| 熔断 | 配方不会「被拒」,不进 `stalledTurns` |
|
||
| 试跑 / 回放 | 配方是纯数据求值,同输入同结果 —— 可回放。**配方里没有时钟与随机**(时刻取 `case:openedAt`) |
|
||
| 记账旗 | **该删的删,不是该 auto** —— `input_confirmed_total` 这类基座本就数得出来 |
|
||
|
||
---
|
||
|
||
## 7. 回溯验算:历史事故有几条会结构性消失
|
||
|
||
| # | 事故 | 落在哪 | auto 后 |
|
||
|---|---|---|---|
|
||
| 1 | 编号从正式表里**别单的案号**里挑 | S0_bind 铸号 | 消失(模板铸号) |
|
||
| 2 | 原 PN 不在库却判「在库」(发现 I) | S0_bind 查库 | 消失(lookup 现查) |
|
||
| 3 | 数据工单派给了**在库**的那颗(发现 J) | S0d_p08 名单 | 消失(where absent) |
|
||
| 4 | 压拍没写骨架就发卡,人打开是空表(发现 Q) | S0d_p08/p10 | 消失(配方按序) |
|
||
| 5 | S1 清单 11 行全漏 `input_item`,人无处可填 | S1 前半 | 消失(字段声明齐全) |
|
||
| 6 | 库里有值的参数被 S1 当缺口再问一遍(发现 AB,三次复现) | S1 前半 | 消失(清单是投影) |
|
||
| 7 | P-10 抄**原 PN 的规格书**安在候选头上(发现 AE) | S0d_p10 | 消失(模型不出现) |
|
||
| 8 | `finish` 撞 worldTouched 墙五拍熔断(发现 AE 同单) | S0d_p10 | 消失(那一步不问模型) |
|
||
|
||
**八条落在会被 auto 掉的三步半上。** 剩下的事故(工具没调、比对入参抄错、验收卡面孔、重做循环)
|
||
不在这个范围内 —— 它们该由别的机制治,这份 ADR 不承诺。
|
||
|
||
---
|
||
|
||
## 8. 不做什么
|
||
|
||
- **不调工具**:工具有副作用面与预算面,先不给(S3 的 `compare → recommend` 串接留作待定;
|
||
实现时换了个更窄的口子解掉同一个需求,见下方「两处改口」与 §11 待定②的销账)
|
||
- ~~**不 `finish`、不 `submit`、不发决策卡**:收步归 `doneWhen`,终局归 submit,岔路口本就是判断~~
|
||
(**`submit` 与发决策卡两条已撤**,见下方「两处改口」;`finish` 这条不变 —— 配方从不
|
||
显式收步,收步仍旧只有「引擎按 `doneWhen` 自动收」与「半 auto 步问模型、模型 finish」两条路)
|
||
- **不写正式表**:仍走草稿层
|
||
- **不做三层以上的嵌套**:两层(关系 × 参数)是 W05 的上限;超出就别 auto
|
||
- **不在治理台上编辑配方**:那就成了低代码平台;配方随包走,改配方 = 升版本重装
|
||
- **不承诺消灭 agent**:§2 的四类判断照旧归它
|
||
|
||
> **两处改口**(2026-08-29,ACT-WORK-05 重写时用户定):`submit` 与**发决策卡**这两条禁令撤掉。
|
||
> 它们原本是**假设还有 agent 在场**时的保守话;而全程无 agent 的活动**没有别人来干这两件事**,
|
||
> 不开口最后两步就没人做。护栏没松:`submit` 只许出现在声明了人工验收清单的那一步,
|
||
> 提交门(判据全绿)照旧把关 —— **系统提交不比模型提交宽松**;决策卡只在 `variant:'review'` 时
|
||
> 放宽到单选项(它不是岔路口,是一道签字关)。
|
||
|
||
---
|
||
|
||
## 9. 代价与风险
|
||
|
||
1. **活动作者要写结构化声明,不能再靠散文。** 但那些散文本来就在(而且更长、还不能测);
|
||
配方**能单测**(纯数据求值,包内自测钉死)。
|
||
2. **代码错是必然的错,模型错是概率的错。** 配方写错 = 每一单都错。
|
||
对策:静态审(§3.7)+ 包内自测 + 安装两审的回放审拿样例入参跑一遍配方。
|
||
**但必然的错比概率的错好查** —— 这正是把它从模型手里拿走的理由。
|
||
3. **立场要改口。** 「组织的工作定义为可编排的工作流……活动是完成一项任务的 Agent 机制」——
|
||
加一句:**agent 只在真需要判断的地方出现,与「人只在责任点与放行点出现」是同一条原则。**
|
||
确定的事交系统,判断交 AI,责任交人。
|
||
4. **把有判断的地方硬写成规则的风险。** `constraint_type` 的 hard/soft 归类按品类会变 ——
|
||
这类**进 DMN 判定表,不进配方**;配方里只许出现「取值、拼装、投影、发卡」。
|
||
5. **现在的「确定」有一半是靠强制命名一致换来的。** S2 能纯 join,前提是「候选与原 PN 参数名一模一样」
|
||
(P-08 建骨架时用中文名硬压 + 门上的行数对账)。**一旦料号来自外部导入**,同义归一就回来了 ——
|
||
那是判断,是 agent 的活。**auto 化不等于永远不需要 agent。**
|
||
|
||
---
|
||
|
||
## 10. 迁移次序(每搬一步都要五案例 e2e:released + 被拒 0 才算数)
|
||
|
||
1. **`S0d_p10_document`** —— 最小、纯粹、刚出过事;拿它验证机制(配方 + 静态审 + 留痕 + 观测)
|
||
2. **`S5_prepare_landing`** —— 整步确定、不发卡;验证「不发卡时接着走 doneWhen 收步」那条路
|
||
3. **`S0_bind`** —— 整步确定、含一张录入卡的分岔;验证 `let` 铸号与 `lookup` 存在性
|
||
4. **`S1_input_confirm` 前半** —— 清单投影 + 发卡;半 auto(收口仍归 guide)
|
||
5. **`S0d_p08_master`** —— **先把 datasheet 抽值切出去**,再 auto
|
||
6. **`S2_normalize`** —— 两层嵌套,最难;搬之前先确认它与比对工具的 join 是否重复(§11)
|
||
|
||
---
|
||
|
||
## 11. 待定(要用户定的)
|
||
|
||
1. ~~**决策卡要不要给配方**~~:S4 第一张卡的 ask 内容是计数投影,确定;但决策卡是岔路口,给了会不会滑坡?
|
||
**已定:给了**——`card.as: 'decide'`(`variant:'review'` 时放宽到单选项),见 §8「两处改口」。
|
||
2. ~~**工具串接要不要做第四个动词**~~:S3 的 `compare → recommend` 之间模型只是转手 counts,却占掉整整一拍。
|
||
**已定:没照原样给**——没有做「按序调用多个工具」那个第四动词,换成了更窄的 `analyze`
|
||
(一次结构化 AI 调用,不给工具不给记忆不多轮),见 §3.2 与 `docs/debt.md`「平台缺『确定性步骤』」条。
|
||
3. **`humanWrites` 该不该细到列**:现在是表级。auto 铺骨架 + 人填内容之后,列级更准。
|
||
4. **S2 与比对工具的 join 是否重复**:`compare-parameters` 1.2.0 起自己从台账取参数对,
|
||
而 S2 让模型抄的 `difference_item` 对照表是**同一份 join**。一份事实做了两遍,一遍还是手抄的 ——
|
||
要么 S2 auto 化,要么让工具的出参直接落 `difference_item`(那是另一个机制:工具出参绑台账)。
|
||
5. **`T_release` 第三条裁量判据**「推荐等级与差异明细一致」就是工具的定级规则本身,
|
||
让模型再裁一次是给自己盖章 —— 该删(与 08-01 在 A1 上拆掉 L4 同款)。
|