Repository navigation
Description
这条 Issue 要解决什么
现在,只要模型结束回答,Agent Loop 就可能把任务标记为成功;达到步数上限时,模型输出 [COMPLETE] 也能得到成功状态。
这只能证明“模型不准备继续了”,不能证明:
- 代码真的修好了;
- 测试真的通过了;
- 用户要求全部满足;
- 没有改坏其他功能;
- 测试通过后代码没有再次变化。
本 Issue 要让 Harness 成为裁判:模型可以说“我完成了”,但最终是否成功必须由与用户要求对应的真实检查决定。
用一个实际场景说明
用户要求:“修复删除按钮误删数据的问题,并补测试。”
Agent 修改了代码,随后说“已经完成并通过测试”,但实际情况可能是:
- 根本没有运行测试;
- 只运行了一个无关测试;
- 测试命令返回成功,但没有覆盖误删场景;
- 测试通过后,Agent 又改了代码;
- 仓库本来就有失败,Agent 没说明哪些是旧问题;
- 子 Agent 在 JSON 里写了
test_summary: passed,Harness 就把它当成证据。
成熟 Harness 应能区分这些情况,而不是都显示“完成”。
当前实现的具体限制
AgentLoop在模型返回end_turn时直接mark_success();_conclude()通过模型输出的[COMPLETE]判断是否完成;- system prompt 只是在文字上提醒模型测试,不是强制规则;
TestResultEvent主要通过 Bash 命令里是否出现 pytest、vitest 等关键词识别测试;- Workflow 检查 Tester/Reviewer 返回的命令、输出和总结是否非空,但这些内容仍可能只是 Agent 自己填写;
sztu-eval已经具备“Agent 运行结束后独立执行验证”的能力,但这套判断没有用于普通任务;- 当前 CI 验证项目代码本身,却没有系统测试“模型谎称完成、证据过期、修复反复失败”等 Harness 行为。
主要入口:
src/sztu_code/core/loop.pysrc/sztu_code/core/context.pysrc/sztu_code/core/tools/invocation.pysrc/sztu_code/core/workflow/orchestrator.pysrc/sztu_code/core/workflow/evaluation.pysrc/sztu_code/evaluation/
修改后应该是什么样
1. 把“程序停了”和“任务成功了”分开
至少分别记录:
- 执行状态:正在运行、等待、已经停止;
- 修改状态:没有修改、待审核、有冲突、已接受、已撤销、存在未知副作用;
- 验证结果:已证明成功、只验证了一部分、未验证、验证失败、环境阻塞、无法判断。
例如,模型正常结束但没跑测试,应显示“执行结束,修改待审核,尚未验证”,而不是“成功”。
2. 开始任务时明确“怎样才算完成”
把用户要求转换成一份完成条件,例如:
- 删除操作必须有二次确认;
- 取消确认后数据不能变化;
- 删除失败时界面显示错误;
- 相关测试通过;
- 不得修改数据库迁移文件。
完成条件来源可以包括用户要求、项目配置、CI、仓库开发说明和 Agent 建议,但必须标明来源。用户明确提出的条件,Agent 不能在执行过程中自行删除或降低。
3. 每条完成条件都要有真实证据
证据不能只是一句“测试通过”,至少要记录:
- 验证了哪条要求;
- 针对哪个代码版本;
- 实际执行的命令或检查;
- 工作目录和关键环境;
- 退出码、测试数量和失败项;
- 原始输出保存位置;
- 检查结果是否仍然有效。
如果测试通过后代码又发生变化,原测试自动变成“已过期”,不能继续用来证明新代码正确。
4. 验证由 Harness 独立运行
Agent 可以建议验证命令,但真正用于判定成功的检查由 Harness 自己执行和记录。
Harness 应从以下位置发现项目验证方式:
pyproject.toml、package scripts、Cargo/Go 配置;- CI workflow;
- 测试目录和项目开发文档;
- 已有的 lint、typecheck、build 和生成文件检查。
它不需要每次运行全部测试,而是先根据改动范围选择相关、成本合适的检查;高风险改动再扩大验证范围。
5. 验证失败后自动进入修复闭环
失败后不要只把几千行日志重新丢给模型。Harness 应:
- 判断是代码问题、旧失败、测试环境问题、权限问题、超时还是偶发失败;
- 提取最相关的报错、修改内容和失败测试;
- 让 Agent 进行下一次修复;
- 先重跑失败检查,再运行可能受影响的回归检查;
- 保存每轮“为什么修改、改了什么、结果如何”。
如果相同错误反复出现,或者代码在 A/B 两种改法之间来回切换,应停止并明确报告,不无限消耗模型调用。
6. 验证结果控制接受和暂存
对于要求验证的任务:
- 验证失败时不能显示成功;
- 测试证据已经过期时不能直接接受;
- 工作区存在冲突或未知副作用时,即使测试通过也不能自动标记为完全成功;
- 用户可以明确选择跳过某项检查,但要记录是谁、为什么、跳过了什么。
必须保证的规则
- 模型的话是“声明”,不是“证据”。
[COMPLETE]和end_turn不能直接产生“已验证成功”。- 每个成功结论都能追溯到用户要求、代码版本和真实检查结果。
- 代码变化后,旧验证结果自动失效。
- 验证失败不能被最后一段成功总结覆盖。
- 仓库已有失败、Agent 新增失败、环境故障和偶发失败必须分开报告。
- Reviewer 的
LGTM不能替代测试或实际检查。 - 无法验证时诚实显示“未验证”或“环境阻塞”,不能伪装成成功。
建议分阶段实现
第一阶段:完成条件和真实证据
- 定义 CompletionContract、Evidence 和 VerificationResult;
- 普通 Agent 结束后不再默认已验证;
- 支持用户显式验证要求和项目固定检查;
- 把验证结果绑定到工作区版本。
第二阶段:自动选择检查并修复
- 发现项目的测试、lint、类型检查和构建命令;
- 根据改动范围选择相关检查;
- 建立验证失败、自动修复、重新验证的循环;
- 与 [Harness Epic] 分清哪些改动是 Agent 做的,并能安全撤销或处理冲突 #93 的工作区版本和接受门禁连接。
第三阶段:持续评测 Harness 自己
- 把真实失败整理为脱敏、版本化的回归任务;
- CI 运行不需要真实模型的 Harness 行为测试;
- 定期运行真实模型和 SWE-bench;
- 报告已验证成功率、误报成功率、未验证比例、成本和耗时。
验收标准
- 模型直接说“完成”但没有运行检查时,结果只能是“未验证”。
- 模型伪造“测试通过”,但 Harness 独立运行失败时,最终结果必须失败。
- 测试通过后再修改任意相关代码,旧证据立即过期,不能用于接受或暂存。
- 每个“已验证成功”都能查到对应完成条件、代码版本、验证命令、退出码和原始输出。
- 人为注入一次测试失败后,系统能完成“发现失败—修复—重新验证”的完整过程并保留两轮记录。
- 仓库旧失败、Agent 引入的新失败、环境缺失和偶发失败得到不同结果分类。
- 同一错误连续出现或修改来回震荡达到阈值后,系统停止自动修复并说明原因。
- CI 包含以下固定场景:模型谎称完成、无关测试通过、证据过期、环境阻塞、偶发失败、工作区冲突和未知副作用。
和现有 Issue 的关系
- 建立上下文压缩信息保持率评测 #11 负责评测上下文压缩是否丢失信息;
- 自动识别项目框架并生成验证策略 #13 负责识别项目框架和可能的验证方式;
- 接入 Multi-SWE-bench 多语言评测 #14 负责 Multi-SWE-bench;
- 建立基于执行轨迹和人工反馈的受控优化数据集 #19 负责从运行轨迹和反馈构建优化数据集。
本 Epic 负责把这些能力接入每天真实运行的“是否完成”判断,而不是只做离线评分。
维护者备注
底层可以使用“完成条件—证据—结论”的关联图,但用户和普通贡献者不需要理解图结构。对外最重要的是:每条要求是否满足、证据是什么、针对哪个代码版本、为什么最终得到成功或失败。
Activity
[-][Harness Epic] 建立证据驱动的完成门禁与自动修复闭环[/-][+][Harness Epic] 建立 Outcome Kernel:用版本化证据图判定完成并驱动修复[/+][-][Harness Epic] 建立 Outcome Kernel:用版本化证据图判定完成并驱动修复[/-][+][Harness Epic] 不再相信 Agent 自称完成:用真实检查决定任务是否成功[/+]LambertClark commentedon Aug 20, 2026
我想认领这个 issue。按 CONTRIBUTING 的要求先说明方案和计划:
方案:拆成 4 个可独立 Review 的堆叠 PR,自底向上实现验证门禁
验证方式:每层配套单元测试(合计 36 个),全量测试套件与 main 基线对比零新增失败,mypy/ruff 通过。
兼容性:默认无契约时行为完全不变;RunFinishedEvent 新字段为可选字段,TS protocol 包的同步计划在后续跟进(会在 PR 中注明)。
预计时间:方案已在本地 fork 完成开发和验证,确认认领后提交第一个 PR,后续 PR 随前置合入依次提交。
LambertClark commentedon Aug 20, 2026
第一个 PR 已提交:#112(第 1 层,验证数据模型层)。后续三层(verification-gating → check-discovery → repair-loop)将随前置 PR 合入依次提交。
feat(verification): add completion contract data model layer (Part of #…
Merge pull request #112 from LambertClark/feat/94-completion-contract
feat(verification): add harness-side verification gating in runner (P…
Merge pull request #113 from LambertClark/feat/94-verification-gating
feat(verification): discover completion checks from user config and p…
feat(verification): add repair loop with triple circuit breaker and s…
Merge pull request #115 from LambertClark/feat/94-repair-loop
LambertClark commentedon Aug 25, 2026
实施进度(Python 四层已全部合入,进入 TS runtime parity 阶段)
Python 侧(src/sztu_code)— 已完成 ✅
Python 运行时现在已具备完整的验证门禁能力:任务完成不再依赖模型自称,而是由真实检查裁决;发现不到检查时结果只能是 unverified。
TypeScript 侧(产品主线 parity)— 进行中
接下来把同样的验证门禁带到 TS runtime(当前
run-manager在 loop 结束后直接标记 success,agent-loop的 conclude 仍依赖[COMPLETE]文本标记,与本 issue 要消除的模式一致):packages/protocol新增 VerificationOutcome 等类型,RunFinishedEvent增加可选验证结果字段(向后兼容)packages/runtime-ts/src/verification/(models / executor / discovery / repair),接入run-manager成功路径与 settings 配置最后一个 PR 将以 Closes #94 收尾。如对 TS 侧拆分粒度有不同意见欢迎指出。
fix(py-runtime): 修复 New-main 合并后的测试套件损坏与 workspace 重命名丢失
feat(runtime): restore verification gate and harden lifecycle on Windows