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:
xcs
2026-08-29 07:24:13 +08:00
co-authored by Claude Opus 5
parent 2bb974a10d
commit dba6071772
4 changed files with 112 additions and 13 deletions
+10 -1
View File
@@ -1646,6 +1646,15 @@
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`。
## 文档权威地图
| 层 | 文件 | 说明 |
@@ -1660,7 +1669,7 @@
| | `docs/API文档-鉴权与人员.md` | 鉴权 / 人员 / 角色→端接口的人话版 + 全部路由归属总表;契约不一致时以 `packages/contracts` 为准 |
| | `docs/ACT-WORK-05-端到端测试记录.md` | **ACT-WORK-05 差异评估的走查账**:六轮逐轮结论 + A–K 十一条发现总表(现象 / 病根 / 治法 / 层) |
| | `docs/数据域字段说明-W05.md` | ACT-WORK-05 的十张台账 / 110 列 / 人填列 27 —— 建活动时照它对字段 |
| | `docs/adr/ADR-014-deterministic-steps.md` | **确定性步骤的设计(提案,未实现)**:W05 九步的确定/判断盘点、`PlanStep.auto` 声明式配方(三动词)、引擎拍内次序、回溯验算、迁移次序、五条待定 |
| | `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 + 判定表 + 台账域 —— 开发活动的业务素材 |
+23 -3
View File
@@ -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
View File
@@ -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 附近),没有静态检查兜底。
+44
View File
@@ -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 包结构