Archived
docs: 确定性步骤落地 —— 规范 §4.6、ADR-014 转已实现、两笔欠账
ADR-014 §8 的两条禁令(不 submit、不发决策卡)撤掉并写明理由: 那是假设还有 agent 在场时的保守话,全程无 agent 的活动没有别人来干这两件事。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# ADR-014 确定性步骤:确定的活由引擎按声明做,不问模型
|
||||
|
||||
状态:**提案**(2026-08-28,待用户定)
|
||||
状态:**已实现**(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(工具契约与落地预检)。
|
||||
@@ -135,6 +135,17 @@
|
||||
- 治理台的活动详情能摆出「这一步系统会做什么」(配方是数据,渲染得出来)—— 这是相对提示词的一大好处;
|
||||
- **自主率的分法要认第三档**:现在两档(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. 声明形状
|
||||
@@ -290,13 +301,22 @@ tick 开始
|
||||
|
||||
## 8. 不做什么
|
||||
|
||||
- **不调工具**:工具有副作用面与预算面,先不给(S3 的 `compare → recommend` 串接留作待定)
|
||||
- **不 `finish`、不 `submit`、不发决策卡**:收步归 `doneWhen`,终局归 submit,岔路口本就是判断
|
||||
- **不调工具**:工具有副作用面与预算面,先不给(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. 代价与风险
|
||||
|
||||
+35
-9
@@ -1309,14 +1309,40 @@ pnpm 硬链到全局 store,真实占盘远小于这个数,但 `du` 看着吓人
|
||||
- **`docs/数据域字段说明-W05.md` §二 / §十二.4 的参数集口径过时**:仍写 `normalized_parameter_set` 是 text 列「不建子表」,
|
||||
而清单早已拆成子表 `parts.parameter`(库里那一列全 null)。一览表也少 `parts.parameter` 一行。
|
||||
|
||||
- **平台缺「确定性步骤」:确定的流程只能交给模型**(2026-08-28 用户点出:「这个不是一个确定的流程吗?
|
||||
根本不需要交给 ai,你直接查库不就知道有没有了吗」)。W05 的「逐个料号查库 → 不在库就铺骨架、发数据工单」
|
||||
是纯规则,却写成了模型的 guide —— 因为一个计划项的做法只有一个落点(模型的 guide):纯工具只读、
|
||||
判定表不写台账也不发卡、`doneWhen` 只收步、哨兵只开门,**没有一个机制能整段承接**「读台账 + 写草稿 + 发人卡」。
|
||||
引擎这三样能力全有(`taskView` / `draftWrite` / `issueExecution`),缺的只是**声明面**。
|
||||
- ~~**平台缺「确定性步骤」:确定的流程只能交给模型**~~(2026-08-29 已实现,销账)。
|
||||
2026-08-28 用户点出:「这个不是一个确定的流程吗?根本不需要交给 ai,你直接查库不就知道有没有了吗」。
|
||||
W05 的「逐个料号查库 → 不在库就铺骨架、发数据工单」是纯规则,却写成了模型的 guide —— 因为一个计划项的做法
|
||||
只有一个落点(模型的 guide):纯工具只读、判定表不写台账也不发卡、`doneWhen` 只收步、哨兵只开门,
|
||||
**没有一个机制能整段承接**「读台账 + 写草稿 + 发人卡」。引擎这三样能力全有
|
||||
(`taskView` / `draftWrite` / `issueExecution`),缺的只是**声明面**。
|
||||
代价已经付过两次:08-27 原 PN 不在库却判「在库」(用 `found_pn_ref` 的 refersTo 兜了一半 ——
|
||||
「说不在库」那一侧至今没有校验);08-28 模型把原 PN 的规格书抄到候选头上(已用 `humanWrites` 立墙)。
|
||||
真治法:剧本加 `auto` 步(声明「这一步引擎按规则做,不问模型」)。**代价**:活动模型往「配置化流程」挪一格,
|
||||
与「活动是 Agent 机制」的立场有张力 —— 但这一段本来就没有判断余地。真需要模型的只剩「有 datasheet 附件时从原文抽值预填」。
|
||||
**2026-08-28 已出设计:`docs/adr/ADR-014-deterministic-steps.md`**(声明式配方、三动词、迁移次序、回溯验算八条、
|
||||
五条待定)—— 待用户定后实现。
|
||||
**`docs/adr/ADR-014-deterministic-steps.md` 已实现**(状态 提案 → 已实现):`PlanStep.auto` 声明式配方,
|
||||
五个动词(`project`/`analyze`/`card`/`submit`/`say`,比 2026-08-28 出设计时的「三动词」多了 `analyze` 与 `submit`)。
|
||||
§11 待定的前两条随实现落了地:①「决策卡要不要给配方」—— 给了,`card.as: 'decide'`;
|
||||
②「工具串接要不要做第四个动词」—— 没照原样给(那会把工具的副作用面与预算面一起引进配方),
|
||||
换成了 `analyze`:一次结构化 AI 调用(系统组装入参、声明出参 schema、系统落表,不给工具不给记忆不多轮),
|
||||
比工具串接窄但够用。第③④⑤条(`humanWrites` 细到列 / S2 与比对工具的 join 重复 /
|
||||
`T_release` 第三条裁量该删)是 W05 具体步骤的事,留给下一份计划。规范 §4.6 记了怎么写。
|
||||
**机制先在纯函数与假端口上钉死**——这一轮 `git diff --stat b995148...HEAD -- activities/` 为空,九个现有活动包一个字没改
|
||||
(它们的剧本里没有 `auto`,新代码在结构上就进不去);机制的第一个真实用户是下一份计划(W05 重写)。
|
||||
|
||||
- **配方没有 `drop` 动词**(2026-08-29):撤行只能靠 `project` 的 `prune`(「这一笔投影出来的就是全部」)。
|
||||
要撤一行而不重投整张表的场合,现在写不出来。等真出现第二个用例再加。
|
||||
- **配方的 `analyze` 不计入 `stalledTurns`,也不进单拍工具缝**(2026-08-29):它烧 token、计预算,
|
||||
但不算「被拒」——熔断看不见它。一份写坏的 `instruction` 会每拍烧一次而不触发熔断;
|
||||
目前靠「auto 步发了卡就收拍」封住(analyze 那一步不发卡,`doneWhen` 不成立就交人),
|
||||
真出现空转再补一道计数。
|
||||
- **治理台的活动详情还摆不出「这一步系统会做什么」**(2026-08-29):配方是数据,渲染得出来 ——
|
||||
这是相对提示词白赚的一件,但要动前端,不在这一轮(后端已经把 `auto` 随清单存进库了)。
|
||||
- **`.stable/**` 进了 `eslint.config.js` 的 `ignores`**(2026-08-29):它是部署快照目录
|
||||
(`stable.sh` 放的旧 commit 源码拷贝,已在 `.gitignore` 里),与既有的 `dist` / `.build` /
|
||||
`api-report` / `.api-tmp` 同类 ——「产物不是源码」,不该被门禁扫。加它是因为本轮门禁曾被
|
||||
`.stable/` 下的旧代码拖红(那份代码不受这次改动约束,红也修不掉)。这条动了门禁配置,
|
||||
按铁规矩③要在这里留痕;要推翻只需删掉这一条 ignore。
|
||||
- **配方留痕的可见性,靠的是「kind 选对 + 不标 internal」,没有机制保证**(2026-08-29,
|
||||
R10 的教训 —— `result` 不进工作日志骨架、`internal:true` 会被 `machinery()` 再滤一道,
|
||||
三段各自「正确」、合起来一笔都看不见,踩了才发现):将来新增一类配方留痕时,若照手感
|
||||
写成 `kind: 'result'` 或顺手加 `internal: true`,它会**静默地**从工作日志上消失 ——
|
||||
没有测试会红、装包也不会拒,人只会发现「这一步好像没留痕」。目前靠代码注释提醒
|
||||
(`turn-runner.ts` R10 附近),没有静态检查兜底。
|
||||
|
||||
@@ -316,6 +316,50 @@ W05 的两张数据工单(人填的值已入库、必填不缺、逐颗对账)
|
||||
|
||||
---
|
||||
|
||||
## 4.6 确定性步骤:这一步系统自己做(2026-08-29)
|
||||
|
||||
一步要么确定,要么不是。**不做「一半 auto」** —— 判断点先从那一步里切出去。
|
||||
|
||||
`PlanStep.auto` 是一份**声明式配方**,五个动词按序执行:
|
||||
|
||||
| 动词 | 做什么 |
|
||||
|---|---|
|
||||
| `project` | 从某个来源的每一行投影出台账行,落草稿层。带 `prune` 时,这一笔投影出来的行**就是这张表在本单草稿里的全部** |
|
||||
| `analyze` | **一次结构化 AI 调用**:系统组装入参、声明出参 schema、系统把结果落表。不给工具、不给记忆、不多轮 |
|
||||
| `card` | 发一张卡(执行工单 / 数据工单 / 决策卡)。**至多一张**,发过就不再发 |
|
||||
| `submit` | 提交放行(只许出现在声明了人工验收清单的那一步) |
|
||||
| `say` | 一句给人看的交代 |
|
||||
|
||||
地址只有四种:`域.对象`(任务视图 = 正式 + 本单草稿叠加,**默认该用的那一种**)· `mine:域.对象` ·
|
||||
`in:入参数组` · `result:xxx`(本拍 analyze 的出参)。
|
||||
|
||||
**guide 可以留空,但只有声明了 auto 才行**:`planStepSchema` 原来要求 `guide` 非空
|
||||
(`.min(1)`)—— 那是防「作者忘了写做法」的老规矩,可它顺手把「这一步一次都不问模型」堵死了。
|
||||
现在改成 `superRefine`:没声明 `auto` 的步照旧非空;声明了 `auto` 的步允许 `guide` 写空串
|
||||
(`guide.trim() === ''`)——引擎正是按这个空串分「全 auto(一次都不问模型)」与
|
||||
「半 auto(确定的先做完,剩下的判断仍问模型)」。**全 auto 的步就把 `guide` 写成空串**,
|
||||
别为了过 schema 塞一句废话。
|
||||
|
||||
**半 auto 的步,人答完卡之后那一截判断仍然是模型的活**:配方发过一张卡、`worldTouched`
|
||||
为真、这一拍没有未答的卡、配方这一拍也没再发新卡 —— 这几个条件都成立时,引擎本可以
|
||||
「卡答过了就收步」抄近道直接收掉这一项。但**这条近道只走没有 `guide` 的步**(全 auto);
|
||||
只要 `guide` 非空(半 auto),就算前面几个条件都成立,也仍然要往下问模型 ——
|
||||
半 auto 存在的意义就是「确定的先做完,剩下的判断仍问模型」:人答完卡之后那份判断
|
||||
(读人写的自由文本、落到具体的行上)恰恰是模型该干的活,收在它前面等于把半 auto 的
|
||||
后半截整个删掉。写半 auto 的步时记住这条:`guide` 不空,这一步答完卡不会被引擎抢先收掉。
|
||||
|
||||
**四条纪律**(每一条都是踩出来的):
|
||||
|
||||
1. **行由确定的那一侧决定,不由 AI 决定。** 明细表要按类型字典 `each` 出来,AI 的出参只是拿主键
|
||||
`lookup` 的一张查表 —— 它漏一条,那一格就是空,`required` 立刻变成 `_missing > 0`,闸与放行门当场拦住。
|
||||
写成 `from each(AI 出参)` 的话,它少给两条就少两行,而每一行看着都合规。
|
||||
2. **判据不许编一个数不出来的数。** 「本类型有几个字段」不是基座数得出来的数(`_rows` 数的是**本单写下的**行);
|
||||
行数对账交给 `prune` 的结构保证,别写进 `doneWhen`。
|
||||
3. **每一笔之前刷读数。** 后一笔常要数前一笔刚写下的行。
|
||||
4. **出错交人,不重试、不退回模型。** 配方抛错是包的 bug;退回模型就是让它去凑。
|
||||
|
||||
---
|
||||
|
||||
## 5. 活动包怎么写
|
||||
|
||||
### 5.1 包结构
|
||||
|
||||
Reference in New Issue
Block a user