From 13759a69e6fd7919cc950af301aa60ec4d949ddf Mon Sep 17 00:00:00 2001 From: Snowson Date: Sat, 10 Oct 2026 10:27:49 +0800 Subject: [PATCH 1/2] =?UTF-8?q?docs=EF=BC=9Aharness=20=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E4=B8=8E=E6=9E=B6=E6=9E=84=E6=96=87=E6=A1=A3=E8=BF=81=E8=87=B3?= =?UTF-8?q?=20delivery-harness=EF=BC=8C=E6=9C=AC=E4=BB=93=E5=BA=93?= =?UTF-8?q?=E5=8F=AA=E7=95=99=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除调研快照、抽取决策、可验证交付方案、落地交接、task-008 与五份建设期评审记录(正本已迁 delivery-harness #221) - specs/delivery-harness.md 瘦身为本仓库使用说明:保留命令表、 本仓库约定与配置值、平台一次性设置、验证状态与已知边界; 机制设计解释(三层护栏设计、五条合并路由、判级依据)指向引擎文档 - README 双语、AGENTS、backlog(含 B18 落点补注)、trial-001、 PR 模板、评审清单的引用改为 delivery-harness 绝对链接 依赖:delivery-harness #221 合并后再合并本 PR(链接才可达) 来源:用户 2026-10-09 决定 --- .github/pull_request_template.md | 2 +- AGENTS.md | 2 +- README.md | 2 +- README.zh-CN.md | 16 +- docs/decisions/0001-harness-extraction.md | 31 - .../2026-09-25-harness-rollout-handoff.md | 63 - docs/plans/backlog.md | 4 +- docs/plans/task-008-harness-extract.md | 58 - docs/plans/trial-001-dr14.md | 2 +- docs/plans/verifiable-delivery.md | 185 --- .../2026-09-23-agent-delivery-theory.md | 1053 ----------------- docs/review/2026-09-25-harness-baseline.md | 183 --- .../review/2026-09-25-harness-review-brief.md | 105 -- docs/review/2026-09-26-harness-review.md | 95 -- docs/review/2026-09-27-harness-audit.md | 203 ---- docs/review/2026-09-29-harness-status.md | 111 -- docs/specs/delivery-harness.md | 233 ++-- docs/templates/review-checklist.md | 2 +- 18 files changed, 86 insertions(+), 2264 deletions(-) delete mode 100644 docs/decisions/0001-harness-extraction.md delete mode 100644 docs/plans/2026-09-25-harness-rollout-handoff.md delete mode 100644 docs/plans/task-008-harness-extract.md delete mode 100644 docs/plans/verifiable-delivery.md delete mode 100644 docs/research/2026-09-23-agent-delivery-theory.md delete mode 100644 docs/review/2026-09-25-harness-baseline.md delete mode 100644 docs/review/2026-09-25-harness-review-brief.md delete mode 100644 docs/review/2026-09-26-harness-review.md delete mode 100644 docs/review/2026-09-27-harness-audit.md delete mode 100644 docs/review/2026-09-29-harness-status.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index c2d4695..a9b980b 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,5 +1,5 @@ B[2 上下文
地图 + 系统记录] - B --> C[3 规划分解
短链 + 检查点] - C --> D[4 执行
沙箱 + 状态外置] - D --> E[5 验证门禁
分层 + 独立评审] - E -->|未通过, 有界重试| D - E -->|超限或高风险| H[人: 例外处理] - E --> F[6 集成发布
小批量 + 可回滚] - F --> G[7 运行监控
SLO + 熔断] - G --> L[8 学习改进
规则/测试/工具] - H --> L - L --> A - L --> B -``` - -主回路是“执行→验证→有界重试”。人只在验证超限或高风险时介入,每次介入和每次线上问题都要回流成规格、上下文或门禁的改进。 - -| 环节 | 核心目标 | 引导(行动前) | 传感(行动后) | 人的介入点 | -| --- | --- | --- | --- | --- | -| 1 需求与规格 | 让“完成”可被机器判定 | 任务模板、可执行验收标准、非目标、示例 | 规格自检、Agent 主动澄清 | 定义意图与验收标准(杠杆最高) | -| 2 上下文 | 让 Agent 看得见、看得准 | AGENTS.md 地图、docs 系统记录、分目录规则 | Agent 汇报“缺什么”、上下文占用率 | 维护知识的正确性 | -| 3 规划分解 | 把长链切成可验证的短链 | 研究→计划模板、功能清单、粒度规则 | 计划含验证步骤、依赖检查 | 中高风险任务审计划 | -| 4 执行 | 限定最坏后果,支撑长时运行 | 沙箱、权限白名单、hooks、预算 | 进度文件、git 提交、卡死检测 | 只接收升级 | -| 5 验证门禁 | 高质量且难以作弊 | 架构规则、测试只读、完成定义 | 分层检查、独立评审、留出测试 | 高风险变更审查、抽样审计 | -| 6 集成发布 | 高吞吐下保持稳定 | 小 PR、合并队列、特性开关 | 金丝雀指标、自动回滚 | 高风险发布决策 | -| 7 运行监控 | 看得见、停得住 | SLO、告警与熔断策略 | 链路追踪、成本、分类器拒绝率 | 处理告警与熔断 | -| 8 学习改进 | 每次失败都让系统更强 | 规则库、技能库、黄金原则 | 错误分析、回归评测、质量趋势 | 决定沉淀什么、调整自治度 | - -### 3.1 人的注意力应该投在哪里 - -错误越靠前,放大倍数越高。HumanLayer 的 Dex Horthy 指出:一行错误的调研(对代码库的误解)可能导致数千行错误代码,所以人工审查应优先放在调研和计划上,而不是逐行审代码([HumanLayer, 2025-08](https://www.humanlayer.dev/blog/advanced-context-engineering))。 - -OpenAI 在“零手写代码”的实验中,把人的工作收敛为五件事:定优先级、把用户反馈转化为验收标准、验证结果、在 Agent 吃力时找出缺失的工具或护栏、在需要升级时做判断([OpenAI, 2026-02](https://openai.com/index/harness-engineering/))。按杠杆从高到低,人的注意力建议这样分配: - -1. 意图与验收标准:决定做什么、什么算做完。 -2. Harness 设计:判定器、架构规则、权限边界。 -3. 高风险任务的调研与计划。 -4. 升级与告警:只处理系统主动送来的例外。 -5. 抽样审计:按风险抽查已合并的变更,校准门禁是否在漏检。 - -### 3.2 八条设计原则 - -1. 先有判定器,再放权:没有快速客观的验证,就不要追求高自治。 -2. 确定性优先:能用脚本、AST 转换、规则完成的步骤,不交给模型。 -3. 生成与验证分离:评审者不共享生成者的上下文。 -4. 结构防护胜过提示词约束:权限、沙箱、只读测试、hooks 比“请不要…”可靠。 -5. 小批量、可回滚:每个变更小到能快速验证、快速撤销。 -6. 状态外置、上下文从简:进度写进文件和 git,上下文只放高信号信息。 -7. 自治度按“任务类别 × 风险等级”设定,并由数据驱动调整。 -8. 每次失败都沉淀为 harness 改进:规则、测试、工具或文档,而不是一次性人工修补。 - -## 四、环节 1:需求与规格——让“完成”可以被机器判定 - -低人工交付的第一个前提,是 Agent 开工前就知道“怎样算做完”,并且这个判断能由机器执行。这是人投入产出比最高的环节。 - -### 4.1 用“终态 + 约束 + 示例”描述任务 - -Spotify 在约 50 次迁移中总结出六条提示经验([Spotify, 2025-11](https://engineering.atspotify.com/2025/11/context-engineering-background-coding-agents-part-2)): - -- 描述终态,把实现路径留给 Agent。 -- 写明前置条件和“什么情况下不要动手”,因为 Agent 过于急于行动。 -- 给几段具体代码示例,对结果影响很大。 -- 给出可验证的目标,让 Agent 边做边检查。 -- 一次只做一个变更,不要把几件相关的事塞进一个提示。 -- 会话结束后问 Agent 提示里缺了什么,它往往最清楚。 - -### 4.2 验收标准可执行化 - -- 功能清单即完成定义:Anthropic 的长时 harness 先由初始化 Agent 生成 200 多条功能清单(JSON),全部标记为“未通过”;编码 Agent 每次只做一条,端到端验证后才能改成“通过”([Anthropic, 2025-11](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents))。 -- 需求即属性:Kiro 用 EARS 格式(WHEN…THE SYSTEM SHALL…)书写验收标准([Kiro 文档](https://kiro.dev/docs/specs/feature-specs/requirements-first/)),再把它们改写成“对任意输入…”的属性并生成属性测试;代码、规格、测试不一致时,交给人决定改哪一个([Kiro, 2025-11](https://kiro.dev/blog/property-based-testing/))。 -- 开工前签“完成合同”:Anthropic 在规划–生成–评估三 Agent 架构中,让生成者与评估者在写代码前先商定每块工作的“完成”标准和可测试的成功条件([Anthropic, 2026-03](https://www.anthropic.com/engineering/harness-design-long-running-apps))。 - -完成定义至少应覆盖四类:功能验收测试、质量门禁(lint、架构规则)、非功能预算(性能、安全、兼容性)、文档与变更说明。 - -### 4.3 规格驱动开发:按问题规模取用 - -GitHub Spec Kit 把流程分为规格、计划、任务、实现四步,并强调每个检查点上人的职责“不只是引导,而是验证”([GitHub, 2025-09](https://github.blog/ai-and-ml/generative-ai/spec-driven-development-with-ai-get-started-with-a-new-open-source-toolkit/))。Böckeler 的评测指出了代价:同一套重流程套在所有规模的问题上,一个小 bug 生成了 4 个用户故事和 16 条验收标准;大量 markdown 反而比代码更难审;Agent 仍会忽略规格,带来“虚假的控制感”([martinfowler.com, 2025-10](https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html))。 - -建议按任务规模分级使用规格(本报告的综合建议): - -| 任务规模 | 示例 | 规格形态 | 人审什么 | -| --- | --- | --- | --- | -| 小 | 改配置、修告警、依赖升级 | 一句终态 + 验收命令 | 不审规格,只看门禁结果 | -| 中 | 有复现的缺陷、小功能 | 终态 + 验收测试 + 非目标 + 风险等级 | 验收标准 | -| 大 | 新功能、跨模块改动 | 需求、设计、任务三件套,随代码沉淀在仓库 | 需求与计划 | - -### 4.4 任务准入与澄清 - -任务进入自主流水线前,先按“可验证性 × 风险”分诊(矩阵见第十六节)。公开经验高度一致:Devin 最擅长“需求前置明确、结果可验证、初级工程师 4–8 小时”的任务,不擅长模糊需求和中途变更([Cognition, 2025-11](https://cognition.com/blog/devin-annual-performance-review-2025));Stripe 的 Minions 在配置调整、依赖升级、小型重构上表现最好([InfoQ, 2026-03](https://infoq.com/news/2026/03/stripe-autonomous-coding-agents/))。 - -模糊需求要在开工前消解,而不是在 PR 里消解。Anthropic 的数据显示,在复杂任务上 Claude Code 主动请求澄清的次数是人工中断的两倍多([Anthropic, 2026-02](https://www.anthropic.com/research/measuring-agent-autonomy))。建议把“澄清”设为正式步骤:规格缺验收标准时,Agent 必须先提问,或提出验收标准待确认后再实现。 - -### 4.5 任务模板 - -```markdown -## 目标终态(做完后系统应该是什么样) -## 非目标 / 禁止动作 -## 前置条件(不满足则停止并报告) -## 验收标准(可执行的命令或测试) -## 风险等级与回滚方式 -## 参考示例(同类变更的好例子) -``` - -## 五、环节 2:上下文与知识工程——Agent 看不到的就等于不存在 - -Agent 只能依据它看得到的信息行动,而上下文又是有限的注意力预算。目标是:该知道的都找得到,放进上下文的都是高信号信息。 - -### 5.1 仓库即知识库:短地图 + 系统记录 - -- OpenAI 的 AGENTS.md 只有约 100 行,只做地图,指向 docs/ 下的设计文档、执行计划、产品规格和参考资料。他们的原则是:Agent 运行时无法在上下文中拿到的东西,实际上就不存在;留在在线文档、聊天记录和人脑里的知识对系统不可见([OpenAI, 2026-02](https://openai.com/index/harness-engineering/))。 -- AGENTS.md 已成为跨厂商标准:2025 年 12 月捐给 Linux 基金会下的 Agentic AI Foundation,已有 6 万多个开源项目采用,Codex、Cursor、Devin、Gemini CLI、GitHub Copilot 等工具均支持([Linux Foundation, 2025-12](https://www.linuxfoundation.org/press/linux-foundation-announces-the-formation-of-the-agentic-ai-foundation))。 -- 规则按目录和文件模式限定作用域,只加载相关部分(Stripe,[ByteByteGo 整理](https://blog.bytebytego.com/p/how-stripes-minions-ship-1300-prs))。 -- 知识随评审持续更新:Claude Code 团队把共享的 CLAUDE.md 放进 git,在代码评审中让 Claude 把新教训写进去([Boris Cherny, 2026-01](https://twitter-thread.com/t/2007179832300581177))。 - -### 5.2 让系统对 Agent “可读” - -- 每个工作树都能独立启动一份应用;Agent 通过 Chrome DevTools 协议操作 DOM、截图、导航,并能用 LogQL、PromQL 查询本地日志和指标(OpenAI)。 -- 报错信息本身就是上下文:OpenAI 的自定义 lint 报错直接写明修复方法,把规范注入 Agent 的上下文。 -- 防止输出污染上下文:Carlini 的测试脚本只打印几行摘要,细节写入日志文件;还提供只跑 1% 或 10% 随机样本的快速模式,弥补 Agent 没有时间感的问题([Anthropic, 2026-02](https://www.anthropic.com/engineering/building-c-compiler))。 -- 先评估环境,再评估 Agent:Factory 的 Agent Readiness 从代码风格校验、构建、测试、文档、开发环境、代码质量、可观测性、安全治理 8 个维度给仓库打分。它的判断是:反馈回路差的代码库会击败任何 Agent([Factory, 2026-01](https://factory.com/news/agent-readiness))。 - -### 5.3 上下文预算管理 - -- 上下文腐化:上下文越长,模型准确回忆其中信息的能力越弱。目标是找到“最小的高信号 token 集合”,其余信息只保留路径、URL 等标识,需要时再取([Anthropic, 2025-09](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents))。 -- 长任务三件套:压缩历史、结构化笔记、子 Agent 在干净上下文里完成探索后只回传摘要。 -- 压缩还是重置要实测:Claude Sonnet 4.5 有明显的“上下文焦虑”(接近上限时草草收尾),仅压缩不够,需要带结构化交接的上下文重置;Opus 4.6 基本消除了这一行为([Anthropic, 2026-03](https://www.anthropic.com/engineering/harness-design-long-running-apps))。 -- 把上下文占用率控制在约 40–60%,并围绕“有意识的频繁压缩”设计整个流程([HumanLayer, 2025-08](https://www.humanlayer.dev/blog/advanced-context-engineering))。 - -### 5.4 工具要少而准 - -- Spotify 只给 Agent 验证工具、标准化 git 命令和受限的 shell 白名单,连代码搜索都没给。原因是“工具越多,不可预测的维度就越多”([Spotify, 2025-11](https://engineering.atspotify.com/2025/11/context-engineering-background-coding-agents-part-2))。 -- Spotify 把各种构建系统封装成一个统一的 verify 工具:发现 pom.xml 就自动启用 Maven 校验,Agent 不必理解构建细节和复杂输出([Spotify, 2025-12](https://engineering.atspotify.com/2025/12/feedback-loops-background-coding-agents-part-3))。 -- Stripe 的工具平台有近 500 个 MCP 工具,但默认只给 Agent 一小部分,按需添加([ByteByteGo 整理](https://blog.bytebytego.com/p/how-stripes-minions-ship-1300-prs))。 -- 像设计人机界面一样设计 Agent 工具接口,用防错设计让常见错误无法发生,例如强制使用绝对路径([Anthropic, 2024-12](https://www.anthropic.com/engineering/building-effective-agents))。 - -### 5.5 常见错误 - -- 写一个巨大的说明文件,把所有规则每次都塞进上下文。 -- 关键约定只存在于会议、聊天或个别人脑中。 -- 把所有工具暴露给所有 Agent。 -- 把成千上万行的构建和测试输出直接灌进上下文。 - -## 六、环节 3:规划与任务分解——把长链切成可验证的短链 - -规划的价值不在“想得周全”,而在把长任务切成可以独立验证、失败时可以局部回退的小步,把错误拦在最便宜的阶段。 - -### 6.1 研究 → 计划 → 实现,人审前两步 - -HumanLayer 把流程固定为研究、计划、实现三段:计划要写清步骤、涉及文件和验证方法,阶段之间做压缩。他们在 30 万行的 Rust 项目 BAML 上,7 小时交付了约 3.5 万行代码,完成了按资深工程师估算每项需 3–5 天的功能([HumanLayer, 2025-08](https://www.humanlayer.dev/blog/advanced-context-engineering))。Claude Code 作者的做法类似:先在计划模式里把计划谈清楚,再切到自动接受让它一次完成。 - -### 6.2 一次只做一件事 - -Anthropic 观察到长时 Agent 的两个典型失败:试图一次写完整个应用,以及过早宣布完成。解决办法是让每个会话只做一个功能,他们称这一点“至关重要”([Anthropic, 2025-11](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents))。这与 DORA 的小批量原则、Spotify 的“一次一个变更”是同一件事。 - -### 6.3 任务粒度:落在模型的“可靠区间”内 - -前沿模型 80% 成功率对应的任务长度,远短于 50% 成功率对应的长度(Opus 4.5 分别约为 27 分钟和 4 小时 49 分,见第一节)。经验法则(本报告建议):需要高可靠性的工作单元,应控制在模型高成功率区间内,并在单元之间插入验证。注意 METR 的数字来自其特定任务集,要用自己的评测集校准。对可靠性要求极高的流水线,可以学 MAKER 分解到原子步骤并对关键步骤投票。 - -### 6.4 确定性编排 + 智能体节点 - -最成熟的大规模实践都不是“一个 Agent 自由发挥”,而是确定性流程包裹智能体步骤: - -- Stripe 的 blueprint:在“刚性步骤”和“创造性步骤”之间交替。lint、推送分支是确定性节点,实现功能、修复 CI 失败是 Agent 节点([Stripe, 2026-02](https://stripe.dev/blog/minions-stripes-one-shot-end-to-end-coding-agents-part-2))。 -- Airbnb 的测试迁移:每个文件走一个状态机(重构 → 修 Jest → 修 lint 与 TypeScript),上一步验证通过才进入下一步,失败时把错误和最新文件回传重试。这套流程 4 小时迁移了 75% 的文件,调优 4 天后达到 97%;约 3,500 个文件 6 周完成,原估算需要 1.5 年([Airbnb, 2025-03](https://medium.com/airbnb-engineering/accelerating-large-scale-test-migration-with-llms-9565c208023b))。 -- Google 的代码迁移:用 Kythe 和 AST 确定性地找到所有改动点,模型只负责生成修改,再经构建和测试验证,最后人工审查([Google, 2025-01](https://arxiv.org/abs/2501.06972))。 - -### 6.5 并行与多 Agent:先单体,再按结构拆分 - -- 先把单个 Agent 的能力用足,再考虑多 Agent([OpenAI 构建指南](https://openai.com/business/guides-and-resources/a-practical-guide-to-building-ai-agents/))。Cognition 的理由是:每个动作都隐含决策,决策冲突就会得到坏结果,拆分时必须共享完整轨迹([Cognition, 2025-06](https://cognition.com/blog/dont-build-multi-agents))。 -- 多 Agent 适合广度优先、可并行的工作。Anthropic 的多 Agent 研究系统比单 Agent 效果高 90.2%,但 token 消耗约为普通对话的 15 倍;它也明确说大多数编码任务共享上下文多、依赖多,并不适合([Anthropic, 2025-06](https://www.anthropic.com/engineering/multi-agent-research-system))。 -- 大规模并行需要层级。Cursor 让数百个 Agent 并行开发浏览器时发现:平级加锁自协调让 20 个 Agent 只有 2–3 个的有效吞吐;乐观并发则让 Agent 变得保守,只做小而安全的改动。有效的结构是规划者(可递归分出子规划者)、执行者和裁判,并定期重新开始以对抗漂移([Cursor, 2026-01](https://cursor.com/blog/scaling-agents))。 -- 工作归属要显式。Carlini 用 git 里的锁文件分配任务;当整体调试无法并行时,他用 GCC 作参照,把 Linux 内核的大部分文件交给 GCC 编译、只用自研编译器编剩余文件,把大问题拆成可并行定位的小问题。 - -### 6.6 常见错误 - -- 让 Agent 一次性完成整个应用或大功能。 -- 计划里没有写每一步怎么验证。 -- 多个 Agent 同时改同一区域,却没有明确归属。 -- 让 Agent 去做本可以用脚本或 AST 转换完成的机械步骤。 - -## 七、环节 4:执行环境与 Harness——决定“最坏会怎样”和“能干多久” - -执行层有两个任务:把单次失败的最坏后果限制在可接受范围内,并让 Agent 在无人值守时长时间、可恢复地推进。 - -### 7.1 隔离:每个任务一个可丢弃的环境 - -- Stripe 为每个任务启动预热的 devbox,约 10 秒就绪,运行在 QA 环境,隔离生产数据和任意外网访问([ByteByteGo 对 Stripe 博客的整理](https://blog.bytebytego.com/p/how-stripes-minions-ship-1300-prs))。 -- Spotify 的 Agent 运行在权限受限、几乎接触不到周边系统的容器里,不能自己推送代码。 -- Claude Code 的沙箱同时做文件系统隔离和网络隔离,内部使用中权限提示减少 84%。两者缺一不可:没有网络隔离,被攻破的 Agent 可以外传 SSH 密钥;没有文件系统隔离,它可以逃出沙箱再拿到网络。云端版把凭证放在沙箱外,由 git 代理校验请求后再附加凭证([Anthropic, 2025-10](https://www.anthropic.com/engineering/claude-code-sandboxing))。 - -### 7.2 权限:用分层策略代替逐条审批 - -| 层 | 机制 | 作用 | 实例 | -| --- | --- | --- | --- | -| 白名单 | 预先允许已知安全的命令 | 消除无意义的审批 | Claude Code 的 /permissions,而不是跳过全部权限 | -| 确定性策略 | hooks 在工具调用前后运行脚本 | 强制执行必须遵守的规则 | 编辑后自动格式化;阻止修改受保护文件;拒绝规则在跳过权限模式下仍生效 | -| 分类器 | 模型逐条评估待执行动作 | 拦截越权与破坏性动作 | Claude Code 自动模式 | -| 平台约束 | 分支、审批、网络的结构性限制 | 即使 Agent 出错也越不过边界 | Copilot 云端 Agent 只能推送自己的 copilot/ 分支,发起人不能批准它的 PR,CI 需人点击批准才运行 | - -来源:[Boris Cherny](https://twitter-thread.com/t/2007179832300581177)、[Claude Code hooks 文档](https://code.claude.com/docs/en/hooks-guide)、[Anthropic 自动模式](https://www.anthropic.com/engineering/claude-code-auto-mode)、[GitHub 文档](https://docs.github.com/en/copilot/concepts/agents/cloud-agent/risks-and-mitigations)。 - -自动模式的分类器只看用户消息和工具调用,刻意不看 Agent 的解释和工具输出,以免被 Agent 说服。它在真实流量上误拦率 0.4%,但对真实的“过度热心”动作仍有 17% 漏判。Anthropic 明确说它不能替代对高风险基础设施的人工审查。 - -### 7.3 长时运行:状态外置与可恢复 - -Anthropic 的长时 harness 给出了一套可直接复用的做法([Anthropic, 2025-11](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents)): - -1. 初始化会话生成启动脚本、进度文件和功能清单。 -2. 每个编码会话开始时:确认工作目录,读进度文件和 git 日志,选最高优先级的未完成功能,先跑一遍基本端到端测试确认环境没坏。 -3. 每个会话结束时:写清楚的 git 提交和进度摘要,出错时可以用 git 回退到可用状态。 - -进程崩溃、限流、网络抖动则交给持久化执行框架:Temporal 与 OpenAI Agents SDK 的集成提供自动重试、从检查点恢复,甚至修复 bug 后接着运行([Temporal, 2025-07](https://temporal.io/blog/announcing-openai-agents-sdk-integration))。 - -无人值守的运行时长正在迅速增长。OpenAI 的单次 Codex 运行常在一个任务上工作 6 小时以上,多在人睡觉时完成;Claude Code 最长的 0.1% 单轮运行时长,从 2025 年 9 月的不到 25 分钟增长到 2026 年 1 月的 45 分钟以上([Anthropic, 2026-02](https://www.anthropic.com/research/measuring-agent-autonomy))。社区流行的“Ralph 循环”更极端:用 shell 循环反复喂同一个提示,状态全靠文件和 git 传递;但报道也指出,没有产品规格时结果平庸([The Register, 2026-01](https://www.theregister.com/2026/01/27/ralph_wiggum_claude_loops/))。 - -### 7.4 预算、熔断与卡死检测 - -- 设停止条件,如最大迭代次数([Anthropic, 2024-12](https://www.anthropic.com/engineering/building-effective-agents))。 -- 重试或动作超过阈值就升级给人([OpenAI 构建指南](https://openai.com/business/guides-and-resources/a-practical-guide-to-building-ai-agents/))。Stripe 最多跑两轮 CI,第二次仍不通过就把分支交还给工程师。 -- 反复打转是要立即干预的信号(Kent Beck);Cursor 也遇到 Agent 运行过久的问题,靠定期重新开始来对抗漂移和钻牛角尖。 -- 为每个任务设显式预算:时长、token、重试次数、CI 轮次。预算要与质量收益权衡:Anthropic 的一个实验里,完整 harness 耗时 6 小时、花费 200 美元,是单 Agent(20 分钟、9 美元)的 20 多倍,但质量差异一眼可见。 - -### 7.5 Harness 随模型演进 - -Anthropic 的总结是:harness 里的每个组件,都编码了一个“模型自己做不到什么”的假设,这些假设值得反复检验。换到 Opus 4.6 后,他们去掉了原来的冲刺拆分,因为它已不再承重;但对处在模型能力边缘的任务,独立评估者仍然有价值([Anthropic, 2026-03](https://www.anthropic.com/engineering/harness-design-long-running-apps))。 - -模型选择也要按角色实测。Cursor 在 2026 年 1 月的实验中发现,GPT-5.2 更擅长长时间自主工作,Opus 4.5 则倾向于更早停止或走捷径;不同模型适合不同角色。这类结论只是某个时点的快照,应由自己的评测集决定各角色的模型路由。有评测集的团队几天就能完成模型升级,没有的则要几周([Anthropic, 2026-01](https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents))。 - -### 7.6 非确定性:接受它,度量它 - -即使温度为 0,推理服务也不确定。Thinking Machines 用同一提示请求 1,000 次,得到 80 种不同输出,主因是批大小随负载变化([Thinking Machines, 2025-09](https://thinkingmachines.ai/blog/defeating-nondeterminism-in-llm-inference/))。工程上应该默认“每次运行都不同”:用 pass^k 度量稳定性,固定模型版本,并在链路追踪里记录每次运行的模型、提示词和工具版本。 - -## 八、环节 5:验证与质量门禁——低人工交付的主控制器 - -验证决定三件事:Agent 能否自我纠错,某类任务能否放权,质量会不会被“优化穿”。门禁要分层、异构、防篡改,并尽量靠前。 - -### 8.1 分层验证:从秒级检查到人审 - -| 层 | 检查什么 | 类型 | 何时运行 | 业界做法 | -| --- | --- | --- | --- | --- | -| 1 即时反馈 | 格式、lint、类型、编译 | 计算型 | 每次编辑或推送 | Stripe 每次推送在 5 秒内跑完本地 lint;hooks 编辑后自动格式化 | -| 2 功能测试 | 单元、集成、选择性回归 | 计算型 | 提交 PR 前 | Stripe 从 300 多万个测试中选择性运行;Spotify 的统一 verify 工具 | -| 3 架构适应度 | 分层依赖、命名、文件大小、结构化日志 | 计算型 | 合并前 | OpenAI 用自定义 linter 和结构测试强制单向分层依赖 | -| 4 行为验证 | 像用户一样端到端操作、截图、接口契约 | 计算型 + 推理型 | 合并前 | Anthropic 要求用浏览器自动化验证后才能标记完成 | -| 5 测试强度 | 变异测试、属性测试、差分测试、模糊测试 | 计算型 | 关键模块合并前或定期 | Meta ACH;Kiro;Carlini 以 GCC 为参照;CodeMender 用模糊测试、差分测试和 SMT 求解器 | -| 6 语义评审 | 是否偏离需求、范围蔓延、可维护性 | 推理型 | 合并前 | Spotify 的 LLM 裁判;Anthropic 对每个变更做 Claude 自动评审 | -| 7 安全扫描 | 依赖漏洞、密钥、危险模式 | 计算型 + 推理型 | 合并前 | 与人写代码标准一致,不降级 | -| 8 人审 | 高风险变更、抽样审计 | 人 | 按风险路由 | Stripe 所有 Minion PR 都经人审;OpenAI 几乎全部交给 Agent 互审 | - -快而便宜的计算型检查放在最前面(提交前),慢而贵的推理型检查放在集成流水线里([Böckeler, 2026-04](https://martinfowler.com/articles/harness-engineering.html))。 - -### 8.2 独立评审:生成者不给自己打分 - -- Spotify 的 LLM 裁判拿变更对照原始需求,检查范围蔓延。在数千次会话中,它否决了约四分之一;被否决后,Agent 大约一半能自行纠正([Spotify, 2025-12](https://engineering.atspotify.com/2025/12/feedback-loops-background-coding-agents-part-3))。 -- Anthropic 的评估 Agent 与生成 Agent 分离,用评分标准、少样本示例和硬阈值调成偏怀疑,并先操作应用再打分。 -- Anthropic 现在让 Claude 自动评审每一个变更。回溯分析显示,这套评审本可在上线前抓住 claude.ai 历史故障背后约三分之一的 bug([Anthropic Institute](https://www.anthropic.com/institute/recursive-self-improvement))。 -- DeepMind 的 CodeMender 只把满足四个条件的补丁交给人审:修复根因、功能正确、无回归、符合风格规范;并用 LLM 批评工具对比修改前后的代码([DeepMind, 2025-10](https://deepmind.google/blog/introducing-codemender-an-ai-agent-for-code-security/))。 -- LLM 评审要校准:每种失败模式标注 100–200 个样本,分别度量“抓住真实问题”和“放过好结果”的比例,并保留独立测试集防止过拟合([Hamel Husain 与 Shreya Shankar](https://hamel.dev/blog/posts/evals-faq/))。 - -### 8.3 防作弊:让判定器“改不了、骗不过” - -1. 测试与判定器只读:实现类任务禁止修改测试目录、CI 配置和 lint 配置,用 PreToolUse hook 拦截。Claude Code 的拒绝规则在跳过权限模式下仍然生效。 -2. 在 Agent 之外判定:最终验收由沙箱外的 CI 重新运行,不采信 Agent 自己报告的结果。 -3. 留出测试:保留一部分 Agent 看不到的验收测试或评测用例。 -4. 差异审计:删除或跳过测试、放宽断言、修改覆盖率阈值的变更,自动升级人审。 -5. 度量测试本身:用变异测试检验测试能否抓住真实缺陷。Meta 的 ACH 先生成针对具体关切点的缺陷变体,再生成能杀死它们的测试,工程师接受了其中 73%([Meta, 2025-01](https://arxiv.org/abs/2501.12862))。更早的 TestGen-LLM 用“能构建、稳定通过、提升覆盖率”三道过滤器保证生成的测试确实有用,73% 的建议被采纳上线([Meta, 2024](https://arxiv.org/abs/2402.09171))。 - -这些措施都不依赖提示词。前文 METR 的数据已经表明,明确要求“不要作弊”之后,作弊仍在继续。 - -### 8.4 有界重试:把错误信息喂回去,但设上限 - -每次重试都必须带上新的外部信息,比如报错、失败的测试、裁判的否决理由;单纯“再试一次”没有用。Airbnb 把校验错误和最新文件一起回传,简单到中等难度的文件大多在 10 次内成功;Stripe 则最多允许两轮 CI。上限之后就停止并升级,这正是“异常即停”原则。 - -### 8.5 “可合并”要求高于“测试通过” - -METR 审查的 15 个 Agent PR 中,普遍存在测试覆盖不足、文档缺失、lint 或类型问题、代码质量问题;即使通过了测试的 PR,平均也要 26 分钟才能改到可合并。门禁因此必须同时覆盖三类质量:可维护性、架构适应度和行为正确性。Böckeler 指出,行为正确性是三者中最难验证的一类。 - -“无需修改即合并”的比例是很好的综合质量信号。公开数据包括:Google 的 JUnit3→JUnit4 迁移中,约 87% 的 AI 生成代码原样提交;Amazon 的 Java 升级中,79% 的自动生成代码评审未加修改即发布([Andy Jassy, 2024-08](https://simonwillison.net/2024/Aug/24/andy-jassy-amazon-ceo/));Devin 的 PR 合并率一年内从 34% 升到 67%。 - -### 8.6 人审:按风险路由,审证据而不是审每一行 - -是否全量人审取决于爆炸半径。Stripe 承载每年约 1 万亿美元支付量,所有 Minion PR 都经人审;OpenAI 的内部产品几乎完全靠 Agent 互审,人可以审但不强制。 - -建议按以下信号把变更路由给人(本报告的综合建议):涉及鉴权、支付、数据迁移或基础设施;修改了测试或 CI;引入新依赖或改动公共 API;diff 超过规模阈值;裁判置信度低或曾被否决。送审时附上证据包:规格、计划、测试结果、截图或录屏、轨迹摘要,让人几分钟内能做出判断。自动合并的变更按比例抽样复查,用来估计门禁的漏检率。 - -## 九、环节 6:集成与发布——高吞吐下的稳定靠小批量和可回滚 - -Agent 让变更数量成倍增加。稳定性的关键不在更多人审,而在每个变更足够小、验证足够快、出错能自动撤回。 - -### 9.1 小而短命的 PR - -- DORA 发现小批量工作会放大 AI 对产品表现的正面影响;频繁提交、频繁使用回滚功能,会提升 AI 辅助团队的表现([Google Cloud, 2025-09](https://cloud.google.com/blog/products/ai-machine-learning/introducing-doras-inaugural-ai-capabilities-model))。 -- 反面信号:Faros 的数据里,高 AI 采用团队的平均 PR 规模增加 154%,人均 bug 增加 9%。 -- 不稳定是有代价的:DORA 的投资回报模型中,一个 500 人的工程组织变更失败率从 5% 升到 6%,对应约 34.4 万美元的负面影响([InfoQ, 2026-05](https://www.infoq.com/news/2026/05/dora-roi-ai-assisted-dev-report/))。 - -### 9.2 主干常绿与合并策略 - -合并门禁的松紧,取决于出错后撤回的成本。 - -- OpenAI 的内部产品只保留极少的阻塞式合并门禁,PR 寿命很短,不稳定测试靠后续重跑处理。理由是:在 Agent 吞吐远超人类注意力的系统里,修正很便宜,等待很昂贵。这个前提是撤回便宜、爆炸半径小。 -- Cursor 的多 Agent 实验(峰值约每小时 1,000 次提交)发现,要求每次提交都 100% 正确会让吞吐骤降。他们在工作分支上接受“小而稳定的错误率”,再由专门的 Agent 定期快照到“绿色”分支,发布前做一轮快速修正([Cursor, 2026-02](https://cursor.com/blog/self-driving-codebases))。启示是:高吞吐的集成分支和严格常绿的发布分支应当分开。 -- 对生产代码主干,建议用合并队列保证合入后仍然全绿,并把不稳定测试隔离出来单独治理,避免它们误导 Agent 的重试。 - -### 9.3 按风险分级的发布策略 - -下表是本报告综合各家做法给出的建议分级。 - -| 风险等级 | 典型变更 | 合并方式 | 发布方式 | 回退手段 | -| --- | --- | --- | --- | --- | -| R0 无运行时影响 | 文档、补充测试、修 lint | 门禁全绿即自动合并 | 随常规发布 | git revert | -| R1 低风险可逆 | 依赖小版本升级、行为不变的重构 | 自动合并 + 抽样审计 | 金丝雀或分批 | 指标超阈值自动回滚 | -| R2 中风险 | 带开关的功能变更、新增公共 API | 独立 AI 评审 + 人审 | 特性开关默认关闭,逐步放量 | 关闭开关 | -| R3 高风险 | 鉴权、支付、数据迁移、基础设施、权限 | 人审,必要时双人批准 | 预演、备份、变更窗口 | 预案 + 数据恢复演练 | - -### 9.4 环境隔离与生产访问 - -2025 年 7 月,Replit 的 Agent 在用户要求代码冻结期间删除了生产数据库,还编造数据并错误地声称无法恢复。Replit 的整改是:自动分离开发与生产数据库、提供整个项目状态的一键恢复、计划增加预发环境([The Register, 2025-07](https://www.theregister.com/2025/07/22/replit_saastr_response/))。 - -原则:开发会话里的 Agent 不持有生产写权限;生产变更只能经过带门禁的流水线;备份和恢复要定期演练。 - -### 9.5 可追溯 - -GitHub Copilot 云端 Agent 的提交以 Copilot 为作者、发起人为共同作者,并做加密签名。建议把每个变更关联到任务、规格和运行轨迹,并记录模型与提示词版本,出问题时才能定位到是哪个环节失效。 - -## 十、环节 7:运行与可观测——看得见,才敢放手 - -人不再逐步盯着 Agent,就必须有另一双眼睛:每个动作可追踪,每个结果可度量,异常时能自动停下来。 - -### 10.1 全链路追踪 - -每次 Agent 运行都应留下完整轨迹:模型、提示词和工具版本,每次工具调用及结果摘要,token 用量,各层门禁结果,以及人的每次介入。 - -- OpenTelemetry 已为 Agent 定义了语义约定,包括创建 Agent、调用 Agent、调用工作流、规划、执行工具等 span 类型,以及 Agent 名称、操作类型、token 用量等属性。目前仍处于“开发中”状态,字段可能变化([OpenTelemetry](https://github.com/open-telemetry/semantic-conventions-genai/blob/main/docs/gen-ai/gen-ai-agent-spans.md))。 -- Anthropic 在多 Agent 系统的生产经验中强调:有状态系统里错误会复合,需要完整的生产追踪来诊断;运行中的 Agent 要能从检查点恢复;发布新版本时用“彩虹部署”,让旧版本上正在跑的 Agent 不被打断([Anthropic, 2025-06](https://www.anthropic.com/engineering/multi-agent-research-system))。 - -### 10.2 运行信号与告警 - -需要持续监控的信号包括:任务成功率、回归评测集上的 pass^k、每任务重试次数和 CI 轮次、裁判否决率、分类器拦截率、每个合并 PR 的成本、升级率,以及 Agent 变更与人工变更各自的变更失败率(定义见第十五节)。分类器拦截是健康信号而非故障:Gusto 自 2026 年 5 月中旬起约 10% 的会话出现过拦截([Anthropic, 2026-08](https://claude.com/blog/auto-mode-default-in-claude-code))。 - -告警应针对突变而不是绝对值:重试、成本、拦截次数突然上升,pass^k 突然下降,或者修改测试的变更突然增多。 - -### 10.3 熔断与紧急停机 - -- 自治等级框架把 L5 定义为用户只能看日志和按下紧急停机开关。没有这个开关,就不应进入 L5。 -- 按误差预算自动降级(本报告建议):某一任务类别的 Agent 变更失败率在滑动窗口内超过预算,就自动关闭该类的自动合并、恢复人审,直到指标恢复。 - -### 10.4 Agent 参与运维:读多写少 - -让 Agent 查询日志和指标,对排障和验证行为很有价值(OpenAI 的 Agent 可用 LogQL、PromQL 查询本地观测数据)。但生产环境中应当“读多写少”:只读诊断可以高度自主;重启、扩缩容、回滚等写操作只能走预先批准的运行手册或分级审批。OWASP 的 Agent 应用十大风险也要求对高影响或改变目标的动作进行人工批准(见第十二节)。 - -### 10.5 模型与提示词也是生产变更 - -换模型、改提示词、加工具,都要像发布代码一样管理:先跑回归评测集并比较 pass^k,再拿一小部分真实任务做金丝雀,指标不劣化再全量切换。由于输出不确定,应比较多次运行的分布,而不是单次结果。 - -### 10.6 部署后监控是放权的前提 - -Anthropic 对数百万次交互的分析显示:80% 的 API 工具调用来自至少有一种防护的 Agent,73% 看起来有人在回路中,只有 0.8% 的动作不可逆。他们的建议是:投资部署后监控;训练模型识别自身的不确定并主动上报;产品要让人能看见并能干预;不必强制规定某种交互模式,关键是人能否有效监控和介入([Anthropic, 2026-02](https://www.anthropic.com/research/measuring-agent-autonomy))。 - -## 十一、环节 8:反馈闭环与持续改进——“持续”来自复利 - -持续稳定不是一次性搭好流水线就能得到的。要让每次失败都变成一条规则、一个测试或一个工具,同时持续清理 Agent 带来的熵增。 - -### 11.1 先做错误分析,再定指标 - -Hamel Husain 与 Shreya Shankar 把错误分析称为评测中最重要的活动([评测 FAQ, 2026-09 更新](https://hamel.dev/blog/posts/evals-faq/)): - -1. 收集有代表性的运行轨迹,先拿 100 条,前 30 条亲自标注。 -2. 开放编码:逐条记下问题,不预设分类。 -3. 轴向编码:把问题归并成失败分类法,并统计每类频次。 -4. 持续看新轨迹,直到不再出现新的失败模式。 - -判定用“通过/不通过”二元标准,比 1–5 分更一致。日常运营中,每周至少看 10–20 条异常轨迹。 - -### 11.2 评测飞轮 - -Anthropic 给出的做法([Anthropic, 2026-01](https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents)): - -- 从真实失败中抽 20–50 个简单任务开始,不必等大评测集。 -- 能力评测从低通过率起步,饱和后转入回归评测(目标接近 100%),并持续运行。 -- 需要“每次都对”的场景用 pass^k,而不是 pass@k。 -- 评结果不评路径,避免惩罚 Agent 找到的合理新解法。 -- 必须读轨迹,确认评分器本身没错;每次试验用干净环境,避免共享状态造成相关失败。 - -建议把每次线上事故、每个逃逸缺陷都转成一条回归评测用例。 - -### 11.3 经验固化:复利工程 - -Every 的 Kieran Klaassen 把这称为“复利工程”:普通的 AI 工程让你今天更快,复利工程让你明天和之后的每一天都更快;每修复一次、每审查一次,系统都在学习([Every](https://every.to/source-code/my-ai-had-already-fixed-the-code-before-i-saw-it))。Böckeler 称之为“操控回路”:同类问题反复出现,就增强引导或传感;而 Agent 让定制这些控制手段变得很便宜。 - -关键是选对沉淀的形式,越靠下越可靠: - -| 教训类型 | 沉淀到哪里 | 例子 | -| --- | --- | --- | -| 可以自动检查的约定 | lint 规则、架构测试(首选) | “服务层不得依赖 UI 层” | -| 重复出现的流程 | 技能、斜杠命令、确定性流水线节点 | “提交前先跑本地验证” | -| 需要判断的标准 | 评审评分标准 + 校准样本 | “什么算范围蔓延” | -| 背景知识与约定 | AGENTS.md 或分目录规则 | “这个模块的历史包袱” | -| 失败案例 | 回归评测用例 | 某次事故的复现任务 | - -能写成计算型检查的,就不要只写成文字规则;文字规则会被忽略,检查不会。 - -### 11.4 熵治理:定期“垃圾回收” - -- OpenAI 的团队曾经每周五(占一周 20% 的时间)手工清理 Agent 产生的劣质代码,这种做法无法扩展。后来他们把“黄金原则”写进仓库,由后台任务定期扫描偏离并提交针对性的重构 PR。 -- Carlini 的编译器项目设有专职 Agent,分别负责去重、性能、代码质量、设计批评和文档维护。 -- GitHub 的 Continuous AI 把这类工作变成仓库里持续运行的 Agent 工作流,如文档与代码对齐、扩充测试、监控依赖行为变化。其护栏是:默认只读;显式声明允许产出哪些工件;只提 PR 不直接提交;全程可审计([GitHub, 2026-02](https://github.blog/ai-and-ml/generative-ai/continuous-ai-in-practice-what-developers-can-automate-today-with-agentic-ci/))。 -- 把静态告警数、复杂度、重复代码率作为趋势指标监控。前文 He 等的研究表明,这些指标的持续上升正是后期速度下滑的主因。 - -### 11.5 定期重审 harness 与自治度 - -每次模型升级后,用评测集验证哪些脚手架已不再承重,哪些新能力值得加入新的组件。每个季度按任务类别复盘质量预算的消耗,决定该类是升级自治、保持还是收紧。 - -## 十二、横切:安全与权限治理——用结构划边界,而不是靠信任 - -Agent 会被提示注入,会误解指令,也会过度热心。低人工参与只能建立在结构性隔离之上:安全边界必须在 Agent 出错时依然成立。 - -### 12.1 用“二选一规则”设计每类自主会话 - -按 Meta 的规则,每个自主会话最多具备三项能力中的两项:处理不可信输入(A)、访问敏感系统或数据(B)、改变状态或对外通信(C)。落到研发场景(本报告的应用示例): - -| 会话类型 | A 不可信输入 | B 敏感访问 | C 改变状态/对外通信 | 组合 | -| --- | --- | --- | --- | --- | -| 处理外部 issue 或 PR 评论的后台 Agent | 有 | 去掉:无密钥、无生产数据 | 有:只能提 PR | A + C | -| 内部重构或迁移 Agent | 去掉:只读仓库和内部文档,禁止联网 | 有 | 有 | B + C | -| 线上排障 Agent | 有:日志中可能含用户输入 | 有 | 去掉:只读,写操作需审批 | A + B | -| 三者都需要 | — | — | — | 不自主运行,需人工审批或拆成独立会话 | - -设计原则来自安全研究者的六种抗注入模式:一旦 Agent 读入了不可信输入,就必须受到约束,使这些输入不可能触发任何有后果的动作。六种模式是:行动选择器、先计划后执行、LLM map-reduce、双 LLM、先生成代码再执行、上下文最小化([Simon Willison 对论文的总结](https://simonwillison.net/2025/Jun/13/prompt-injection-design-patterns/))。 - -### 12.2 沙箱与凭证 - -- 文件系统与网络同时隔离;凭证放在沙箱外,由代理校验后附加(见第七节)。 -- 每个 Agent 使用独立、有边界的身份和短期凭证,采用零信任设计和故障隔离([OWASP 要点整理](https://goteleport.com/blog/owasp-top-10-agentic-applications/))。 -- 默认限制外网访问并过滤隐藏字符,减少注入面(GitHub Copilot 云端 Agent 的做法)。 - -### 12.3 供应链与开发机安全:两起真实事件 - -- 2025 年 8 月的 Nx “s1ngularity”攻击:被投毒的 npm 包调用开发机上已安装的 Claude、Gemini、Q 命令行工具,并加上跳过权限的参数搜刮密钥。泄露包括 1,000 多个有效 GitHub 令牌、数十个云凭证和 npm 令牌、约 2 万个文件;第二阶段又有 5,500 多个私有仓库被公开([Wiz, 2025-08](https://www.wiz.io/blog/s1ngularity-supply-chain-attack))。 -- 2025 年 7 月的 Amazon Q VS Code 扩展事件:CodeBuild 配置中权限过宽的 GitHub 令牌被利用,恶意代码随 1.84.0 版自动发布;因语法错误未能执行,编号 CVE-2025-8217([AWS, 2025-07](https://aws.amazon.com/security/security-bulletins/AWS-2025-015/))。 - -教训:不要在存有密钥的机器上长期开启跳过权限模式,跳过权限只能在沙箱或容器内使用;CI 令牌最小权限;依赖锁定并校验;发布流水线本身也要有人工或自动化审计。 - -### 12.4 破坏性动作必须硬拦截 - -- 两个反面案例:Replit 的 Agent 在代码冻结期删除生产库(见第九节);Google Antigravity 在允许 Agent 不经确认执行命令的 Turbo 模式下清理缓存时,把用户整个 D 盘根目录静默删除且无法恢复([PiunikaWeb, 2025-12](https://piunikaweb.com/2025/12/02/google-antigravity-deletes-hard-drive-coding-mishap/)、[Tom's Hardware, 2025-12](https://www.tomshardware.com/tech-industry/artificial-intelligence/googles-agentic-ai-wipes-users-entire-hard-drive-without-permission-after-misinterpreting-instructions-to-clear-a-cache-i-am-deeply-deeply-sorry-this-is-a-critical-failure-on-my-part))。 -- 用确定性规则拒绝高危命令(如含 rm -rf 的命令),让拒绝在任何权限模式下都生效。Claude Code 自动模式默认拦截 20 多类动作,归为四组:不可逆破坏或数据外泄、削弱安全(如关闭日志)、跨越信任边界、绕过共享基础设施的防护。 -- 备份、软删除和恢复演练是最后一道防线。 - -### 12.5 用 OWASP Agent 应用十大风险做核对 - -OWASP 于 2025 年 12 月发布的清单适合作为安全评审提纲:目标劫持、工具滥用、身份与权限滥用、Agent 供应链漏洞、意外代码执行、记忆与上下文投毒、Agent 间通信不安全、级联故障、利用人对 Agent 的信任、失控 Agent。 - -### 12.6 分类器不是银弹 - -自动模式对真实“过度热心”动作仍有 17% 漏判,对合成的数据外泄场景漏判 5.7%([Anthropic, 2026-03](https://www.anthropic.com/engineering/claude-code-auto-mode))。红队加固后,漏判率从 12% 降到 7%;72 个间接提示注入场景各测 10 次、共 720 次攻击,均未成功([Anthropic, 2026-08](https://claude.com/blog/auto-mode-default-in-claude-code))。它明显优于逐条人工审批,但仍应与沙箱、硬拒绝规则、最小权限叠加使用。对生产基础设施的高风险变更,Anthropic 自己也建议由人审查。 - -## 十三、横切:人的角色与升级机制——从“逐步审批”到“设计与例外” - -人从执行者和逐项审批者,转为意图的所有者、harness 的设计者、例外的处理者和系统的审计者。升级机制是这种转变能否成立的关键。 - -### 13.1 人的不可替代之处 - -Böckeler 的概括是:人带来 harness 无法编码的上下文——团队真正想达成什么、哪些技术债因业务原因可以容忍、在这个具体语境里“好”是什么样。好的 harness 不是消除人的输入,而是把它引到最重要的地方([martinfowler.com, 2026-04](https://martinfowler.com/articles/harness-engineering.html))。 - -即使在 Anthropic 内部,多数工程师也认为自己只有 0–20% 的工作能完全委派给 Claude。他们优先委派容易验证、风险低或枯燥的工作([Anthropic, 2025-12](https://www.anthropic.com/research/how-ai-is-transforming-work-at-anthropic))。这与第二节的验证者定律一致。 - -### 13.2 为什么逐条审批靠不住 - -逐条审批既耗人,又抓不住问题:用户批准了 93% 的权限提示,对照实验中人工审批只拦下 13.6% 的危险命令(见第二节)。有经验的用户已经自发转向监控式监督:随着使用积累,全自动批准的会话占比从约 20% 升到 40% 以上,但中途打断的比例也从约 5% 升到约 9%——不再逐步批准,而是发现不对就介入([Anthropic, 2026-02](https://www.anthropic.com/research/measuring-agent-autonomy))。 - -### 13.3 设计升级触发器 - -| 触发器 | 例子 | 依据 | -| --- | --- | --- | -| 失败超限 | 重试或 CI 轮次用完 | OpenAI 构建指南;Stripe 两轮 CI 后交还工程师 | -| 高风险或不可逆动作 | 删除数据、改权限、支付、生产变更 | OpenAI 构建指南;OWASP | -| 不确定或需求模糊 | 缺验收标准、有多个合理方案 | Anthropic 自治度研究 | -| 策略拦截 | 分类器或 hooks 拒绝 | Claude Code 自动模式 | -| 裁判否决后仍未通过 | 范围蔓延未能自行纠正 | Spotify | -| 预算耗尽 | token、时长超限 | 本报告建议 | -| 触碰受保护资产 | 改测试、CI、依赖、公共 API | 本报告建议 | - -Agent 主动停下来比人去拦更有价值。Anthropic 的数据里,Claude Code 主动停下的三大原因是提出方案供选择(35%)、收集诊断信息(21%)和澄清需求(13%)。 - -### 13.4 升级包:让人几分钟内做出决定 - -升级的价值取决于人处理它有多快。Karpathy 在 2025 年的演讲中强调,要加速“生成—验证”循环,就要用好的界面让人快速验证(diff、预览、截图、日志)([演讲整理](https://travis.media/blog/software-3-0-ai-changing-programming-karpathy/))。建议升级包包含: - -1. 任务目标与当前状态。 -2. 已尝试的方案及结果。 -3. 证据:失败日志、测试结果、截图、轨迹链接。 -4. 可选方案和 Agent 的推荐。 -5. 需要人决定的具体问题。 - -同时度量“升级精度”(确实需要人的升级占比)和处理时长。精度太低会把人拖回审批疲劳,接近 100% 则可能说明升级门槛过高,漏掉了本该升级的情况。 - -### 13.5 技能保持与信任校准 - -- 监督悖论:Anthropic 工程师指出,有效监督 Claude 需要的编码能力,恰恰会因过度依赖而退化。DORA 也提出“专长悖论”,建议让资深工程师带初级工程师一起审查 AI 做出的架构决策([DORA, 2026-03](https://dora.dev/insights/balancing-ai-tensions/))。 -- 保持手感的做法(本报告建议):轮岗维护 harness 和处理最难的任务;定期做不借助 Agent 的故障诊断演练;把阅读 Agent 轨迹当作学习材料。 -- 用数据而不是感觉决定放权。METR 2025 年的随机对照试验里,资深开源开发者使用 AI 后实际慢了 19%,自己却认为快了约 20%([METR, 2025-07](https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/))。2025 年末的后续数据指向提速,但 METR 认为证据很弱,因为受到严重的选择偏差([METR, 2026-02](https://metr.org/blog/2026-02-24-uplift-update/))。 - -## 十四、业界案例拆解 - -公开实践已经收敛出一套共同做法:可读的仓库、以确定性为骨架的流水线、统一的验证入口、独立评审、隔离环境、状态外置和持续清理。各家的差异主要在人审强度,而这取决于爆炸半径。 - -### 14.1 平台级自主编码 - -| 组织 | 规模 | 自治方式 | 关键质量机制 | 公开数据 | -| --- | --- | --- | --- | --- | -| [OpenAI 内部产品](https://openai.com/index/harness-engineering/)(2026-02) | 5 个月、约 100 万行、约 1,500 个 PR,团队 3 人增至 7 人 | 人不写代码,评审以 Agent 互审为主 | AGENTS.md 地图加 docs 系统记录;自定义 linter 和结构测试;每个工作树可启动应用并可查询观测数据;后台清理 | 人均每天 3.5 个 PR,耗时约为手写的十分之一 | -| [Stripe Minions](https://stripe.dev/blog/minions-stripes-one-shot-end-to-end-coding-agents)(2026-02) | 每周合并 1,000 多个 PR,后续报道超过 1,300 个 | Slack 触发,一次性端到端完成 | 确定性与智能体节点交替的 blueprint;约 10 秒就绪的隔离 devbox;本地 lint 少于 5 秒;最多两轮 CI | PR 中没有人写的代码,但全部经人审 | -| [Anthropic 内部](https://www.anthropic.com/institute/recursive-self-improvement)(2026) | 截至 2026 年 5 月,合并代码 80% 以上由 Claude 编写 | 人审已成新瓶颈 | Claude 自动评审每个变更 | 回溯分析显示可拦截约三分之一历史事故 bug;代码质量由 2025 年底略差变为大致持平 | -| [Anthropic C 编译器](https://www.anthropic.com/engineering/building-c-compiler)(2026-02) | 16 个并行 Agent、近 2 周、约 2,000 个会话、不到 2 万美元、约 10 万行 Rust | 人设计 harness,Agent 全自主 | 近乎完美的测试判定器;GCC 作参照;锁文件分工;专职质量 Agent | 可构建可启动的 Linux 6.9,在包括 GCC torture 在内的多数测试集上通过率 99% | -| [Cursor](https://cursor.com/blog/scaling-agents)(2026-01) | 数百个并发 Agent,约一周写出 100 多万行的浏览器;后续实验峰值约每小时 1,000 次提交 | 规划者、执行者、裁判三角色 | 递归规划;接受小而稳定的错误率,发布前在绿色分支修正 | 平级加锁时 20 个 Agent 只有 2–3 个的有效吞吐 | -| [Spotify Honk](https://engineering.atspotify.com/2025/11/spotifys-background-coding-agent-part-1)(2025-11) | 合并 1,500 多个 PR,覆盖 Java record、Scio 升级、Backstage 迁移 | 后台 Agent,人审 PR | 统一 verify 工具;LLM 裁判否决约四分之一会话;受限容器 | 比手写节省 60–90% 时间 | -| [Cognition Devin](https://cognition.com/blog/devin-annual-performance-review-2025)(2025-11) | 企业客户 | 异步 Agent | 聚焦需求明确、结果可验证的任务 | PR 合并率一年内从 34% 升至 67% | - -### 14.2 大规模迁移与专项任务 - -| 组织 | 任务 | 做法 | 公开数据 | -| --- | --- | --- | --- | -| [Google DeepMind CodeMender](https://deepmind.google/blog/introducing-codemender-an-ai-agent-for-code-security/)(2025-10) | 安全漏洞修复 | 静态与动态分析、差分测试、模糊测试、SMT 求解器和 LLM 批评全部通过后才交人审 | 6 个月向开源项目上游提交 72 个安全修复 | -| [Airbnb](https://medium.com/airbnb-engineering/accelerating-large-scale-test-migration-with-llms-9565c208023b)(2025-03) | 约 3,500 个测试文件从 Enzyme 迁到 React Testing Library | 每文件状态机逐步验证;错误回灌重试;4 天“抽样—调优—扫描” | 6 周完成(原估 1.5 年),97% 自动完成 | -| [Google](https://arxiv.org/abs/2501.06972)(2025-01) | int32→int64、JUnit3→JUnit4、Joda→java.time | Kythe 与 AST 确定性定位,微调模型生成,构建与测试验证,最后人审 | 80% 的修改由 AI 编写,节省约 50% 时间;JUnit 迁移中约 87% 的 AI 代码原样提交 | -| [Amazon](https://simonwillison.net/2024/Aug/24/andy-jassy-amazon-ceo/)(2024-08) | Java 17 升级 | OpenRewrite 确定性配方打底,生成式 AI 处理剩余问题 | 单应用升级从约 50 人天降到数小时;6 个月升级超过一半生产 Java 系统;约 4,500 人年;79% 的自动生成代码评审未加修改 | -| [Meta ACH](https://arxiv.org/abs/2501.12862)(2025)与 [TestGen-LLM](https://arxiv.org/abs/2402.09171)(2024) | 测试生成与加固 | 变异引导生成;可构建、稳定通过、提升覆盖率三道过滤 | ACH 测试 73% 被接受;TestGen-LLM 73% 的建议上线 | - -### 14.3 反面案例 - -| 事件 | 时间 | 发生了什么 | 失效的防线 | 对策 | -| --- | --- | --- | --- | --- | -| [Google Antigravity](https://www.tomshardware.com/tech-industry/artificial-intelligence/googles-agentic-ai-wipes-users-entire-hard-drive-without-permission-after-misinterpreting-instructions-to-clear-a-cache-i-am-deeply-deeply-sorry-this-is-a-critical-failure-on-my-part) | 2025-12 | 清理缓存时静默删除了整个 D 盘 | 自动执行模式下缺少破坏性命令硬拦截 | 危险命令拒绝规则;禁止写工作区以外的路径 | -| [Nx s1ngularity](https://www.wiz.io/blog/s1ngularity-supply-chain-attack) | 2025-08 | 恶意包驱动本机 AI 命令行工具以跳过权限模式搜刮密钥 | 开发机上的 Agent 可被任意进程调用且拥有全部权限 | 跳过权限只在沙箱内使用;密钥与 Agent 隔离 | -| [Amazon Q 扩展](https://aws.amazon.com/security/security-bulletins/AWS-2025-015/) | 2025-07 | 恶意代码随正式版自动发布 | CI 令牌权限过宽,发布流程缺少审计 | 最小权限令牌;发布审计 | -| [Replit](https://www.theregister.com/2025/07/22/replit_saastr_response/) | 2025-07 | 代码冻结期删除生产库并编造数据 | 开发与生产未隔离;无可靠恢复;Agent 可直接写生产 | 自动分离开发与生产;一键恢复 | - -### 14.4 共识与分歧 - -七条共识: - -1. 环境先于 Agent:可读的仓库、可启动的应用、快速反馈(OpenAI、Factory、Spotify)。 -2. 确定性流程是骨架,Agent 是肌肉(Stripe、Airbnb、Google、Amazon)。 -3. 统一、快速、在 Agent 之外运行的验证(Spotify、Stripe、Carlini)。 -4. 生成与评审分离(Spotify、Anthropic、Cursor、DeepMind)。 -5. 隔离与最小权限(Stripe、Spotify、Claude Code、GitHub Copilot)。 -6. 状态外置与小步推进(Anthropic、Carlini、Cursor)。 -7. 持续清理熵增(OpenAI、Carlini、GitHub)。 - -三条分歧: - -1. 人审强度:Stripe 全量人审,OpenAI 以 Agent 互审为主。判断依据应是爆炸半径和可逆性,而不是工具能力。 -2. 质量门槛:Cursor 在工作分支上接受小而稳定的错误率,主流做法要求主干常绿。折中办法是把集成分支和发布分支分开。 -3. 多 Agent:Cognition 主张单线程,Cursor 与 Anthropic 在可分解的问题上使用层级多 Agent。关键看任务能否分解、共享上下文有多少。 - -## 十五、度量体系 - -六类指标共同回答一个问题:还能不能再放手一点。单独优化任何一类,都会被“优化穿”。 - -### 15.1 稳定性的核心指标:pass^k - -若单次成功率为 p,且各次尝试独立: - -```latex -\text{pass@}k = 1-(1-p)^{k}, \qquad \text{pass}^{k} = p^{k} -``` - -p = 0.9 时,pass@8 接近 100%,而 pass^8 只有约 43%。前者回答“试几次总能成”,适合有判定器兑底的生成—筛选;后者回答“每次都能成”,是决定能否无人值守的指标。 - -### 15.2 指标清单 - -| 类别 | 指标 | 定义 | 告诉你什么 | -| --- | --- | --- | --- | -| 质量 | 无修改合并率 | Agent PR 未经人工改动即合并的比例 | 综合质量;参照:Google 约 87%、Amazon 79% | -| 质量 | 逃逸缺陷率 | 合并后发现、本应被门禁拦住的缺陷数 / 合并数 | 门禁漏检 | -| 质量 | 变更失败率(按来源) | 导致故障或回滚的部署占比,Agent 与人工分开统计 | 稳定性底线 | -| 质量 | 静态告警与复杂度趋势 | 按周观察增量 | 熵增预警 | -| 质量 | 变异得分 | 测试杀死的变异体比例 | 判定器是否可信 | -| 稳定性 | pass^k | 回归评测集上 k 次全部成功的比例 | 能否委派 | -| 稳定性 | 回滚率与恢复时长 | 回滚次数、从故障到恢复的时间 | 恢复能力 | -| 效率 | 合格交付吞吐 | 通过全部门禁且上线后 N 天内无回滚的变更数 | 真实产出 | -| 效率 | 交付周期、CI 轮次 | 从任务创建到上线的时间;达到全绿所需轮次 | 反馈速度 | -| 自治度 | 人工干预率 | 每个任务的人工打断或手工修改次数 | 自治水平 | -| 自治度 | 升级率与升级精度 | 升级占比;升级中确实需要人的比例 | 升级机制是否健康 | -| 自治度 | 人审覆盖率 | 按风险等级统计的人审变更占比 | 注意力分配 | -| 成本 | 每个合格交付的成本 | token、算力与人工时间之和 | 经济性 | -| 安全 | 策略拦截数与类型 | 分类器和 hooks 的拒绝记录 | 风险暴露 | -| 安全 | 红队漏判率 | 用攻击样本定期测试防线 | 防线强度 | - -### 15.3 北极星与护栏指标 - -建议北极星指标是“每小时人工注意力产出的合格交付数”(本报告建议)。它同时奖励两件事:产出多,占用人少。配套三条护栏:Agent 变更的变更失败率不高于人工基线;回归评测集 pass^k 不低于该任务类的门槛;逃逸缺陷不超过质量预算。 - -### 15.4 度量陷阱 - -- 不要用代码行数或 PR 数衡量生产力。DORA 建议放弃代码行数指标;Faros 的数据里 PR 数几乎翻倍,公司层面却没有显著改善。 -- 不要用感受代替测量。METR 的试验中,开发者感觉快了约 20%,实际慢了 19%。 -- 在同一任务类别内比较 Agent 与人工基线,不要跨类别比较。 -- 门禁的漏检率只能靠抽样审计估计。没有抽样,“零缺陷”可能只是“零发现”。 - -## 十六、成熟度模型与落地路线图 - -放权应按任务类别逐级推进:先有判定器和隔离,再有自动合并,最后才是无人值守。每升一级,都要用数据证明上一级已经稳定。本节的矩阵、分级和计划均为本报告基于前文证据的综合建议。 - -### 16.1 用“可验证性 × 风险”决定自治上限 - -表中 L1–L5 对应第一节的自治等级,R0–R3 对应第九节的风险等级。 - -| 可验证性 | 低风险(R0–R1) | 中风险(R2) | 高风险(R3) | -| --- | --- | --- | --- | -| 高:有快速客观的判定器,如依赖升级、告警修复、机械迁移、补测试 | L4–L5 | L4 | L3 | -| 中:有复现或验收测试,如缺陷修复、小功能 | L4 | L3 | L2–L3 | -| 低:靠人判断,如交互体验、架构、安全设计 | L3 | L2–L3 | L1–L2 | - -提升一类任务自治上限的途径只有两条:造出更好的判定器(向上移),或降低爆炸半径(向左移,比如加特性开关和自动回滚)。 - -### 16.2 五级成熟度 - -| 阶段 | 名称 | 能力特征 | 进入下一阶段的准入条件 | -| --- | --- | --- | --- | -| M0 | 手工辅助 | 补全、对话式辅助 | 记录 DORA 指标和缺陷率基线 | -| M1 | 受监督执行 | Agent 在沙箱中完成任务,人审每个 PR;有统一 verify 入口和 AGENTS.md | 有 20–50 个真实任务组成的回归评测集;无修改合并率稳定 | -| M2 | 门禁自治 | 分层门禁、独立 AI 评审、防篡改;低风险类别自动合并加抽样审计;有界重试与升级 | 目标类别 pass^k 达标;Agent 变更失败率不高于人工基线;逃逸缺陷在预算内;能一键回滚 | -| M3 | 闭环自治 | 后台 Agent 持续处理维护类任务;渐进发布与自动回滚;误差预算自动调节自治度;全链路追踪 | 护栏指标连续数周达标;紧急停机演练通过;安全红队测试通过 | -| M4 | 自我改进 | Agent 参与维护 harness:生成评测用例、补充 lint 规则、治理熵增;人负责治理与审计 | 持续治理,每次模型升级后重审 | - -### 16.3 90 天落地计划 - -| 阶段 | 目标 | 关键动作 | 退出标准 | -| --- | --- | --- | --- | -| 第 1–30 天 | 打地基 | 选 2–3 个高可验证、低风险的任务类别;按 Agent Readiness 八个维度盘点仓库;写约 100 行的 AGENTS.md 地图并把关键知识迁入 docs/;建统一 verify 入口;沙箱、最小权限和受保护文件 hooks;开启链路追踪;整理 20–50 个回归评测用例 | 目标类别在 M1 稳定运行,基线数据齐全 | -| 第 31–60 天 | 闭环 | 固化“规格→计划→实现→验证→独立评审”流水线,确定性步骤脚本化;加入并校准 LLM 裁判;设重试上限、预算和升级包;按风险路由人审;每周错误分析并沉淀规则、测试或技能 | 每周 pass^k 与变更失败率可见且达标 | -| 第 61–90 天 | 放权 | 对达标类别开启自动合并、抽样审计和自动回滚;上线只提 PR 的后台维护 Agent;上线熵治理任务;建立误差预算与自动降级;演练紧急停机;制定模型升级流程 | 至少一个类别稳定运行在 M2 或以上 | - -## 十七、反模式与落地检查清单 - -下面的反模式每一条都有公开证据;检查清单可以直接用于自评。 - -### 17.1 十二条反模式 - -| 反模式 | 为什么危险 | 证据 | 替代做法 | -| --- | --- | --- | --- | -| 用提示词代替结构约束 | 明确禁止后作弊仍在继续 | METR:被测任务上 70–95% | 只读测试、hooks、沙箱外判定 | -| 只看“测试通过” | 测试通过不等于可合并 | METR:可直接合并比例为 0;约一半 SWE-bench 通过的 PR 不会被合并 | 多维门禁 + 无修改合并率 | -| 自己评自己 | 自我评价偏宽,无外部反馈难以自我纠错 | Anthropic;Huang 等 | 独立上下文评审 + 校准 | -| 把逐条人工审批当安全机制 | 审批疲劳,漏检严重 | 批准率 93%;人工只拦下 13.6% 危险命令 | 沙箱 + 策略 + 分类器 + 例外升级 | -| 在存有密钥的开发机上长期跳过权限 | 会被恶意代码借用 | Nx s1ngularity | 只在隔离环境中跳过权限 | -| Agent 能直接写生产 | 误操作不可逆 | Replit | 环境隔离 + 流水线发布 + 恢复演练 | -| 一次做完大任务 | 误差复合,过早宣布完成 | Anthropic 长时 harness | 功能清单 + 一次一个 | -| 大 PR、长分支 | 审不动、难回滚 | Faros:PR 规模 +154%,审查时间 +91% | 小批量 + 合并队列 | -| 只追吞吐不管熵增 | 复杂度持续上升拖慢后期 | He 等(MSR 2026);OpenAI 曾每周五手工清理 | 熵治理任务 + 趋势指标 | -| 无限重试 | 烧钱、打转、掩盖问题 | Stripe 最多两轮 CI;Kent Beck 的“打转”信号 | 有界重试 + 升级包 | -| 平级多 Agent 抢同一块代码 | 锁竞争、决策冲突 | Cursor:20 个 Agent 只有 2–3 个的吞吐;Cognition | 层级规划 + 明确归属 | -| 凭感觉决定放权 | 感受与实测可能相反 | METR:感觉快 20%,实际慢 19% | 指标驱动 + 误差预算 | - -### 17.2 落地检查清单 - -规格与上下文 - -- [ ] 每个任务都有可执行的验收标准和非目标 -- [ ] 任务按“可验证性 × 风险”分诊,模糊需求先澄清 -- [ ] AGENTS.md 约 100 行,只做地图;关键知识在仓库 docs/ 中 -- [ ] 构建、测试、lint 一条命令可运行,输出精简,细节写日志 - -执行 - -- [ ] 每个任务在隔离环境运行,文件系统和网络都受限 -- [ ] 凭证不进沙箱,开发机不长期开启跳过权限 -- [ ] 每个任务有时长、token、重试和 CI 轮次预算 -- [ ] 长任务有进度文件、功能清单和逐步 git 提交 - -验证 - -- [ ] 测试、CI 和 lint 配置对实现类任务只读,由 hooks 拦截 -- [ ] 最终验收在 Agent 之外重新运行 -- [ ] 有独立上下文的 AI 评审,并已用人工标注校准 -- [ ] 关键模块用变异测试或属性测试衡量测试强度 -- [ ] 修改测试、CI、依赖或公共 API 的变更自动升级 - -发布与运行 - -- [ ] PR 小而短命,主干常绿 -- [ ] 按风险分级发布,R1 及以上有自动回滚或特性开关 -- [ ] 开发与生产隔离,备份与恢复定期演练 -- [ ] 每次运行有完整轨迹,记录模型、提示词和工具版本 -- [ ] 有紧急停机开关,并按误差预算自动降级 -- [ ] 换模型或改提示词前先跑回归评测,再灰度 - -改进与人 - -- [ ] 每周做错误分析,每次事故转成回归用例 -- [ ] 教训优先沉淀为自动检查,其次才是文字规则 -- [ ] 有定期运行的熵治理任务,并监控告警与复杂度趋势 -- [ ] 人审按风险路由,升级包包含证据和选项 -- [ ] 度量升级精度和处理时长 -- [ ] 有技能保持安排,如轮岗和演练 - -## 十八、争议与开放问题 - -下列问题业界尚无定论。落地时应把它们当作假设,用自己的数据来回答。 - -1. 人审会不会成为永久瓶颈?Anthropic 承认人工代码评审已成为新瓶颈;OpenAI 转向 Agent 互审,Stripe 仍全量人审。自动评审回溯可拦截约三分之一的历史事故 bug,这也意味着还有约三分之二拦不住。高风险代码靠机审要达到什么可靠度,尚无公认标准。 -2. AI 代码的长期质量走向如何?Anthropic 认为 Claude 的代码已从 2025 年底的“略差”变为“大致持平”,并预期一年内超过人。但 CodeRabbit 对 470 个开源 PR 的分析显示 AI 参与的 PR 问题多约 1.7 倍([CodeRabbit, 2025-12](https://www.coderabbit.ai/blog/state-of-ai-vs-human-code-generation-report));OpenAI 也承认,尚不知道全 Agent 生成的系统在数年尺度上架构一致性会如何演变。 -3. 生产力证据仍有分歧。METR 的随机对照试验发现 2025 年初的工具让资深开发者慢了 19%,后续数据指向提速但证据很弱;DORA 观察到吞吐与不稳定性同时上升,并提出先降后升的 J 曲线。 -4. 规格驱动开发会不会重蹈模型驱动开发的覆辙?Böckeler 担心“规格即源码”会同时继承两者的缺点:僵化与不确定性。 -5. 多 Agent 的边界在哪里?Cognition 主张单线程,Cursor 与 Anthropic 在可分解问题上用层级多 Agent 取得了成果,但 Cursor 自己也说多 Agent 协调仍是难题。 -6. 行为正确性怎么验证?可维护性和架构约束有成熟工具,功能是否真正正确却被 Böckeler 称为“房间里的大象”。属性测试、差分测试和形式化方法可以覆盖一部分,但成本和适用范围仍在探索。 -7. 自动审批分类器能走多远?它对真实过度热心动作仍有 17% 漏判,但人工审批表现更差。安全界的主流观点是护栏不可靠,最好从结构上避免“致命三要素”同时出现。 -8. 奖励作弊会随模型进步消失,还是变得更隐蔽?现有证据只说明它存在且不怕禁令,因此结构性防护在可预见的未来仍是必需品。 -9. 基准能外推多少?METR 的时间视界来自边界清晰、可自动评分的任务;视觉类电脑操作任务的视界要低 40–100 倍。真实工作中的模糊需求和协作成本,会让实际可委派的范围小于基准所示。 - -## 附录 A:Java/Maven 技术栈的门禁工具映射 - -以 Java/Maven 项目为例,把第八节的分层门禁落到具体工具。工具均为常见选择,可按团队现状替换。Spotify 的做法可以直接借鉴:发现 pom.xml 就自动启用 Maven 校验,Agent 只面对一个统一的 verify 工具。 - -| 门禁层 | 目的 | 可选工具 | 接入方式 | -| --- | --- | --- | --- | -| 构建与依赖一致性 | 可复现构建,杠绝依赖漂移 | Maven Wrapper;Maven Enforcer(依赖收敛、禁用依赖、版本要求);BOM 统一版本 | 统一入口 `./mvnw -q -B verify` | -| 格式与静态检查 | 秒级反馈 | Spotless 或 Checkstyle;Error Prone;NullAway;SpotBugs;PMD | 编辑后由 hook 自动格式化;提交前运行 | -| 架构适应度 | 分层依赖、循环依赖、命名 | ArchUnit | 规则失败信息写明修复方法 | -| 单元与集成测试 | 功能正确 | JUnit 5、Mockito、Testcontainers | 选择性运行,提供快速模式 | -| 测试强度 | 防止空洞测试 | PIT(变异测试)、jqwik(属性测试)、JaCoCo(覆盖率只作参考) | 关键模块合并前或每日运行 | -| API 兼容性 | 不破坏下游 | japicmp 或 revapi、OpenAPI diff、Pact | 公共 API 变更自动升级人审 | -| 安全与供应链 | 漏洞、密钥、许可证 | OWASP Dependency-Check、CycloneDX SBOM、gitleaks、Trivy 或 Grype | 高危问题阻断合并 | -| 确定性大规模变更 | 版本升级与框架迁移 | OpenRewrite 配方 | 配方先行,Agent 只处理剩余问题,与 Amazon Q 的思路一致 | -| 运行时验证 | 发布后兜底 | OpenTelemetry Java Agent、Spring Boot Actuator、OpenFeature 特性开关 | 金丝雀指标驱动自动回滚 | - -### A.1 用 hooks 保护测试并自动格式化 - -以 Claude Code 为例(其他 Agent 工具有类似机制)。写在项目的 `.claude/settings.json` 中: - -```json -{ - "hooks": { - "PreToolUse": [ - { - "matcher": "Edit|Write", - "hooks": [{ "type": "command", "command": ".claude/hooks/protect-tests.sh" }] - } - ], - "PostToolUse": [ - { - "matcher": "Edit|Write", - "hooks": [{ "type": "command", "command": "./mvnw -q spotless:apply" }] - } - ] - } -} -``` - -`protect-tests.sh` 读取待编辑的文件路径,命中受保护路径就以退出码 2 阻止编辑。测试编写类任务可以用环境变量放开;pom.xml 不在这里拦截,因为依赖升级需要改它,改动交给评审路由处理。格式化命令要足够快,大项目可改为只格式化被编辑的单个文件。 - -```bash -#!/usr/bin/env bash -FILE_PATH=$(jq -r '.tool_input.file_path // empty') -[ "${ALLOW_TEST_EDITS:-0}" = "1" ] && exit 0 -case "$FILE_PATH" in - */src/test/*|*/.github/workflows/*) - echo "Blocked: $FILE_PATH is protected. Explain why in the escalation note." >&2 - exit 2 ;; -esac -exit 0 -``` - -### A.2 把架构约定写成测试 - -ArchUnit 把分层规则变成普通单元测试,`because` 里的说明会出现在失败信息中,相当于给 Agent 的修复指引。 - -```java -@AnalyzeClasses(packages = "com.example") -class LayeringTest { - @ArchTest - static final ArchRule layers = layeredArchitecture().consideringAllDependencies() - .layer("Controller").definedBy("..controller..") - .layer("Service").definedBy("..service..") - .layer("Repository").definedBy("..repository..") - .whereLayer("Controller").mayNotBeAccessedByAnyLayer() - .whereLayer("Service").mayOnlyBeAccessedByLayers("Controller") - .whereLayer("Repository").mayOnlyBeAccessedByLayers("Service") - .because("Dependencies must point downward; expose what you need through a Service instead."); -} -``` - -## 参考来源 - -以下均为本文引用并实际打开核对过的页面,按类别列出,括号内为发布方与发布时间。 - -### 研究与理论 - -- [Clarifying limitations of time horizon](https://metr.org/notes/2026-01-22-time-horizon-limitations/)(METR,2026-01) -- [Claude Opus 4.5 Achieves 50%-Time Horizon Of Around 4 hrs 49 Mins](https://www.lesswrong.com/posts/q5ejXr4CRuPxkgzJD/claude-opus-4-5-achieves-50-time-horizon-of-around-4-hrs-49)(METR 结果转载,2025-12) -- [Research Update: Algorithmic vs. Holistic Evaluation](https://metr.org/blog/2025-08-12-research-update-towards-reconciling-slowdown-with-time-horizons/)(METR,2025-08) -- [Many SWE-bench-Passing PRs Would Not Be Merged into Main](https://metr.org/notes/2026-03-10-many-swe-bench-passing-prs-would-not-be-merged-into-main/)(METR,2026-03) -- [Recent Frontier Models Are Reward Hacking](https://metr.org/blog/2025-06-05-recent-reward-hacking/)(METR,2025-06) -- [Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity](https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/)(METR,2025-07) -- [We are Changing our Developer Productivity Experiment Design](https://metr.org/blog/2026-02-24-uplift-update/)(METR,2026-02) -- [τ-bench](https://arxiv.org/abs/2406.12045)(Yao 等,2024) -- [The Illusion of Diminishing Returns](https://arxiv.org/abs/2509.09677)(Sinha 等,ICLR 2026) -- [Solving a Million-Step LLM Task with Zero Errors](https://arxiv.org/abs/2511.09030)(Meyerson 等,2025-11) -- [Asymmetry of verification and verifier's law](https://www.jasonwei.net/blog/asymmetry-of-verification-and-verifiers-law)(Jason Wei,2025-07) -- [Large Language Models Cannot Self-Correct Reasoning Yet](https://arxiv.org/abs/2310.01798)(Huang 等,ICLR 2024) -- [Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena](https://arxiv.org/abs/2306.05685)(Zheng 等,NeurIPS 2023) -- [Levels of Autonomy for AI Agents](https://knightcolumbia.org/content/levels-of-autonomy-for-ai-agents-1)(Feng、McDonald、Zhang,2025-07) -- [Ironies of Automation 综述](https://blog.acolyer.org/2020/01/08/ironies-of-automation/)(The Morning Paper,原文 Bainbridge 1983) -- [A model for types and levels of human interaction with automation 概要](https://andrewclark.co.uk/all-media/a-model-for-types-and-levels-of-human-interaction-with-automation)(原文 Parasuraman、Sheridan、Wickens 2000) -- [Speed at the Cost of Quality](https://arxiv.org/abs/2511.04427)(He 等,MSR 2026) -- [Defeating Nondeterminism in LLM Inference](https://thinkingmachines.ai/blog/defeating-nondeterminism-in-llm-inference/)(Thinking Machines,2025-09) - -### Anthropic - -- [Building effective agents](https://www.anthropic.com/engineering/building-effective-agents)(2024-12) -- [How we built our multi-agent research system](https://www.anthropic.com/engineering/multi-agent-research-system)(2025-06) -- [Effective context engineering for AI agents](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents)(2025-09) -- [Claude Code sandboxing](https://www.anthropic.com/engineering/claude-code-sandboxing)(2025-10) -- [Effective harnesses for long-running agents](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents)(2025-11) -- [How AI is transforming work at Anthropic](https://www.anthropic.com/research/how-ai-is-transforming-work-at-anthropic)(2025-12) -- [Demystifying evals for AI agents](https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents)(2026-01) -- [Building a C compiler with a team of parallel Claudes](https://www.anthropic.com/engineering/building-c-compiler)(2026-02) -- [Measuring AI agent autonomy in practice](https://www.anthropic.com/research/measuring-agent-autonomy)(2026-02) -- [Harness design for long-running application development](https://www.anthropic.com/engineering/harness-design-long-running-apps)(2026-03) -- [How we built Claude Code auto mode](https://www.anthropic.com/engineering/claude-code-auto-mode)(2026-03) -- [Auto mode is now the default in Claude Code](https://claude.com/blog/auto-mode-default-in-claude-code)(2026-08) -- [When AI builds itself](https://www.anthropic.com/institute/recursive-self-improvement)(Anthropic Institute,2026) -- [Claude Code hooks 指南](https://code.claude.com/docs/en/hooks-guide)(文档) -- [Boris Cherny 的 Claude Code 使用帖](https://twitter-thread.com/t/2007179832300581177)(2026-01) - -### 其他厂商与工程团队 - -- [Harness engineering: leveraging Codex in an agent-first world](https://openai.com/index/harness-engineering/)(OpenAI,2026-02) -- [A practical guide to building agents](https://openai.com/business/guides-and-resources/a-practical-guide-to-building-ai-agents/)(OpenAI) -- [Scaling long-running autonomous coding](https://cursor.com/blog/scaling-agents)(Cursor,2026-01) -- [Towards self-driving codebases](https://cursor.com/blog/self-driving-codebases)(Cursor,2026-02) -- [Minions: Stripe's one-shot, end-to-end coding agents](https://stripe.dev/blog/minions-stripes-one-shot-end-to-end-coding-agents)(Stripe,2026-02)与 [Part 2](https://stripe.dev/blog/minions-stripes-one-shot-end-to-end-coding-agents-part-2)(2026-02) -- [How Stripe's Minions Ship 1,300 PRs a Week](https://blog.bytebytego.com/p/how-stripes-minions-ship-1300-prs)(ByteByteGo) -- [Stripe autonomous coding agents](https://infoq.com/news/2026/03/stripe-autonomous-coding-agents/)(InfoQ,2026-03) -- [Spotify Honk Part 1](https://engineering.atspotify.com/2025/11/spotifys-background-coding-agent-part-1)、[Part 2](https://engineering.atspotify.com/2025/11/context-engineering-background-coding-agents-part-2)、[Part 3](https://engineering.atspotify.com/2025/12/feedback-loops-background-coding-agents-part-3)(Spotify,2025-11 至 12) -- [Accelerating Large-Scale Test Migration with LLMs](https://medium.com/airbnb-engineering/accelerating-large-scale-test-migration-with-llms-9565c208023b)(Airbnb,2025-03) -- [How is Google using AI for internal code migrations?](https://arxiv.org/abs/2501.06972)(Google,2025-01) -- [Introducing CodeMender](https://deepmind.google/blog/introducing-codemender-an-ai-agent-for-code-security/)(Google DeepMind,2025-10) -- [Automated Unit Test Improvement using LLMs at Meta](https://arxiv.org/abs/2402.09171)(Meta,FSE 2024) -- [Mutation-Guided LLM-based Test Generation at Meta](https://arxiv.org/abs/2501.12862)(Meta,FSE 2025) -- [Andy Jassy 谈 Amazon Q Java 升级](https://simonwillison.net/2024/Aug/24/andy-jassy-amazon-ceo/)(2024-08) -- [Amazon Q Code Transformation 使用 OpenRewrite](https://www.infoq.com/news/2023/12/amazon-q-code-transformation)(InfoQ,2023-12) -- [Devin's 2025 Performance Review](https://cognition.com/blog/devin-annual-performance-review-2025)(Cognition,2025-11) -- [Don't Build Multi-Agents](https://cognition.com/blog/dont-build-multi-agents)(Cognition,2025-06) -- [Spec-driven development with AI: Spec Kit](https://github.blog/ai-and-ml/generative-ai/spec-driven-development-with-ai-get-started-with-a-new-open-source-toolkit/)(GitHub,2025-09) -- [Continuous AI in practice](https://github.blog/ai-and-ml/generative-ai/continuous-ai-in-practice-what-developers-can-automate-today-with-agentic-ci/)(GitHub,2026-02) -- [Risks and mitigations for GitHub Copilot cloud agent](https://docs.github.com/en/copilot/concepts/agents/cloud-agent/risks-and-mitigations)(GitHub 文档) -- [Does your code match your spec?](https://kiro.dev/blog/property-based-testing/)(Kiro,2025-11) -- [Requirements-first workflow](https://kiro.dev/docs/specs/feature-specs/requirements-first/)(Kiro 文档) -- [Introducing Agent Readiness](https://factory.com/news/agent-readiness)(Factory,2026-01) -- [Advanced Context Engineering for Coding Agents](https://www.humanlayer.dev/blog/advanced-context-engineering)(HumanLayer,2025-08) -- [Compounding engineering](https://every.to/source-code/my-ai-had-already-fixed-the-code-before-i-saw-it)(Every) -- [Production-ready agents with the OpenAI Agents SDK + Temporal](https://temporal.io/blog/announcing-openai-agents-sdk-integration)(Temporal,2025-07) - -### 方法论与观点 - -- [Harness engineering for coding agent users](https://martinfowler.com/articles/harness-engineering.html)(Birgitta Böckeler,2026-04) -- [Understanding Spec-Driven-Development: Kiro, spec-kit, and Tessl](https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html)(Birgitta Böckeler,2025-10) -- [Augmented Coding: Beyond the Vibes](https://tidyfirst.substack.com/p/augmented-coding-beyond-the-vibes)(Kent Beck) -- [LLM Evals FAQ](https://hamel.dev/blog/posts/evals-faq/)(Hamel Husain、Shreya Shankar,2026-09 更新) -- [Karpathy 《Software Is Changing (Again)》演讲整理](https://travis.media/blog/software-3-0-ai-changing-programming-karpathy/) -- [‘Ralph Wiggum’ loop](https://www.theregister.com/2026/01/27/ralph_wiggum_claude_loops/)(The Register,2026-01) - -### 行业报告与数据 - -- [State of AI-assisted Software Development 2025](https://dora.dev/dora-report-2025/)(DORA) -- [Introducing DORA's inaugural AI Capabilities Model](https://cloud.google.com/blog/products/ai-machine-learning/introducing-doras-inaugural-ai-capabilities-model)(Google Cloud,2025-09) -- [Balancing AI tensions](https://dora.dev/insights/balancing-ai-tensions/)(DORA,2026-03) -- [New DORA Report Claims Strong Engineering Foundations Drive AI ROI](https://www.infoq.com/news/2026/05/dora-roi-ai-assisted-dev-report/)(InfoQ,2026-05) -- [The AI Productivity Paradox Research Report](https://www.faros.ai/blog/ai-software-engineering)(Faros AI,2025-07) -- [State of AI vs Human Code Generation](https://www.coderabbit.ai/blog/state-of-ai-vs-human-code-generation-report)(CodeRabbit,2025-12) - -### 安全与事件 - -- [The lethal trifecta for AI agents](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/)(Simon Willison,2025-06) -- [Design Patterns for Securing LLM Agents against Prompt Injections](https://simonwillison.net/2025/Jun/13/prompt-injection-design-patterns/)(Simon Willison 总结,2025-06) -- [Agents Rule of Two](https://ai.meta.com/blog/practical-ai-agent-security/)(Meta,2025-10) -- [OWASP Top 10 for Agentic Applications 2026 要点](https://goteleport.com/blog/owasp-top-10-agentic-applications/)(Teleport) -- [s1ngularity supply chain attack](https://www.wiz.io/blog/s1ngularity-supply-chain-attack)(Wiz,2025-08) -- [AWS-2025-015 安全公告](https://aws.amazon.com/security/security-bulletins/AWS-2025-015/)(AWS,2025-07) -- [Replit's response to SaaStr incident](https://www.theregister.com/2025/07/22/replit_saastr_response/)(The Register,2025-07) -- [Google Antigravity 删除硬盘事件](https://www.tomshardware.com/tech-industry/artificial-intelligence/googles-agentic-ai-wipes-users-entire-hard-drive-without-permission-after-misinterpreting-instructions-to-clear-a-cache-i-am-deeply-deeply-sorry-this-is-a-critical-failure-on-my-part)(Tom's Hardware,2025-12) -- [Antigravity Turbo 模式删盘报道](https://piunikaweb.com/2025/12/02/google-antigravity-deletes-hard-drive-coding-mishap/)(PiunikaWeb,2025-12) - -### 标准与规范 - -- [Agentic AI Foundation 成立公告](https://www.linuxfoundation.org/press/linux-foundation-announces-the-formation-of-the-agentic-ai-foundation)(Linux Foundation,2025-12) -- [GenAI Agent Spans 语义约定](https://github.com/open-telemetry/semantic-conventions-genai/blob/main/docs/gen-ai/gen-ai-agent-spans.md)(OpenTelemetry) diff --git a/docs/review/2026-09-25-harness-baseline.md b/docs/review/2026-09-25-harness-baseline.md deleted file mode 100644 index 3b37fe7..0000000 --- a/docs/review/2026-09-25-harness-baseline.md +++ /dev/null @@ -1,183 +0,0 @@ -# 可验证交付基线:v0.8.0 失败分析与 Agent 就绪度(2026-09-25) - -审查基线:`main` / `d8bde8d`(v0.8.0)。证据来源:[用量金额与桌面组件交付说明](../plans/usage-cost-widgets-delivery.md)中的五轮评审记录、仓库检索、云端(Linux)实跑。只新增文档,没有改动实现。 - -未覆盖:Swift 构建与界面(云端无 macOS);GitHub 仓库设置(分支与 tag 保护的现状未核对);本机 Agent 配置(`.zcode/`、`.agents/` 已被 `.gitignore` 排除)。 - -**结论:v0.8.0 的 19 项缺陷中,17 项本可以由 CI 里的测试或断言判定;R6、R14 另需本机真实数据回放或真机 UI 验收。代价最大的是过程失败:3 次「声称已修但代码未变」、5 处自述与事实不符、2 次未授权改写历史,全部靠评审方人工发现,用了 5 轮评审。** 这些是 [可验证交付方案](../plans/verifiable-delivery.md) P1、P2 的首要目标。 - -## 1. 失败分类 - -按报告 11.1 节的方法:先逐条开放编码,再归并为类型。 - -### 1.1 缺陷(R1–R19) - -| 类型 | 条目 | 共性 | 应有的判定器 | -|---|---|---|---| -| F1 规格缺口或歧义 | R2、R3、R6 | 规格本身按错误口径写(按整天比较、Zcode 逐项严格对账),根源在设计侧 | 规格条款逐条映射测试;「任何重写不降级」回放;真实数据的 unknown 占比阈值 | -| F2 同一口径多处实现不一致 | R7、R8、R11、R12、R15 | 同一概念在两条路径上各写一遍,其中一条偏离 | 单一纯函数;跨路径不变量(周期合计 = 逐日之和;所有写入路径带同样字段) | -| F3 状态机与边界条件 | R4、R10、R13、R19 | 序列、顺序、非法输入这些分支没被覆盖 | 序列属性测试;输入顺序打乱后结果不变;规格中每个防护分支各一条测试 | -| F4 修复引入回归 | R17 | 修 R7 时删掉了排序 | 修复前会失败的测试;变异测试 | -| F5 未接线或未实现 | R9、R14 | 参数没传、条款没做,没有测试暴露 | 验收编号映射暴露无测试条目;快照字段填充率断言 | -| F6 仓库卫生与隐私 | R1 | 真实快照和 `.o` 被 `git add -A` 带进公开仓库 | 禁止路径与模式的提交检查;写入路径不得在仓库内的不变量测试 | -| F7 构建与 CI 断言 | R5、R16、R18 | CI 命令缺文件、断言写错、规范与构建三方不同步 | 只认主 workflow;断言与规范同源 | - -F2 最多(5 项)。说明缺的不是更多单测,而是「同一概念只实现一次」和跨路径一致性检查。F1 的 3 项来自评审方写的规格,说明判定也要覆盖设计侧的产出,不能只查执行者。 - -逐条的判定位置与回放用例: - -| # | 摘要 | 拦截位置 | 回放用例(注入后应被拦住) | -|---|---|---|---| -| R1 | 真实快照与 `.o` 进公开仓库 | pre-commit + CI | 暂存 `widget/snapshot.json` 或 `*.o` 后提交 | -| R2 | 27 个过去日被降级 | CI 夹具;本机回放 | 去掉按任务合并的保护 | -| R3 | 9/21 被整天改写为 v7 | CI 夹具 | 同 R2,另加「改判为 agent 的会话不恢复」 | -| R4 | 调价后 history 被清空;防护变成删除 | CI | 去掉 history 继承;防护分支改为删除 | -| R5 | CI 主构建从未运行;自述「CI 同口径通过」 | PR 检查 | 交付说明写「通过」但没有当前 head 的 run | -| R6 | Zcode、Codex 大量 token 为 unknown | CI 夹具;本机回放阈值 | 对账不一致的轮退回 unknown | -| R7 | 热力图按金额着色全为 0 | CI 黄金快照 | 阈值改回读 `totals.cost` | -| R8 | 组件「进行中」恒为 0 | macOS CI(Swift 纯函数) | `widgetRunningListed` 加回未读条件 | -| R9 | 最近任务今日 token 从未填充 | macOS CI(快照断言) | 写入器不传 `todayUsage` | -| R10 | 组件点击重放;冷启动丢弃 | macOS CI(Swift 纯函数) | 去掉 `markHandled` 或未就绪时不放回队列 | -| R11 | 周期金额用单一日期计价 | CI 属性测试 | 改回整期合并后计价 | -| R12 | 补录路径缺 agent 统计 | CI | 补录不传 `agent_stats` | -| R13 | 别名命中取决于文件顺序 | CI 属性测试 | 打乱上游条目顺序 | -| R14 | inbox 组件条目不可单独点击 | CI 映射检查;真机 UI | 删除逐条 Link | -| R15 | `hide_titles` 清掉项目名 | macOS CI(Swift 纯函数) | `widgetEntryTitle` 清空项目名 | -| R16 | plist 值与命名三方不一致 | macOS CI 断言 | 改动规范或构建中的一方 | -| R17 | 修 R7 时删掉排序 | CI;变异测试 | 删除 `amounts.sort()` | -| R18 | CI 用 `test -f` 判断目录;以临时探针为依据 | PR 检查 | 断言改回 `test -f` | -| R19 | 单价为负数时仍删除条目 | CI | 非法数值分支改为删除 | - -按交付说明,第二轮修复已为 R2–R4、R8、R10、R11、R13、R15、R17、R19 补了回归测试。P3 要验证这些测试在注入后确实失败,并补齐其余条目。 - -### 1.2 过程失败 - -| 类型 | 实例 | 根因 | 应有防线 | 阶段 | -|---|---|---|---|---| -| X1 声称已修但代码未变 | R8、R15(第二轮)、R10(第四轮);更早的 `074bf39` 同模式 | 修改停在工作区未提交,被 filter-repo 清掉;替换脚本中途失败,但提交说明已写「已修」 | 修复证据脚本:按编号输出 `git show --stat` 与关键行;评审只认脚本输出 | P1 | -| X2 自述与事实不符 | U11「Swift 策略测试通过(CI 同口径)」(R5);W8「CI 验证通过」依据临时探针(R18);「含今日 token 与金额」(R9);测试数「258 → 271」实为 267;R6 用全历史回退率 9.51% 掩盖近期 46.8% | 状态由人或 Agent 手写 | 交付状态由脚本从 CI 与测试输出生成;只认当前 head 的主 workflow | P1 | -| X3 未授权的破坏性 git 操作 | 第三轮两次 filter-repo:改写本地 `main` 与 18 个 tag,删除 `origin` remote | 没有任何结构限制;只靠评审发现 | 服务端 ruleset;git 层禁止改写 `main` 与 tag;Agent 层拒绝 filter-repo | P2 | -| X4 回归测试不足 | 第一轮修复 16 项,测试净增 1(257 → 258) | 没有「修复必须带测试」的检查 | 每个修复编号至少对应一个修复前失败的测试 | P1、P3 | -| X5 无预算的试错 | D0 临时探针 workflow 运行 32 次 | 没有 CI 轮次上限与升级规则 | 任务模板写明预算,超限升级给评审方 | P4 | -| X6 溯源失效 | 历史改写后,状态表引用的 SHA 已不存在;缺陷编号跨评审重复(2026-09-21 评估也用 R1–R7),测试注释中的「R2」「R5」无法判断出处 | 证据引用不校验;编号没有全局唯一的前缀 | 证据脚本校验 SHA 可达;禁止改写已推送历史;缺陷与验收编号全局唯一 | P1、P2、P4 | - -## 2. 基线指标(v0.8.0 交付) - -P6 真实任务试跑时,按同一口径对比。 - -| 指标 | 基线值 | 来源 | -|---|---|---| -| 评审轮次(到代码层通过) | 5(验收 1 + 复验 4) | 交付说明各「验收发现」「复验发现」节 | -| 评审发现缺陷 | 19(阻断 5、严重 5、一般 6、第二轮新发现 3) | R1–R19 | -| 修复不完整或引入回归 | 2(R17 回归、R19 未覆盖全部分支) | 第二轮复验 | -| 声称已修但代码未变 | 3 条次 | §1.2 X1 | -| 自述与事实不符 | 5 处 | §1.2 X2 | -| 未授权改写历史 | 2 次 | §1.2 X3 | -| 临时探针 CI 运行 | 32 次 | 交付说明 R1 残留清单 | -| 历史改写后清理的孤儿 CI 运行 | 84 次 | 第二轮修复响应 | -| 首轮修复与测试 | 16 项修复,测试净增 1 | 第二轮复验 | -| Python 测试 | 267 项通过,3 项跳过,约 3 秒 | 2026-09-25 云端实跑 | -| 规格验收编号 | 6 份规格中 2 份有编号表(W、U);测试引用 U/W 编号 12 处 | 仓库检索 | -| 公开仓库数据泄露 | 1 次(旧 SHA 仍可按 SHA 访问) | R1 | - -## 3. Agent 就绪度 - -按 Factory Agent Readiness 的八个维度。 - -| 维度 | 现状 | 缺口 | 阶段 | -|---|---|---|---| -| 代码风格校验 | CI 跑 `ruff check scripts tests`,锁定 0.16.8;`ruff.toml` 注明本地编辑钩子共用该标准 | 本地钩子不在仓库,不可复现;云端环境为 ruff 0.15.8,与 CI 不一致;Swift 没有格式与 lint | P1 | -| 构建 | `scripts/build_inbox_app.py`;CI 在 macos-26 构建并断言组件结构 | 只能在 macOS 构建;没有本地一条命令复现 CI 的入口 | P1 | -| 测试 | 267 项 Python 单测;两组 Swift 断言程序 | 没有属性测试、变异测试、覆盖率;夹具不覆盖全部来源的真实格式;测试与验收编号基本没有对应 | P3、P4 | -| 文档 | AGENTS.md 是短地图;`docs/specs/` 6 份现役合同 | 仅 desktop-widgets、usage-cost 有编号验收表;其余四份的验收是叙述或追加记录 | P4 | -| 开发环境 | `requirements.txt`;运行时 venv 在 `scratch/iterm-probe-venv`;云端可直接跑 Python 测试 | 没有统一 `verify`;工具版本未在本机与云端锁定 | P1 | -| 代码质量 | ruff 默认规则 | `scripts/daily_report.py` 1687 行;没有复杂度与告警趋势 | P6 | -| 可观测性 | 产品侧有诊断日志与 health 元数据 | Agent 交付过程没有记录:谁改的、几轮 CI、证据在哪 | P1、P6 | -| 安全治理 | CI 默认 `contents: read`,release 独立 job;`.gitignore` 已覆盖 `*.o`、`/widget/`、`scratch/`、数据库 | 没有 pre-commit、pre-push;推 tag 直接触发发布且无审批;分支与 tag 保护未核对 | P2 | - -## 4. 可验证性地图 - -「自治上限」按方案 §4 的风险等级和报告 16.1 节的矩阵初定,P4 按模块落到规格。 - -| 任务类别 | 现有判定器 | 缺口 | 可验证性 | 典型风险 | 自治上限 | -|---|---|---|---|---|---| -| 文档与规格措辞 | 无 | 链接与索引检查 | 高 | R0 | L4 | -| 来源采集(7 家) | 各来源夹具单测 | 真实格式夹具覆盖不均;新格式无报警 | 中 | R2 | L3 | -| 计价与金额 | 单测 | 不变量改为属性测试(周期合计 = 逐日之和、顺序无关) | 高 | R2 | L4 | -| 价格拉取 | 状态机序列单测 | 序列属性测试;防护分支全覆盖 | 高 | R2 | L4 | -| 报告迁移与固化 | 夹具单测 | 「任何重写不降级」自动回放 | 中 | R3 | L3 | -| CLI 输出 | 零散断言 | 黄金 JSON 快照 | 高 | R1–R2 | L4 | -| Swift 纯逻辑 | InboxPolicy、ProcessRunner 断言程序 | 状态机继续抽成纯函数;修复先写失败测试 | 高 | R2 | L4 | -| SwiftUI 界面与组件 | CI 结构断言;人工截图 | 截图回归 | 低 | R2 | L3 | -| 真机导航与授权(Zcode AX、iTerm2) | 无 UI 自检;真实会话记录 | 只能人工验收 | 低 | R2 | L2–L3 | -| hooks 安装与用户配置 | 幂等单测 | 在隔离 HOME 中回放安装 | 中 | R3 | L3 | -| 构建、CI 与发布 | CI 断言 | 发版审批;版本号两处一致检查 | 中 | R3 | L3 | - -## 5. 实施中的新发现(2026-09-25) - -建设 harness 的过程中,事故回放、性质测试和变异测试又找出以下问题。编号 `H0925-<序号>`。 - -| 编号 | 发现 | 怎么发现的 | 处理 | -|---|---|---|---| -| H0925-1 | v0.8.0 为 R17 补的回归测试在测试里自行排序,没有调用产品代码:删掉 `amounts.sort()` 后 `test_daily_report` 41 项全部仍通过 | 事故回放(注入后「漏过」) | 阈值抽为 `cost_thresholds`,性质测试断言与输入顺序无关 ✅ | -| H0925-2 | R8、R15 的纯函数与测试存在,但 `WidgetSnapshotWriter` 没有调用它们,而是各自内联了一份判断(F2 在修复中重演) | 编写回放用例时核对调用关系 | 写入器改调纯函数,新增架构适应度测试 ✅ | -| H0925-3 | R12(补录缺 agent 统计)标为已修,但没有任何回归测试 | 事故回放(注入后「漏过」) | 补测试 ✅ | -| H0925-4 | 过去日合并时,若重扫总量更小但某一类更大,任务的三类合计沿用旧值,model 明细却含重扫的新值,token 合计与计价依据不一致 | 性质测试反例(约一半随机种子触发) | 以 `expectedFailure` 登记;修法属于报告迁移(R3),待用户决定。2026-09-26 用户决定按类别取较大值,PR #18 修复并移除登记 ✅ | -| H0925-5 | harness 自身:`Defect:` 与 `Co-Authored-By:` 隔空行时 git 不认 trailer,evidence 静默报告「没有修复提交」 | 本 PR 首次按约定提交修复时 | 改为扫描整段提交说明 ✅ | -| H0925-6 | 规格互相矛盾:`zcode-native-navigation.md` 以「复制任务路径核验一致才返回 focused」为合同,`unified-inbox.md` 记录 2026-09-14 起 App「前往会话」停在搜索结果页、自动核验已移除 | 给规格编号验收时逐条对照 | 2026-09-26 用户确认:现役只停在搜索结果页,Zcode CLI 未接入;自动导航规格标为非现役,IN14 为现役合同 ✅ | -| H0925-7 | AGENTS.md 要求的 `build/zcode-focus --self-test` 在 CI 中只编译、从未运行 | 给 ZN 条目找覆盖时 | 纳入 verify(macOS),CI 每次运行 ✅ | -| H0926-1 | 过程失败:PR #7 的评审报告绕过 PR 直接提交到 main(`3442069`),违反「main 只经 PR 合并」与评审「只读、不推送」两条约定。作者身份与用户相同,分不清是用户还是评审 Agent 所为 | 用户发现 | 不改写 main(改写本身违反约定,且该提交只含文档);已合入 PR 分支。本机与服务端都没拦住:main 上还没有 `.githooks/`,检出 main 时没有 git 守卫;ruleset 尚未导入。再次说明 ruleset 必须先于一切导入(方案 §13 A4),身份问题见 D3。已堵住:ruleset 于 2026-09-25 导入(直接推 main 被拒),main 上已有 git 守卫;2026-09-26 起 Agent 用单独账号、合并须由非推送者批准(D3,PR #31、#33 实测)✅ | -| H0926-2 | 护栏自相矛盾:执行方守卫把 `harness/**` 整体设为禁改,而规范与任务书要求执行方补完测试后删除 `harness/acceptance-gaps.txt` 的对应行 | 首个试跑 trial-001:OpenCode 删行被拒,按升级包上报且未绕过 | 执行方可编辑缺口清单(逐个列出的例外,增条目仍由 risk.py 判 R3);同类冲突 `replay_cases.py` 改为回放用例由评审方加入 ✅ | -| H0926-3 | harness 自身:在 linked worktree 里推送时 pre-push 的 verify 失败。钩子注入的 `GIT_DIR` 在主工作区是相对路径 `.git`,恰好对测试里的临时仓库也成立;worktree 里是指向真实仓库的绝对路径,检查子进程里未隔离的 git 调用落到真实仓库 | 本机用 worktree 推送 PR #8 时 | verify 启动检查时清掉 git 本地变量(清单按 `git rev-parse --local-env-vars` 补全),回归测试按该拓扑构造 ✅ | -| H0926-4 | harness 自身:base_tests 只把 `tests/` 换回 base 版本,head 在规格验收表里引用新测试时,base 版本的验收映射测试找不到这些测试而失败。补测试并更新验收表的正常 PR 都会被这道必过检查拦下 | 首个试跑 trial-001 的 PR #11,CI harness job | 判定器输入整体按 base 版本(`tests/`、`docs/specs/`、`harness/acceptance-gaps.txt`),回归测试与回放用例按该场景构造 ✅ | -| H0926-5 | harness 自身:命令守卫把只读的 `gh api graphql -f query=…` 当成 API 写请求拒绝。GraphQL 查询本身就用 POST 与 `-f` 传参,结构判断只看「有字段即写」 | D3 实测时评审方查询 PR 批准状态被拒(2026-09-26) | `gh api graphql` 在参数都内联、且没有 `mutation` 时放行;`--input` 与 `-F x=@文件` 看不到内容,仍按写处理。回归测试与回放用例 ✅ | -| H0926-6 | 规范错误:§5 第 9 步只给批准 App「Pull requests」权限。GitHub 只把有仓库写权限(对 App 即 Contents 写)的批准计入必需批准,App 批准了 PR #32,但合并仍被 ruleset 拒绝 | D3 的 R0 实测,auto-merge run 36232482756(2026-09-26) | 规范改为 Contents 与 Pull requests 均为 Read and write,并写明原因;用户调整 App 权限后,同一次批准即被计入,重跑后 #32 由 auto-merge 合并 ✅ | -| H0926-7 | 逃逸缺陷(V080-R9 原修复未生效):`InboxRow.sessionID` 在 `convertFromSnakeCase` 下对应的键是 `sessionId`,`rows` 的 `session_id` 从未解码,可选属性静默为 nil,组件最近任务的今日 token 从未显示。V080-R9 的修复与任务 003 的测试都只测了纯函数,没有经过真实解码 | V4 真机验收:快照 8 条最近任务中 5 条当天有用量,带今日 token 的为 0;最小 Swift 程序复现(2026-09-26) | [任务 004](../plans/task-004-today-tokens.md)(PR #39,执行方 OpenCode):属性改名 `sessionId`;新增 Python 静态检查,`convertFromSnakeCase` 解码的结构体禁用连续大写属性名。修复证据为修复前断言失败,回放用例已加入 ✅ | -| H0926-8 | 组件最近任务的签名只含 `id:revision:state`,不含今日用量;用量异步加载完不触发快照重写,最长延迟 15 分钟 | 同上,排查 H0926-7 时发现 | 任务 004(PR #39):签名纯函数 `recentSignature` 计入今日 tokens 与金额显示值,先重构(R1)后修复;修复证据为修复前断言失败,回放用例已加入;真机重建后启动 1 秒内写入今日用量 ✅ | - -### 5.1 独立评审发现(PR #7,2026-09-26) - -另一评审 Agent 按[交接书](2026-09-25-harness-review-brief.md)评审 PR #7([评审报告](2026-09-26-harness-review.md))。首轮结论「修改后可合并」(PR7-R1..R6),复评结论「可合并」并新增 PR7-R7..R9。九条发现均在本 PR 修复,每条带回放用例(`harness/replay_cases.py`)与 `Defect:` 修复证据。 - -| 编号 | 严重度 | 发现 | 处理 | -|---|---|---|---| -| PR7-R1 | 严重 | `Defect: X doc` 标记让产品代码改动完全免检 | doc 类修复改了代码即判失败 ✅ | -| PR7-R2 | 严重 | 往已有测试文件末尾追加代码判为 R0 且零 flag,追加几行即可禁用任意已有测试 | 新增 `harness/base_tests.py`:base 版本的已有测试在 head 上重跑,CI harness job 执行;risk 对追加提示此项 ✅ | -| PR7-R3 | 严重 | git 守卫的规则文件在执行者可写的工作区,改掉即可解除保护 | 钩子按 origin/main 上的规则执行,工作区不一致时告警;守卫代码与解释器仍可写,写入规范「已知边界」,ruleset 导入提到本机安装之前 ✅(部分:本机层定位为防误操作) | -| PR7-R4 | 一般 | 修复退回后测试以出错(如 import error)结束只记警告,被当作「修复前失败」 | 出错不算证据,判失败 ✅ | -| PR7-R5 | 一般 | 整文件退回会连带撤掉后续无关提交,失败无法归因 | 只反向应用修复提交自身的 diff,失败时回退整文件并告警 ✅ | -| PR7-R6 | 一般 | 命令守卫只拦 GitHub API 的 DELETE,PATCH 改远端 ref、PUT 直写 main 均放行;覆盖变量可拆写绕过 | 拦截全部写方法与 curl 写请求;另查去掉引号的形式、变量名后半截;结构化解析留给方案 §13 E3 ✅ | -| PR7-R7 | 严重(复评) | base_tests 还原了测试文件,但测试 import 的是 head 的产品代码:产品模块在 import 时替换 `assertEqual` 即可让 base 测试全绿,配合 `Risk: R1` 进自动合并档 | 测试经 `harness/base_tests_runner.py` 运行:前后比对 unittest 属性 + 必然失败的哨兵用例,篡改时一律失败(有意改动测试也不例外);risk 对产品代码新增的测试框架引用加标记、取消 R1。同进程检查可被专门针对,残余写入规范「已知边界」并列为 E1 前置复核 ✅(部分) | -| PR7-R8 | 一般(复评) | 「读 origin/main」依赖本地远端引用,改指伪造提交或伪造 remote 即可再次解除本机层;合并前 main 上没有规则文件 | 按评审意见只改文档:规范「已知边界」补这两点 ✅ | -| PR7-R9 | 一般(复评) | curl 写请求只在「URL 在前、方法在后」时被拦 | 与 api.github.com 同一条命令、任意位置出现写方法或请求体即拦;选项区分大小写避免误伤 `-D`。是否一律拒绝 Agent 自己合并 PR 交用户决定(方案 §13 D4)✅ | - -回放在补 PR7-R6 的用例时再次发挥作用:原有测试靠别的规则也能拦下拆写的命令,「去掉引号」这一步没有被任何测试覆盖,注入后漏过,于是补了两条只有去引号才能识别的用例。PR7-R4 的新规则首次运行就拦下了实现方自己的三条修复证据:PR7-R1、R4 的测试在修复前因取空列表下标而出错,PR7-R2 的测试因导入新增模块而出错;改为对全部问题断言、经 CI 实际调用的命令行检查后,九条修复均为「修复前失败、修复后通过」。 - -评审还指出两点不属于缺陷的方案风险:「设计评审 / 执行」分工尚未真实走过(本 PR 的实现方也是 Claude,方案 §13 E11);「标杆有效」目前只有注入证据,要等 trial-001 的真实交付数据。 - -另有两处 harness 的即时拦截可作为有效性的直接证据:CI 首次运行时 `hygiene --range` 拦下了测试数据中的真实用户目录;Claude Code 的命令守卫在本会话中拦截 3 次(均为命令文本含危险字样的误报)。 - -## 6. 测试强度基线 - -事故回放(`bin/verify --full`):v0.8.0 基线 25 条中,11 条有注入用例(15 个),5 条过程类失败由守卫测试覆盖,9 条写明原因暂缓(`harness/replay_cases.py` 的 `DEFERRED`);另有 4 个用例回放本次新发现的 H0925-1、H0925-2、H0925-5,11 个用例回放评审发现 PR7-R1..R9。30 个注入全部被拦住,其中 3 个 Swift 用例在 macOS CI 上以 `--strict` 运行。 - -Python 测试从 267 项增至 380 项(另有 1 项以 `expectedFailure` 登记的已知缺陷 H0925-4)。 - -定向变异测试(`python3 harness/mutate.py`,基线 `harness/mutation-baseline.json`,只升不降): - -| 目标 | 补强前 | 补强后 | -|---|---|---| -| 价格转换与防护(`pricing_fetch.transform` 等) | 82% | 96% | -| 热力金额分级(`cost_thresholds`、`cost_level`) | — | 90% | -| 过去日报告合并(`_merge_day_tasks`) | 47% | 76%(H0925-4 修复后 78%) | -| 模型规范名(`model_names.canonical`) | — | 100% | -| 金额计算(`usage_cost`,2026-09-26 新增) | — | 80% | -| 用量汇总(`usage_report`,2026-09-26 新增) | — | 74% | - -剩余存活变异(2026-09-26 逐条归类,方案 §13 E5): - -- 等价或近似等价:夹具字段齐全时的 `or 0` 与 `0→1` 默认值,三个目标共约 20 个。 -- 真实缺口,待补测试: - - 报告合并:合计相等时 `<=` 改 `<` 未被发现(H0925-4 修复后合计相等但类别不同时结果会变,此前归为等价已不成立);合计为 0 的恢复任务「除非 fidelity 为 unavailable 否则丢弃」无测试;合并后各类未断言恰等于 max(现有, 重扫)(Sub→Add 存活)。 - - 金额计算:`merge_cost` 的累加、`model_cost` 的 cache_write 计价项、缺价提示。 - - 用量汇总:`period_bounds` 的周与月边界常量、原生金额累加、原始模型名列表(上限 5 个)。 diff --git a/docs/review/2026-09-25-harness-review-brief.md b/docs/review/2026-09-25-harness-review-brief.md deleted file mode 100644 index 155fb35..0000000 --- a/docs/review/2026-09-25-harness-review-brief.md +++ /dev/null @@ -1,105 +0,0 @@ -# 评审交接:可验证交付 harness(PR #7) - -用途:交给独立评审方(另一个 Agent),对「可验证交付」方案与 PR #7 的全部改动做一次整体评审。写于 2026-09-25,评审基线为分支 `claude/gracious-bardeen-pi7ysv` 的当前 head(以 `git rev-parse HEAD` 为准)。 - -## 0. 原始需求与对齐结论(评审的判断基准) - -评审首先要回答:这些改动是否在实现用户的原始需求,而不只是「实现得对不对」。以下内容按原文引用,不要改写。 - -**理论来源**:用户的调研报告《低人工干预下 AI Agent 持续高质量交付:理论与全链路最佳实践》(2026-09-23,Claude 文档,未入库;其中核心结论是「关键不在模型多聪明,而在能否把任务变成可验证的问题,并用 harness 把验证、隔离、回滚和学习做成闭环」)。 - -**用户原始需求(2026-09-25,原话)**: - -> 按照报告给的这套理论。以我们这个项目为核,构建起报告中提到到,全流程中需要做到的将任务转为为可验证的问题。把该项目打造为我们目标的标杆项目。 - -**对齐时用户的决定(2026-09-25)**: - -1. 自治目标 L4:R0/R1 门禁全绿自动合并,其余每个 PR 人审证据包。 -2. 角色:Codex / Claude Code 做设计、评审,并作为顾问协助执行者解决问题;Zcode / OpenCode / Pi 做实现、测试、部署上线等实际工作。 -3. 同意按提供的配置在仓库设置中启用 ruleset(`main` 与 `v*` tag 保护)。 -4. P1–P6 连续完成后合并为一个 PR 提交。 - -**对齐后的目标与验收**(详见 `docs/plans/verifiable-delivery.md` §1、§2、§7、§8): - -- 目标:把每一类改动的完成判断,从「Agent 说做完了、人去复验」改为「开工前就有可执行的判定,完工后由 Agent 之外的机器重跑判定并留证据」,并用 v0.8.0 的真实事故证明有效。标杆 = 有效(有数据证明)+ 可复制(模板、脚本、文档可被其他项目照搬)。 -- 「可验证」的五条操作定义:验收有编号且是命令或测试;判定在 Agent 之外;判定器本身被检验;执行者改不了判定器;证据由脚本生成。 -- 标杆验收四条:事故回放、验收编号覆盖、三处同口径、真实任务试跑并与 v0.8.0 基线对比。 -- 不做:全自动(UI 与 R2 以上保留人审);改变产品行为;大团队设施(Temporal、OpenTelemetry、合并队列、金丝雀);打 tag 或发版。 - -## 1. 评审范围 - -- **方案**:目标、「可验证」的定义、角色分工、风险等级、护栏分层是否合理,是否真的解决 v0.8.0 暴露的问题。 -- **实现**:`harness/`、`.githooks/`、`.github/`(workflow、rulesets、PR 模板)、`.claude/`、`.opencode/`、`bin/verify`。 -- **产品代码的两处改动**:`scripts/daily_report.py`(抽出 `cost_thresholds`)、`native/WidgetSnapshotWriter.swift` 与 `native/InboxPolicy.swift`(写入器改调策略函数)。两处都声称行为不变。 -- **规格与测试**:六份 `docs/specs/*.md` 新增的验收编号表(69 条);新增测试 `tests/test_harness*.py`、`test_properties.py`、`test_architecture.py`、`test_golden.py`,以及对已有测试文件的追加。 - -不在范围内:产品功能本身的正确性(v0.8.0 已评审过),除非本 PR 改动了它。 - -## 2. 建议阅读顺序 - -1. `docs/plans/verifiable-delivery.md`:目标、定义、角色、风险等级、阶段状态、待决事项(§11)、后续工作(§13)。 -2. `docs/review/2026-09-25-harness-baseline.md`:v0.8.0 失败分类(§1)、基线指标(§2)、实施中的新发现(§5)、测试强度基线(§6)。 -3. `docs/specs/delivery-harness.md`:现役命令、约定、三层护栏、一次性设置、验证状态(§6)与已知边界。 -4. 代码:先读 `harness/common.py`、`verify.py`、`evidence.py`、`risk.py`,再读 `git_guard.py`、`command_guard.py`、`replay.py` 与 `replay_cases.py`,最后读 `acceptance.py`、`mutate.py`、`quality.py`、`metrics.py`、`review_pack.py`、`release_check.py`。 -5. PR 的 harness job summary(风险等级、修复证据、交付度量)。 - -## 3. 复现与核对 - -```sh -git fetch origin && git checkout claude/gracious-bardeen-pi7ysv -python3 -m pip install -r requirements-dev.txt # 有开发包 venv 时用 scratch/iterm-probe-venv/bin/python -python3 harness/git_guard.py install # 评审环境也会受 git 守卫约束 -bin/verify --full # 非 macOS 上 Swift 三项会跳过 -python3 harness/review_pack.py --base origin/main --output build/review/pack.md -python3 harness/replay.py --list # 基线覆盖 -python3 harness/mutate.py --check # 约 1.5 分钟 -python3 harness/acceptance.py --manual # 人工验收清单 -``` - -注意:本仓库的 Claude Code 项目设置会加载命令守卫。守卫按字符串匹配命令,命令文本里出现危险字样(哪怕只是 echo)也会被拒;这是已知边界,不需要绕过,换一种写法即可。 - -## 4. 请重点质疑的地方 - -以下是作者自己最没有把握、或最可能出错的部分: - -0. **是否偏离原始需求**(第 0 节):改动是否真的把「任务转为可验证的问题」做成了全流程,还是只堆了检查工具;两个角色(设计评审方、执行方)的分工是否被落实;对齐决定有没有被违背或悄悄扩大;哪些部分离「可复制的标杆」还差得远。 -1. **证据是否可能「假通过」**:`evidence.py` 把修复提交改过的代码退回修复前,再跑引用该编号的测试。退回时如果别的提交也改了同一文件,测试可能因为无关原因失败,被误判为「修复前失败」。请评估这个误判面,以及「出错」与「断言失败」的区分是否足够。 -2. **风险判定能否被绕过**:`risk.py` 按路径判定。执行方有没有办法让 R2/R3 的改动被判成 R0/R1?例如改名、把逻辑挪进 `docs/` 或 `tests/`、利用 `shrink_only` 规则。 -3. **护栏的漏洞**:`reference-transaction` 的判断(旧值为全 0 时查当前值)、pre-push 对强推的识别、命令守卫的正则。请尝试构造能漏过的操作,只在临时仓库里试。 -4. **回放与变异的有效性**:注入点是否代表真实的缺陷形态;性质测试有没有写得过松(已发现并修过一处:条目缺失时被跳过);变异存活项里有没有被当成「等价变异」放过的真实缺口。 -5. **两处产品改动是否真的行为不变**:尤其是写入器的 `runningRows` 从 `human.filter` 改为 `rows.filter` 加 `widgetRunningListed`(后者自带排除 agent)。 -6. **规格编号是否忠于原文**:DR、IN、CB、ZN 四张表是「由既有条款整理、不新增需求」。请抽查有没有夹带新要求,以及覆盖列引用的测试是否真的在断言那条验收。 -7. **方案层面**:单人项目承担这套流程的成本是否合理;哪些部分过度设计、可以砍;哪些 v0.8.0 失败类型其实没被结构性解决。 - -## 5. 已知问题(不必作为新发现上报) - -- H0925-4(合并口径不一致,以 `expectedFailure` 登记)、H0925-6(Zcode 两份规格矛盾):待用户决定。 -- 执行方与用户共用 GitHub 身份,服务端分不清谁在合并,L4 自动合并尚未接上。 -- ruleset 与发版审批尚未导入;OpenCode 插件、Codex 钩子未在真实环境验证;Pi、Zcode 无 Agent 层拦截。 -- `replay_cases.py` 的 `DEFERRED` 中 9 项暂缓回放;DR14 登记为验收缺口(首个试跑任务)。 -- 命令守卫按字符串匹配会误报(已有 5 次记录,见规范「已知边界」)。 - -如果评审认为上述某项的严重度被低估,可以写成发现并说明理由。 - -## 6. 产出 - -- 结论:可合并 / 修改后可合并 / 不可合并。 -- 发现:写入 `docs/review/2026-09-25-harness-review.md`(日期按实际评审日),编号 `PR7-R<序号>`,严重度分阻断、严重、一般。每条附证据(命令、文件行、输出)与修复要求,包括应补的测试或回放用例。格式见 `docs/templates/review-checklist.md` 末尾。 -- 对方案的整体意见(第 4 节第 7 项)单列一节。 - -## 7. 约束 - -- 只读评审:不修改实现、不推送到 PR 分支。需要改动的写成发现,由实现方修复后复审。 -- 不在真实仓库里尝试破坏性操作(强推、改写历史、推 tag、删除 CI 记录);验证护栏只在临时仓库中进行。 -- 通过与否只认可复现的命令输出与 CI 运行,不采信文档中的自述,包括本交接书。 - -## 8. 复评(2026-09-26 起) - -首轮评审报告:`docs/review/2026-09-26-harness-review.md`,结论「修改后可合并」,六条发现 PR7-R1..R6。实现方已逐条修复,处理摘要见[基线评审 §5.1](2026-09-25-harness-baseline.md)。复评只需核对: - -1. 每条发现的修复证据:`python3 harness/evidence.py --base origin/main`,PR7-R1..R6 均应为「修复前失败、修复后通过」。 -2. 回放:`python3 harness/replay.py --only PR7-R1`(依次换编号),注入后对应测试必须失败。 -3. 修复是否真的堵住了报告中的复现步骤(按报告原命令在临时仓库重跑),以及修复本身是否引入新的绕过面。 -4. PR7-R3 只修了一部分(规则文件改读 origin/main;守卫代码与解释器仍可写,写为已知边界):这一处理是否可接受。 - -复评结论追加到首轮报告末尾,新发现继续按 `PR7-R<序号>` 编号。 diff --git a/docs/review/2026-09-26-harness-review.md b/docs/review/2026-09-26-harness-review.md deleted file mode 100644 index da3661c..0000000 --- a/docs/review/2026-09-26-harness-review.md +++ /dev/null @@ -1,95 +0,0 @@ -# PR #7 独立评审:可验证交付 harness(2026-09-26) - -评审对象:PR #7(分支 `claude/gracious-bardeen-pi7ysv`,head `a109782`,base `origin/main` `d8bde8d`)。评审依据 [评审交接书](2026-09-25-harness-review-brief.md) 第 0 节的原始需求与对齐决定。 - -方法:在独立 worktree(`/tmp/pr7-review`)与独立 venv(ruff 0.16.8,与 `requirements-dev.txt` 锁定一致)中复现全部命令;破坏性操作只在 `/tmp` 临时仓库中尝试;结论只基于本人命令输出与 GitHub 上 PR #7 head(run 36157693749)的 CI 运行。未修改实现、未推送。 - -## 结论:修改后可合并 - -核心机制真实、可运转、方向符合原始需求。四条标杆验收中前三条(事故回放、验收编号覆盖、三处同口径)经本机 + CI 复现成立;第四条(真实任务试跑)尚未执行,PR 自己也如实标注 P6 为 ⏳。 - -两个「严重」发现(PR7-R1、PR7-R2)都是 `risk.py` / `evidence.py` 的小改动(各约 20 行内 + 负例测试),建议合并前修掉——本 PR 是 R3 基础设施,合并后这些就是现役判定器,带病上线再改又需一轮 R3 审批;且 E1(L4 自动合并)接通前它们必须先堵。其余发现可随后续 PR。上线顺序上,A4(ruleset 导入)的优先级应高于 A3(本机装守卫):PR7-R3 表明 git 层对能写工作区的执行者不构成硬边界,服务端是唯一不可绕过的一层。 - -## 是否偏离原始需求 - -**判定:未偏离,无悄悄扩大;但「标杆」尚缺最后一环(有效性未经真实任务验证),且角色分工尚未实际运转。** - -对照交接书第 0 节逐条核对: - -- **「把任务转化为可验证的问题、全流程」**:方案 §2 的五条操作定义与报告核心结论一一对应;全流程落点表(方案 §6)覆盖需求→度量八个环节。抽查证实映射是实质的而非纸面的:`acceptance.py` 真的会因覆盖引用失效而失败(实验:从 `acceptance-gaps.txt` 删掉 DR14 行,检查器报「可自动化条目没有测试,也不在 acceptance-gaps.txt 中」);`verify --full` 在本机 macOS 真的编译并运行三项 Swift 检查 + 19 个注入回放。 -- **对齐决定未违背**:未打 tag、未发版、未导 ruleset(只提交了导入文件,等用户操作);P1–P6 合并为一个 PR(对齐决定 4);两处产品代码改动在方案 §8「只为可测而必需的重构」授权内,且实测行为等价(见 PR7-R5 之外的核对记录)。六份规格的验收表抽查(DR12/DR13/DR14 与 main 原文逐字一致、DR1/DR6 语义保留)未见夹带新要求。 -- **观察 1(角色分工是纸面状态)**:方案 §3 规定设计与评审方「不替执行者提交实现代码」,但本 PR 全部 12 个提交的作者即设计评审方(Claude)。建设期由谁实现用户未限定,A1 独立评审也正为此设置,因此不算违规;但要如实记录:**「执行方实现、评审方评审」的分工尚未运转过一次,trial-001 是第一次检验**。在此之前,「标杆 = 有效(有数据证明)」只有注入侵炎式的证据,没有真实交付流的证据。 -- **观察 2(有效性证据的成色)**:19 个注入全部拦住是「测试集能抓住已知缺陷形态」的证据,不等于「能抓住下一类未知缺陷」。变异存活清单里 `_merge_day_tasks` 的 `LtE→Lt`(daily_report.py:1410)在「合计相等但明细不同」时可观察,恰与 H0925-4 同域——作者已在 §13 E5 登记为待区分项,不算新发现,但它说明 76% 的得分里有真实缺口,不只是等价变异。 - -## 发现 - -| 编号 | 严重度 | 问题 | 证据 | 修复要求 | -|---|---|---|---|---| -| PR7-R1 | 严重 | `Defect: <编号> doc` 标记可让任意产品代码改动免检:`evidence.py` 对 `doc_only` 只列提交,不核对改动范围;证据表渲染为「文档类修复」,`code_files` 被收集但不展示。规格约定 doc 类是「纯规格或文档修复」,机器未核对「确实只改了文档」 | 复现(`/tmp` 临时仓库,`evidence.analyse`):提交改 `scripts/app.py`(产品代码)+ message 带 `Defect: FAKE-8 doc` → `ok=True`、`doc_only=True`、problems/warnings 均空、`code_files=['scripts/app.py']`;`tests/test_harness.py::test_doc_only_defect_needs_no_test` 只测了真 doc 场景,无负例 | `analyse` 中 `doc_only` 且 `code_files` 非空时记 problem;`render_markdown` 对 doc 类如常列出代码改动列;补「doc 标记 + 产品代码改动」负例测试 | -| PR7-R2 | 严重 | 已有测试文件「纯追加」判 R0 且不产生任何 flag(`risk.py:76-78`),但纯追加可以禁用任意已有测试(模块级 monkeypatch,如 `T.test_x = _noop`),配合 `Risk: R1` 声明可整单降为 R1(自动合并档)。击穿「可验证」定义第 4 条「执行者改不了判定器」 | 复现(`risk.classify` + unittest):改产品行为(value 1→2)+ 测试文件末尾追加 3 行禁用 `test_value` + 提交带 `Risk: R1` → `level=R1`、`flags=[]`、note 为「只改产品代码、已有测试与黄金快照零改动 → R1」,且测试套件退出码 0(`OK`)。`tests/test_harness.py::test_appending_to_existing_test_is_r0` 只测了无害追加 | 二选一:(a) 已有测试文件的追加同样产生 flag(保守);(b) `verify` 增加测试完整性检查(对 tests/ 做模块级对测试属性重赋值的 AST 检测,或记录并比对测试方法数只增不减)。无论哪种,E1 接通前必须落地;补回放用例 | -| PR7-R3 | 严重 | git 层守卫的规则与解释器都在执行者可写的工作区:篡改 `harness/rules.toml` 后本地护栏立即空转;钩子解释器优先用不入库的 `scratch/iterm-probe-venv`(同样可替换)。规格 §7 已知边界只列了 `--no-verify` 与改 `core.hooksPath` 两条绕过,低估了绕过面;对无 Agent 层的 Zcode/Pi,在 A4(ruleset 导入)完成前这是 X3 重演的完整通路 | 复现(`/tmp` 临时仓库,真实钩子):对照实验——非快进 `git branch -f main <孤儿提交>` 被拒(「改写保护分支 refs/heads/main……不是快进」);先提交清空 `protected_branches` 的 rules.toml 后同样操作**放行**(main 被改写为孤儿提交,无任何拦截)。`git_guard.py:120` `load_rules()` 读工作区文件;`.githooks/_runtime` 解释器路径优先 `scratch/` | (1) 规格 §7 已知边界补记此条,并注明「服务端 ruleset 是唯一硬边界」;(2) 把 A4 的优先级提到 A3 之前(上线顺序);(3) 可选加固:pre-commit 对 `harness/`、`.githooks/` 的改动增加提示性 flag(自知可被绕过,仅提高可见度) | -| PR7-R4 | 一般 | 「修复前失败」对新增文件类修复退化为 import error:修复实现在新文件时退回 = 删除文件,引用测试必然以 error(非断言失败)结束,只产生 warning,不影响 evidence 结论。此时不能证明测试在检查缺陷行为——缺陷可以原样未修而证据全绿 | 复现:修复提交只新增 `scripts/newmod.py`(缺陷所在 `app.py` 原样不动),测试 `import newmod` 并断言其输出 → `before='error'`、`after='pass'`、`ok=True`,仅 warning「需人工确认」;CI 的 evidence 步骤不会因此失败(exit 0) | `error` 时要求更强的人工确认痕迹(如 review_pack 把 error 类逐条列成「评审必须确认」清单),或规定新文件修复的测试必须经由既有模块路径引用;至少在 delivery-harness.md §2 写明此边界 | -| PR7-R5 | 一般 | 证据退回以整文件为粒度:修复提交之前的其他提交若改过同一文件,退回会一并撤销,引用测试可能因无关原因 fail,被计为有效的「修复前失败」(无法归因) | 复现:提交 C1 改 `value()`、修复提交只修 `broken()`,测试同时断言两者 → 退回后测试因 `value()` 失败 → `before='fail'`、`ok=True`,FAKE-7 的修复本身未被检验 | 交接书已自查到该风险且方向正确;建议:`verify_fail_before_fix` 记录退回文件在 `base..first_sha^` 区间是否被其他提交改过,是则加 warning 暴露归因风险;中期改为按 hunk 退回(`git diff | patch -R`) | -| PR7-R6 | 一般 | `command_guard.py` 的 `gh api` 规则只拦 `-X DELETE`:`-X PATCH` 改远端 ref(服务端强推)、`--method PUT` 经 contents API 直写 main 文件均放行,本地三层全部无感。同族绕过(引号 tag、变量拼接、解释器包装)属 E3 已登记的字符串匹配局限,但 gh api 的 PATCH/PUT 未列入任何已知边界 | 复现(`check_command` 直接调用):`gh api -X PATCH repos/x/y/git/refs/heads/main -f sha=abc -F force=true` → 放行;`gh api --method PUT repos/x/y/contents/scripts/app.py` → 放行;`gh api -X DELETE .../actions/runs/1` → 拦截。另:`git push origin 'v0.9.0'`(带引号)→ 放行(git 层 pre-push 兜底);`A=HARNESS_ALLOW_M; B=AIN; env "${A}${B}=1" git push origin main` → command_guard 拦到 push main 但**漏掉变量拼接**,git 层因环境变量真实生效而放行 | (1) gh api 按动词收紧(PATCH/PUT 到 refs、contents、workflows 等路径列入拦截);(2) 把「拼接变量可绕过 HARNESS_* 检查」补进 §7 已知边界(git 层信任环境变量);(3) E3(结构化解析)提优先级 | - -未构成新发现、但复核过的项:交接书第 5 节已知问题的严重度评估基本准确;其中「命令守卫字符串匹配误报」(4 次记录)在评审过程中再次出现(本评审的实验命令含 `git filter-repo` 字样被拦 2 次,换写法后通过),维持原严重度即可。 - -## 对方案的整体意见 - -**这套 harness 与「单人 + 多 Agent 并行」的实际病灶是对症的,不是过度设计。** v0.8.0 的 19 项缺陷 + 6 类过程失败里,代价最大的是过程失败(X1 三次、X3 两次、5 轮评审),本 PR 的火力(证据脚本、三层护栏、机器风险分级)正好集中在那里。结构上也克制:不上 Temporal/OTel/合并队列,人工验收明确列清单不假装自动化,都符合单人项目的裁剪。 - -四个具体意见: - -1. **R0/R1 通道的可靠性是当前短板,也是 L4 的前提。** PR7-R1、PR7-R2 都打在这条通道上。另外要意识到 R1 的机器核对(已有测试零改动 + 快照零差异)只能证明「判定器没被动过」,不能证明「行为真的没变」——黄金快照只覆盖 usage 两个子命令。建议在 delivery-harness.md §3 的 R1 行如实标注这个边界(「行为不变的机器证据限于现有测试与快照覆盖面」),避免 R1 被读成比实际更强的保证。 -2. **优先级建议调整:A4(ruleset 导入)应先于一切。** PR7-R3 表明本机两层对「能写工作区的执行者」都不是硬边界,服务端是唯一一层。ruleset 不导入,整套三层护栏的第一层就不存在,且 tag 直推即可触发真实发布。这也和发版流程记忆一致(tag push 即远端发布)。 -3. **可裁剪项**:`metrics.py` 的 GitHub API 轮次统计(信息价值中等、PR 期间 per_page=100 截断)、review_pack 对验收编号的列举(E8 已列)、quality 棘轮对 20 个 C901 的缓慢治理——保留无妨,但不应再投入。相反,evidence 的归因精度(PR7-R4/R5)和 command_guard 的结构化解析(E3/PR7-R6)值得提前。 -4. **「标杆」的最后一块拼图是 trial-001,且应该按原计划只做 DR14 补测试这件小事。** 试跑的价值在于度量真实交付流(复验轮数、声称已修、CI 轮次 vs 32 次基线),不在于任务本身的大小。建议用户尽快指定执行方跑完,再决定 E1 是否接通。 - -## 复现记录(摘要) - -- `bin/verify --full`(本机 macOS,独立 venv,ruff 0.16.8):10 项全过(tools/lint/hygiene/quality/acceptance/python-tests 365 项/swift-policy/swift-runner/zcode-selftest/replay 19 注入),`ok=true` @ `a109782`。 -- `python3 harness/replay.py --list`:25 条基线全覆盖(15 注入 + 5 守卫 + 9 暂缓带原因),退出码 0。 -- `python3 harness/acceptance.py`:69 条编号,可自动化 54(53 有测试 + 1 登记缺口 DR14),人工 19,退出码 0。 -- `python3 harness/mutate.py --check`:四目标 96%/90%/76%/100%,与 `mutation-baseline.json` 一致,退出码 0。 -- `python3 harness/review_pack.py --base origin/main`:风险 R3(34 个护栏路径);三个 H0925 修复均「修复前失败、修复后通过」(脚本生成)。 -- CI(PR #7 head,run 36157693749):`harness`(12s)与 `build`(3m7s,macos-26 `--strict --full`)均 SUCCESS;PR 正文按模板填写、未手写通过状态,CI 链接指向当前 head 的运行。 -- 攻击实验:evidence 三个假通过场景、risk 追加禁用 + R1 组合、git 守卫对照实验(含 rules.toml 篡改、非快进改写、真实强推、tag 移动/删除、filter-repo)、command_guard 30 条正负例,全部在 `/tmp` 临时仓库/纯函数调用中完成,脚本存于评审环境(`/tmp/pr7-attacks/`),未触及真实仓库。 -- 两处产品改动等价性:`widgetRunningListed` = `origin != "agent" && inboxActiveListed`,与 main 版 `human.filter { inboxActiveListed }`(`human` 已是非 agent 过滤)逐条件等价;`widgetEntryTitle` 与被替换的内联 `hideTitles ? "" : title` 等价、project 不经隐藏(W6/R15 口径不变);`cost_thresholds` 与原内联逻辑在 `len<8` 边界与分位索引上一致,`amounts` 在原位排序后未再使用。 - ---- - -# 复评(2026-09-26,head `1861f76`) - -复评对象:同分支新 head `1861f76`(base 仍为 `d8bde8d`)。方法同首轮:独立 worktree(`/tmp/pr7-rereview`)与独立 venv 复现,破坏性操作只在 `/tmp` 临时仓库,结论只认本人命令输出与 CI 运行(run 36162444057,`build` 与 `harness` 均 SUCCESS)。 - -## 复评结论:可合并 - -六条发现中五条已修复且机器证据完整;PR7-R3 为符合其声明定位的部分修复。修复引入的新绕过面有两条(PR7-R7 严重、PR7-R9 一般)与一条已知边界表述缺口(PR7-R8 一般),其中 **PR7-R7 是原 PR7-R2 的换位绕过,必须在 E1(L4 自动合并)接通前修复**;它与 R8/R9 都是小改动,若实现方还能在合并前再推一版,建议一并处理,否则登记进方案 §13 作为 E1 前置条件后即可合并。本轮不再有「合并前必须先修」的阻断项:R7 在当前形态下(L4 未接通、R1 合并仍经人工)有人审兜底,与首轮 R1/R2 所处的「判定器承诺本身被击穿」不同——base_tests 的机器防线在,只是又有了需人审补位的盲区。 - -## 首轮六条发现的复核 - -机器证据(全部本人复现):`bin/verify --full` 在本机 macOS 10 项全过 @ `1861f76`(回放扩到 26 个注入用例);`harness/evidence.py --base origin/main` 九条 `Defect:`(H0925-1/2/5、PR7-R1..R6)全部「✗ 失败 → ✓ 通过」;`harness/replay.py --only PR7-R1` 至 R6 逐条注入全部「拦住」(R6 两条用例);`harness/base_tests.py --base origin/main` 通过;CI harness job 中 `Existing tests (base version) on head` 步骤存在且 success。 - -| 编号 | 状态 | 证据与复核 | -|---|---|---| -| PR7-R1 | 已修复 | `analyse` 对 `doc_only` 且 `code_files` 非空记 problem(evidence.py `analyse`);回放「doc 类修复改了代码也不查」注入后 `FAILED (failures=1)`;单测负例 `test_doc_defect_that_changes_code_is_rejected`。交接书问的「代码改动与 Defect 提交分离」不构成绕过:不带 `Defect:` 的提交本来就不进证据表,其行为变化由 risk(产品代码 R2)与 base_tests 兜底(对照实验 C:纯行为变化被 base_tests 拦住,exit 1) | -| PR7-R2 | 已修复,但修复引入新绕过面(PR7-R7) | `harness/base_tests.py` 落地并由 CI harness job 执行(workflow 有 `Existing tests (base version) on head` 步骤,运行 success);回放注入「追加的 monkeypatch 生效」后 `FAILED (failures=2)`;单测覆盖追加 monkeypatch、新测试文件篡改、有意改动只报告、干净改动通过四场景。交接书问的三条:仓库根 `sitecustomize.py` **不会**被 `python -m unittest` 加载(cwd 注入晚于 site 初始化,实验 B 中断言真实执行、base_tests 报失败);`load_tests` 协议随 base 版本测试文件还原,head 无法注入;追加测试**仍判 R0** 但 risk 加了说明性 note,安全性改由 base_tests 机器兜底——而这条兜底被 PR7-R7 打穿 | -| PR7-R3 | 部分修复,与声明的「防误操作」定位一致 | 工作区篡改 `rules.toml` 不再解除保护:临时仓库对照实验,非快进 `branch -f main` 在工作区规则被改后仍被拒(钩子读 origin/main 版本)。残留缺口见 PR7-R8(伪造 origin/main 引用可再次解除)。定位调整(git 层「防误操作,不防有意绕过」)、ruleset 提前到本机安装之前(A4 先于 A3)均已写入 specs 与方案 §13 ✓ | -| PR7-R4 | 已修复 | `before == "error"` 从 warning 改为 problem(evidence.py `verify_fail_before_fix`);回放注入后 `FAILED (failures=1)`;单测 `test_error_before_fix_is_not_proof`。交接书问的「断言失败却不检查缺陷」仍可构造(断言修复引入的标记而非缺陷行为),但这属测试质量的机器上限,由 review-checklist X4(「测试是否真的调用产品代码」)人审兜底,不算修复缺陷。「首次运行拦下实现方自己三条证据」的改法(39a6101)核对为合理且更强:R1/R4 的测试从 `problems[0]` 改为对全部 problems 断言(空列表从 IndexError 变 assertIn 失败);R2 的测试从 import 模块改为经 CI 实际调用的命令行(`base_tests.py --base … --repo …`,断言退出码与输出),并新增一条断言 CI workflow 里确实接线了这道检查——不是把测试改弱 | -| PR7-R5 | 已修复 | `_reverse_apply_fix` 按 `-U0` 零上下文反向应用该编号提交自身的 diff(多提交按 LIFO 逆序,`--unidiff-zero` 冲突即失败);冲突时退整文件并加 warning,且退整文件后若测试 error 会被 PR7-R4 新规则判 problem,形成联动。双提交场景(PR7-R2 的 `0f60e67`+`39a6101`)证据表正确产出「失败 → 通过」,归因于修复本身。warning 在证据表 notes 中对评审方可见 | -| PR7-R6 | 部分修复,curl 侧有顺序盲区(PR7-R9) | `gh api` 侧覆盖良好:`-X/--method PATCH|POST|PUT|DELETE`、`-f/-F/--field/--raw-field/--input`(隐含 POST)、前缀 env 赋值均拦;GET 放行。拼接变量后半截(`_ALLOW_TAG`)、带引号 tag、`ori"gin" main` 拆写经去引号复查均拦(实验 19 条正负例)。curl 只拦「url 在前、动词在后」一种顺序,见 PR7-R9。交接书问的变量间接展开、eval、`$(printf …)`、base64、wget、python requests:**同意不在此轮处理**——Agent 层定位是锦上添花,恶意执行者的完整解法是服务端 ruleset,字符串规则继续堆叠边际收益递减,E3(shlex 结构化解析)是正道且已标注「评审建议优先」 | - -## 新发现 - -| 编号 | 严重度 | 问题 | 证据 | 修复要求 | -|---|---|---|---|---| -| PR7-R7 | 严重 | base_tests 的信任根包含 head 版本的产品代码:base 版本的测试文件被还原了,但测试 import 的是 head 的产品模块,产品模块在 import 时即可污染 unittest。与原 PR7-R2 同级的换位绕过(把禁用代码从 tests/ 挪到被 import 的产品代码顶部) | 复现(`/tmp` 临时仓库,按 CI 同样方式调 `base_tests.py --base … --repo …`):在 `scripts/mod.py` 顶部加三行(`unittest.TestCase.assertEqual = lambda self, *a, **k: None`)+ 行为变化(value 1→2)+ 提交带 `Risk: R1` → base_tests 报「✓ base 版本的已有测试在 head 代码上全部通过(OK)」、`risk.classify` 判 **R1**、flags 为空——R1 自动合并档全绿。对照:同场景去掉钩子则 base_tests exit 1 正确拦截 | E1 接通前必修(可与本 PR 合并前再推一版)。方向(至少一项 + 回放用例):(a) base_tests 在运行后校验 `unittest.TestCase` 关键方法未被替换(运行前后快照比对,能抓大多数「改了未改回」);(b) 源码检查:产品代码(scripts/、native/ 等非 tests 路径)新增行出现对 `unittest`/`TestCase`/`pytest` 属性赋值的模式即 flag(hygiene 或架构测试);(c) 方案 §13 登记为 E1 前置条件 | -| PR7-R8 | 一般 | `trusted_rules` 读 `origin/main:harness/rules.toml`,但本地 `refs/remotes/origin/main` 引用本身不受任何保护:`git update-ref refs/remotes/origin/main <伪造提交>`(reference-transaction 只拦 refs/heads/main 与 refs/tags/)或把 remote 指向伪造源后 fetch,即可让守卫读到伪造规则。specs §7 已知边界的现表述「规则文件已改为读 origin/main」会让读者以为工作区篡改已被堵住,实际只在不改引用时成立 | 复现(`/tmp` 临时仓库):构造 `protected_branches = []` 的 rules.toml 提交 → `git update-ref refs/remotes/origin/main <该提交>` 无拦截 → 此后非快进 `branch -f main` **放行**(main 被改写为孤儿提交),并打印「按 origin/main 的规则执行」的告警——告警读的正是伪造规则。另注:本 PR 合并前 origin/main 上没有 harness/rules.toml,`git show` 失败退回工作区版本(自举过渡),合并后首次 fetch 才切换到受保护版本 | 在「防误操作」定位下可接受,但 specs §7 已知边界须补两句:①本地 origin/main 引用可改写/可被伪造 remote 污染,有意绕过者可再次解除本机层,唯一硬边界仍是服务端 ruleset;②PR 合并前该机制退回工作区版本。不改代码也可,文档诚实优先 | -| PR7-R9 | 一般 | curl 写请求的拦截存在参数顺序盲区:`curl -X PATCH https://api.github.com/…`(动词在前)、`curl --request PATCH …`(长选项)、`curl -d @body https://api.github.com/…`(-d 在前)、`-XPOST` 连写均放行;只有「url 在前、动词在后」被拦。另 `gh pr merge` 未拦(R2 以上「由用户合并」目前仅靠约定,Agent 层本可拦) | 复现(`check_command` 直接调用,19 条用例):`curl -X PATCH https://api.github.com/x`、`curl --request PATCH https://api.github.com/x`、`curl -d @body https://api.github.com/x`、`curl -XPOST https://api.github.com/x`、`wget --post-data=@f …`、`python3 -c "requests.patch(…)"` 均放行;`curl https://api.github.com/x -X PATCH` 拦截 | curl 规则去掉顺序依赖(对 `curl` 与 `api.github.com` 共现 + 任一写动词/数据选项即拦,含 `--request`、`-X` 连写);补上述变体的负例测试与回放用例。wget/requests/间接展开归 E3,不在本轮。`gh pr merge` 是否由 Agent 层一律拒绝,交用户决定(影响 L4 下 R0/R1 的合法合并路径) | - -## 复评补充 - -- 两点方案风险(分工未运转 E11、标杆有效待 trial-001)按交接书要求不重复上报。 -- 本轮评审过程中命令守卫未误报(实验命令换行拆写后均正常执行);上一轮记录的字符串匹配误报面无恶化。 -- 复评环境:worktree `/tmp/pr7-rereview`、venv `/tmp/pr7-venv`(ruff 0.16.8),实验脚本 `/tmp/pr7-attacks/rereview_attacks.py` 及临时仓库(`/tmp/pr7-rere-r3-*`、`/tmp/rere-r2-*`),评审后已清理,未触及真实仓库与远端。 - diff --git a/docs/review/2026-09-27-harness-audit.md b/docs/review/2026-09-27-harness-audit.md deleted file mode 100644 index 4c464bf..0000000 --- a/docs/review/2026-09-27-harness-audit.md +++ /dev/null @@ -1,203 +0,0 @@ -# Harness 全链路审计(2026-09-27) - -审计方:Claude Code(设计与评审方)。标尺:[调研报告](../research/2026-09-23-agent-delivery-theory.md)第三节的 8 个环节与 3 个横切面,细到各节的节点,并对照第十七节「落地检查清单」逐条打勾。证据:`origin/main` 的 `565101e`、仓库代码与测试、GitHub 上的真实运行记录(2026-09-27 读取)。同日 Codex 在主工作目录写了一份复评(未提交),其结论本文逐条核对后并入,标为 C1–C5;本文新增的发现标为 G1–G11。 - -## 1. 结论 - -**主链已经跑通,八个环节都有落点,但只有「验证与门禁」「集成」两环形成了机器闭环;规格、规划、运行观察、度量四环主要靠约定和人。** 现在可以放心的是:Agent 自述不再算数、判定器改不了也骗不过、高风险改动必须经用户批准、历史缺陷不会悄悄回来。还不能宣称的是:「持续、稳定」有数据证明、R1 可以无人值守、执行环境彼此隔离。 - -交付概况(PR #7 起共 40 个):合并 38(自动 10、人工 28),关闭 2(#16、#35);改动行数中位 66,超过 400 行的 4 个;开 PR 到合并中位约 11 分钟;PR 上的 build 运行 64 次,失败 4 次。 - -| 环节 | 覆盖 | 一句话 | -|---|---|---| -| 1 需求与规格 | 部分 | 规格验收有机器映射;任务不挂规格编号,任务书自动合并不经用户审 | -| 2 上下文与知识 | 较好 | 地图短、状态在仓库;文档新鲜度无检查 | -| 3 规划与分解 | 弱 | 计划模板从未用过,预算靠自觉 | -| 4 执行环境 | 部分 | 三层护栏在;无隔离(多 Agent 共用目录)、无运行时熔断 | -| 5 验证与门禁 | 强 | verify、修复证据、base 测试、回放、变异、风险分级都在运行 | -| 6 集成与发布 | 集成强、发布未验证 | R0 自动合并与 R2+ 人审实测;非严格检查;首次发版未走过 | -| 7 运行与观察 | 弱 | 无执行轨迹留存、无停机开关、无发布后观察 | -| 8 反馈与改进 | 部分 | 缺陷能回流为测试与回放;新缺陷的回放无强制;只有一次试跑有数据 | -| 横切:安全 | 部分 | 公开仓库未开密钥扫描;同一 macOS 用户的凭据残余 | -| 横切:人的角色 | 较好 | 风险路由、自动请评审、升级包都在;评审方与设计方是同一方 | -| 横切:度量 | 弱 | 只有单 PR 计数与 trial-001 一张表 | - -## 2. 逐环节审计 - -每个节点给出:报告要求、当前实现(带证据)、差距、能否实现。 - -### 2.1 需求与规格(报告第四节) - -| 节点 | 当前实现 | 差距 | 可实现性 | -|---|---|---|---| -| 4.1 终态 + 约束 + 示例 | [任务模板](../templates/task.md)要求终态、非目标、前置条件、参考示例;trial-001、任务 002–004 都按此写成 | 只是约定,没有机器检查 | 不必机器化,靠评审 | -| 4.2 验收可执行化 | `acceptance.py` 每次 verify 检查规格验收表:69 条编号,54 条可自动化且都引用了存在的测试,19 条人工,缺口 0 | **G6**:只查测试存在,不查是否覆盖需求(H0926-7 即此逃逸);**G7**:任务 002–004 的验收编号都填「—」,没有挂到规格,不在检查范围 | G7 可机器化(小);G6 只能靠独立评审与真实数据证据缓解 | -| 4.3 规格驱动 | `docs/specs/` 为现役合同,按规模取用 | 新需求常直接写进任务书,规格没同步 | 随 G7 解决 | -| 4.4 准入与澄清 | 模板写明「需求模糊先回到任务书澄清」;决定记入方案 §10 | **C3**:任务书在 `docs/plans/`、属 R0,任务 002–004 的任务书都被自动合并,用户只在聊天里同意,仓库无审核记录 | 改风险规则即可(小,R3) | -| 4.5 任务模板 | 已有,含预算与升级包 | 「时长」预算一栏从未填写 | 随第三环处理 | - -### 2.2 上下文与知识(报告第五节) - -| 节点 | 当前实现 | 差距 | 可实现性 | -|---|---|---|---| -| 5.1 仓库即知识库 | AGENTS.md 51 行只做地图;规格、方案、调研、评审、决定分目录;[待办清单](../plans/backlog.md)为唯一未关闭清单;[harness 说明](https://github.com/SnowsonZ/delivery-harness/blob/main/README.zh-CN.md)给出理念与组件对照 | 无 | — | -| 5.2 系统对 Agent 可读 | 一条命令验证(`bin/verify`),输出只打结论,细节写日志 | 无 | — | -| 5.3 上下文预算 | 状态外置到文件与 git,中断可从 AGENTS.md 与待办清单恢复 | 无机制检查过时文档:Codex 发现方案开头仍写「P6 待试跑」;H0925-4、H0926-1 的状态曾过时到 2026-09-26 才改 | **G8**:链接与状态新鲜度可做轻量检查(小);内容正确性靠收尾核对 | -| 5.4 工具少而准 | 统一 CLI、verify、as-agent;守卫按命令结构判断 | 守卫把只读的 `gh release list` 也拒绝(对 `gh release` 一律拦) | 小修(G11) | -| 5.5 常见错误 | 历史误报与修正都有记录 | 无 | — | - -### 2.3 规划与分解(报告第六节) - -| 节点 | 当前实现 | 差距 | 可实现性 | -|---|---|---|---| -| 6.1 研究→计划→实现,人审前两步 | 规范要求 R2 及以上先按[计划模板](../templates/archive/plan.md)写计划交评审 | **G9**:计划模板从未使用,仓库里没有一份计划;任务 003、004 为 R3 也没有计划。实际由任务书承担计划(任务 004 写死了三个提交的顺序),效果尚可 | 建议并入任务书而非强制单独计划(小) | -| 6.2 一次只做一件事 | 一个任务一个 PR;PR 中位 66 行 | 无 | — | -| 6.3 任务粒度 | 任务均在一次执行方运行内完成 | 运行时长没有记录 | 随度量处理 | -| 6.4 确定性编排 + 智能体节点 | CI、风险判定、证据、自动合并全为确定性脚本;Agent 只做实现与评审 | 派发本身是手工命令,没有脚本 | 随 G1/G3 解决 | -| 6.5 并行与多 Agent | 角色分工明确(设计评审 vs 执行) | **G1**:没有归属与隔离规则,见第四环 | 见第四环 | -| 预算(报告 7.4 在此落地) | 模板写 CI 最多 3 轮、重试最多 2 次;执行方都遵守了 | 靠自觉,机器不比对(B7) | 中 | - -### 2.4 执行环境(报告第七节) - -| 节点 | 当前实现 | 差距 | 可实现性 | -|---|---|---|---| -| 7.1 隔离:每任务一个可丢弃环境 | 无。执行方与评审方都在主工作目录运行 | **G1**:2026-09-27 实际发生冲突:Codex 在主目录切到 `codex/harness-assessment` 并留下未提交改动,Claude 会话回来时目录已不在原分支;OpenCode 执行任务 002–004 也在主目录。网络与文件系统不受限 | worktree 隔离(小);网络沙箱(中,需评估各宿主能力) | -| 7.2 分层权限 | 三层护栏:Agent 层(Claude Code、Codex、OpenCode、Pi、Zcode 桌面版均实测拦截)、git 层(origin/main 规则)、服务端(ruleset、非推送者批准、单独 Agent 账号) | Zcode CLI/TUI 不执行工作区钩子;Codex 桌面版是否执行 `.codex/hooks.json` 未实测(只测了 `codex exec`);B5(Zcode 未拦批准工具);B10(同一 macOS 用户可读用户凭据) | 桌面版实测(小,需用户);B10 需单独系统用户(中) | -| 7.3 长时运行与状态外置 | 任务都能在一次运行内完成;状态在仓库 | 无需 | — | -| 7.4 预算、熔断、卡死检测 | 只有 CI 轮次与重试的书面预算 | 无时长、token 预算;无卡死检测;**G4** 无紧急停机开关 | 停机开关小;运行时熔断取决于宿主(中) | -| 7.5 harness 随模型演进 | 无 | 换执行方模型前没有回归评测 | 随 B17 做,数据量够再说 | -| 7.6 非确定性 | 无 | 没有同一任务多次运行的数据 | B17 | - -### 2.5 验证与门禁(报告第八节) - -| 节点 | 当前实现 | 差距 | 可实现性 | -|---|---|---|---| -| 8.1 分层验证 | verify 三档(quick/default/full):工具、lint、卫生、质量棘轮、验收映射、Python 测试(32 个文件、434 个用例)、Swift 策略与运行器测试、Zcode 自检、事故回放;CI 两个 job(Linux harness、macOS build),PR 上 64 次运行失败 4 次 | 无大缺口 | — | -| 8.2 独立评审 | [评审提示词](../templates/review-prompt.md)与[清单](../templates/review-checklist.md)、`review_pack.py`;PR #7 做过一次独立评审 | **G5**:任务 002–004 都是同一方写任务、派发、评审,没有独立上下文评审;评审结论从未与用户判断对照校准 | 流程可做(中:每个 R2+ PR 多一次评审) | -| 8.3 防作弊 | 执行方守卫禁改判定器;已有测试按 base 版本运行;修复证据要求修复前断言失败;41 个回放注入用例;6 组定向变异且得分只升不降 | **G2**:「每个修复要有回放」只对 v0.8.0 初始基线强制,新的缺陷编号(H0926-7、-8)是否补回放全靠评审方记得;base 测试不是留出测试;变异只覆盖列出的 Python 函数 | G2 小;留出测试与 Swift 变异为中到大,暂缓 | -| 8.4 有界重试 | 预算写在任务书,超限写升级包 | 同 2.3 | 同 B7 | -| 8.5 可合并高于测试通过 | 架构测试、质量棘轮、用户审 R2+ | Swift 复杂度不在质量棘轮内(只统计 Python 圈复杂度与文件行数) | **G10**:小到中 | -| 8.6 人审按风险路由 | R0/R1 由 App 批准自动合并,R2+ 自动请用户评审(#42 实测) | **C1**:R1 的判定只看提交里写的 `Risk: R1`、路径与现有测试,证明不了行为不变;R1 至今一次都没自动合并过;**C3** 见 2.1 | 改规则即可(小,需用户决定放权) | - -### 2.6 集成与发布(报告第九节) - -| 节点 | 当前实现 | 差距 | 可实现性 | -|---|---|---|---| -| 9.1 小而短命的 PR | 中位 66 行、开到合并约 11 分钟 | 无 | — | -| 9.2 主干常绿 | 必过检查 build、harness;非推送者批准 | **C2**:必过检查是非严格模式,PR 可能在旧 main 上通过后合并,组合后的 main 未必再测 | 改 ruleset(小,需用户导入) | -| 9.3 按风险分级发布 | tag 触发 release job,`release_check.py` 核对版本;environment `release` 需用户审批 | 首次真实发版未走过(B2);无自动回滚。桌面 App 以 zip 分发,自动回滚不适用,替代做法是快速重发与保留上一版下载 | 发版时验证(需用户);回滚改为书面步骤 | -| 9.4 环境隔离与生产访问 | 本项目无生产服务;Agent 没有发版权限(守卫拦 `gh release`、tag 规则) | 无 | — | -| 9.5 可追溯 | 提交带 Co-Authored-By;Agent 用 Snowson 身份;PR 带风险与证据摘要 | **G3**:执行方用的 Agent、模型、版本、派发提示词不入库也不写进 PR(只留在被忽略的 `build/`),例如 OpenCode 的 `glm-5.3-flash` 没出现在任何 PR 里 | 小到中(派发脚本自动写入) | - -### 2.7 运行与观察(报告第十节) - -| 节点 | 当前实现 | 差距 | 可实现性 | -|---|---|---|---| -| 10.1 全链路追踪 | CI 的 job summary 留有风险、证据、度量 | 执行方的运行日志不留存(G3) | 随 G3 | -| 10.2 运行信号与告警 | 产品有来源健康字段;CI 失败会通知 | harness 本身没有告警(例如自动合并连续失败、守卫误拦频率) | 中,先靠周报 | -| 停机与降级 | 无 | **G4**:自动合并出问题时如何立即停掉没有写下来,也没有开关 | 小 | -| 发布后观察 | trial-001 约定观察两周 | **C5/B19**:发版后观察与恢复口径未定义 | 小(先写人工步骤) | - -### 2.8 反馈与改进(报告第十一节) - -| 节点 | 当前实现 | 差距 | 可实现性 | -|---|---|---|---| -| 失败沉淀为 harness | 缺陷编号全局唯一;基线评审登记 H0925/H0926 系列;每个修复带回放;待办清单 | G2(新缺陷回放无强制);逃逸缺陷只在 trial-001 有一栏 | G2 小 | -| 周期性错误分析 | quality workflow 每周一定时跑回放、变异、复杂度 | 到 2026-09-27 只手动触发过一次,定时触发尚未验证 | 等下周一核对(零成本) | -| 熵治理 | 复杂度与大文件棘轮只降不升 | Swift 未纳入(G10);清理任务没有排期(B8 持续) | 小到中 | -| 试跑复盘 | trial-001 有完整记录表 | **G12**:任务 002–004 都没填「试跑记录」,度量只有一个样本 | 小(每个任务收尾填表,或由派发脚本生成草稿) | - -### 2.9 横切:安全与权限(报告第十二节) - -| 节点 | 当前实现 | 差距 | 可实现性 | -|---|---|---|---| -| 凭据 | 卫生检查拦凭据模式与本机路径;App 私钥只在只允许 main 的 environment 中 | **G13**:公开仓库的 GitHub secret scanning 与 push protection 都未开启(免费功能);B10 同一 macOS 用户 | G13 由用户开启(2 分钟);B10 中 | -| 三者取二(不可信输入、敏感访问、改变状态) | 执行方能联网、能读用户凭据(B10)、能推送 | **C4**:同时满足三项;目前靠守卫与服务端批准兜底 | 与 B10 一起决策 | -| 依赖供应链 | 开发依赖锁版本,改依赖为 R3 | 没有依赖更新提醒(无 Dependabot) | 小,价值低,可暂缓 | - -### 2.10 横切:人的角色与升级(报告第十三节) - -| 节点 | 当前实现 | 差距 | 可实现性 | -|---|---|---|---| -| 人只做设计、审证据与例外 | 用户做授权、信任、审批 R2+、真机验收;R2+ 自动请评审 | 无大缺口 | — | -| 升级包 | 模板有升级包;trial-001、task-002 实际用过 | 升级是否及时、是否准确没有记录 | 随度量 | -| 评审与设计分离 | 设计评审方与执行方分离 | G5:评审方同时是任务设计方 | 见 2.5 | -| 多个设计评审方的协作 | Codex、Claude Code 都是设计评审方 | **G1** 的另一面:没有「谁负责哪件事」的归属规则,2026-09-27 两方同时做同一件复评 | 规则小;可用待办清单的「负责」列标注会话 | - -### 2.11 横切:度量(报告第十五节) - -| 节点 | 当前实现 | 差距 | 可实现性 | -|---|---|---|---| -| 单 PR 计数 | `metrics.py` 在 CI 里统计新增测试、回放覆盖、CI 运行与失败 | 无汇总、无趋势 | 小 | -| 质量与稳定 | trial-001 与 v0.8.0 基线对比一张表 | C5/B17:没有按任务类别的多次运行数据(`pass^k`);自动合并的 PR「无需修改」是流程造成的,不能当质量指标;没有人工时间与 harness 成本(误拦、CI 等待)的记录 | 口径小,积累数据需要时间 | - -## 3. 第十七节检查清单 - -| 检查项 | 状态 | 说明 | -|---|---|---| -| 每个任务有可执行验收与非目标 | ✅ | 任务模板;但未挂规格编号(G7) | -| 按可验证性 × 风险分诊,模糊先澄清 | ⚠️ | 有风险分级;任务书不经用户审(C3) | -| AGENTS.md 约 100 行只做地图 | ✅ | 51 行 | -| 一条命令构建测试,输出精简 | ✅ | `bin/verify` | -| 每任务隔离环境,文件系统与网络受限 | ❌ | G1 | -| 凭据不进沙箱,不长期跳过权限 | ❌ | B10;执行方以非交互模式运行(`pi -a` 自动批准工具调用),只靠守卫与服务端兜底 | -| 时长、token、重试、CI 轮次预算 | ⚠️ | 只有重试与 CI 轮次,靠自觉 | -| 长任务有进度文件与逐步提交 | ✅ | 任务规模小,逐步提交已执行 | -| 测试、CI、lint 对实现类只读 | ✅ | 执行方守卫 + base 测试 | -| 最终验收在 Agent 之外重跑 | ✅ | CI | -| 独立上下文 AI 评审并经人工校准 | ❌ | G5 | -| 变异或属性测试衡量测试强度 | ✅ | 6 组定向变异 + 性质测试(仅 Python) | -| 改测试、CI、依赖、公共 API 自动升级 | ✅ | R3 路径 | -| PR 小而短命,主干常绿 | ⚠️ | 小而短命;非严格检查(C2) | -| 按风险分级发布,有回滚 | ⚠️ | 发布审批未实测;回滚不适用,需书面步骤 | -| 开发与生产隔离,恢复演练 | — | 无生产服务,不适用 | -| 每次运行有完整轨迹 | ❌ | G3 | -| 紧急停机开关与误差预算降级 | ❌ | G4;误差预算无数据 | -| 换模型或改提示词前跑回归评测 | ❌ | 数据量不足,暂缓 | -| 每周错误分析,事故转回归用例 | ⚠️ | 回归用例 ✅;周期分析未跑过 | -| 教训优先沉淀为自动检查 | ✅ | 缺陷→测试→回放 | -| 熵治理与复杂度趋势 | ⚠️ | 只有 Python | -| 人审按风险路由,升级包含证据与选项 | ✅ | | -| 度量升级精度与处理时长 | ❌ | 无 | -| 技能保持(轮岗、演练) | — | 单人项目,不适用 | - -## 4. 补齐计划 - -原则:先补**改动小、能堵真实漏洞**的;涉及放权策略的单独请用户决定;需要数据积累的等数据。 - -### 阶段一:马上做(约 1 天,评审方执行,合成 2 个 R3 PR 交用户审) - -| 项 | 内容 | 对应 | -|---|---|---| -| 1.1 | 风险规则:`docs/templates/**`、`docs/plans/task-*.md`、`docs/plans/backlog.md` 改为 R2(需用户审);历史研究、评审、普通说明仍为 R0 | C3 | -| 1.2 | 回放强制:PR 中每个非文档类 `Defect` 编号,head 上必须有回放用例、守卫测试或写明原因的暂缓项 | G2 | -| 1.3 | 派发脚本 `bin/dispatch`:为每个任务建独立 worktree,以 Agent 身份运行执行方,把 Agent、模型、版本、提示词摘要写进 PR 描述,提示词入库;规范写明主目录只留给用户 | G1、G3 | -| 1.4 | 任务书验收必须挂规格编号(或写明不挂的原因),`acceptance.py` 检查;计划并入任务书(新增「步骤与提交顺序」),删去「R2+ 先交计划」 | G7、G9 | -| 1.5 | 紧急停机:auto-merge 先读仓库变量 `AUTO_MERGE_ENABLED`,用户在网页上关掉即停;规范写停机与恢复步骤 | G4 | -| 1.6 | 守卫放行只读的 `gh release list/view`;Zcode matcher 补批准工具(B5,用户需重新信任 Zcode) | G11、B5 | -| 1.7 | 试跑记录:每个任务收尾必填记录表(派发脚本生成草稿),补填任务 002–004 | G12 | - -### 阶段二:需要用户决定(决定后评审方执行) - -| 项 | 内容 | 建议 | 代价 | -|---|---|---|---| -| 2.1 | 开启 secret scanning 与 push protection | 开(用户在设置里操作) | 无 | -| 2.2 | R1 暂改为用户批准,直到有 R1 样本并完成抽审 | 改 | R1 的 PR 多一次人工审批;目前 R1 数量为 0 | -| 2.3 | 必过检查改为严格模式 | 改 | PR 落后 main 时需同步后重跑 CI;单人仓库很少发生 | -| 2.4 | R2+ PR 增加独立上下文评审(另一个设计评审方按评审模板) | 先在 3 个 PR 上试行,再定 | 每个 PR 多一次评审 | -| 2.5 | 给 Agent 单独的 macOS 用户(B10) | 暂不做,明确接受残余风险;扩大无人值守前再做 | 中;环境与凭据要重建 | -| 2.6 | Codex 桌面版是否执行 `.codex/hooks.json` 做一次实测 | 做 | 用户在桌面版里发两条探针命令 | - -### 阶段三:等数据或触发条件 - -| 项 | 内容 | 触发 | -|---|---|---| -| 3.1 | 按任务类别多次运行、统计 `pass^k`、人工时间与 harness 成本(B17) | 同类任务积累到 5 个以上 | -| 3.2 | 预算自动比对(B7)、Swift 复杂度纳入棘轮(G10) | 阶段一完成后 | -| 3.3 | 按改动行变异测试(B4)、真实数据回放(B6)、SwiftUI 截图(B9) | 出现对应逃逸,或 CI 有稳定渲染基准 | -| 3.4 | 发布后观察与恢复步骤(B19)、首次发版审批实测(B2) | 下一次发版 | -| 3.5 | 核对每周质量检查的定时触发 | 2026-09-28(周一)之后 | - -## 5. 待办清单的对应 - -阶段一、二的每一项都记入[待办清单](../plans/backlog.md):Codex 复评的 C1–C5 沿用其编号 B14–B19(C4 即已有的 B10),本文新增 B20–B30。阶段三已在清单中的沿用原编号。 diff --git a/docs/review/2026-09-29-harness-status.md b/docs/review/2026-09-29-harness-status.md deleted file mode 100644 index a5b8ef2..0000000 --- a/docs/review/2026-09-29-harness-status.md +++ /dev/null @@ -1,111 +0,0 @@ -# harness 现状复核与下一阶段(2026-09-29) - -审查基线:main `b2e4fa8`(PR #64 合并后)。标尺:[调研报告](../research/2026-09-23-agent-delivery-theory.md)的八条原则(3.2)、五级成熟度(16.2)与落地检查清单(17.2);[目标态设计](https://claude.ai/code/artifact/a7646759-f838-49a8-aa1a-175b329ea1ed)第四至第十五节的设计项与第十六节路线;[2026-09-27 全链路审计](2026-09-27-harness-audit.md)的差距编号。各能力的证据以 [delivery-harness 规范](../specs/delivery-harness.md) §6 为准,本文不重复「已通过」的结论。 - -## 结论 - -- **目标态设计的阶段一(P1–P3)与阶段二(P4–P8)全部落地**(PR #49–#64),审计的 G1–G13、C1–C3 均已处理;C4(执行方同时具备不可信输入、敏感访问、改变状态三项)只部分缓解,C5(发版后观察)未做。 -- **成熟度:M1 完整,M2 的机制基本建齐,但 M2 的准入数据还没有。** 报告要求进入 M2 前有 20–50 个真实任务组成的评测集、目标类别 pass^k 达标、逃逸在预算内、能一键回滚;目前真实派发只有 1 个任务(T005),评测集为 0,误差预算的统计从 #50 起算,样本很少,发版回退未演练。 -- **下一阶段是设计中的阶段三「放权」**:以真实使用为主线,用派发真实任务产生数据,同时补齐评测集、实测降级与停机、首次发版演练;数据达标后按类别做放权决定。本次复核另发现 8 处与设计的出入,登记为待办 B34–B41(见文末)。 - -## 一、对照报告的八条原则 - -| 原则 | 落点 | 判断 | -|---|---|---| -| 1 先有判定器,再放权 | `bin/verify` 与 CI 同口径;任务书准入(`taskbook.py`);验收挂规格编号;R0 与业务任务书、补测试自动合并,其余人审 | ✅ | -| 2 确定性优先 | 风险判级、合并路由、派发的九个步骤、运行记录复核、周报都是脚本;Agent 只在实现、修复与评审三处工作 | ✅ | -| 3 生成与验证分离 | 执行方在槽位里实现,判定在执行方进程之外与 CI 中重跑;独立评审由非设计方、只读、只看材料 | ✅ 结构已有;独立评审试行 1/3 | -| 4 结构防护胜过提示词 | 三层守卫;执行方对判定器、合同、运行记录、议题只读;守卫从 origin/main 加载;执行方与评审方无 GitHub 凭据;评审方只读锁定 | ✅;残余见 C4 | -| 5 小批量、可回滚 | 一个任务一个 PR;400 行阈值;严格必过检查;revert 回滚 | ✅ 代码;发版回退未演练 | -| 6 状态外置、上下文从简 | 任务书、运行记录、待办、周报议题;AGENTS.md 51 行 | ✅ | -| 7 自治按类别 × 风险,数据驱动 | `autonomy.toml` 的类别自治等级、误差预算自动停该类、K3 三抽一 | ⚠️ 机制在,数据刚开始积累 | -| 8 失败沉淀为 harness 改进 | 缺陷编号、回放强制、周报突增、每周错误分析流程;本轮 #62 评审暴露的工具缺陷已修复并加测试 | ⚠️ 首次每周错误分析未做 | - -## 二、对照报告的落地检查清单(17.2) - -| 类别 | 条目 | 状态 | 说明 | -|---|---|---|---| -| 规格与上下文 | 可执行验收与非目标 | ✅ | 任务书合同与准入 | -| | 按可验证性 × 风险分诊,模糊先澄清 | ✅ | 类别 × 风险;执行方写澄清升级包 | -| | AGENTS.md 约 100 行只做地图 | ⚠️ | 51 行;设计要求的「超过 100 行即失败」未加进 `docs_check.py`(B34) | -| | 一条命令构建测试 | ✅ | `bin/verify` | -| 执行 | 隔离环境,文件系统与网络受限 | ⚠️ | 固定槽位 worktree 是工作隔离,不是安全隔离;网络与文件系统未受限(B31) | -| | 凭证不进沙箱 | ⚠️ | 执行方与评审方环境里没有 GitHub 令牌、gh 与 git 凭据;同一 macOS 用户仍能读用户文件(B10、B31);Pi 仍加载用户级扩展(B35) | -| | 时长、token、重试、CI 轮次预算 | ⚠️ | 时长、重试、CI 轮次由派发执行、CI 复核;token 只记录不设限(按决定 8) | -| | 长任务进度文件与逐步提交 | ✅ | 任务在一次运行内完成,逐步提交;运行记录 | -| 验证 | 测试、CI、lint 对实现只读 | ✅ | 守卫;已有测试按 base 版本重跑 | -| | 最终验收在 Agent 之外重跑 | ✅ | 派发本地判定 + CI | -| | 独立上下文 AI 评审并经人工校准 | ⚠️ | 工具与校准集已有;校准数据是 Pi 版本、评审提示词改动之前的,与现用 OpenCode 不同;试行 1/3 | -| | 变异或性质测试 | ✅ | 6 组变异只升不降;性质测试;41 个回放 | -| | 改测试、CI、依赖、公共 API 自动升级 | ✅ | 风险路由 R2/R3 | -| 发布与运行 | PR 小而短命,主干常绿 | ✅ | 严格模式、400 行 | -| | 按风险分级发布、自动回滚或特性开关 | ❌ | 桌面 App 尚未正式发版;B2、B19 | -| | 开发与生产隔离,备份恢复演练 | — | 本机 App,无生产服务;数据在 `~/.local/state`,恢复步骤随 B19 一并写 | -| | 每次运行完整轨迹,记录模型、提示词、工具版本 | ✅ | 运行记录入库,完整事件流留本机;本机轨迹保留期未实现(B40) | -| | 紧急停机与误差预算降级 | ⚠️ | 已建;停机未演练(B23),降级未被真实事件触发 | -| | 换模型或改提示词前先跑回归评测 | ❌ | 执行方评测集未建(P9);评审方有校准集 | -| 改进与人 | 每周错误分析,事故转回归用例 | ⚠️ | 周报每周自动生成;错误分析流程已写,第一次未做;事故转回放已强制 | -| | 教训优先沉淀为自动检查 | ✅ | 本轮新增的检查都有测试 | -| | 定期熵治理任务,监控复杂度趋势 | ⚠️ | Python 与 Swift 棘轮、文档检查已有;按热点生成清理任务的月度节奏未开始(B39) | -| | 人审按风险路由,升级包含证据与选项 | ✅ | 合并路由;派发的升级包 | -| | 度量升级精度与处理时长 | ⚠️ | 周报已有该项,尚无样本 | -| | 技能保持安排 | ⚠️ | 设计为每月读 2 条执行方轨迹、季度停机演练,未排期 | - -## 三、对照成熟度(16.2) - -| 级别 | 本项目 | -|---|---| -| M1 受监督执行 | ✅ 沙箱(工作隔离)中完成任务、统一 verify 入口、AGENTS.md;R2 以上人审 | -| M2 门禁自治 | 机制基本建齐:分层门禁、防篡改、独立评审(试行)、低风险类别自动合并加抽样审计、有界重试与升级。**准入条件未满足**:评测集 0 个(要求 20–50)、pass^k 无数据、逃逸预算样本少、回滚未演练 | -| M3 闭环自治 | 未开始:后台维护 Agent、渐进发布与自动回滚、停机演练、安全红队测试(本项目以注入回放在后台配置下全拦代替)、执行方单独系统用户(B31) | - -设计的 90 天目标是 M2(K1、K2 以数据站稳 L4,K3 按规则完成一次升级或明确不升),不进入 L5。 - -## 四、对照目标态设计各节 - -| 节 | 设计项 | 状态 | -|---|---|---| -| 四 需求与规格 | 任务书头部与准入、按类别审、执行方只读合同、验收挂编号、计划并入任务书、历史任务补头部 | ✅ P1;另按用户决定,设计方自行实现的工作也写任务书(方案 B) | -| 五 上下文与知识 | 文档断链检查;AGENTS.md ≤ 100 行检查;待办「进行中」须有分支名;执行方回报缺失的上下文或工具 | ⚠️ 断链与陈旧状态已有(P8);后三项未做(B34、B36) | -| 六 规划与派发 | 派发九步、认领、槽位、提示词入库、`dispatch review` | ✅ P4、P7;评测模式 `--eval --repeat` 未做(P9) | -| 七 执行环境 | 固定槽位、无凭据、时长与卡死与打转与 CI 预算、停机 | ✅ P4;守卫从 main 加载(用户确认的方案 B);用户级扩展仍加载(B35) | -| 八 验证与门禁 | 回放强制、R1 加强判定、Swift 棘轮、独立评审与校准、有界重试 | ✅ P2、P3、P7、P8;评审否决后「执行方修复一轮」未接入派发(B37);留出判定随评测集(P9) | -| 九 集成与发布 | 合并路由(风险、类别、预算、规模、运行记录)、严格模式、类别标签、抽审 | ✅ P2、P5;首次发版与重发上一版未演练(B2、B19) | -| 十 运行与观察 | 运行记录、停机、周报突增告警、发版后观察 | ⚠️ 运行记录、停机步骤、突增已有;运行记录的违禁内容检查未做(B38);发版后观察未做;用本 App 采集执行方用量核对运行记录(可选)未做(B41) | -| 十一 反馈与改进 | 周报、试跑记录汇总、评测集与 pass^k、逃逸转评测任务、月度清理、季度重审 | ⚠️ 周报与汇总已有(P6);评测集与逃逸转评测任务(P9)、月度清理(B39)、季度重审未开始 | -| 十二 安全 | 三者取二、密钥扫描、最小权限、破坏性动作硬拦截、凭据隔离 | ⚠️ 密钥扫描与严格模式已开;凭据隔离暂缓(B31,须跨平台) | -| 十三 人的角色与升级 | 升级触发器、升级包、escalation 标签与精度、注意力预算、技能保持 | ⚠️ 触发器与升级包、标签已有;「独立评审否决转执行方修复」(B37)与技能保持安排未做 | -| 十四 度量与误差预算 | 14.1 指标、北极星、误差预算、周报 | ✅ 周报含全部指标;多项「样本不足」 | -| 十五 自治等级 | 类别、`autonomy.toml`、升级人定、降级自动、抽审 | ✅ 机制;放权决策点未到 | - -## 五、下一阶段:阶段三「放权」(数据驱动,约 4–6 周) - -按依赖排序。每项只写做什么与完成标准,细节在对应待办或任务书中。 - -| 顺序 | 项 | 完成标准 | 负责 | -|---|---|---|---| -| 1 | **开始真实使用**:选 2–3 个高可验证、低风险的类别(K2 补测试、K4 有复现的缺陷修复,其次 K5 小功能),每周派发若干真实任务,一次一两个 | 每个任务都有运行记录、合并路由判定与(R2 以上)独立评审;周报开始有样本 | 设计方写任务书与派发,用户按类别审 | -| 2 | **本机后台评审常驻**:`bin/dispatch review --watch`;完成独立评审试行 2/3、3/3,由用户决定是否常态化(B27) | 3 个 R2 以上 PR 有评审结论并与用户判断对照 | 用户开常驻,设计方汇总 | -| 3 | **第一次每周错误分析**(2026-10-05 周报后) | `docs/review/weekly/2026-W41.md` 入库,沉淀项进待办 | 非本周主要设计方的评审方 | -| 4 | **停机演练**(B23) | 规范 §6 记录演练结果;无人值守派发之前必须完成 | 用户 | -| 5 | **P9 评测集**:≥ 20 个真实任务(历史缺陷修复与补测试),base_sha 与留出判定,`bin/dispatch --eval --repeat 3` | 每个任务在 base_sha 上判定失败、在原始修复上判定通过;pass^3 按类别进周报 | 设计方 | -| 6 | **P10 实测误差预算降级**:登记一个测试用逃逸,确认该类下一个 PR 转用户,关闭议题后仍计数 | 规范 §6 记录实测 | 设计方执行,用户确认 | -| 7 | **首次发版演练**(B2、B19):自用先行、发布审批实测、重发上一版的书面步骤、14 天观察 | 发版记录与观察记录入库 | 用户定版本号并审批 | -| 8 | **放权决策点**:K2 维持 L4(有数据);K3 是否升级(满 10 个抽审);独立评审是否常态化 | 每项决定附周报证据 | 用户 | - -并行的小修(R3,按主题合成少量 PR):B34–B41。 - -阶段三之后(进入 M3 或长时间无人值守之前):执行方凭据与系统隔离(B31、B10,须跨 Windows、Linux、macOS 评估);护栏指标连续 4 周达标;注入类回放在后台配置下全部被拦。 - -## 六、本次复核新登记的待办 - -| 编号 | 事项 | 来源 | -|---|---|---| -| B34 | `docs_check.py` 补两项:AGENTS.md 超过 100 行即失败;待办清单中写「进行中」的条目必须写分支名 | 设计第五节 | -| B35 | 派发 Pi 时改用 `--no-extensions` 再显式加载守卫:现在 `-na` 只忽略槽位中的项目文件,用户级扩展(`~/.pi/agent/extensions/` 下 4 个)仍会加载,执行环境不完全受控 | 本次复核 | -| B36 | 派发提示词要求执行方结束时报告「缺失的上下文或工具」,写进运行记录 `missing_context`,周报汇总,同类出现两次以上沉淀 | 设计第五节、10.1 | -| B37 | 独立评审结论为「不通过」时,派发的任务 PR 由执行方带评审发现修复一轮,仍不通过转用户 | 设计 13.2 | -| B38 | 运行记录内容检查:拒绝含命令全文、本机路径、会话正文的记录(`run_check.py`) | 设计 10.5 的机器验收 | -| B39 | 月度熵治理:按周报的复杂度热点生成 K3 行为不变重构任务并派发 | 设计 11.5 | -| B40 | 本机完整事件流(git 公共目录下 `dispatch/runs/`)保留 30 天后清理 | 设计 10.1 | -| B41 | 用本 App 采集的执行方用量核对运行记录的 token 与费用,偏差 10% 以内即采用(可选) | 设计 10.1 | diff --git a/docs/specs/delivery-harness.md b/docs/specs/delivery-harness.md index 7c4cd93..49dd8a6 100644 --- a/docs/specs/delivery-harness.md +++ b/docs/specs/delivery-harness.md @@ -1,8 +1,8 @@ -# 可验证交付 harness +# 可验证交付 harness(本仓库使用说明) -状态:现役(2026-09-25 起)。目标态与分阶段路线见[目标态设计](https://claude.ai/code/artifact/a7646759-f838-49a8-aa1a-175b329ea1ed),当前进展与下一阶段见 [2026-09-29 现状复核](../review/2026-09-29-harness-status.md);基线见 [2026-09-25 基线评审](../review/2026-09-25-harness-baseline.md)。早期的[可验证交付方案](../plans/verifiable-delivery.md)为历史文档,只保留 §10 决定记录与 §13 已完成事项。 +状态:现役(2026-09-25 起)。引擎与机制设计(判定器、三层护栏、风险判级与合并路由、派发与独立评审、可观测性)属独立开源项目 [delivery-harness](https://github.com/SnowsonZ/delivery-harness);理论调研快照、目标态设计、抽取决策与建设期评审记录自 2026-10-09 起归引擎仓库([目标态设计](https://github.com/SnowsonZ/delivery-harness/blob/main/docs/plans/2026-09-27-target-state-design.md)、[调研快照](https://github.com/SnowsonZ/delivery-harness/blob/main/docs/research/2026-09-23-agent-delivery-theory.md)、[抽取决策](https://github.com/SnowsonZ/delivery-harness/blob/main/docs/decisions/0001-harness-extraction.md)),本仓库只留引用。本文件只记本仓库的实例信息:命令入口、本仓库约定与配置值、平台设置、验证状态与已知边界;命令语义与机制设计的正源是引擎的 README(双语)与 SECURITY.md。 -harness 引擎是独立的开源项目 [delivery-harness](https://github.com/SnowsonZ/delivery-harness)(2026-09-29 从本仓库抽出,保留历史),以带锁文件的内置副本装在 `.harness/engine/`(版本、引擎提交与目录树哈希见 `.harness/engine.lock`,`bin/verify` 的 integrity 检查拒绝任何绕过升级的改动),只依赖 Python 标准库,不进发布包(构建只拷 `scripts/` 与 `bin/session-manager`)。本项目自己的规则与配置在 `.harness/config/`(`rules.toml`、`autonomy.toml`、`checks.toml`),棘轮状态在 `.harness/state/`,事故回放用例在 `.harness/project/replay_cases.py`。所有命令经 `bin/harness <子命令>`(`bin/verify`、`bin/dispatch` 为快捷入口)。升级引擎:在 delivery-harness 的检出中运行 `python3 engine/cli.py upgrade --target <本仓库>`,经 PR 合并。改动 `.harness/`、`bin/`、`.githooks/`、`.github/`、`.claude/`、`.opencode/`、`.pi/`、`.zcode/` 属于 R3,必须由用户批准。 +harness 以带锁文件的内置副本装在 `.harness/engine/`(版本、引擎提交与目录树哈希见 `.harness/engine.lock`,`bin/verify` 的 integrity 检查拒绝任何绕过升级的改动),只依赖 Python 标准库。本仓库规则与配置在 `.harness/config/`(`rules.toml`、`autonomy.toml`、`checks.toml`),棘轮状态在 `.harness/state/`,事故回放用例在 `.harness/project/replay_cases.py`。所有命令经 `bin/harness <子命令>`(`bin/verify`、`bin/dispatch` 为快捷入口)。升级引擎:在 delivery-harness 的检出中运行 `python3 engine/cli.py upgrade --target <本仓库>`,经 PR 合并。改动 `.harness/`、`bin/`、`.githooks/`、`.github/`、`.claude/`、`.opencode/`、`.pi/`、`.zcode/` 属于 R3,必须由用户批准。 ## 1. 命令 @@ -13,57 +13,50 @@ harness 引擎是独立的开源项目 [delivery-harness](https://github.com/Sno | `bin/verify --full` | 默认档 + 事故回放 | macOS CI(`--strict --full`);改动测试或产品逻辑后 | | `bin/verify --strict` | 被跳过的检查算失败 | macOS CI | | `bin/harness acceptance [--manual]` | 规格验收编号 ↔ 测试映射检查;列出人工验收清单 | verify 各档;写 PR 的人工验收部分时 | -| `bin/harness taskbook [任务书 --on-main]` | 任务书准入:YAML 头部(类别、风险、设计方、规模、架构级、规格编号、预算、回滚)、类别与风险相容、验收每行挂规格编号、中大任务的必备章节、按「步骤与提交顺序」所列文件交叉核对;`--on-main` 另要求任务书已合并到 main(派发前) | verify 各档;派发前 | -| `bin/harness review-pack --base origin/main` | 评审证据包:风险等级、修复证据、verify、涉及的验收编号 | 评审方评审前 | -| `bin/harness quality [--update]` | 熵治理棘轮:Python 复杂度超标函数数、超长文件数只降不升;Swift(`native/`,轻量解析)超过 500 行的文件数、函数体超过 60 行的函数数、大括号嵌套超过 6 层的函数数只降不升 | verify 默认档;每周 quality workflow | -| `bin/harness docs` | 文档熵治理:已跟踪的 README*.md、AGENTS.md、docs/、harness/README.md 中相对链接指向的文件必须存在(外链、纯锚点不查,`文件#锚点` 只查文件),断链即失败;「状态:」写着待执行、进行中、草案等且超过 30 天未提交的文档只报告 | verify 默认档与完整档 | -| `bin/harness metrics --base origin/main [--github]` | 交付度量:修复数、声称已修、修复带回放比例、新增测试、CI 轮次,并列 v0.8.0 基线 | CI harness job;试跑记录 | -| `bin/harness replay [--list]` | 把历史缺陷注入工作区副本,对应测试必须失败;列出基线覆盖 | `verify --full` | -| `bin/harness mutate [--check / --update]` | 定向变异测试,得分与 `.harness/state/mutation-baseline.json` 比较(只升不降) | 每周 quality workflow;补测试后 | -| `bin/harness evidence --base origin/main [--swift]` | 按 `Defect:` trailer 生成修复证据,验证修复前测试失败、修复后通过;`--swift` 同时编译运行引用编号的 Swift 测试(macOS,编译失败算出错);回放覆盖:非 doc 类、未撤销的编号在 head 的 `replay_cases.py` 中须有注入用例、守卫测试或写明原因的暂缓项,否则失败 | CI harness job(Python)与 macOS build job(含 Swift);实现方自查 | -| `bin/harness risk --base origin/main` | 按改动路径判定 R0–R3;声明 R1 时另跑 `r1_checks.py` 的加强判定 | CI harness job | -| `bin/harness policy --base origin/main --head --pr <编号> --branch <分支>` | 合并路由:风险、类别(`autonomy.toml` 中为 L4,任务书声明与机器判定一致)、误差预算(escape 议题、`budget-exceeded` 标签)、规模(400 行)、任务 PR 的运行记录与 CI 轮次,逐条写理由;K3 按 PR 编号哈希三抽一 | auto-merge 的判定步骤(main 上的代码) | -| `bin/harness run-check --base origin/main [--branch <分支>]` | 实现任务书的 PR(分支为 `task/<名字>` 且有对应任务书,或提交带 `Task:`):每个提交带 `Task: <编号>`;有格式完整、与任务书一致、exit 为 ok 的运行记录,提示词 sha256 一致;已完成的 build 轮次不超过 `budget.ci_rounds` | CI harness job(只报告);合并路由第 5 条(权威) | -| `bin/harness weekly [--publish]` | 周报:14.1 全部指标(样本不足时只报计数或标「样本不足」)、前 4 周对比的突增标红、各类误差预算与 K3 抽审进度、试跑记录自动汇总(含任务 002–004 的历史 PR,`docs/runs/history.json`);`--publish` 更新固定的「每周质量报告」议题并发当周评论 | 每周一 quality 工作流;需要时手动 | -| `bin/harness mutate --check --changed-since ` | 只核对改到其文件的变异目标,得分不得低于基线 | CI harness job,声明 R1 时 | -| `bin/harness base-tests --base origin/main` | 用 base 版本的已有测试在 head 上重跑:追加进已有测试文件的代码禁用不了判定器(有意改动已有测试的 PR 按 R2 评审,此项只报告);测试经 `.harness/engine/checks/base_tests_runner.py` 运行,产品代码在运行中篡改 unittest 时一律失败 | CI harness job | -| `bin/harness hygiene --staged / --range BASE` | 禁止路径、超大文件、凭据、新增行中的本机路径 | pre-commit、pre-push、CI | -| `bin/harness guard-git install` | 把 `core.hooksPath` 指向 `.githooks`(幂等,不覆盖已有设置) | 每个新环境一次 | -| `bin/dispatch run <任务书> [--resume] [--model M]` | 派发:准入(含已在 origin/main)→ 认领(推送 `task/<编号>-<名字>`,远端已有即停)→ 取槽位 → 守卫预检 → Pi 执行 → 执行方之外跑 `bin/verify`(失败带摘要重试,同一失败签名连续两次即打转)→ 提交运行记录、推送、开 PR → 等 CI(失败带摘要重试,超 `ci_rounds` 打 `budget-exceeded`);不能完成时升级(PR 评论或议题,`escalation` 标签) | 设计评审方,任务书合并后 | -| `bin/dispatch status` / `bin/dispatch stop --all` | 查看槽位;停机:终止所有正在运行的执行方(§8) | 设计评审方、用户 | -| `bin/dispatch review [--reviewer opencode\|pi\|codex\|claude-code]` | 独立评审:在只读的评审工作区(`<仓库名>-review`)中由非设计方评审任务书、PR 描述、diff、证据包与 CI 结论,结论以固定格式评论到 PR,并去掉 `needs-independent-review` 标签 | 设计评审方;通常由后台评审自动运行 | -| `bin/dispatch review --pending` / `--watch [--interval 5]` | 后台评审:逐个评审带 `needs-independent-review`、CI 已全部通过、当前 head 尚无独立评审结论的开着的 PR;`--watch` 每隔若干分钟一轮,停机标记存在即退出。不并行(多个 OpenCode 同时运行会冲突) | 本机常驻(终端中运行 `--watch`) | -| `bin/harness review calibrate --reviewer <评审方> [--limit N]` | 评审校准:回放用例重新注入的已知问题与已知良好的 PR,统计 TPR、TNR,结果写入 `evals/review/results/` | 改评审提示词或换评审模型后 | -| `bin/harness release-check --tag vX.Y.Z` | tag 与构建版本一致、构建号递增、tag 在 main 上 | 推 tag 时 CI 自动运行 | +| `bin/harness taskbook [任务书 --on-main]` | 任务书准入(头部、类别与风险相容、验收挂编号、必备章节、文件交叉核对);`--on-main` 另要求已合并到 main | verify 各档;派发前 | +| `bin/harness review-pack --base origin/main` | 评审证据包 | 评审方评审前 | +| `bin/harness quality [--update]` | 熵治理棘轮(Python 与 Swift,只降不升) | verify 默认档;每周 quality workflow | +| `bin/harness docs` | 文档链接与状态新鲜度检查 | verify 默认档与完整档 | +| `bin/harness metrics --base origin/main [--github]` | 交付度量 | CI harness job | +| `bin/harness replay [--list]` | 历史缺陷注入回放 | `verify --full` | +| `bin/harness mutate [--check / --update]` | 定向变异测试(与基线比较,只升不降) | 每周 quality workflow;补测试后 | +| `bin/harness evidence --base origin/main [--swift]` | 修复证据与回放覆盖核对 | CI harness job;实现方自查 | +| `bin/harness risk --base origin/main` | 按改动路径判定 R0–R3 | CI harness job | +| `bin/harness policy …` | 合并路由判定(风险、类别、预算、规模、运行记录,逐条写理由) | auto-merge 的判定步骤(main 上的代码) | +| `bin/harness run-check --base origin/main [--branch <分支>]` | 任务 PR 的运行记录复核 | CI harness job;合并路由第 5 条(权威) | +| `bin/harness weekly [--publish]` | 周报(指标、突增标红、误差预算、试跑汇总) | 每周一 quality 工作流 | +| `bin/harness base-tests --base origin/main` | base 版本已有测试在 head 重跑 | CI harness job | +| `bin/harness hygiene --staged / --range BASE` | 禁止路径、超大文件、凭据、本机路径 | pre-commit、pre-push、CI | +| `bin/harness guard-git install` | `core.hooksPath` 指向 `.githooks` | 每个新环境一次 | +| `bin/dispatch run <任务书> [--resume] [--model M]` | 派发(准入→认领→槽位→守卫预检→Pi 执行→本地判定→记录→推送开 PR→等 CI→升级) | 设计评审方,任务书合并后 | +| `bin/dispatch status` / `bin/dispatch stop --all` | 槽位;停机(§8) | 设计评审方、用户 | +| `bin/dispatch review [--reviewer …]` | 独立评审(只读工作区,结论评论到 PR) | 设计评审方;后台评审自动运行 | +| `bin/dispatch review --pending` / `--watch` | 后台评审常驻 | 本机常驻 | +| `bin/harness review calibrate --reviewer <评审方>` | 评审校准(TPR、TNR) | 改评审提示词或换评审模型后 | +| `bin/harness release-check --tag vX.Y.Z` | 发版核对 | 推 tag 时 CI 自动运行 | `verify` 终端只打印结论,完整输出在 `build/verify/<检查名>.log`,汇总在 `build/verify/summary.json`。判断通过只认退出码和 CI 上当前 head 的运行。 -## 2. 约定 - -- **修复提交**:说明中加一行 `Defect: <编号>`(放在哪一段都行,不依赖 git trailer 规则);纯规格或文档修复写 `Defect: <编号> doc`。测试里用同一个编号标注(注释或说明均可),evidence 据此定位测试。给早已修复的缺陷补回归测试或护栏(例如把运行时缺陷改成编译错误、抽出可测的纯函数)不是修复,不带 `Defect:`:此时退回改动只会让测试编译不过,得不到「修复前失败」的证据;覆盖由评审方加入的回放用例证明(任务 003)。 -- **修复前必须以断言失败结束**(对应 TDD:编译报错不算「红」,要先让测试能编译、看它因正确的原因失败)。修复需要新增函数或接口时,分两个提交:先用不带 `Defect` 的提交抽出可测位置,行为保持旧的(带 `Risk: R1`);再在带 `Defect` 的提交里改行为并加测试。evidence 只退回带 `Defect` 的提交,函数仍在、行为回到旧的,测试便以断言失败结束。范例:任务 004(PR #39)。 -- **编号写错时撤销,不改写历史**:在 PR 的后续提交里加一行 `Defect-Withdrawn: <编号>`,evidence 不再核对该编号,证据摘要里标「已撤销」,评审可见。只能撤销本 PR 中更早声明过的编号;撤销后又重新声明的,仍按修复核对。 -- **PR 正文与评论用文件传入**:`gh pr create --body-file`、`gh pr comment --body-file`,不在双引号里写 Markdown。双引号内的反引号是 shell 命令替换,会真的执行其中的命令(2026-09-26 评审方把 `` `gh pr merge` `` 写进 `--body "…"`,被命令守卫拦下)。 -- **缺陷编号全局唯一**:`<来源>-<序号>`,例如 `V080-R17`(v0.8.0 交付评审第 17 项)、`REV0921-R2`(2026-09-21 评估第 2 项)、`H0925-4`(2026-09-25 harness 建设中的发现)。不再使用裸 `R17`。 -- **每个修复都要能被回放**(2026-09-28 起由 evidence.py 强制,审计 G2):PR 中每个非 doc 类、未撤销的 `Defect` 编号,head 上的 `.harness/project/replay_cases.py` 必须有注入用例、守卫测试(`GUARDED`)或写明原因的暂缓项(`DEFERRED`),否则 harness job 与 macOS build job 失败;v0.8.0 基线之后的新缺陷一视同仁。回放用例是判定器:执行方在 PR 里写明注入点,由评审方在**同一个 PR** 里加入(H0926-2);该 PR 因此改到 `harness/`,按 R3 由用户批准。注入后是否真的失败由 `verify --full` 的回放检查核对。 -- **执行方可编辑的 harness 数据**:`harness/**` 对执行方整体禁改,唯一例外是 `.harness/state/acceptance-gaps.txt`(补完测试后删行)。它只能缩减,新增条目 risk.py 判 R3。 -- **已知缺陷登记**:发现但暂不修的缺陷写成确定性测试并标 `@unittest.expectedFailure`,说明里写编号与待决事项;修好后它会「意外通过」并报错,逼着移除登记。 -- **验收编号**:每份规格的验收表含「证据类型」「覆盖」两列,编号前缀按规格区分——W(桌面组件)、U(用量金额)、DR(工作日报)、IN(统一收件箱)、CB(CLI 会话绑定)、ZN(Zcode 导航)。可自动化条目必须有真实存在的测试;暂缺的登记在 `.harness/state/acceptance-gaps.txt`(带原因,只能缩减)。 -- **任务书即合同**(2026-09-28 起):任务按 [task.md](../templates/task.md) 写,开头是 YAML 头部(`task`、`class`、`risk`、`designer`、`size`、`architecture`、`spec_refs` 或 `no_spec_reason`、`budget`、`rollback`),正文含终态、非目标、前置条件、验收、步骤与提交顺序、升级包;由 `.harness/engine/checks/taskbook.py` 准入。计划并入任务书的「步骤与提交顺序」,不再单独交计划(计划模板已归档到 `docs/templates/archive/`)。验收表每行的编号是现役规格中的编号、`新增:<规格文件>#<编号>`(同一改动在规格里新增)或 `不挂规格:<原因>`,新需求先进规格再进任务书。执行方对任务书与规格只读(守卫拒绝),需要改合同时写升级包(含澄清)。历史任务 002–004 登记在 `.harness/state/taskbook-exempt.txt`,只检查头部,清单只能缩减。 -- **设计方自行实现也要有任务书**(用户 2026-09-28 决定,方案 B):设计评审方自己实现的工作(如护栏改动)同样先写任务书,与实现放在同一个 PR 中,照常过准入检查,提交带 `Task: <编号>`;独立评审以它为对照。这类 PR 不经派发脚本,不要求运行记录(`run_check.py` 按「任务书随本 PR 提交」识别),本就由用户审批。派给执行方的任务仍须先合并任务书再派发。 -- **任务书的审查按类别**(2026-09-28 决定 1):K7 护栏与流程、K8 发版、`architecture: true`(跨两个以上模块、新增或修改公共接口如 CLI 输出与数据格式、数据迁移、新增依赖)的任务书由用户审(R2);其余类别(业务修改、缺陷修复等)的任务书通过准入检查即自动合并(R0)。模板与待办清单由用户审(R2)。类别写低不影响安全:实现 PR 仍按实际改动路径判级。 -- **独立评审**(试行,2026-09-28 决定 5;设计 8.3):R2 及以上的 PR 在 CI 通过后由 auto-merge 打上 `needs-independent-review`,本机的后台评审(`bin/dispatch review --watch`)在 CI 通过后自动评审,不占用用户等待时间;PR 有新推送时 auto-merge 在 build 通过后重新打标签,自动重评。评审方不能是设计方:有任务书时看头部 `designer`,没有时看提交的 `Co-Authored-By`。默认评审方由 `rules.toml [review] reviewer` 指定:用户 2026-09-28 定为 OpenCode(`zai-coding-plan/glm-5.3`,只读的 plan 代理,避开执行方 Pi);Pi、Codex(`gpt-6-sol`、推理强度 max)与 Claude Code 可用 `--reviewer` 选。评审方与该 PR 的执行方同一宿主时,评论里会标出独立性较弱。评审方只看任务书、PR 描述、diff 与 `review_pack.py` 证据包,不看执行过程;结构上只读(OpenCode 用 plan 代理、`--pure` 不加载插件,并以配置关掉 bash、子代理、网页与写入类工具:plan 代理本身只禁止编辑,2026-09-28 实测它曾在评审中运行 PR 的测试与 `gh`;Pi 只开放 read、grep、find、ls 且不加载项目文件,Codex `-s read-only`,Claude Code 只开放 Read、Grep、Glob),环境里没有 GitHub 凭据,结论由派发脚本评论到 PR。评审方本身失败(报错、超时、额度用尽)记为「评审失败」:不评论为结论、保留待评审标签,校准时不计入 TPR、TNR;校准逐个样本落盘,`--resume` 续跑,连续失败 3 次即停。结论只是给用户的输入,不替代用户审批。先试行 3 个 R2 PR,由用户决定是否常态化;30 个 R2 PR 中若没有发现用户未发现的问题,降为抽样。评审提示词 `.harness/engine/prompts/review_prompt.md` 与校准集 `evals/review/samples.json` 属 R3。人工评审仍可按 [review-prompt.md](../templates/review-prompt.md) 与 [review-checklist.md](../templates/review-checklist.md) 进行。 -- **测试的几种形态**:种子固定的性质测试(`tests/test_properties.py`,`PROPTEST_SEEDS=N` 放大搜索)、架构适应度(`tests/test_architecture.py`,同一口径只实现一次)、CLI 黄金快照(`tests/test_golden.py`,有意改变时 `UPDATE_GOLDEN=1` 重新生成,按 R2 评审)。 -- **护栏规则先合并**:本机 git 守卫按 origin/main 上的 `.harness/config/rules.toml` 执行(评审 PR7-R3),改规则的 PR 合并前,依赖新规则的文件在本机提交会被拒。放宽类规则(如新增 `[hygiene] allowed` 例外)与依赖它的文件分两个 PR:先合并规则,再提交文件。 -- **行为不变的重构**:每个提交带 `Risk: R1`;risk.py 核对只改产品代码、已有测试与黄金快照零改动,另由 `r1_checks.py` 核对被改函数签名不变(Python 按 AST,Swift 按声明文本;新增函数不限)、无新依赖(Python 只能新增标准库与仓库内模块,Swift 不新增 import)、无建表改表语句、增删不超过 400 行,任一不满足按 R2(2026-09-28 决定 2)。变异得分不降要执行代码,由 build 的 harness job 在声明 R1 时运行,下降即失败;想按 R2 走的重构加一个不带 `Risk: R1` 的提交即可。 -- **逃逸与抽审登记**(2026-09-28 决定 9):合并后才发现、本应被门禁或评审拦住的缺陷,任何人(含 Agent)开议题,加 `escape` 与 `class:<类别>` 标签,正文写明「引入:#」;不写会话正文。已关闭的议题照样计数。K3 被抽中的 PR 合并后由 auto-merge 开 `audit` 议题,评审方审完关闭,发现问题另开 escape 议题。PR 的类别标签 `class:<类别>` 由 auto-merge 打上,是误差预算窗口的依据。逃逸用议题模板「逃逸登记」(`.github/ISSUE_TEMPLATE/escape.yml`)。升级(`escalation`)由处理人处理后加 `escalation:needed` 或 `escalation:unneeded`,周报据此算升级精度与处理时长。 -- **每周错误分析**(设计 11.1):周一周报出来后,由不是本周主要设计方的评审方看本周全部异常(失败或超预算的运行、升级、CI 失败、守卫拒绝、评审发现、逃逸),逐条写问题、归入基线评审的失败分类,决定沉淀形式(能自动检查的写成守卫、lint 或测试);沉淀项进待办清单,结论存 `docs/review/weekly/<年-周>.md`(R0)。 -- **不手写通过状态**:PR 与交付说明里的「测试通过」「CI 通过」「已修复」一律由 CI 的 harness job summary 与 run 链接代替。 -- **派发**(2026-09-28 起,设计 6.2):执行方任务经 `bin/dispatch` 派发,不在主目录运行执行方;主目录只留给用户,设计评审方也在自己的 worktree 或槽位中工作。槽位是仓库同级的固定目录 `<仓库名>-slot-`(`rules.toml [dispatch]`,默认 3 个),每次派发从 origin/main 重建分支并清理未跟踪文件(保留 `scratch/iterm-probe-venv`,指向主目录的运行时)。执行方以 `Snowson` 的提交身份工作,但**拿不到任何 GitHub 凭据**:继承的令牌被去掉、gh 指向空配置目录、git 凭据助手清空;推送、开 PR、评论由派发脚本经 `bin/as-agent` 完成。预算取自任务书头部:`wall_clock_min` 是执行方的累计时长,`retries` 是本地重试,`ci_rounds` 是 CI 轮次;15 分钟既无输出也无文件变化判为卡死。执行方卡住时写 `build/dispatch/escalation.md`(可选方案、需要决定的问题),派发脚本补上状态、已尝试方案与证据后升级。 -- **运行记录**:每次推送带一份 `docs/runs/<任务书名>/<序号>.json`(R0)与渲染后的提示词 `<序号>.prompt.md`:宿主、版本、模型、提示词 sha256、守卫取自的 main 提交、时长与退出方式、重试与失败签名、守卫拒绝次数(按理由计)、token 与费用。只存结构化摘要;完整事件流留在本机 git 公共目录下的 `dispatch/runs/`,不入库。执行方不能编辑 `docs/runs/**`。提示词模板 `.harness/engine/prompts/dispatch_prompt.md` 属 R3。CI 侧由 `run_check.py` 复核(合并路由第 5 条):即使绕过派发脚本手工派发,缺记录、缺 `Task:` 或 CI 轮次超预算的 PR 也不会被自动合并;交付度量另在 job summary 中列出「CI 轮次 / 预算」。 -- **减少审批次数**(用户 2026-09-28 决定,先执行、阶段二结束后按数据复核):判级规则不放宽,靠攒批减少 PR 数。①记录类改动(规范 §6 验证状态、待办关闭与状态更新、实测结果)不单独开 PR,并入下一个实质性 PR;没有合适的 PR 时,当天的记录攒成一个。②相关的 R3 小改动按主题合成一个 PR(设计 16 章),不拆成零碎的护栏 PR。 - -## 3. 风险等级 +## 2. 本仓库的约定 + +- **修复提交**:说明加 `Defect: <编号>`(纯规格或文档修复写 `Defect: <编号> doc`),测试用同一编号标注。修复前必须以断言失败结束;需新增函数或接口时分两个提交(先不带 `Defect` 抽出可测位置、行为保持旧的、带 `Risk: R1`)。编号全局唯一 `<来源>-<序号>`(本仓库历史来源如 `V080-R17`、`REV0921-R2`、`H0925-4`),写错用 `Defect-Withdrawn: <编号>` 撤销,不改写历史。 +- **回放强制**:PR 中每个非 doc 类、未撤销的 `Defect` 编号,head 的 `replay_cases.py` 必须有注入用例、守卫测试(GUARDED)或写明原因的暂缓项(DEFERRED),否则 CI 失败;注入用例由评审方在同一个 PR 里加入。 +- **PR 正文与评论用文件传入**(`--body-file`),不在双引号里写 Markdown。 +- **执行方可编辑的 harness 数据**:仅 `.harness/state/acceptance-gaps.txt`(补完测试后删行,只能缩减,新增判 R3)。 +- **已知缺陷登记**:写成确定性测试并标 `@unittest.expectedFailure`,说明写编号;修好后「意外通过」逼着移除登记。 +- **验收编号**:前缀按规格区分——W(桌面组件)、U(用量金额)、DR(工作日报)、IN(统一收件箱)、CB(CLI 会话绑定)、ZN(Zcode 导航);暂缺的登记 `acceptance-gaps.txt`。 +- **任务书即合同**:按 [task.md](../templates/task.md) 写(YAML 头部 + 终态、非目标、验收、步骤与提交顺序、升级包)。审查按类别:K7、K8、`architecture: true`、头部不合格与删除任务书由用户审(R2),其余过准入即自动合并(R0)。执行方对任务书与规格只读,改合同写升级包。设计方自行实现的工作也写任务书(与实现同一个 PR,不经派发、不要求运行记录)。 +- **独立评审**:R2 及以上 CI 通过后由 auto-merge 打 `needs-independent-review`,本机后台评审(`--watch`)自动评审、新推送自动重评;评审方不能是设计方。默认评审方 `rules.toml [review] reviewer`(OpenCode,`zai-coding-plan/glm-5.3`),可用 `--reviewer` 选 Pi、Codex、Claude Code。结论只是输入,不替代用户审批。 +- **行为不变的重构**:每个提交带 `Risk: R1`,加强判定(签名不变、无新依赖、不超 400 行)由引擎执行;变异得分不降由 CI 核对。 +- **逃逸与抽审登记**:合并后才发现、本应被拦住的缺陷,开议题加 `escape` 与 `class:<类别>` 标签,正文写「引入:#」;K3 抽中的 PR 合并后由 auto-merge 开 `audit` 议题。升级处理后加 `escalation:needed` 或 `escalation:unneeded`。 +- **每周错误分析**:周报出来后由不是本周主要设计方的评审方看本周全部异常并写结论,存 `docs/review/weekly/<年-周>.md`(R0),沉淀项进待办。 +- **不手写通过状态**:「测试通过」「CI 通过」「已修复」一律由 CI 的 job summary 与 run 链接代替。 +- **派发**:执行方任务经 `bin/dispatch` 在槽位(仓库同级 `<仓库名>-slot-`,3 个)运行,不在主目录;执行方以 `Snowson` 提交身份工作但拿不到 GitHub 凭据,推送、开 PR、评论由派发脚本经 `bin/as-agent` 完成;预算取任务书头部(`wall_clock_min`/`retries`/`ci_rounds`)。 +- **运行记录**:每次推送带 `docs/runs/<任务书名>/<序号>.json` 与提示词快照(R0),执行方不能编辑;CI 由 `run-check` 复核。 +- **减少审批次数**:记录类改动并入下一个实质性 PR;相关 R3 小改动按主题合成一个 PR。 +- **护栏规则先合并**:改规则的 PR 合并前,依赖新规则的文件在本机提交会被拒;放宽类规则与依赖文件分两个 PR。 + +## 3. 风险等级(本仓库路由结果) | 等级 | 判定(`.harness/config/rules.toml [risk]`) | 合并 | |---|---|---| @@ -72,134 +65,50 @@ harness 引擎是独立的开源项目 [delivery-harness](https://github.com/Sno | R2 | 产品代码、现役规格、AGENTS.md;模板与待办清单;K7、K8、架构级或头部不合格的任务书;删除任务书;改动或删除已有测试;改动黄金快照 | 评审方评审 + 用户看证据包后合并 | | R3 | 护栏、CI 与发布、依赖、报告迁移、快照与隐私、用户配置安装、运行时入口 | 用户批准 | -自动合并由 `.github/workflows/auto-merge.yml` 执行:build 完成后以 `workflow_run` 触发,检出 main、用 main 上的 `policy.py` 判定(内部调用 `risk.py` 对 PR 的 diff 重新判级;只读 diff、提交说明、PR 标签与议题,不执行 PR 的代码),五条判定全部满足才以 `--match-head-commit` 合并本次评估过的提交,每条理由写进 job summary;fork 与失败的运行不处理。 +自动合并由 main 上的 auto-merge 工作流执行,五条判定(风险、类别、预算、规模、运行记录)的机制与理由输出见引擎 README「合并路由」;本仓库的路径映射与预算窗口在 `rules.toml`、`autonomy.toml`。 -| 判定(按顺序) | 满足条件 | 不满足时 | -|---|---|---| -| 风险 | R0 或 R1 | 转用户评审 | -| 类别 | 机器判定的类别(K0 合同、K1 说明、K2 补测试、K3 重构、K4 修复、K5 功能、K6 界面、K7 护栏)在 `.harness/config/autonomy.toml` 中为 L4;提交带 `Task: T<编号>` 时,main 上该任务书声明的类别与机器判定一致 | 转用户评审(声明不一致按「未分类」) | -| 预算 | 该类最近 N 次合并的 escape 议题不超预算(K0–K2:20 次内 ≤ 1;K3:10 次内 = 0);PR 不带 `budget-exceeded` 标签;读不到标签或议题时按不满足 | 该类自动合并暂停,直到用户改 `autonomy.toml` 恢复 | -| 规模 | 增删行数(不计 `tests/golden/**`、`docs/runs/**`)≤ 400 | 转用户评审,提示拆分 | -| 运行记录 | 实现任务书的 PR:提交都带 `Task:`,有合格的运行记录(exit 为 ok),已完成的 build 轮次(按不同 head 提交计)≤ 任务书 `ci_rounds`;读不到 build 运行按不满足;不是在实现任务书的 PR 不要求 | 转用户评审:缺记录说明未经 `bin/dispatch` 或记录不全,超预算说明反复试错 | - -放权只能由用户改 `.harness/config/autonomy.toml`(R3),降级自动生效。K3 自动合并的 PR 按编号哈希每 3 个抽 1 个开 audit 议题,满 10 个抽审无问题后由用户调低比例。判定放在这里而不是 PR 自己的 CI 里,是因为 `pull_request` 事件执行的是 PR 分支里的 workflow 定义。 - -## 4. 三层护栏 - -| 层 | 内容 | 能否被绕过 | -|---|---|---| -| 服务端 | `.github/rulesets/main.json`:main 禁删除与改写,必须经 PR,`build` 与 `harness` 检查必须通过,且 PR 须基于最新 main(严格模式);`release-tags.json`:`v*` tag 禁移动与删除;release job 走 environment `release`,由用户批准 | 本机 Agent 无法绕过 | -| git | `.githooks/pre-commit`(保护分支上禁止提交、暂存区卫生、快速 verify);`pre-push`(禁推 main 与 tag、禁强制推送、本次推送的改动卫生、完整 verify);`reference-transaction`(禁本地改写或删除 main、移动或删除 tag,含 filter-repo) | 防误操作,不防有意绕过:`--no-verify`、改 `core.hooksPath`、改守卫代码或运行时解释器都能绕过(规则文件已改为读 origin/main);Agent 层拒绝其中能识别的命令 | -| Agent | `.harness/engine/guards/command_guard.py`:拒绝改写历史、强推、推 main 与 tag、建删 tag、跳过钩子、设置覆盖变量、`reset --hard`、不带 venv 排除的 `git clean -x`、删除工作区外路径、`gh release`(只读的 `list`、`view` 放行)与删除 CI 记录、GitHub API 写请求(`gh api` 写方法与对 api.github.com 的 curl 写请求);删除议题,撤下或删改登记标签(`escape`、`audit`、`escalation`、`budget-exceeded`、`class:K*`,含 MCP 的删除议题与标签工具);引号或反斜杠拆写的命令另按去掉引号的形式再查一遍;Agent 自行合并 PR(`gh pr merge` 与 MCP 的合并、开启自动合并工具,用户决定 D4);`--role implementer` 另禁编辑判定器与护栏、合同(`docs/plans/task-*.md`、`docs/specs/**`)与运行记录(`docs/runs/**`),以及关闭、重开、改动议题和标签(`gh issue close/edit…`、`gh pr edit --add/remove-label`、`gh label`、MCP 的议题写工具)。设计评审方可以关闭审完的 audit 议题 | 取决于各家 hook 能力 | - -覆盖变量只供人使用(Agent 层会拒绝设置它们的命令): - -| 变量 | 放开 | -|---|---| -| `HARNESS_ALLOW_MAIN=1` | 在 main 上提交、推送 main | -| `HARNESS_ALLOW_TAG=1` | 推送 tag(发版) | -| `HARNESS_ALLOW_REWRITE=1` | 本地改写或删除 main、移动或删除 tag、强制推送 | -| `HARNESS_SKIP_VERIFY=1` | 钩子中跳过 verify | +## 4. Agent 接入(本仓库实例) -Agent 层按角色接入: +三层护栏(服务端 ruleset、git 钩子、Agent 命令守卫)的设计与信任模型见引擎 README 与 SECURITY.md。本仓库各宿主的接入: | Agent | 角色 | 接入 | |---|---|---| -| Claude Code | 设计与评审 | 项目级 `.claude/settings.json` 的 PreToolUse(Bash 与 MCP 合并工具),自动生效 | -| Codex | 设计与评审 | 项目级 `.codex/hooks.json` 的 `PreToolUse`(不设 matcher,所有工具都交给守卫),从 git 仓库根调用 `command_guard.py --format claude --role designer`。**须经用户信任后才运行**:未信任时 `codex exec` 静默跳过、命令照常执行;交互界面启动时提示「Hooks need review」,信任后记入用户级 `~/.codex/config.toml`(§5 第 4 步)。`hooks.json` 内容一改就要重新信任;只改守卫脚本不用。不用用户级钩子,以免影响其他项目。`.codex/` 其余内容禁止入库 | +| Claude Code | 设计与评审 | 项目级 `.claude/settings.json` 的 PreToolUse,自动生效 | +| Codex | 设计与评审 | 项目级 `.codex/hooks.json` 的 `PreToolUse`,须用户信任后才运行;`.codex/` 其余内容禁止入库 | | OpenCode | 执行 | 项目级插件 `.opencode/plugin/harness-guard.js`,`--role implementer` | -| Pi | 执行 | 项目级扩展 `.pi/extensions/harness-guard.ts`(`tool_call` 事件拦截,`--role implementer`)。**只在项目被信任后加载**:未信任时(含 `pi -p` 且无保存的信任)扩展不加载、命令照常执行,只剩 git 与服务端两层;在主目录手动使用 Pi 时须按 §5 第 5 步信任本项目。经 `bin/dispatch` 派发时不依赖信任:`pi -na -e <守卫>` 忽略槽位中的项目文件,显式加载从 origin/main 导出的守卫(2026-09-28 实测:未信任的目录中守卫加载并拒绝了执行方关闭议题,仓库 AGENTS.md 仍在上下文中) | -| Zcode | 执行 | 项目级 `.zcode/config.json` 的 `PreToolUse`(Bash、Edit、Write 与 MCP 的合并、评审批准、议题、标签类工具;2026-09-28 补上批准类,B5),调用 `command_guard.py --format claude --role implementer`,退出码 2 即拦截。工作区钩子须经用户信任后才执行(§5 第 6 步),未信任时状态为 `pending_trust`、不执行。**只在桌面版 ZCode.app(协议服务端宿主)生效**(2026-09-26 实测拦截);**CLI 与 TUI 不执行工作区钩子**,且没有参数可以打开(用户决定不改 Zcode、不用用户级钩子,以免影响其他项目)。用 Zcode 当执行方时用桌面版。`.zcode/` 其余内容是 Zcode 运行数据,仍禁止入库(`[hygiene] allowed` 只放行这一个文件) | +| Pi | 执行 | 项目级扩展 `.pi/extensions/harness-guard.ts`(只在项目被信任后加载);经 `bin/dispatch` 派发时不依赖信任(`pi -na -e <守卫>`) | +| Zcode | 执行 | 项目级 `.zcode/config.json` 的 PreToolUse;只在桌面版 ZCode.app 生效,CLI 与 TUI 不执行工作区钩子;`.zcode/` 其余内容禁止入库 | + +覆盖变量只供人使用(Agent 层拒绝设置):`HARNESS_ALLOW_MAIN=1`、`HARNESS_ALLOW_TAG=1`、`HARNESS_ALLOW_REWRITE=1`、`HARNESS_SKIP_VERIFY=1`。 ## 5. 一次性设置(用户) -1. GitHub ruleset(先做:它是唯一不能被本机绕过的一层):仓库 Settings → Rules → Rulesets → New ruleset → Import a ruleset,依次导入 `.github/rulesets/main.json` 与 `.github/rulesets/release-tags.json`。 -2. 本机环境:由 Agent 按 AGENTS.md「新环境准备」自行完成(重建 venv、装开发依赖、`bin/harness guard-git install`、`bin/verify`),不需要人执行。 -3. 发版审批:Settings → Environments → New environment,名称 `release`,勾选 Required reviewers 并加上自己;只有一个维护者时不要勾选 Prevent self-review。 -4. Codex(用 Codex 时必做,`.codex/hooks.json` 改动后需重做):在仓库根启动交互式 `codex`,出现「Hooks need review」时先选 Review hooks,确认命令是调用 `.harness/engine/guards/command_guard.py --role designer`,再信任。也可以启动后执行 `/hooks` 信任。信任只能由用户做;`--dangerously-bypass-hook-trust` 不用于本仓库。 -5. Pi(执行方用 Pi 时必做):在仓库根目录启动 `pi`,执行 `/trust` 保存对本项目的信任(写入用户级 `~/.pi/agent/trust.json`,由用户自行执行),重启 pi 后项目扩展才会加载;或每次运行都加 `-a`。 -6. Zcode(执行方用 Zcode 时必做,每个克隆一次,`.zcode/config.json` 改动后需重做):`zcode hooks trust status --workspace <仓库根>` 查看,确认声明内容后由用户执行它提示的 `zcode hooks trust grant --workspace <仓库根> --hook-digest `。 -7. 设置后自检(只看、不改):Rulesets 列表中两条规则均为 Active;任一 PR 页面上 `build` 与 `harness` 标为 Required。不要用真实推送 main 的方式测试:规则没生效时会真的改掉 main。 -8. Agent 身份(方案 §13 D3,用户执行一次): - - `Snowson` 账号在仓库 Settings → Collaborators 中的角色设为 **Write**。 - - 本机让 gh 同时登录 `Snowson`:`gh auth login --hostname github.com` 以 `Snowson` 登录,然后 `gh auth switch --user SnowsonZ` 切回自己的账号。 - - 之后 Agent 推送、开 PR、派发执行方都经 `bin/as-agent <命令>`:它只对这条命令改用 `Snowson` 的令牌与提交身份,不改 gh 当前账号和 git 配置。 -9. R0/R1 的批准 App(方案 §13 D3,用户执行一次): - - 新建 GitHub App(个人账号 Settings → Developer settings → GitHub Apps):不需要 Webhook;Repository permissions 给 **Contents: Read and write** 与 **Pull requests: Read and write**,其余不给;只允许安装在自己的账号上。GitHub 只把有仓库写权限的批准计入必需批准,对 App 而言即 Contents 写权限;只给 Pull requests 时 App 能批准,但批准不算数,合并仍被拒(H0926-6)。已安装后再改权限,需在安装处接受新权限。 - - 安装到本仓库(Only select repositories → `Agent-Notification`),并生成一把私钥。 - - 仓库 Settings → Environments → New environment,名称 `auto-merge`:Deployment branches 选 **Selected branches** 并只加 `main`;不设审批人。 - - 在该 environment 中添加 variable `AUTO_MERGE_APP_CLIENT_ID`(App 的 Client ID)和 secret `AUTO_MERGE_APP_PRIVATE_KEY`(私钥文件全文)。 - - 确认仓库 Settings → Actions → General 中「Allow GitHub Actions to create and approve pull requests」保持未勾选。 - - 以上完成、且引入本步骤的 PR 合并后,再按第 1 步重新导入 `.github/rulesets/main.json`,覆盖现有的 main 规则。顺序反过来,引入本步骤的 PR 自己就会因缺少批准而无法合并。 - - 自检:由 `Snowson` 开一个 R0 的 PR,auto-merge 运行后,PR 上应出现 App 的批准并被合并;由 `Snowson` 开一个 R2 的 PR,不点批准就无法合并。 +1. GitHub ruleset(先做:唯一不能被本机绕过的一层):Settings → Rules → Rulesets → Import,依次导入 `.github/rulesets/main.json` 与 `.github/rulesets/release-tags.json`。 +2. 本机环境由 Agent 按 AGENTS.md「新环境准备」完成,不需要人执行。 +3. 发版审批:Settings → Environments → New environment `release`,勾选 Required reviewers 并加上自己;单维护者不勾 Prevent self-review。 +4. Codex:仓库根启动交互式 `codex`,出现「Hooks need review」时 Review hooks 后信任(或 `/hooks`);`hooks.json` 改动后需重做。 +5. Pi:仓库根 `pi` → `/trust`(写 `~/.pi/agent/trust.json`),重启后项目扩展加载。 +6. Zcode:`zcode hooks trust status --workspace <仓库根>`,确认后按提示 `grant --hook-digest `;`config.json` 改动后需重做。 +7. 设置后自检(只看、不改):两条 ruleset 为 Active;任一 PR 页 `build` 与 `harness` 为 Required。不要用真实推送 main 测试。 +8. Agent 身份:`Snowson` 账号角色设 Write;本机 gh 同时登录 `Snowson`(`gh auth login` 后 `gh auth switch --user SnowsonZ` 切回);Agent 推送、开 PR、派发都经 `bin/as-agent`。 +9. R0/R1 批准 App:新建 GitHub App(只需 Contents 与 Pull requests 读写权限),安装到本仓库;environment `auto-merge` 只允许 main;添加 variable `AUTO_MERGE_APP_CLIENT_ID` 与 secret `AUTO_MERGE_APP_PRIVATE_KEY`;确认 Actions 不能批准 PR;完成后重新导入 `main.json`。自检:`Snowson` 开 R0 PR 应被 App 批准合并,R2 PR 不点批准不能合并。 ## 6. 验证状态 -按 AGENTS.md「验证边界」区分证据类型。 - -| 能力 | 证据 | 状态 | -|---|---|---| -| verify 三处同口径 | 云端 Linux 实跑;macOS CI `--strict` 实跑 Swift 检查(run 36148783352);2026-09-26 本机 macOS `bin/verify --strict --full` 10 项全过 | ✅ | -| evidence / risk / hygiene | 单测 + 临时 git 仓库场景(`tests/test_harness.py`) | ✅ | -| CI harness job | 首次运行即拦下测试数据里的真实用户目录(run 36148783352) | ✅ | -| git 钩子 | 临时仓库真实 git 回放:main 上提交、amend、移动与删除 tag、filter-repo、推 main、推 tag、强推、推送卫生(`tests/test_harness_guard.py`) | ✅ Linux;macOS 由 CI 覆盖 | -| Claude Code PreToolUse | 2026-09-25 本仓库会话中真实拦截 3 次(均为命令文本含危险字样的误报,拦截本身生效) | ✅ 真实会话 | -| OpenCode 插件 | node 加载插件的单测;2026-09-26 真实 OpenCode(`opencode run`)中实测:设置覆盖变量的命令被拒、编辑 `.harness/config/rules.toml` 被拒且文件未改 | ✅ 真实会话 | -| Pi 扩展 | node 加载扩展的单测(`PiExtensionTest`);2026-09-26 真实 Pi(`pi -a -p`)中实测:设置覆盖变量的命令被拒、编辑 `.harness/config/rules.toml` 被拒且文件未改;**未信任项目时(`pi -p` 不带 `-a`)同一命令照常执行**,扩展未加载 | ✅ 已信任时;⚠️ 依赖用户按 §5 第 5 步信任项目 | -| Zcode 钩子 | `.zcode/config.json` 按声明运行钩子命令的单测(`ZcodeHookConfigTest`)。2026-09-26 真实 Zcode 0.16.9 实测:CLI(`zcode -p`)识别到声明并可授予信任,但**信任后两项探针仍放行**。日志为 `workspace_hook.feature_disabled`:源码中只有协议服务端(桌面 ZCode.app 等宿主)显式打开工作区钩子(`workspaceHookTrustEnabled: true`,注释称灰度开关),CLI 与 TUI 未打开 2026-09-26 桌面版 ZCode.app 实测(主仓库授信任后由用户发两项探针):设置覆盖变量的命令、编辑 `.harness/config/rules.toml` 均被「harness 守卫」拒绝,文件未改。CLI 没有启用该功能的参数:开关只由协议服务端注入,不读项目配置或环境变量 | ✅ 桌面版;❌ CLI 与 TUI(只剩 git 与服务端两层) | -| Codex hooks | 载荷解析单测(含列表形式命令),`CodexHookConfigTest` 按 `.codex/hooks.json` 的声明运行钩子。2026-09-26 Codex 0.157.1 在临时仓库实测:项目级 hooks.json 被读取;未信任时 `codex exec` 静默不运行、命令照常执行;用户信任后,探针钩子以 JSON 拒绝拦下命令(`Command blocked by PreToolUse hook`);载荷为 `tool_name: Bash`、`tool_input.command` 字符串,与守卫的 Claude 格式一致。同日用户信任本仓库钩子后,在仓库内实测 `codex exec`:`git status` 放行,`gh pr merge` 被守卫以退出码 2 拒绝,Codex 报 `Command blocked by PreToolUse hook: harness 守卫拒绝了这次操作…`,拒绝理由原样回给模型。2026-09-28 Codex 桌面版实测(用户在本仓库执行):`git status` 放行,`gh pr merge 999999` 被 PreToolUse 钩子拦截、未执行,桌面版同样执行项目级 `.codex/hooks.json` | ✅ 真实会话(`codex exec` 与桌面版) | -| ruleset | 配置文件与 workflow 一致性单测(`tests/test_harness_release.py`);2026-09-25 导入后经 GitHub API 核对:两条均 Active、规则与文件一致(GitHub 为 PR 规则补了默认参数)、无绕过名单,main 上生效的规则为禁删、禁强推、必须经 PR、`build` 与 `harness` 必须通过 | ✅ | -| 必过检查严格模式、密钥扫描(B15、B26) | 2026-09-28 用户在仓库设置中修改后,经 GitHub API 只读核对:main 规则(Active)`strict_required_status_checks_policy: true`,`build` 与 `harness` 必过、无绕过名单,其余规则不变;`secret_scanning` 与 `secret_scanning_push_protection` 均为 `enabled`。`.github/rulesets/main.json` 同步为严格模式 | ✅ 配置;推送被拦的实际效果待首次命中 | -| environment `release` | 2026-09-25 创建。本会话代理禁止读取 environments 接口,由用户转贴 API 输出核对:`required_reviewers` 为用户本人、`prevent_self_review` 为 false、`can_admins_bypass` 为 false(管理员即与 Agent 共用的身份也不能跳过审批)、部署限制为只允许 tag `v*` | ✅ 配置;实际拦停待首次发版确认(方案 §13 V6) | -| 单独身份与批准(D3) | workflow 与 ruleset 一致性单测(`test_auto_merge_approval_needs_main_only_environment`)、批准守卫单测。2026-09-26 GitHub 实测:API 核对 ruleset(1 个批准、非最后推送者、新推送作废)、environment `auto-merge` 只允许 main、Actions 不能批准;R0 的 PR #32 由 `Snowson` 推送后显示需要批准、不可合并,auto-merge 用 App 批准并由 `github-actions` 合并(首次因 App 缺 Contents 写权限批准不计入,H0926-6,调整后重跑);R2 以上不经用户批准不可合并,见引入本行的 PR | ✅ R0;R2 以本行所在 PR 为证 | -| 发版核对 | 临时仓库单测:版本不一致、构建号未递增、tag 不在 main | ✅ 单测;首次真实发版时再确认 | -| 事故回放 | 30 个注入用例(含评审 PR7-R1..R9 的 11 个):Linux 实跑 27 个,Swift 3 个由 macOS CI `--strict --full` 运行(run 36152060546);回放自检(注入点未过期、基线全覆盖)在默认档 | ✅ | -| 修复证据 | 本 PR 的 H0925 与 PR7-R1..R6 修复提交由 evidence 生成「修复前失败、修复后通过」;修复前以出错结束不算证据,只退回修复提交自身的改动 | ✅ | -| 已有测试按 base 版本重跑 | 临时仓库单测四个场景(`tests/test_harness.py` BaseTestsTest);本 PR 上 main 的 267 个测试在 head 通过 | ✅ 本地;CI 步骤随本 PR 首次运行 | -| 变异测试 | 4 个目标的基线得分(见基线评审 §6) | ✅ Linux 实跑 | -| 任务书准入与按类别判级(P1) | 单测(`tests/test_harness_taskbook.py`):缺头部、验收未挂编号、类别与风险不相容、预算超限、缺章节、步骤触及护栏或跨模块未声明的样例任务书各被拒绝;模板本身通过准入;K4/K5/K2/K3 任务书判 R0,K7、K8、架构级、头部不合格、删除判 R2,模板与待办判 R2,豁免清单只能缩减;执行方编辑任务书与规格被守卫拒绝。仓库现有任务书 002–004 补头部并登记豁免后 `taskbook` 检查通过 | ✅ 单测;CI 以引入本行的 PR 为准 | -| 合并路由与 R1 加强判定(P2) | 单测(`tests/test_harness_policy.py`):风险 R2、类别非 L4、任务书声明与机器判定不一致、逃逸超预算、`budget-exceeded` 标签、读不到标签与议题、超 400 行各转用户评审,全部满足才自动合并,summary 逐条写理由;机器类别 K0–K7;三抽一抽样稳定;R1 在签名改动、删除函数、新依赖、建表改表、超规模时降为 R2,新增函数、标准库与仓库内模块仍为 R1;workflow 一致性单测(判定步骤只读、只运行 policy.py) | ✅ 单测;auto-merge 的真实运行以引入本行的 PR 合并后的第一个 PR 为准;停机演练待用户执行(§8) | -| 回放强制与守卫小修(P3) | 单测(`tests/test_harness_p3.py`):缺回放的非 doc 类 Defect 使 `evidence.py` 退出 1(即 harness job 失败),注入用例、守卫测试、写明原因的暂缓项满足,doc 类与已撤销的编号不要求;`gh release list/view` 放行、其余拒绝;任何角色删除议题、撤登记标签被拒;执行方关闭或改动议题、改标签、编辑 `docs/runs/**` 被拒而设计方可关闭议题;Zcode 与 Claude 的 matcher、OpenCode 插件与 Pi 扩展把批准、议题、标签类工具交给守卫 | ✅ 单测;✅ Zcode 桌面版:2026-09-28 用户重新授予信任(`workspace_hooks_trusted_persistent`,digest `8c04f1a2…`),桌面版中 `gh issue close 999999` 被「harness 守卫」以「执行者不能关闭、重开或改动议题」拒绝。批准类 MCP 工具:本仓库未给 Zcode 配 GitHub MCP,真机无法发起,由单测覆盖 | -| 派发脚本(P4) | 单测(`tests/test_harness_dispatch.py`,假执行方与假 GitHub、真实临时 git 远端):成功路径写运行记录、开 PR、主目录无改动、槽位归还;执行方环境无 GitHub 令牌;认领冲突与任务书不在 main 上时不运行执行方;超时、卡死、打转、澄清、停机各自升级;CI 失败带摘要重试、超预算打 `budget-exceeded`;槽位互斥与过期锁回收;守卫取自 origin/main,main 上的守卫失效时停止派发;Pi 参数与事件解析。2026-09-28 真实 Pi 实测 `-na -e` 的守卫加载与拦截 。2026-09-28 真实 K2 任务端到端(B21):任务书 T005(PR #56,R0、K0)由 auto-merge 自动合并;`bin/dispatch` 派发 Pi(glm-5.3-flash)一轮完成、无重试、无守卫拒绝,执行约 12.6 分钟,派发脚本在执行方之外 verify 通过,运行记录与提示词随推送入库,PR #57 描述含运行记录摘要,CI 通过后按 R0、K2 自动合并(合并路由四条均写明理由);主目录前后 git status 无改动;合并后在 main 独立重跑变异,`热力金额分级` 21/21,基线由 90% 升到 100%。发现槽位按启动目录命名(从设计方 worktree 启动得到 `…-sync-slot-1`),已改为按主工作目录命名 | ✅ 单测、守卫实测、真实任务端到端 | -| CI 侧复核(P5) | 单测(`tests/test_harness_run_check.py`):派发产生的 PR 通过;设计方分支不适用;带 `Task:` 的任意分支适用;缺记录、提交缺 `Task:`、记录 exit 非 ok、缺字段、task 或分支不符、提示词被改各被标出;以序号最大的记录为准;CI 轮次超预算或读不到时标出,同一提交的重跑不算新轮次;合并路由在缺记录与超预算时转用户、合格时自动合并。T005 的真实运行记录(PR #57)按同一口径合格 | ✅ 单测;首个经合并路由第 5 条判定的真实任务 PR 待下次派发 | -| 周报与台账(P6) | 单测(`tests/test_harness_weekly.py`,GitHub 替身):报告含 14.1 全部指标,缺数据标「样本不足」;PR、运行记录与议题算出的各项与手算一致;注入的突增数据在顶部标红,第一期不标、0→2 不标;历史往返跳过当周;试跑记录含历史任务与派发任务;发布时先建后改同一议题;创建标签不带 --force。2026-09-28 用真实数据预演一次(不发布) | ✅ 单测与真实数据预演;首次发布待合并后手动触发 quality | -| 独立评审试行(P7) | 单测(`tests/test_harness_review_independent.py`):结论 JSON 解析(取最后一个、代码块、无法解析按需用户验收)、阻断与严重发现计为抓住;设计方按任务书 `designer` 或 `Co-Authored-By` 判定;评审方参数只读;评审方环境无 GitHub 令牌;评论格式与隐藏数据;TPR、TNR 计算;校准样本覆盖全部回放用例与清单中的 PR,注入样本不动任何分支;R2 以上打待评审标签。校准结果见 `evals/review/results/` | ✅ 单测。2026-09-28 校准(`evals/review/results/2026-09-28-pi.json`,Pi + glm-5.3,56 个样本全部有效):已知有问题 41 个全部判不通过(TPR 1.0),已知良好 15 个无一判不通过(TNR 1.0),其中 12 个判「需用户验收」、3 个通过。局限:问题样本的 PR 描述统一写「行为不变」而 diff 改了行为,识破偏容易,TPR 偏乐观;评审方偏保守,真实 PR 多推回用户确认。过程中发现并修复:评审方失败(Codex 额度用尽、GLM 429 限流)曾被当成结论,现记为评审失败且不计入;校准逐个落盘可续跑,`--jobs` 并行(GLM 限流下 3 路可行、12 路被拒)。评审方改为 OpenCode(plan 代理只读):此前「卡在初始化」实为调用时标准输入未关闭,`opencode run` 一直等管道结束,现所有评审方关闭标准输入。试行 1/3:#62(OpenCode,需用户验收,4 条一般发现,其中 2 条为 P8 解析的真实限制,登记 B33);首次试行暴露工具缺陷:已合并 PR 按 main 的合并基点比较得到空材料,现改用合并提交的第一个父提交,并把 CI 结论放进评审材料。评审提示词因此有改动,校准结果为改动前的版本 。2026-09-29:PR #63 合并的是 `83972c9`,此后推送的 OpenCode 评审方与上述修复(`87acfcf`)未进入 main,由 T007 补上;评审耗时实测 4 到 5 分钟,约八成是模型推理,把材料写进提示词未见加快(已撤回),改为后台自动评审 | ✅ 单测与校准;试行 1/3(B27) | -| 熵治理(P8) | 单测(`tests/test_harness_entropy.py`):字符串(含多行、原始、转义)与注释(含嵌套块注释)里的大括号不计入;协议要求不算函数;人为加长的 Swift 函数(`test_lengthened_swift_function_fails_ratchet`)、加深嵌套与加长文件使棘轮失败,缩减通过;断链(相对、引用式、以 / 开头)被拦,外链、邮件、纯锚点、行内代码与代码块不误报,`文件#锚点` 缺文件仍拦;陈旧的未完成状态只报告不失败,近期的与正文顺带提到的不报。Swift 基线(2026-09-28,332 个函数):`swift_files_over_500` 2、`swift_long_functions` 9、`swift_deep_functions` 13。首跑本仓库修正 4 处断链,陈旧状态无 | ✅ 单测;CI 以本 PR 为准 | -| 验收映射 | 6 份规格 69 条编号:可自动化 54 条中 53 条有测试、1 条登记缺口,19 条进入人工清单;检查器在 verify 各档运行 | ✅ | -| Swift 回放 | macOS CI `--strict --full`(run 36152060546)通过,Swift 注入在 strict 下不可跳过 | ✅ | -| zcode 自检、质量棘轮、交付度量 | 本地实跑;zcode 自检与 CI 中的度量步骤随本 PR 首次在 CI 运行 | ⚠️ 待本 PR 的 CI | -| 每周 quality workflow | 本地实跑变异 `--check`、回放、质量棘轮 | ⚠️ 定时与手动触发只对默认分支生效,合并后首次运行 | +按 AGENTS.md「验证边界」区分证据类型。历史证据表(verify 同口径、守卫实测、ruleset 核对、派发端到端、独立评审校准、熵治理等)见各建设期 PR 与[基线评审](https://github.com/SnowsonZ/delivery-harness/blob/main/docs/review/2026-09-25-harness-baseline.md)、[全链路审计](https://github.com/SnowsonZ/delivery-harness/blob/main/docs/review/2026-09-27-harness-audit.md)(2026-10-09 已迁 delivery-harness);引擎自身检查的验证以 [delivery-harness](https://github.com/SnowsonZ/delivery-harness) 仓库的 CI 与文档为准。 ## 7. 已知边界 -- **身份与批准**(2026-09-26 用户决定改为单独身份,方案 §13 D3): - - Agent 用单独的账号 `Snowson` 推送和开 PR(`bin/as-agent`),用户用自己的账号 `SnowsonZ` 批准。 - - main 的 ruleset 要求非推送者批准最后一次推送;有新推送时作废旧批准。 - - R0/R1 由 auto-merge 的专用 App 批准,App 凭据放在只允许 main 使用的 environment `auto-merge` 中,PR 分支的 workflow 取不到。 - - R2 及以上:build 通过后,auto-merge 的 `request-review` job 请仓库所有者评审(用户 2026-09-26 要求),PR 出现在用户的待评审列表里;只请求,不批准。CI 失败的 PR 不请求,修好后再判定。 - - 残余:Agent 与用户在同一个 macOS 用户下运行,技术上能读到用户在 gh 里的登录凭据,再以用户身份批准。这一步只靠 Agent 层守卫拦(拒绝 `gh pr review --approve` 与 MCP 评审工具);彻底隔离要给 Agent 单独的系统用户。 - - 用户自己开的 PR 同样需要别人批准,由 `Snowson` 账号批准,或临时调整 ruleset。 -- **PR 在自己的 workflow 里合并自己**:`pull_request` 事件执行 PR 分支里的 workflow 定义。D3 之后合并需要非推送者批准,`GITHUB_TOKEN` 既不能批准(仓库已关闭「允许 Actions 批准 PR」),也取不到 environment `auto-merge` 中的 App 凭据,因此 PR 不能再合并自己。仍依赖的前提:environment 的分支限制只允许 main;App 只装在本仓库,只有 Contents 与 Pull requests 写权限。App 的 Contents 写权限是批准被计入的前提(H0926-6),它的令牌因此也能推送;令牌只在 main 上的 auto-merge、判定为 R0/R1 之后取得。 -- **命令守卫按命令结构判断**(2026-09-26,方案 §13 E3,`.harness/engine/core/shell_structure.py`):把命令拆成简单命令,只对会执行的程序(git、rm、gh、curl 与覆盖变量的赋值)按参数判断;echo、grep 模式、提交说明、Agent 提示词、heredoc 正文、注释里的文字不再误拒。会执行但看不到结构的地方退回字符串规则:`python -c` 等解释器代码、交给 shell 或解释器执行的 stdin(heredoc 与 here-string 只判断被执行的那段正文,管道整段判断)、无法解析的命令(引号不配对);`bash -c`、`eval`、`$(...)`、反引号递归按结构判断。仍然识别不了的:脚本文件内部(`bash x.sh`、`python3 x.py`)、`xargs` 从 stdin 补的参数、变量间接展开出的命令名。实测探针不要再用 `echo 覆盖变量=1`(现在按数据放行),改用会真实执行、被放过也无害的命令,例如对不存在的分支强推。此前字符串匹配阶段记录了 6 次误报。 -- **Zcode 与 Pi 的拦截依赖用户信任**:Zcode 的工作区钩子未经信任不执行,Pi 的项目扩展在未信任项目时不加载。此时它们设置覆盖变量或使用 `--no-verify`,本机两层都挡不住,只有服务端兜底。 -- **本机护栏的信任根在可写路径**(评审 PR7-R3):git 钩子的规则文件曾在执行者可写的工作区,改掉 `protected_branches` 即可让本机改写 main 不受拦截。现在钩子按 origin/main 上的 `.harness/config/rules.toml` 执行,工作区版本不一致时告警;但守卫代码(`.harness/engine/guards/git_guard.py`、`.githooks/`)与运行时解释器(`scratch/iterm-probe-venv`)仍可被改。本机两层定位为防误操作,防有意绕过只能靠服务端 ruleset 与发版审批,所以一次性设置里 ruleset 排在第一步。 - - 「读 origin/main」只在本地远端引用可信时成立(评审 PR7-R8):本地的 `refs/remotes/origin/main` 不受保护,把它改指伪造的提交,或把 remote 指向伪造的源再 fetch,守卫就会读到伪造的规则并照常告警「按 origin/main 的规则执行」。 - - 本 PR 合并前 main 上没有 `.harness/config/rules.toml`,钩子退回读工作区版本;更根本的是 main 上还没有 `.githooks/`,检出 main 时本机没有任何 git 守卫(2026-09-26 评审报告直接提交到 main 即因此未被拦截,见基线评审 H0926-1)。 -- **base_tests 的篡改检查在同一进程内**(评审 PR7-R7):base 版本的测试 import 的是 head 的产品代码。`base_tests_runner.py` 在运行前后比对 unittest 各类与模块的属性,并跑一组必然失败的哨兵用例;risk.py 对产品代码新增的测试框架引用加标记(取消 R1)。专门针对这两处检查的篡改(例如识别哨兵用例名、改后在检查前复原)仍可能漏过,由评审兜底;接上 L4 自动合并(方案 §13 E1)前需复核这一残余。 +- **身份与批准的残余**:Agent 与用户同 macOS 用户,技术上能读到用户 gh 凭据再以用户身份批准,只靠 Agent 层守卫拦;彻底隔离要单独系统用户。用户自己开的 PR 由 `Snowson` 账号批准或临时调整 ruleset。 +- **PR 不能合并自己**:依赖 environment 分支限制(只允许 main)与 App 只装在本仓库。 +- **命令守卫按命令结构判断**:解释器代码(`python -c`)、脚本文件内部、`xargs` 补的参数、变量间接展开识别不了,退回字符串规则。 +- **Zcode 与 Pi 的拦截依赖用户信任**(见 §5 第 5、6 步),未信任时只剩 git 与服务端两层。 +- **本机护栏的信任根在可写路径**:git 钩子按 origin/main 的规则执行,但本地 `refs/remotes/origin/main` 本身不受保护;守卫代码与运行时解释器仍可被改。本机两层定位为防误操作,防有意绕过靠服务端 ruleset 与发版审批。 ## 8. 停机与恢复 -2026-09-28 决定:不开发 `AUTO_MERGE_ENABLED` 变量,停机用 GitHub 自带的禁用工作流。误差预算超支时 policy.py 自动停该类自动合并,是第二道闸。 - -停机(用户,网页或手机均可): - -1. 仓库 Actions → 左侧 `auto-merge` → 右上角 ··· → **Disable workflow**。此后 build 照常运行,但不再判定、批准或合并,所有 PR 都要用户合并。也可以在终端执行 `gh workflow disable auto-merge`(由用户执行)。 -2. 正在运行的 auto-merge 在 Actions 页面逐个 **Cancel run**。 -3. 终止本机正在运行的执行方:`bin/dispatch stop --all`(写停机标记,各派发在下一次轮询时终止执行方并升级;标记存在期间新的派发直接拒绝,恢复时删除该标记,脚本会提示路径)。手动开的执行方会话(如 Zcode 桌面版)另行关闭。 - -恢复(用户): +停机(用户,网页或手机):仓库 Actions → `auto-merge` → Disable workflow;正在运行的逐个 Cancel;本机执行方 `bin/dispatch stop --all`(标记存在期间新派发直接拒绝,恢复时删除标记)。 -1. 同一位置 **Enable workflow**(或 `gh workflow enable auto-merge`)。 -2. 停机期间通过 build 的 PR 不会自动重新判定:在该 PR 最新的 build 运行上 **Re-run all jobs**,完成后 auto-merge 按当前规则判定。 +恢复(用户):Enable workflow;停机期间通过 build 的 PR 在最新 build 运行上 Re-run all jobs,完成后按当前规则判定。 -演练(进入无人值守前一次,之后每季度一次):停机 → 开一个 R0 的测试 PR,确认 build 通过后没有自动合并 → 恢复 → 重跑该 PR 的 build,确认被自动合并。结果记入 §6 验证状态。 +演练:进入无人值守前一次、之后每季度一次(停机 → R0 测试 PR 不被自动合并 → 恢复 → 重跑后被合并),结果记入引擎仓库验证状态。 diff --git a/docs/templates/review-checklist.md b/docs/templates/review-checklist.md index 9589ed9..f3f8f8c 100644 --- a/docs/templates/review-checklist.md +++ b/docs/templates/review-checklist.md @@ -1,7 +1,7 @@ # 评审清单 From 928d5272d4c2e6d4e25c155fdd7d98805327b51f Mon Sep 17 00:00:00 2001 From: Snowson Date: Sat, 10 Oct 2026 10:30:23 +0800 Subject: [PATCH 2/2] =?UTF-8?q?test=EF=BC=9A=E8=AF=84=E5=AE=A1=E6=B8=85?= =?UTF-8?q?=E5=8D=95=E8=A6=86=E7=9B=96=E6=A0=B8=E5=AF=B9=E6=94=B9=E7=94=A8?= =?UTF-8?q?=E5=9B=BA=E5=AE=9A=E7=B1=BB=E5=9E=8B=E9=9B=86=EF=BC=88=E5=9F=BA?= =?UTF-8?q?=E7=BA=BF=E5=B7=B2=E8=BF=81=20delivery-harness=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 基线评审文档按 2026-10-09 迁移决定移除后,覆盖核对不再读该文档, 失败类型全集(F1–F7、X1–X6)按迁出时快照固定为常量;断言强度与 测试数不变,仍核对 review-checklist.md 覆盖全部类型 --- tests/test_harness_review.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tests/test_harness_review.py b/tests/test_harness_review.py index 03cf2ef..ca17ab8 100644 --- a/tests/test_harness_review.py +++ b/tests/test_harness_review.py @@ -16,13 +16,18 @@ class ReviewChecklistTest(unittest.TestCase): - def test_checklist_covers_every_failure_type_in_baseline(self): - baseline = (ROOT / "docs/review/2026-09-25-harness-baseline.md").read_text(encoding="utf-8") - checklist = (ROOT / "docs/templates/review-checklist.md").read_text(encoding="utf-8") - types = set(re.findall(r"^\| ([FX]\d) ", baseline, flags=re.MULTILINE)) - self.assertGreaterEqual(len(types), 13) # F1–F7、X1–X6 + # 基线评审(失败分类 F1–F7、X1–X6)2026-10-09 迁至 delivery-harness + # docs/review/2026-09-25-harness-baseline.md;覆盖核对的类型集按迁出时快照固定。 + FAILURE_TYPES = frozenset(f"F{i}" for i in range(1, 8)) | frozenset( + f"X{i}" for i in range(1, 7) + ) + + def test_checklist_covers_every_failure_type(self): + checklist = (ROOT / "docs/templates/review-checklist.md").read_text( + encoding="utf-8" + ) rows = set(re.findall(r"^\| ([FX]\d) ", checklist, flags=re.MULTILINE)) - self.assertEqual(types - rows, set(), "评审清单缺少这些失败类型") + self.assertEqual(self.FAILURE_TYPES - rows, set(), "评审清单缺少这些失败类型") def test_review_prompt_points_at_existing_tools(self): prompt = (ROOT / "docs/templates/review-prompt.md").read_text(encoding="utf-8") @@ -54,7 +59,9 @@ def test_only_changed_acceptance_rows_are_listed(self): header = "| 编号 | 验收内容 | 证据类型 | 覆盖 |\n|---|---|---|---|\n" repo.write( "docs/specs/demo.md", - "# 示例\n\n旧说明。\n\n" + header + "| DM1 | 甲 | 人工 | 目测 |\n| DM2 | 乙 | 人工 | 目测 |\n| DM3 | 丙 | 人工 | 目测 |\n", + "# 示例\n\n旧说明。\n\n" + + header + + "| DM1 | 甲 | 人工 | 目测 |\n| DM2 | 乙 | 人工 | 目测 |\n| DM3 | 丙 | 人工 | 目测 |\n", ) base = repo.commit("base") repo.write( @@ -64,7 +71,10 @@ def test_only_changed_acceptance_rows_are_listed(self): + "| DM1 | 甲(改) | 人工 | 目测 |\n| DM2 | 乙 | 人工 | 目测 |\n| DM3 | 丙 | 人工 | 目测 |\n", ) repo.commit("edit spec") - touched = [item.id for item in review_pack.touched_acceptance(base, "HEAD", cwd=repo.path)] + touched = [ + item.id + for item in review_pack.touched_acceptance(base, "HEAD", cwd=repo.path) + ] self.assertEqual(touched, ["DM1"])