Skip to content

v0.3.1

Choose a tag to compare

@MichaelShii MichaelShii released this 18 Oct 08:42
· 51 commits to main since this release

v0.3.1 发布说明(取证)

版本:0.3.1(patch)
基线:v0.3.0 → HEAD,12 笔提交 / 18 个文件 / +1540 −24 行(git log v0.3.0..HEAD 生成)
主题:确认单上的「改 PRD」做成闭环 —— 改写绑定版本、在原 child 上下文里续跑、用量准确、批准语义收紧。
本文件是取证与论证;结论层见 CHANGELOG.md。


1. 为什么做这一版

v0.3.0 把「确认单必须由人批准」这道闸门立起来了,但用户提出「要改」时,链路还是断的:

  1. 改完 PRD,上一版的批准没有失效 ⇒ 改过的 PRD 从未被批准却直接开工(issue #11,用户截图实证);
  2. 修成「重出确认单」后加了次数上限(2 次)⇒ 第 3 次直接拒绝,用户只能重开 run、白丢已跑的 PRD;
  3. 改写实现是重跑整个 PRD 子代理(新 spawn、从零读需求)⇒ 又贵又漂移:用户只要求改一处,
    没提的部分也可能被顺手改写;
  4. 放开次数后又发现:confirmApprovedRev 被模型自己写死 ⇒ PRD 永久改不动。

本版把这条链路补完整,并用真机逐环验通。


2. 变更清单(按 git 对比,逐笔归属)

提交 类型 内容
90012eb fix 确认单绑 PRD 版本:改写后批准失效、必须重出单(当时含次数上限)
c831b07 fix 去掉次数上限,改为「版本号 + 上一版快照」
ba628a5 feat 改写走 continuable 续跑(prd-revise.ts),失败回落重跑
ad617c0 fix 批准语义:无 supplement 的 resume 必须有显式批准;记账加严
5ca24d9 fix prdChildId 必须在摘阶段记录之前取;回落出口全部可见
ccd7bb0 fix 续跑等待 180s→300s;回落原因拆成三条可区分诊断
f8988ed fix 快照路径:runDocs 是相对路径,必须拼工作区
e93859b fix 快照从任务夹移到 logs/teamflow/<runId>/(不进交付物)
7daa91d fix 阶段用量必须累计(改写多轮时前几轮 token 不能消失)
2c5a933 fix 修用量精确翻倍(prdUsageAcc 与 stage.usage 同引用 ⇒ addUsage(a,a))
22aa418 chore 用量逐轮留痕 + 重复护栏
edde46e docs ADR-0011 追加「快照=机器可查的落实证据」

3. 真机取证

工具链:dsh --profile web,插件经 deploy.mjs --sync 同步(50 文件),每条 run 均重启宿主后执行。

3.1 改写闭环(hy3)

run 轮数 结果
tf-mvchuuvf-j7kmzk 5 版 第 4/5 版走续跑;第 5 版正确删除 --depth、保留 children 与 stdout/stderr
tf-mvcl5m8t-0qhl8y 5 版 同上;第 3 版曾因 180s 超时回落(后提到 300s)
tf-mvdeqi60-p48r0f 4 版 每版都命中续跑、零回落
tf-mvdhxn6h-87vnog 3 版 11 条 AC 逐条对上两次要求;旧结构字段只出现在说明性语境

上下文累积的直接证据:PRD.v1 → v2 → PRD.md 的特征计数
(--depth 0→16、children 0→11),证明第 1 轮加参数、第 2 轮改 JSON 结构的落地情况。

3.2 续跑 vs 重跑的成本(同一子代理、按 turn 统计)

路由 轮次 每轮新算 input cacheRead 耗时
workbuddy/hy3 重跑 / 续跑 ×2 217,782 / 203,350 / 231,713 27,904 / 7,744 / 2,368 122s / 116s / 163s
deepseek-account/deepseek-flash 首版 / 续跑 ×3 16,168 / 14,072 / 17,877 / 18,687 278k → 1.47M(累计) — / 84s / 78s

结论:续跑的技术收益(同上下文、不漂移)与路由无关;成本收益取决于路由是否做 prompt 缓存——
真机 workbuddy/hy3 三轮 request/header 前缀 40,790 字节逐字节相同(仅末字段 initial→resume),
但 cacheWrite 恒为 0 ⇒ 服务端没做自动缓存;deepseek-flash 有 ⇒ 每轮新算降到 1.5 万量级。

判据沉淀:看 cacheWrite 是否恒 0,别只看 cacheRead(cacheRead 低可能只是前缀变了)。

3.3 批准闸门(双向)

方向 run 证据
拦得住代批 tf-mvdhxn6h-87vnog 暂停后零人类消息 ⇒ 续跑被拒:确认单必须由用户本人批准
放得行真批准 tf-mvdixrhs-asht1p 用户「批准,开始吧」⇒ 放行、approvedRev == prdRev、进技术方案

3.4 用量(修复前后)

journal 子会话实际 结论
修复前(tf-mvdeqi60) in 2,419,276 in 1,209,638 精确 2 倍
修复后(tf-mvdhxn6h) in 608,144 in 608,144 逐项一致

逐轮日志(修复后):144,949 → +260,198 = 405,147 → +202,997 = 608,144,算术正确。


4. 门禁与变异

新增/更新门禁 覆盖
test/prd-revise.test.js(38 条) 取文本字段名、offset 切分、turn/end 结束判据、六种失败全部回落、读不到基线不投递
test/human-approval.test.js §5/§6 批准词真值表、否定优先、修改词、AUQ 答案解析、以最后一条为准、三态
test/orchestration.test.js 续跑不 spawn、对原 child 投递、快照落 logs、用量累计、批准拒绝/放行
test/metering.test.js addUsage 真值表(含真机那组数)
test/smoke.js §11/§12 续跑接线、回落可见性、快照落点、累计与护栏的源码锁

变异(每次只有一个维度被破坏,期望只有新断言变红):

变异 结果
禁用续跑 orchestration 6 红
关掉显式批准闸门 orchestration 2 红 + smoke 1 红
去掉「修改词」判定 human-approval 2 红(第一版夹具没区分力,补「批准,但把 X 改成 Y」后才有牙)
usage 忽略 offset prd-revise 1 红(夹具同样需要第一轮带 usage 才有区分力)

⚠️ 三次「夹具无区分力」都被记录下来——这是本版最值得复用的教训:
夹具必须先证明它能区分正确实现与错误实现,否则测的是寂寞。


5. 已知未验

  1. 桌面版(宿主 0.2.0-rc.2):本插件 0.3.x 要求宿主 ≥ 0.2.1-alpha.2,桌面侧需等上游发版。
    已 grep 确认 2c5a933 之前的续跑所需 API(sendMessage / observeSession / prepareContinuable)
    在 rc.2 中也存在,但 startActivation 不存在 ⇒ 桌面目前跑不了 0.3.x。
  2. 重复护栏(log.usageAccumDup)从未触发:修复后不再需要它,保留作保险,属于死路径。
  3. 超 5 轮改写未验:上下文会被 compaction 裁剪(窗口 192k),早期内容存在被挤掉的风险。
    缓解手段是快照(文件不丢),但没有量化验证。

6. 升级指引

  • 无 engines 变化,无 schema / journal / 任务夹契约变更。
  • 升级后必须重启 dsh --profile web(桌面版重启应用)——插件是构建产物 lib/host.mjs,
    进程不重启则仍加载旧代码(本版排查中曾因此误判过一次"修复无效")。
  • 想验证改写是否走了续跑:看日志里 PRD 改写走**续跑**;出现 回落为重跑 会写明是哪一类原因。