[Module] Agent 编码正确性工作流:快照回滚、AST 增量守卫与测试强检
架构落地演进说明 (Architecture Evolution Note) :
本 Issue 完整记录了编码正确性工作流最初规划的 7 阶段体系。在实际工程落地与场景验收中(见 PR #33 / Commit 60c4d75 及 docs/architecture.md),团队对收尾链路进行了进一步聚焦与精简:
移除收工独立旁路复审(Evaluate) :原阶段五计划在命令验证通过后调度的二次纯净小模型挑刺复审(evaluating)已正式下线,前端不再绘制复审卡片,收尾质检彻底收敛为工程级命令强检(verifying 门禁) ,测试通过后直接撰写收尾说明进入 completed。
复审模型职责收敛 :独立评判模型(EvaluatorModel)不再参与收尾,专职收敛于工具出站安全审批 (在 auto 审批模式下辅助填单、以及对工作区目录外的越界写操作进行安全审计)。
下文保留原设计各阶段完整规格与时序图,以便追溯方案演进脉络。
功能职责
编码正确性工作流为 Agent 的任务执行建立全流程质量门禁:从入口探索降本、写时实时拦截,到收尾命令验证、独立旁路复审、Git 快照回滚与文档同步断言,确保编码结果可验证、可审计、可撤销。
阶段一(探索降本,只读子代理):
增加专用的只读探索能力,主模型检索代码时由便宜小模型(如 flash 级别)子代理先行翻阅文件与搜索关键词。
在子代理内部完成信息提炼,仅向主上下文回传带精确 文件:行号 引用的紧凑结论,避免成百上千行原文塞入主对话,在入口处大幅降低 Token 消耗。
阶段二(编辑守卫,写时拦截):
代码写盘后即时进行语法解析与局部编译校验,重点拦截括号缺失、语法断裂、引用未定义等 100% 确定的硬伤错误,不拦截代码风格与非致命告警。
自动比对改动前后的错误差异,只拦截本次修改新引入的增量错误,放行历史遗留错误,避免误伤。
发现新错误时立即自动回滚文件至修改前基线,将工具调用标为失败,并将报错位置、改动前后代码对比及明确的避坑提示组合反馈给模型,防止破损代码沉淀与连续劣质重试。
阶段三(计划契约,测试约束):
规范计划文件的结构化验收清单,强制要求每条验收项明确目标、验证命令(业务逻辑必须绑定具体测试命令)、初始 false 的通过状态以及支撑依据。
在保存计划时强校验验收结构完整性,且对已有计划条目只增不删,禁止模型删除条目或弱化验证命令。
对已有测试文件实行写入保护:修改既有测试文件必须经过人工审批,禁止自动放行,杜绝模型删改旧断言让代码蒙混过关;新测试在旧代码上必须为红,防止生成无意义假测试。
提供单向受控的标记工具,仅允许模型把验收状态从 false 翻转为 true 且必须提供对应的测试或工具凭据。
阶段四(验证门禁,收尾强检):
识别会话写操作行为:当模型单轮不再调用工具准备结束、且本次 Run 存在写文件或执行命令等副作用时,自动拦截结束流程并触发工程级验证;纯只读对话自动放行。
加载工作区约定的验证规则,执行构建、测试、类型检查等自动化命令序列,并向用户实时推送验证进度与结果事实。
细分验证出口:全部通过则放行进入后续阶段;测试或构建失败时裁剪报错日志作为上下文反馈模型继续修复;环境故障、命令不存在或超时等外部问题明确判定为无法验证并挂起转交人工,不归咎于模型。
建立防死循环保护网:限制单次 Run 内最大打回轮次;对失败日志提取特征指纹,连续两次相同指纹立即熔断转人工,防止模型无意义原地空转。
阶段五(旁路复审,独立裁定):
在自动化验证通过后,将本次任务瘦身后的完整代码 diff、带通过状态及证据的验收清单、以及自动化验证摘要打包送审。
采用无写工具、未参与编码的纯净独立上下文进行挑剔审查,排除模型自我辩解与认知盲区,重点筛查偷删既有测试、弱化断言、未履约的虚假通过以及范围越界等隐蔽缺陷。
实施极致 Token 压缩策略:剥离锁文件与构建产物、纯空格改动,并在改动超过阈值时拆分或熔断;同指纹改动不重复送审。
严格输出结构化裁定:全部合格判定通过;存在瑕疵判定需要修改并附带精准到文件与位置的问题清单,打回原模型继续修复;复审异常、超时或无法解析时实施 fail-close 策略,一律转交人工裁定。
阶段六(快照回滚,兜底撤销):
在一次 Run 即将执行首个破坏性写操作(改文件、执行副作用命令)前,直接复用本机 Git 静默捕获当前工作区的轻量暂存快照并记录未跟踪文件清单,不生成垃圾提交,不干扰正常 Git 历史。
提供三种粒度的安全退回机制:仅恢复代码文件(保留对话以调整提示重试)、仅截断失败消息(保留代码继续排查)、全面回滚(代码与对话同步还原至任务开始前)。
在验证失败、复审驳回及打回超限的人工裁决卡片上无缝集成一键回退入口,解除用户开启高度自动化执行的后顾之忧。
阶段七(架构断言,文档同步):
将架构设计文档中约定的模块单向流转、禁止反向依赖与层级穿透等抽象规则,转化为确定性的自动化测试断言。
建立代码事实与文档的双向同步断言:代码新增的核心目录、工具名与事件类型必须在架构文档中出现;文档提及的历史模块在代码中必须存在,违规时输出包含“问题/修复指引/参考文档”的标准三段式诊断。
将架构合规测试纳入收尾验证流水线,作为任务正常完成的基础前置条件。
边界
守卫只拦截确定性的语法与编译破损,不拦截代码风格、命名或测试失败
修改已有测试文件必须人工审批,Agent 模式与 Yolo 模式均不可自动放行;新增测试文件不受限
验收项状态只允许从 false 翻为 true 且必须附带证据,不允许删除条目或弱化验证命令
验证失败喂回模型继续修,不直接标记 Run 失败;连续相同失败或环境不可执行时挂起转人工,不无限打回
复审模型使用只读无工具纯净上下文,不读取编码过程中的历史对话,不与写代码模型共用上下文
复审输入严格过滤锁文件与生成代码;若模型未改代码便重复申请结束,直接复用上次裁决,不再发起模型调用
探索子代理只读,其运行不计为写操作副作用,不触发快照与收尾验证,其调用产生的 Token 单独记账
快照仅用于本次 Run 的故障恢复与人工接管回滚,仅支持 Git 仓库工作区(非 Git 目录降级提示),不搞文件全量复制,不维护 shadow git 冲突源
架构断言与文档同步测试只检查包间依赖方向与层级单向流转,不检查具体业务逻辑正确性
状态机与核心时序(时序驱动)
业务代码的流转完全由 Agent 运行时状态机保证。系统一拍(Step)只干一件事,数据库在每拍结束时保持原子一致性。
1. 三层核心概念
层级
职责
存储位置
关键枚举/取值
状态(RunStatus)
任务当前对外停留在哪个阶段
runs.status
queued / loading_context / running_llm / executing_tools / verifying(新增)/ evaluating(新增)/ waiting_approval / 终态(completed / failed / cancelled)
唤醒原因(Phase)
这一拍为什么被触发执行
内存 StepJob.Phase
user_input / llm_result / tools_batch_result / verify_result(新增)/ evaluate_result(新增)/ human_approved / human_override(新增)/ human_abort
指令(Instruction)
Brain 决策本拍该调度什么执行器
内存 Instruction.Type
call_llm / call_tools_batch / verify(新增)/ evaluate(新增)/ finish
2. 分阶段时序设计(极简纯线性,无框选干扰)
为彻底消除图例重叠与多层框选线带来的视觉干扰,各阶段统一采用单线直出的泳道时序,分支结果直接标注在线条文字上:
阶段一:需求输入与只读探索(降 Token)
主模型查阅代码时,调度廉价小模型子代理先行翻阅,返回紧凑的精确引用结论,避免大量原文涌入主模型上下文。
sequenceDiagram
autonumber
actor User as 用户
participant Coord as 协调器
participant Engine as 执行引擎
participant Explorer as 探索子代理 (小模型)
participant MainLLM as 主编码模型
User->>Coord: 发送编程需求
Coord->>Engine: 启动任务 (call_llm)
Engine->>Explorer: 派发探索任务 (只读查阅代码与关键词)
Explorer-->>Engine: 返回精确行号引用与提炼结论 (Citations)
Engine->>MainLLM: 携带提炼结论与上下文发起推理
MainLLM-->>Engine: 产出精确代码修改指令 (write / edit)
Loading
流转要点 :
探索子代理只读不写,其调用不计入写操作副作用(HadSideEffects = false),不触发 Git 快照。
子代理消耗的 Token 独立计量展示,主对话上下文保持干净紧凑。
阶段二:写前快照与写时守卫(防写坏)
写代码前静默拍快照;写盘后立即做增量 AST 语法与编译轻检,一旦发现新增硬伤错误立刻自动撤销并恢复原文件。
sequenceDiagram
autonumber
participant Engine as 执行引擎
participant Snapshot as 快照管理器
participant Guard as 写时守卫
participant MainLLM as 主编码模型
Engine->>Snapshot: 首次写代码前,静默拍下工作区暂存快照
Snapshot-->>Engine: 记录快照 SnapshotOID 与基线文件清单
Engine->>Guard: 执行代码写入 (write / edit)
Guard->>Guard: 即时 AST 语法树解析与单包编译对比轻检
Guard-->>Engine: 【情况A 正常】:语法无硬伤,安全写入工作区磁盘
Guard-->>Engine: 【情况B 破损】:检测到新增语法/编译错误,当场撤销并回滚原文件
Engine-->>MainLLM: 喂回结果 (正常则继续下一项;报错则附带改动对比促其修复)
Loading
流转要点 :
仅比对增量错误,放行既有历史错误,不发生误杀。
出错瞬间文件基线毫秒级复原,破损代码绝不沉淀在磁盘上。
阶段三:申请结束与收尾命令验证(Verify 强检)
模型自认为做完了(不再调用工具)时,大脑直接拦截结束流程;只要动过代码,强制跑自动化测试与构建。
sequenceDiagram
autonumber
actor User as 用户
participant MainLLM as 主编码模型
participant Brain as 决策大脑
participant Engine as 执行引擎
participant Verifier as 验证门禁
MainLLM->>Brain: 模型自认完成,不再调用工具 (申请收工)
Brain->>Brain: 拦截收工,检查 HadSideEffects (动过代码强制安检)
Brain->>Engine: 下发 verify 指令 (状态迁移至 verifying)
Engine->>Verifier: 按改动文件定向执行构建与测试 (.cursor/verify.yaml)
Verifier-->>Engine: 返回验证结果 (测试日志与错误指纹)
Engine->>Brain: 【验证通过】全绿放行,准备进入独立复审 (evaluating)
Engine-->>MainLLM: 【测试失败】包装报错日志,打回模型继续修复重试
Engine-->>User: 【指纹重复/超限】触发防死循环熔断,挂起转人工卡片
Loading
流转要点 :
结束权收归系统,模型无权自主单方面收工。
提取失败指纹,连续两次完全相同错误立刻熔断转人工,绝不无意义原地空转。
阶段四:纯净独立旁路复审(Evaluate 挑刺)
自动化测试通过后,由未经编码上下文污染的独立模型执行挑剔审查,排查偷删测试、弱化断言等隐蔽作弊行为。
sequenceDiagram
autonumber
actor User as 用户
participant Coord as 协调器
participant Engine as 执行引擎
participant Evaluator as 独立复审 (纯净小模型)
participant MainLLM as 主编码模型
Coord->>Engine: 自动化验证通过,下发 evaluate 指令 (evaluating)
Engine->>Evaluator: 传入瘦身 diff + 验收证据 + 验证摘要 (无历史对话)
Evaluator->>Evaluator: 挑剔审查:排查偷删测试、弱化断言或范围越界
Evaluator-->>Coord: 【复审通过】判定合格,任务正常结束 (completed)
Evaluator-->>MainLLM: 【发现瑕疵】返回结构化驳回清单,打回模型整改
Evaluator-->>User: 【超限或异常】打回超限或结果说不清,fail-close 挂起转人工
Loading
流转要点 :
纯净独立裁判:不读编码历史对话,无认知盲区与自我辩解偏向。
极限降本:剔除 lock 文件与空白改动,同指纹改动直接复用上次裁决。
阶段五:人工兜底与一键撤销(Human Override)
当验证或复审熔断转人工时,用户可通过操作卡片实施裁决,包括一键将工作区复原至修改前。
sequenceDiagram
autonumber
actor User as 用户
participant Coord as 协调器
participant Snapshot as 快照管理器
participant MainLLM as 主编码模型
Coord->>User: 任务挂起并弹出操作卡片 (附带日志、差异与回退按钮)
User->>Coord: 用户在操作卡片上做出人工裁决
Coord-->>User: 【裁决 A: Accept】人工确认无碍,强制标记任务完成
Coord->>MainLLM: 【裁决 B: Retry】补充提示并清空失败指纹,允许模型重试
Coord->>Snapshot: 【裁决 C: Abort】彻底放弃,调用 Snapshot.Restore
Snapshot->>Snapshot: git reset 还原代码至 SnapshotOID 并清理多余新增文件
Snapshot-->>User: 工作区毫秒级无损复原,任务标记为已取消 (cancelled)
Loading
流转要点 :
依靠原生轻量 Git stash,秒级回滚且不污染分支历史。
赋予防御性安全感:随时可一键撤销全部写操作。
3. 详细流转规则汇总
写副作用标记与快照触发 :
在 call_tools_batch 中,首次成功调用 write / edit / bash / powershell 前,检查 HadSideEffects 是否为 false。
若为 false,立即通过 Git 捕获轻量快照生成 SnapshotID,随后置 HadSideEffects = true。
收尾分叉判定(PhaseLLMResult) :
模型回复结束且无 pending 工具调用:
若 HadSideEffects == false(纯问答、只读搜索):Brain 下发 finish(completed),直接结束。
若 HadSideEffects == true:Brain 下发 verify 指令,Run 状态迁移为 verifying。
验证结果裁决(PhaseVerifyResult) :
验证通过(passed):Brain 下发 evaluate 指令,状态迁移为 evaluating。
验证失败(failed):
若当前失败日志指纹与 LastVerifyFingerprint 相同,或 VerifyRound >= MaxVerifyRounds:立刻熔断,挂起为 waiting_approval(审批单附带失败日志与一键回滚选项)。
否则:记录指纹,VerifyRound++,将报错信息封装为 tool 消息喂回模型,下发 call_llm,状态转为 running_llm。
无法运行(cannot_run,如环境依赖缺失、命令超时):明确归为外部环境异常,直接挂起为 waiting_approval 转人工。
旁路复审裁决(PhaseEvaluateResult) :
复审通过(pass):Brain 下发 finish(completed),任务成功收尾。
存在问题(needs_work):
若 EvaluateRound >= MaxEvaluateRounds:熔断挂起为 waiting_approval。
否则:EvaluateRound++,将问题清单注入上下文,下发 call_llm 进入修复。
说不清或复审异常(escalate):fail-close 挂起为 waiting_approval 转人工。
人工介入裁定(PhaseHumanOverride) :
人工在验证/复审挂起卡片上裁决:
Accept:用户确认无碍,直接 finish(completed) 归档。
Retry:清除重复指纹,下发 call_llm 允许模型继续修正。
Abort:调用快照恢复文件至初始干净基线,下发 finish(cancelled)。
重启与断点恢复 :
服务重启扫描可恢复状态白名单增加 verifying 与 evaluating。
recoverPhase 映射:verifying 安全回退至 llm_result 重新触发验证(命令执行具备幂等性);evaluating 回退至 verify_result{passed} 重新发起复审。
内部拆分
编辑守卫(EditGuard)
管文件修改后的即时增量语法与编译解析检查、新旧错误对比、出错自动恢复文件基线并生成对比反馈。不管业务逻辑正确性,不跑全量测试,不拦截代码风格。
// LintSeverity 诊断级别(严重错误阻断提交,告警信息仅作提示)。
type LintSeverity string
const (
SeverityError LintSeverity = "error" // 语法断裂或编译硬伤,必须阻断并回滚。
SeverityWarning LintSeverity = "warning" // 代码风格或非致命提示,放行不阻断。
)
// LintDiagnostic 语法与编译轻检诊断明细。
type LintDiagnostic struct {
Line int // 错误发生的起始行号(1-based)。
Column int // 错误发生的列号(1-based)。
Message string // 编译器或语法解析器输出的原始报错描述。
Severity LintSeverity // 诊断严重程度:error 触发回滚,warning 放行。
}
// EditInspection 文件编辑守卫校验结果报告。
type EditInspection struct {
FilePath string // 被校验的文件路径(工作区相对路径)。
OldContent string // 修改前的文件基线原始内容(用于回滚与生成对比)。
NewContent string // 本次修改后试图写入的新内容。
NewErrors []LintDiagnostic // 本次改动新引入的增量错误(已自动排除修改前既有的历史错误)。
RollbackDone bool // 是否已自动撤销修改并还原文件(仅当存在 NewErrors 时为 true)。
DiffSnippet string // 用于反馈给模型的错误位置上下文对比代码片段。
}
// InspectEdit 在文件写盘后立即做增量语法与局部编译轻检。
// 参数:
// - filePath: 被修改的文件路径(工作区相对路径)
// - oldContent: 修改前的文件原始内容基线
// - newContent: 本次修改试图写入的新内容
// 返回:
// - inspection: 检查结果(含增量错误与是否已自动回滚)
// - err: 执行检查本身的系统异常(非代码语法错误)
func InspectEdit (filePath string , oldContent string , newContent string ) (inspection EditInspection , err error )
计划契约与测试约束(PlanContract)
管计划文件中验收条目的结构解析与强校验、受控的状态翻转(由 false 变 true)、事实依据绑定,以及已有测试文件的写入审批拦截与新测试红绿判定。不管业务代码如何修改,不执行实际业务命令。
// PlanItem 计划验收清单中的独立验收项契约。
type PlanItem struct {
ID string // 验收项唯一标识(如 "item-1"、"item-2")。
Description string // 验收目标描述,清晰说明本项要实现或验证的业务功能。
VerifyCmd string // 验证命令(业务项强制绑定具体测试命令,如 "go test -run TestX";纯文档/配置项可标 "manual")。
Passes bool // 验收是否通过;创建时强制为 false,仅允许通过 plan_pass 单向翻转为 true,不可逆转。
Evidence string // 支撑通过的客观凭据(工具调用 ID、测试运行日志摘要,翻转为 true 时必填,禁止为空)。
IsTestBound bool // 是否绑定了自动化测试命令(业务逻辑项强制为 true)。
}
// PlanContract 计划文件的结构化数据契约。
type PlanContract struct {
PlanName string // 计划文件名称或相对路径(如 ".cursor/plans/foo.plan.md")。
Title string // 计划标题。
Items []PlanItem // 结构化验收清单;修改保存时只增不删,禁止弱化已有命令。
UpdatedAt int64 // 契约最后更新的 Unix 毫秒时间戳。
}
// ValidatePlan 校验计划 frontmatter 结构与验收清单合法性。
// 参数:
// - content: 计划文件全文内容(含 frontmatter 结构化数据)
// - existing: 之前已保存的旧契约对象(若首次创建则为 nil)
// 返回:
// - contract: 校验通过后解析出的有效计划契约
// - err: 校验失败原因(如验收清单缺失、试图删减既有条目、或弱化验证命令)
func ValidatePlan (content string , existing * PlanContract ) (contract PlanContract , err error )
// MarkPassed 将指定验收条目标记为通过(受控单向状态翻转)。
// 参数:
// - planName: 计划文件名或相对路径
// - itemID: 待标记通过的验收条目 ID
// - evidence: 证明通过的客观证据(测试运行记录或工具执行 ID,禁止为空)
// 返回:
// - contract: 更新后的完整计划契约
// - err: 条目不存在或证据缺失导致的错误
func MarkPassed (planName string , itemID string , evidence string ) (contract PlanContract , err error )
// IsExistingTestFile 判定目标文件是否为已存在的既有测试文件。
// 参数:
// - workspaceRoot: 工作区根目录绝对路径
// - filePath: 待检查的目标文件相对路径
// 返回:
// - true 表示目标是已存在的测试文件(*_test.go / *.test.ts 等),其写操作必须强制进入人工审批
func IsExistingTestFile (workspaceRoot string , filePath string ) bool
// VerifyTestFailsOnBase 校验新测试在修改前的基线代码上执行是否失败(防作弊测试验证)。
// 参数:
// - workspaceRoot: 工作区根目录绝对路径
// - baseOID: 本次任务发起前的代码基线快照或提交 OID
// - testFilePath: 本次任务新编写的测试文件路径
// 返回:
// - failsOnBase: 在旧代码上是否如期失败(若通过说明测试未测到新行为,判定为假测试)
// - err: 检出基线或执行测试时的系统异常
func VerifyTestFailsOnBase (workspaceRoot string , baseOID string , testFilePath string ) (failsOnBase bool , err error )
验证门禁(Verifier)
管在模型准备结束时调度工作区验证命令,根据退出码判定通过、失败或不可执行;根据改动范围定向缩小测试范围;维护打回轮次与报错指纹,识别原地打转。不管如何修改代码,不负责模型调用。
// VerifyStatus 工作区验证的判定状态枚举。
type VerifyStatus string
const (
VerifyStatusPassed VerifyStatus = "passed" // 全部验证命令退出码为 0,验证全通。
VerifyStatusFailed VerifyStatus = "failed" // 测试断言失败或编译未通过,打回模型修复。
VerifyStatusCannotRun VerifyStatus = "cannot_run" // 外部环境异常(命令不存在、超时、缺少系统依赖),挂起转人工。
)
// VerifyRule 单个包或模块的验证规则配置(读取自 .cursor/verify.yaml)。
type VerifyRule struct {
Commands []string // 待顺序执行的 shell 验证命令序列(如 ["go test ./...", "pnpm test"])。
TimeoutSec int // 单次验证执行超时时间(秒,防止挂起死锁,默认 120s)。
MaxRounds int // 允许模型最大打回重试轮次(超出则触发熔断转人工,默认 3 次)。
ScopeGlob string // 关联的文件 glob 匹配规则,用于根据 diff 改动文件做定向按需测试。
}
// VerifyResult 验证流水线执行输出与状态分析报告。
type VerifyResult struct {
Status VerifyStatus // 验证判定结论:passed / failed / cannot_run。
FailedCommand string // 导致失败的首个命令文本(全通时为空)。
ExitCode int // 失败命令的系统进程退出码(0 表示正常退出)。
Output string // 裁剪后的关键报错日志输出(过滤冗余输出,保留关键堆栈)。
Fingerprint string // 报错特征指纹哈希(基于失败文件与报错信息计算,用于识别死循环)。
Round int // 当前验证所处的打回轮次序号(1-based)。
DurationMs int64 // 验证执行耗时(毫秒)。
}
// CheckWorkspace 根据本次任务改动的文件定向执行工程级验证。
// 参数:
// - workspaceRoot: 工作区根目录绝对路径
// - diffFiles: 本次任务已变更的文件相对路径列表(用于缩小测试执行范围)
// - round: 当前重试轮次序号
// - lastFingerprint: 上一次失败记录的错误特征指纹(用于防死循环比对)
// 返回:
// - result: 验证执行结果(状态、日志与特征指纹)
// - err: 规则文件解析失败等系统故障
func CheckWorkspace (workspaceRoot string , diffFiles []string , round int , lastFingerprint string ) (result VerifyResult , err error )
// IsLooping 判断验证失败是否已陷入原地空转或超出最大容忍轮次。
// 参数:
// - currentFingerprint: 本轮失败提取出的错误指纹哈希
// - lastFingerprint: 上一轮失败记录的错误指纹哈希
// - round: 当前处于第几轮打回重试
// - maxRounds: 配置的最大允许重试轮次上限
// 返回:
// - true 表示连续两次指纹相同(原地打转)或超出最大轮次,需触发系统熔断转人工
func IsLooping (currentFingerprint string , lastFingerprint string , round int , maxRounds int ) bool
旁路复审(Evaluator)
管接收瘦身后的改动 diff、验收条目状态及验证摘要,以无工具纯净上下文进行挑剔审查,重点排查偷删测试与虚假通过;输出结构化决议与驳回清单;维护 diff 指纹防止重复开销。不修改代码,不执行命令。
// EvaluationVerdict 独立旁路复审裁决枚举。
type EvaluationVerdict string
const (
VerdictPass EvaluationVerdict = "pass" // 复审满意,全部合格,准予收工。
VerdictNeedsWork EvaluationVerdict = "needs_work" // 发现代码或测试瑕疵,打回主模型继续修复。
VerdictEscalate EvaluationVerdict = "escalate" // 复审无法形成一致意见、解析失败或模型异常,转人工裁决。
)
// IssueCategory 复审缺陷分类枚举。
type IssueCategory string
const (
IssueDeletedTest IssueCategory = "deleted_test" // 违规删除既有测试用例。
IssueWeakenedAssert IssueCategory = "weakened_assert" // 弱化或注释掉关键测试断言。
IssueFalseClaim IssueCategory = "false_claim" // 验收清单宣称通过但证据不符或无事实依据。
IssueOutOfScope IssueCategory = "out_of_scope" // 代码修改范围严重越界,超出需求范畴。
IssueLogicDefect IssueCategory = "logic_defect" // 明显的业务边界漏洞或潜在空指针/泄漏。
)
// EvaluationIssue 审查发现的具体缺陷明细。
type EvaluationIssue struct {
FilePath string // 存在缺陷的源码文件路径。
Line int // 缺陷所在的起始行号。
Category IssueCategory // 缺陷类型枚举。
Reason string // 驳回说明:客观指出何处违规或不符。
SuggestedFix string // 给模型的具体修复整改建议。
}
// EvaluationResult 独立旁路复审输出的完整决策报告。
type EvaluationResult struct {
Verdict EvaluationVerdict // 综合裁定:pass / needs_work / escalate。
Issues []EvaluationIssue // 结构化驳回问题列表(needs_work 时必填)。
Summary string // 审查总体意见说明(注入上下文或展示给用户)。
DiffFingerprint string // 本次送审 diff 的内容哈希(用于未修改代码直接再申请时的缓存跳过)。
TokensUsed int // 独立复审调用所消耗的 Token 数量(独立记账)。
}
// SanitizeDiff 清洗与压缩用于复审的代码变更 diff。
// 参数:
// - rawDiff: git 产生的原始完整 diff 文本
// - maxBytes: 允许送审的最大字节上限(默认 60KB,超出则截断或分片)
// 返回:
// - sanitizedDiff: 过滤掉 lock 文件、生成代码与纯空白变动后的干净 diff
// - err: 过滤异常或 diff 严重超限导致的错误
func SanitizeDiff (rawDiff string , maxBytes int ) (sanitizedDiff string , err error )
// EvaluateRun 对照任务改动与验收契约发起客观旁路审查。
// 参数:
// - ctx: 复审执行上下文(含超时控制)
// - sanitizedDiff: 清洗后的代码变更 diff
// - items: 计划验收清单及各自绑定的客观证据
// - verifySummary: 收尾验证通过的日志摘要事实
// - lastFingerprint: 上一次复审的 diff 指纹(若代码未改动则直接复用上次裁决,不发模型请求)
// 返回:
// - result: 结构化复审裁定(通过、需要修改或人工升级)
// - err: 复审模型调用故障
func EvaluateRun (ctx context.Context , sanitizedDiff string , items []PlanItem , verifySummary string , lastFingerprint string ) (result EvaluationResult , err error )
探索子代理(Explorer)
管调度轻量模型与只读工具组合翻阅代码、搜索关键词,提取带引用的结构化短结论回传主上下文。不修改任何文件,不执行任何写命令,不污染主会话上下文。
// ExploreInput 只读探索子任务的输入参数。
type ExploreInput struct {
Query string // 探索目标(如 "查找 RunCoordinator 的状态恢复逻辑" 或具体符号)。
PathHints []string // 限定搜索的文件或目录路径模式(如 ["server/internal/agent/*.go"],可选)。
MaxBudgetTokens int // 本次探索允许消耗的最大 Token 预算上限(默认 10,000 tokens,防止无节制展开)。
}
// Citation 探索子代理提炼出的精准代码引用。
type Citation struct {
FilePath string // 引用代码所在的文件相对路径。
StartLine int // 引用代码片段的起始行号。
EndLine int // 引用代码片段的结束行号。
Snippet string // 精确的代码原文片段,供主模型直接引用定位与替换。
}
// ExploreOutput 探索子代理汇总提炼后的结构化结果。
type ExploreOutput struct {
Summary string // 针对探索目标提炼的高密度短结论(直接解答问题,去除冗余原文)。
Citations []Citation // 支撑结论的精准行号引用列表。
TokensUsed int // 子代理在整个探索过程中消耗的 Token 总量(单独上报记账)。
Completed bool // 是否在预算内完整完成探索(false 表示由于达到预算上限提前截断)。
}
// Explore 调度轻量只读子代理深入项目探索代码事实。
// 参数:
// - ctx: 探索执行上下文(支持超时与用户取消)
// - input: 包含探索目标、路径提示与预算上限的输入配置
// 返回:
// - output: 包含高密度摘要与精准引用的结构化结论
// - err: 执行子代理探索时的系统异常
func Explore (ctx context.Context , input ExploreInput ) (output ExploreOutput , err error )
快照回滚(Snapshot)
管在首个写操作前捕获基于 Git 的轻量暂存快照并记录未跟踪文件清单,提供代码恢复、对话截断、全量回滚三种粒度的恢复操作。不管任务为何失败,不决定何时回滚,不污染正常提交分支。
// RestoreMode 快照回滚的安全粒度模式枚举。
type RestoreMode string
const (
RestoreFiles RestoreMode = "restore_files" // 仅撤销工作区代码修改并清理新增文件,保留后续对话供重新尝试。
RestoreMessages RestoreMode = "restore_messages" // 仅截断失败消息与工具记录,代码变更保持不变以便继续调试。
RestoreAll RestoreMode = "restore_all" // 全量回滚:代码还原至任务开始前,对话截断至任务起点。
)
// WorkspaceSnapshot 任务开始前的工作区环境轻量快照。
type WorkspaceSnapshot struct {
SnapshotOID string // git stash create 产出的轻量暂存提交 SHA(悬空提交,不产生提交历史记录)。
UntrackedFiles []string // 快照生成时工作区内已存在的未跟踪文件路径清单。
RunID string // 本次快照绑定的 Agent Run 任务唯一标识。
CreatedAt int64 // 快照捕获时刻的 Unix 毫秒时间戳。
}
// Take 在首次产生破坏性写操作(修改文件、执行命令)前捕获工作区干净快照。
// 参数:
// - workspaceRoot: 工作区根目录绝对路径
// - runID: 当前任务 Run ID
// 返回:
// - snap: 记录快照提交 SHA 与未跟踪文件清单的快照对象
// - err: git stash 执行失败异常
func Take (workspaceRoot string , runID string ) (snap WorkspaceSnapshot , err error )
// Restore 依据快照与选定模式将工作区或会话安全复原。
// 参数:
// - workspaceRoot: 工作区根目录绝对路径
// - snap: 之前捕获的工作区快照数据(包含 SnapshotOID 与初始未跟踪文件)
// - mode: 回滚粒度模式(restore_files / restore_messages / restore_all)
// 返回:
// - err: 工作区重置或清理文件失败的异常
func Restore (workspaceRoot string , snap WorkspaceSnapshot , mode RestoreMode ) error
架构与文档断言(ArchChecker)
管遍历模块依赖关系与分层约束,检查代码事实与架构文档的双向一致性,违规时产出包含问题、改法和出处的三段式规范诊断。不改动源码,不参与状态机运行时流转。
// ArchViolation 单条架构规则或文档一致性违规诊断信息。
type ArchViolation struct {
SourceFile string // 触发违规的源文件路径(如 "server/pkg/agent/foo.go")。
TargetPkg string // 被违规引用的目标包路径(如 "server/internal/events")。
RuleName string // 触发的规则唯一标识(如 "no-downward-dep" 或 "docsync-missing-tool")。
Problem string // 标准三段式诊断之「问题说明」:直白阐述代码破坏了哪项规则。
Fix string // 标准三段式诊断之「修复指引」:清晰告知模型应该如何重构以符合规范。
DocRef string // 标准三段式诊断之「参考章节」:标注对应的架构文档或规范路径(如 "docs/architecture.md")。
}
// CheckDependencies 执行架构依赖单向流转与分层边界静态检查。
// 参数:
// - workspaceRoot: 工作区根目录绝对路径
// 返回:
// - violations: 违背依赖规则的违规项列表(包含三段式修复指导)
// - err: 解析依赖包列表本身的系统错误
func CheckDependencies (workspaceRoot string ) (violations []ArchViolation , err error )
// CheckDocSync 执行代码事实与架构设计文档的双向同步断言。
// 参数:
// - workspaceRoot: 工作区根目录绝对路径
// 返回:
// - violations: 代码与文档不一致的违规项列表(如代码新增工具但文档未记录,或文档记录了已废弃目录)
// - err: 文档或代码符号扫描异常
func CheckDocSync (workspaceRoot string ) (violations []ArchViolation , err error )
流程
用户发起编码需求,Agent 在探索子代理辅助下规划并执行,经由写时守卫、命令验证与旁路复审三重门禁完成收尾;异常时一键安全回退。
// 规划阶段:校验计划与测试验收条目
PlanContract.ValidatePlan (... )
// 编码准备:只读子代理先行探索代码,提炼带引用事实
Explorer.Explore (... )
// 编码阶段:首次写前静默拍快照;动已有测试强制人工审批;修改文件时即时守卫
Snapshot.Take (... )
PlanContract.IsExistingTestFile (... ) // 若是已有测试,走人工审批
EditGuard.InspectEdit (... )
// 模型自称完成:Brain 拦截收工,触发工作区定向验证
Verifier.CheckWorkspace (... )
// 验证全通:清洗瘦身 diff,触发独立无工具模型复审
Evaluator.SanitizeDiff (... )
Evaluator.EvaluateRun (... )
// 复审通过:核验新测试在基线上为红,受控标记验收条目并收尾
PlanContract.VerifyTestFailsOnBase (... )
PlanContract.MarkPassed (... )
// 若验证报错、复审驳回或人工判定放弃:一键回退
Snapshot.Restore (... )
实施清单与验收标准(开发驱动)
本 issue 分为 7 个迭代阶段,各阶段均可独立提交 PR 并通过测试验收:
阶段一:写代码实时守卫(EditGuard)
阶段二:状态机与两线骨架升级(State Machine & Runtime)
阶段三:收尾命令验证与防死循环(Verifier)
阶段四:Git 原生快照与三档回滚(Snapshot)
阶段五:独立旁路复审与 Token 极限压缩(Evaluator)
阶段六:计划验收清单与测试纪律约束(PlanContract)
阶段七:探索子代理与架构/文档同步断言(Explorer & Arch/DocSync)
[Module] Agent 编码正确性工作流:快照回滚、AST 增量守卫与测试强检
功能职责
编码正确性工作流为 Agent 的任务执行建立全流程质量门禁:从入口探索降本、写时实时拦截,到收尾命令验证、独立旁路复审、Git 快照回滚与文档同步断言,确保编码结果可验证、可审计、可撤销。
文件:行号引用的紧凑结论,避免成百上千行原文塞入主对话,在入口处大幅降低 Token 消耗。边界
状态机与核心时序(时序驱动)
业务代码的流转完全由 Agent 运行时状态机保证。系统一拍(Step)只干一件事,数据库在每拍结束时保持原子一致性。
1. 三层核心概念
runs.statusqueued/loading_context/running_llm/executing_tools/verifying(新增)/evaluating(新增)/waiting_approval/ 终态(completed/failed/cancelled)StepJob.Phaseuser_input/llm_result/tools_batch_result/verify_result(新增)/evaluate_result(新增)/human_approved/human_override(新增)/human_abortInstruction.Typecall_llm/call_tools_batch/verify(新增)/evaluate(新增)/finish2. 分阶段时序设计(极简纯线性,无框选干扰)
为彻底消除图例重叠与多层框选线带来的视觉干扰,各阶段统一采用单线直出的泳道时序,分支结果直接标注在线条文字上:
阶段一:需求输入与只读探索(降 Token)
主模型查阅代码时,调度廉价小模型子代理先行翻阅,返回紧凑的精确引用结论,避免大量原文涌入主模型上下文。
流转要点:
HadSideEffects = false),不触发 Git 快照。阶段二:写前快照与写时守卫(防写坏)
写代码前静默拍快照;写盘后立即做增量 AST 语法与编译轻检,一旦发现新增硬伤错误立刻自动撤销并恢复原文件。
流转要点:
阶段三:申请结束与收尾命令验证(Verify 强检)
模型自认为做完了(不再调用工具)时,大脑直接拦截结束流程;只要动过代码,强制跑自动化测试与构建。
流转要点:
阶段四:纯净独立旁路复审(Evaluate 挑刺)
自动化测试通过后,由未经编码上下文污染的独立模型执行挑剔审查,排查偷删测试、弱化断言等隐蔽作弊行为。
流转要点:
阶段五:人工兜底与一键撤销(Human Override)
当验证或复审熔断转人工时,用户可通过操作卡片实施裁决,包括一键将工作区复原至修改前。
流转要点:
3. 详细流转规则汇总
call_tools_batch中,首次成功调用write/edit/bash/powershell前,检查HadSideEffects是否为 false。SnapshotID,随后置HadSideEffects = true。HadSideEffects == false(纯问答、只读搜索):Brain 下发finish(completed),直接结束。HadSideEffects == true:Brain 下发verify指令,Run 状态迁移为verifying。passed):Brain 下发evaluate指令,状态迁移为evaluating。failed):LastVerifyFingerprint相同,或VerifyRound >= MaxVerifyRounds:立刻熔断,挂起为waiting_approval(审批单附带失败日志与一键回滚选项)。VerifyRound++,将报错信息封装为 tool 消息喂回模型,下发call_llm,状态转为running_llm。cannot_run,如环境依赖缺失、命令超时):明确归为外部环境异常,直接挂起为waiting_approval转人工。pass):Brain 下发finish(completed),任务成功收尾。needs_work):EvaluateRound >= MaxEvaluateRounds:熔断挂起为waiting_approval。EvaluateRound++,将问题清单注入上下文,下发call_llm进入修复。escalate):fail-close 挂起为waiting_approval转人工。Accept:用户确认无碍,直接finish(completed)归档。Retry:清除重复指纹,下发call_llm允许模型继续修正。Abort:调用快照恢复文件至初始干净基线,下发finish(cancelled)。verifying与evaluating。recoverPhase映射:verifying安全回退至llm_result重新触发验证(命令执行具备幂等性);evaluating回退至verify_result{passed}重新发起复审。内部拆分
编辑守卫(EditGuard)
管文件修改后的即时增量语法与编译解析检查、新旧错误对比、出错自动恢复文件基线并生成对比反馈。不管业务逻辑正确性,不跑全量测试,不拦截代码风格。
计划契约与测试约束(PlanContract)
管计划文件中验收条目的结构解析与强校验、受控的状态翻转(由 false 变 true)、事实依据绑定,以及已有测试文件的写入审批拦截与新测试红绿判定。不管业务代码如何修改,不执行实际业务命令。
验证门禁(Verifier)
管在模型准备结束时调度工作区验证命令,根据退出码判定通过、失败或不可执行;根据改动范围定向缩小测试范围;维护打回轮次与报错指纹,识别原地打转。不管如何修改代码,不负责模型调用。
旁路复审(Evaluator)
管接收瘦身后的改动 diff、验收条目状态及验证摘要,以无工具纯净上下文进行挑剔审查,重点排查偷删测试与虚假通过;输出结构化决议与驳回清单;维护 diff 指纹防止重复开销。不修改代码,不执行命令。
探索子代理(Explorer)
管调度轻量模型与只读工具组合翻阅代码、搜索关键词,提取带引用的结构化短结论回传主上下文。不修改任何文件,不执行任何写命令,不污染主会话上下文。
快照回滚(Snapshot)
管在首个写操作前捕获基于 Git 的轻量暂存快照并记录未跟踪文件清单,提供代码恢复、对话截断、全量回滚三种粒度的恢复操作。不管任务为何失败,不决定何时回滚,不污染正常提交分支。
架构与文档断言(ArchChecker)
管遍历模块依赖关系与分层约束,检查代码事实与架构文档的双向一致性,违规时产出包含问题、改法和出处的三段式规范诊断。不改动源码,不参与状态机运行时流转。
流程
用户发起编码需求,Agent 在探索子代理辅助下规划并执行,经由写时守卫、命令验证与旁路复审三重门禁完成收尾;异常时一键安全回退。
实施清单与验收标准(开发驱动)
本 issue 分为 7 个迭代阶段,各阶段均可独立提交 PR 并通过测试验收:
阶段一:写代码实时守卫(EditGuard)
internal/agent/tools/register.go的Ports中增加代码检查接口Lint(filePath, content)。edit.go与write.go中,在写盘操作后接入语法检查逻辑。阶段二:状态机与两线骨架升级(State Machine & Runtime)
server/pkg/agent/plane.go中新增 Phase(verify_result,evaluate_result,human_override)与 Instruction(verify,evaluate)。server/pkg/agent/types.go中新增 RunStatus(verifying,evaluating)及事件类型。AgentState中扩展HadSideEffects,SnapshotID,VerifyRound,LastVerifyFingerprint,EvaluateRound字段。Brain.Decide:在PhaseLLMResult且无 pending 工具时,根据HadSideEffects分叉至verify或finish。CanTransition允许迁移至新状态;扩展recoverPhase确保重启后能恢复断点。阶段三:收尾命令验证与防死循环(Verifier)
server/pkg/agent/engine.go中实现runVerify执行器,读取工作区.cursor/verify.yaml。pkg/git模块,根据改动文件列表支持定向执行相关包测试。waiting_approval。verify.started与verify.result卡片。阶段四:Git 原生快照与三档回滚(Snapshot)
server/pkg/git中增加CaptureUntracked,并在RestoreWork恢复流程中补全多余未跟踪文件的清理机制。runs表增加snapshot_oid字段,并在首次产生写副作用前捕获快照。POST /runs/{id}/restore,支持files/messages/all三种粒度回退。阶段五:独立旁路复审与 Token 极限压缩(Evaluator)
server/pkg/agent/evaluate.go中实现无状态的独立复审函数,支持独立配置SubagentModel。阶段六:计划验收清单与测试纪律约束(PlanContract)
server/internal/agent/tools/plan.go中实现 frontmatter 验收清单的强校验,条目只增不删。plan_pass,模型必须提供工具调用 ID 或验证记录作为 evidence 才能翻转状态。*_test.go和*.test.ts的写入操作,强制转入人工审批。plan_pass被拦截;修改已有测试触发人工审批单。阶段七:探索子代理与架构/文档同步断言(Explorer & Arch/DocSync)
server/internal/agent/tools中新增explore工具,由轻量小模型执行只读探索并输出带引用的结论。server/internal/archtest/deps_test.go,用go list刚性断言架构文档中的依赖单向流转规则。server/internal/archtest/docsync_test.go,断言核心代码目录、工具和事件在架构文档中双向存在。.cursor/verify.yaml。