Keep pouch naming and .pouch/ack project state, and bring in ACK regression mode, deployer test-environment binding, and manage-release updates from main.
9.4 KiB
优化方法(稳定核心)
减少"开发声称完成但复测不过"的循环成本。本文件是验收信号写法和三轮失败策略的 SSOT,其它文件引用这里。
三角色分工(Coordinator 编排 / Test 验证 / Developer 实现)见 roles-and-permissions.md;复测步骤、Coordinator 终检与环境对齐见 closed-loop.md。
1. 先把验收写成可观测信号(SSOT)
不要只写"页面可用""体验更好"。每个任务至少写三类信号:
| 类型 | 示例 |
|---|---|
| 可见文本 | 页面出现 确认应用标签、取消、将修改 |
| API 结果 | POST /api/... 返回 code=0 且字段存在 |
| 交互结果 | 点击按钮后出现确认区;取消后不触发写入 |
好的验收:
点击"预览变更"后,页面必须出现 API 返回的 diff 行:
- title
- 修改前值
- 修改后值
- coverChanged 提示
不好的验收:
预览功能正常。
2. 回报必须带证据,不带结论
Developer 的 worker_done 应报告:改了哪些文件、跑了哪些命令、自己如何复现验收路径、仍可能有的风险。Test 的复测报告同理:跑了哪些命令、命中/缺失了哪些验收信号、实际观察到什么、证据(snapshot / API 结果)。两者的"结论"都不作数;任务结论只有 Coordinator 落盘到 tasks.yaml 才算数,跨任务知识只有 Coordinator 落盘到 knowledge.yaml 才会生效。
不要写:
已完成,应该可以了。
要写:
修改 web/app/fix/page.tsx。已运行 npm run build、go test ./...。
手测 /fix?fileId=1:搜索、选择候选、预览、确认区都可见。
风险:未执行真实写文件 apply。
3. 验证权在 Test,Coordinator 只信证据
即使 Developer 的 worker_done 写了"全部通过",也必须由独立的 Test 复测(验证者 ≠ 实现者)。完整复测步骤与 worktree/服务对齐见 closed-loop.md。独立复测可避免三类假通过:测错服务实例、测到旧构建产物、开发只验证静态文本没验证真实交互。
Coordinator 不亲自复测,但要做终检:读 Test 的证据,确认它覆盖了每条验收信号且符合原始意图,避免"过了字面没过意图"。终检不通过就回写 failed_retest。
4. 有效复验、环境失败与三轮策略(SSOT)
4.1 什么才计算一轮
三轮预算只计算有效产品复验:Test 已确认正确 worktree、最新服务、必要测试数据和 可用验证工具,并实际执行目标验收信号;结果要么全部通过,要么观察到由待测产品行为 导致的信号失败。
以下情况属于环境失败,不是产品失败,也不占复验轮次:worker 未启动或消息未投递、 sandbox/权限阻止访问待测服务、服务实例或构建不匹配、必要测试数据缺失、浏览器或测试 工具不可用、编排 IPC 失败。若已有独立的产品信号明确失败,只把该产品失败计入轮次; 其余环境问题另行记录,不能用“环境失败”掩盖产品证据。
Coordinator 派发后必须确认消息已投递且 worker 已开始执行:只凭 check --wait
超时无法区分慢任务与未执行,等待期间要用终端活性探测(scripts/worker_probe.py)
定期检查。检测到卡在审批提示、投递后未回车或命中额度限制时,按环境失败记录并做
有界恢复,不消耗产品复验轮次。
环境失败写入 dispatch.environmentIncidents,不要追加到 dispatch.rounds,也不要把
任务写成 failed_retest。实现已经完成时保持 fixed_by_dev;恢复后再进入
retesting。确实需要用户或外部条件才能继续时可暂时写 blocked,环境恢复后回到
原闭环状态。
每条环境事件必须包含:
dispatch:
environmentIncidents:
- id: "BUG-001-ENV-1"
attemptId: "BUG-001-A1"
role: test
phase: browser
status: resolved
summary: "测试环境没有可用浏览器"
evidence: "chromium/playwright lookup 均为空"
impact: "没有执行点击级验收,不能据此判断产品失败"
recoveryAction: "改用受支持的浏览器运行时并启动 fresh Test"
userAction: "无需操作;Coordinator 继续恢复"
reportedAt: "<timestamp>"
resolvedAt: "<timestamp>"
userAction 必须明确:无需用户操作时写清 Coordinator 下一步;需要用户介入时给出一个
具体决定、命令或外部条件,不能只写“请处理环境”。Coordinator 可以先做一次不扩大权限、
不改变产品数据的有界恢复;仍未解决、需要用户动作或阻断本轮时,在当前会话立即报告。
即使事件已自动恢复,最终报告也必须列出环境事件、影响和恢复结果,让用户知道发生过什么。
4.2 三轮有效产品失败
每个任务最多自动派发三轮:
round 1: 常规修复
round 2: 带复测失败证据的定向修复
round 3: 明确指出重复失败点,要求 worker 自己复现完整路径
failed after round 3: 标记 leftover,继续下一个任务
三轮有效产品失败后不要继续消耗同一个 worker。常见原因:验收标准需要重新设计、 Worker 对问题模型理解错了,或需要人工观察和专项调试。环境事件数量不受三轮预算限制, 但必须有界恢复和透明报告,不能无限重试。
留档字段(结构见 templates/tasks.schema.json):
status: leftover
resolution:
leftoverReason: "failed after 3 supervised developer rounds"
dispatch:
rounds:
- round: 1
result: failed
evidence: "<why failed>"
- round: 2
result: failed
evidence: "<why failed>"
- round: 3
result: failed
evidence: "<why failed>"
5. 任务排序
- P0 阻塞主流程。
- P1 高频用户路径。
- P1/P2 体验改进。
- 重构和内部质量。
三轮失败的 P0 可以留档,但发布前需人工决策:降级范围、改验收标准、换新 Agent / 新 worktree 重做、人工修复。
6. 每轮派发只修一个明确问题
不要一次让 Developer Worker 修太多失败项,除非它们共享同一根因:
one dispatch = one bug = one acceptance path
优点:复测更快、失败原因更清楚、三轮失败留档更准确。
7. 把失败证据写给下一轮 worker
第二轮以后,派发 prompt 应突出"上一轮为什么没过",而非重复原始描述。模板见 prompt-templates.md §「复测失败再派发模板」。
8. 优先让测试可执行化
如果某个问题需要多轮修复,说明它值得沉淀成自动化检查。黑盒回归目录是
.pouch/ack/regression.yaml(见 regression.md);可执行脚本仍由 Test 维护在
<integration_test_paths>。优先级:
- 把本轮验收信号收获进
regression.yaml。 - API smoke。
- 浏览器脚本或
automationRef。 - 单元测试。
- 人工检查清单。
目标不是全部自动化,而是把最容易反复误判的路径变成可重复跑的回归用例。任务
verified 后必须给出新增/更新/退役/无回归四选一。
9. 让经验成为有证据、会过期的知识护栏
项目特有、跨任务复用且会改变后续开发或验证行为的经验,可以提名到项目知识护栏。 不要把全部对话、日志或单次猜测自动保存成“记忆”。
Developer / Test 当前任务观测
-> knowledgeCandidates(只留在任务证据)
-> Test 独立验证 + Coordinator gate
-> Coordinator 写入 active knowledge
-> stale
-> superseded / archived
prepare(task) 时只按 component、path、dependency、version 和 tag 推荐相关
active 条目;自动匹配只负责推荐,Coordinator 确认固定 revision 的显式
knowledgeRefs 才是本轮权威上下文。每轮只派发命中的少量条目,不全量注入知识库。
Developer 回报实际采用的 knowledgeApplied 和带当前观测证据的
knowledgeCandidates。Test 对本轮显式引用回报 knowledgeChecks,并用独立观测
确认或否定 candidate。同一 Agent 不能把自己读到的旧知识复述成新证据,避免错误
知识自我强化。
知识中的验证只能引用 knowledge.yaml.verificationRegistry 中已经审查的仓库内
相对 path 和结构化 args,不能把正文或选择器输出拼接成自由 shell 执行。实际运行
只把 registry ID 交给 <ack-skill-dir>/scripts/run_verification.py。安全、正确性
和兼容性等关键约束一旦稳定,应下沉为测试、lint、CI 或正式规范;知识项继续解释
触发条件、原因与证据,不替代可执行控制。
依赖、配置、路径或版本变化后应重新审查相关知识。临时 workaround 必须有失效或 移除条件;冲突规则不能靠“最后写入者获胜”处理。
10. 结束条件
一轮闭环结束时,必须能回答:
- 哪些任务 verified?哪些 leftover?
- 每个 leftover 失败了几轮?最后一轮失败证据是什么?
- 当前工作树有哪些未提交改动?
- 是否还有 open / failed_retest 未处理?
- 本轮有哪些环境事件?是否已解决?用户下一步是“无需操作”还是一个明确动作?
- 本轮显式
knowledgeRefs是否都有必要的knowledgeChecks? - 是否有待验证 candidate,或因依赖、路径、版本变化需要转为 stale 的知识?
答不清楚,闭环就还没结束。