Agent 长程任务的完成度信任问题,以及 Zagens 如何用组合式 Harness 解决它
术语速查
| LHT | Long-Horizon Task,长程代码任务模式;Layer 1 的强制继续机制 |
| CRAFT | 多代理 QA 段(Implementer + Reviewer + Verifier),与 LHT 实现段交替 |
| Machine Oracle | 机器裁决:退出码、路径/glob 命中等可回放信号 |
| graph_complete | 模型自产 plan + checklist 均无可办项时的完成候选状态 |
| audit_unmet | 有界轮次耗尽后门仍未全绿时的诚实停机,不产生假绿灯 |
| MicroStack02 | Go 微服务框架压测用例:24 类交付物 + 四门验收,暴露欠分解假绿 |
| DEMO3–6 | Monkey 解释器等长程实证压测序列,逐轮修补早停泄漏与假绿路径 |
1. 引言:Agent 的「声称完成」陷阱
2025–2026 年,LLM Agent 的编码能力已经很强——能写数千行代码、做多文件重构、跑测试。但实践中暴露出一类深层问题:模型经常过早「声称完成」,而大量交付物实际上并未落地。
这不是模型在说谎。根因在于:
- 模型自建的 checklist 存在欠分解(under-decomposition)——某些必要交付物从未进入它自己的任务图;
- 模型检查自己的 checklist 全部打勾 → 任务图显示 open_items: 0 → 模型合法地宣布完成;
- 但检视才发现:gzip 中间件没写,router trie 重构没做,e2e 脚本没跑过。
用 Zagens 团队的内部术语说:完成度的天花板 = 模型自分解 checklist 的完整性。模型自己画的作战地图画漏了,按图索骥也找不到漏掉的目标。
#mermaid-svg-jJupXfvS0VBaXKfz{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jJupXfvS0VBaXKfz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jJupXfvS0VBaXKfz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jJupXfvS0VBaXKfz .error-icon{fill:#552222;}#mermaid-svg-jJupXfvS0VBaXKfz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jJupXfvS0VBaXKfz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jJupXfvS0VBaXKfz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jJupXfvS0VBaXKfz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jJupXfvS0VBaXKfz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jJupXfvS0VBaXKfz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jJupXfvS0VBaXKfz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jJupXfvS0VBaXKfz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jJupXfvS0VBaXKfz .marker.cross{stroke:#333333;}#mermaid-svg-jJupXfvS0VBaXKfz svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jJupXfvS0VBaXKfz p{margin:0;}#mermaid-svg-jJupXfvS0VBaXKfz .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-jJupXfvS0VBaXKfz .cluster-label text{fill:#333;}#mermaid-svg-jJupXfvS0VBaXKfz .cluster-label span{color:#333;}#mermaid-svg-jJupXfvS0VBaXKfz .cluster-label span p{background-color:transparent;}#mermaid-svg-jJupXfvS0VBaXKfz .label text,#mermaid-svg-jJupXfvS0VBaXKfz span{fill:#333;color:#333;}#mermaid-svg-jJupXfvS0VBaXKfz .node rect,#mermaid-svg-jJupXfvS0VBaXKfz .node circle,#mermaid-svg-jJupXfvS0VBaXKfz .node ellipse,#mermaid-svg-jJupXfvS0VBaXKfz .node polygon,#mermaid-svg-jJupXfvS0VBaXKfz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jJupXfvS0VBaXKfz .rough-node .label text,#mermaid-svg-jJupXfvS0VBaXKfz .node .label text,#mermaid-svg-jJupXfvS0VBaXKfz .image-shape .label,#mermaid-svg-jJupXfvS0VBaXKfz .icon-shape .label{text-anchor:middle;}#mermaid-svg-jJupXfvS0VBaXKfz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jJupXfvS0VBaXKfz .rough-node .label,#mermaid-svg-jJupXfvS0VBaXKfz .node .label,#mermaid-svg-jJupXfvS0VBaXKfz .image-shape .label,#mermaid-svg-jJupXfvS0VBaXKfz .icon-shape .label{text-align:center;}#mermaid-svg-jJupXfvS0VBaXKfz .node.clickable{cursor:pointer;}#mermaid-svg-jJupXfvS0VBaXKfz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jJupXfvS0VBaXKfz .arrowheadPath{fill:#333333;}#mermaid-svg-jJupXfvS0VBaXKfz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jJupXfvS0VBaXKfz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jJupXfvS0VBaXKfz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jJupXfvS0VBaXKfz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jJupXfvS0VBaXKfz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jJupXfvS0VBaXKfz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jJupXfvS0VBaXKfz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jJupXfvS0VBaXKfz .cluster text{fill:#333;}#mermaid-svg-jJupXfvS0VBaXKfz .cluster span{color:#333;}#mermaid-svg-jJupXfvS0VBaXKfz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jJupXfvS0VBaXKfz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jJupXfvS0VBaXKfz rect.text{fill:none;stroke-width:0;}#mermaid-svg-jJupXfvS0VBaXKfz .icon-shape,#mermaid-svg-jJupXfvS0VBaXKfz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jJupXfvS0VBaXKfz .icon-shape p,#mermaid-svg-jJupXfvS0VBaXKfz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jJupXfvS0VBaXKfz .icon-shape .label rect,#mermaid-svg-jJupXfvS0VBaXKfz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jJupXfvS0VBaXKfz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jJupXfvS0VBaXKfz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jJupXfvS0VBaXKfz :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
模型自建 checklist(欠分解)
必要交付物从未进入任务图
open_items: 0
模型合法宣布完成
检视发现遗漏gzip / trie 重构 / e2e
Zagens 作为面向 DeepSeek V4 的开源 Agent Harness,核心工程命题是:如何构建一套不依赖模型自我声明的、可审计的、可回放的完成度信任机制。
本文从工程架构角度,拆解 Zagens Harness 系统的设计与实现。
2. 核心理念:Harness,不是聊天壳
Zagens 的判断很明确:不能信任模型自己说「做完了」。需要一套独立于模型的完成度判定系统。
这套系统的三条设计原则(源自 Zagens Harness 设计文档,经 DeepSeek Agent + Harness 负责人 Deli Chen 的持续学习研究印证):
这些原则落实到工程上,就是 Zagens 的组合式 Harness(Composable Harness)—— 三层可插拔门禁系统。
#mermaid-svg-D64cqMM7gYfjiQ1H{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-D64cqMM7gYfjiQ1H .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-D64cqMM7gYfjiQ1H .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-D64cqMM7gYfjiQ1H .error-icon{fill:#552222;}#mermaid-svg-D64cqMM7gYfjiQ1H .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-D64cqMM7gYfjiQ1H .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-D64cqMM7gYfjiQ1H .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-D64cqMM7gYfjiQ1H .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-D64cqMM7gYfjiQ1H .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-D64cqMM7gYfjiQ1H .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-D64cqMM7gYfjiQ1H .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-D64cqMM7gYfjiQ1H .marker{fill:#333333;stroke:#333333;}#mermaid-svg-D64cqMM7gYfjiQ1H .marker.cross{stroke:#333333;}#mermaid-svg-D64cqMM7gYfjiQ1H svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-D64cqMM7gYfjiQ1H p{margin:0;}#mermaid-svg-D64cqMM7gYfjiQ1H .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-D64cqMM7gYfjiQ1H .cluster-label text{fill:#333;}#mermaid-svg-D64cqMM7gYfjiQ1H .cluster-label span{color:#333;}#mermaid-svg-D64cqMM7gYfjiQ1H .cluster-label span p{background-color:transparent;}#mermaid-svg-D64cqMM7gYfjiQ1H .label text,#mermaid-svg-D64cqMM7gYfjiQ1H span{fill:#333;color:#333;}#mermaid-svg-D64cqMM7gYfjiQ1H .node rect,#mermaid-svg-D64cqMM7gYfjiQ1H .node circle,#mermaid-svg-D64cqMM7gYfjiQ1H .node ellipse,#mermaid-svg-D64cqMM7gYfjiQ1H .node polygon,#mermaid-svg-D64cqMM7gYfjiQ1H .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-D64cqMM7gYfjiQ1H .rough-node .label text,#mermaid-svg-D64cqMM7gYfjiQ1H .node .label text,#mermaid-svg-D64cqMM7gYfjiQ1H .image-shape .label,#mermaid-svg-D64cqMM7gYfjiQ1H .icon-shape .label{text-anchor:middle;}#mermaid-svg-D64cqMM7gYfjiQ1H .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-D64cqMM7gYfjiQ1H .rough-node .label,#mermaid-svg-D64cqMM7gYfjiQ1H .node .label,#mermaid-svg-D64cqMM7gYfjiQ1H .image-shape .label,#mermaid-svg-D64cqMM7gYfjiQ1H .icon-shape .label{text-align:center;}#mermaid-svg-D64cqMM7gYfjiQ1H .node.clickable{cursor:pointer;}#mermaid-svg-D64cqMM7gYfjiQ1H .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-D64cqMM7gYfjiQ1H .arrowheadPath{fill:#333333;}#mermaid-svg-D64cqMM7gYfjiQ1H .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-D64cqMM7gYfjiQ1H .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-D64cqMM7gYfjiQ1H .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-D64cqMM7gYfjiQ1H .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-D64cqMM7gYfjiQ1H .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-D64cqMM7gYfjiQ1H .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-D64cqMM7gYfjiQ1H .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-D64cqMM7gYfjiQ1H .cluster text{fill:#333;}#mermaid-svg-D64cqMM7gYfjiQ1H .cluster span{color:#333;}#mermaid-svg-D64cqMM7gYfjiQ1H div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-D64cqMM7gYfjiQ1H .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-D64cqMM7gYfjiQ1H rect.text{fill:none;stroke-width:0;}#mermaid-svg-D64cqMM7gYfjiQ1H .icon-shape,#mermaid-svg-D64cqMM7gYfjiQ1H .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-D64cqMM7gYfjiQ1H .icon-shape p,#mermaid-svg-D64cqMM7gYfjiQ1H .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-D64cqMM7gYfjiQ1H .icon-shape .label rect,#mermaid-svg-D64cqMM7gYfjiQ1H .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-D64cqMM7gYfjiQ1H .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-D64cqMM7gYfjiQ1H .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-D64cqMM7gYfjiQ1H :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
Harness 设计原则
信号质量 = 机器裁决退出码 · 路径命中 · 可回放
信号独立性规则独立 + Agent 独立
禁止 LLM 盖章审计者不能当法官
组合式 Harness三层可插拔门禁
3. 引擎基础:Kernel V3 —— 事件溯源的 Turn 引擎
Harness 门禁要可审计、可回放,离不开底层引擎的事件持久化。Zagens v0.8.2 的 Kernel V3 是事件溯源 turn 循环——下文只保留与 Harness 相关的要点;完整 turn 机状态机见源码 LiveTurnMachine / ReplayTurnMachine。
#mermaid-svg-Jecs9Qt4r0mcXizn{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Jecs9Qt4r0mcXizn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Jecs9Qt4r0mcXizn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Jecs9Qt4r0mcXizn .error-icon{fill:#552222;}#mermaid-svg-Jecs9Qt4r0mcXizn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Jecs9Qt4r0mcXizn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Jecs9Qt4r0mcXizn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Jecs9Qt4r0mcXizn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Jecs9Qt4r0mcXizn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Jecs9Qt4r0mcXizn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Jecs9Qt4r0mcXizn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Jecs9Qt4r0mcXizn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Jecs9Qt4r0mcXizn .marker.cross{stroke:#333333;}#mermaid-svg-Jecs9Qt4r0mcXizn svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Jecs9Qt4r0mcXizn p{margin:0;}#mermaid-svg-Jecs9Qt4r0mcXizn .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Jecs9Qt4r0mcXizn .cluster-label text{fill:#333;}#mermaid-svg-Jecs9Qt4r0mcXizn .cluster-label span{color:#333;}#mermaid-svg-Jecs9Qt4r0mcXizn .cluster-label span p{background-color:transparent;}#mermaid-svg-Jecs9Qt4r0mcXizn .label text,#mermaid-svg-Jecs9Qt4r0mcXizn span{fill:#333;color:#333;}#mermaid-svg-Jecs9Qt4r0mcXizn .node rect,#mermaid-svg-Jecs9Qt4r0mcXizn .node circle,#mermaid-svg-Jecs9Qt4r0mcXizn .node ellipse,#mermaid-svg-Jecs9Qt4r0mcXizn .node polygon,#mermaid-svg-Jecs9Qt4r0mcXizn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Jecs9Qt4r0mcXizn .rough-node .label text,#mermaid-svg-Jecs9Qt4r0mcXizn .node .label text,#mermaid-svg-Jecs9Qt4r0mcXizn .image-shape .label,#mermaid-svg-Jecs9Qt4r0mcXizn .icon-shape .label{text-anchor:middle;}#mermaid-svg-Jecs9Qt4r0mcXizn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Jecs9Qt4r0mcXizn .rough-node .label,#mermaid-svg-Jecs9Qt4r0mcXizn .node .label,#mermaid-svg-Jecs9Qt4r0mcXizn .image-shape .label,#mermaid-svg-Jecs9Qt4r0mcXizn .icon-shape .label{text-align:center;}#mermaid-svg-Jecs9Qt4r0mcXizn .node.clickable{cursor:pointer;}#mermaid-svg-Jecs9Qt4r0mcXizn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Jecs9Qt4r0mcXizn .arrowheadPath{fill:#333333;}#mermaid-svg-Jecs9Qt4r0mcXizn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Jecs9Qt4r0mcXizn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Jecs9Qt4r0mcXizn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Jecs9Qt4r0mcXizn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Jecs9Qt4r0mcXizn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Jecs9Qt4r0mcXizn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Jecs9Qt4r0mcXizn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Jecs9Qt4r0mcXizn .cluster text{fill:#333;}#mermaid-svg-Jecs9Qt4r0mcXizn .cluster span{color:#333;}#mermaid-svg-Jecs9Qt4r0mcXizn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Jecs9Qt4r0mcXizn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Jecs9Qt4r0mcXizn rect.text{fill:none;stroke-width:0;}#mermaid-svg-Jecs9Qt4r0mcXizn .icon-shape,#mermaid-svg-Jecs9Qt4r0mcXizn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Jecs9Qt4r0mcXizn .icon-shape p,#mermaid-svg-Jecs9Qt4r0mcXizn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Jecs9Qt4r0mcXizn .icon-shape .label rect,#mermaid-svg-Jecs9Qt4r0mcXizn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Jecs9Qt4r0mcXizn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Jecs9Qt4r0mcXizn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Jecs9Qt4r0mcXizn :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
事件溯源持久化
KernelEvent
LiveTurnMachine
outer 循环step-frame → pre-inner → inner→ post-inner → boundary grants
inner 循环inner_step_live_plan→ EffectInterpreter
InnerStepHost IOstreaming · tool execution · LSP notify
handle_deepseek_turn
Turn endruntime-server host_impl
finish_kernel_turn
kernel_turn_replay_verify+ projection compare
kernel_eventsSQLite
每次 turn 的完整生命周期被记录为 KernelEvent,存储在 SQLite 的 kernel_events 表:
CREATE TABLE kernel_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
seq INTEGER NOT NULL,
ts_ms INTEGER NOT NULL,
kind TEXT NOT NULL,
turn_id TEXT,
payload TEXT NOT NULL — JSON KernelEvent
);
事件溯源对 Harness 的价值:
- 可回放(Replayable):ReplayTurnMachine 能从事件日志重建状态,Harness 的金色夹具(golden fixtures)可在 CI 中精确验证门禁行为;
- 可审计:所有 turn 生命周期事件(模型请求、工具调用结果、门禁判定)都有结构化持久化记录;
- 可恢复:log-first 会话恢复优先从事件日志重建消息,不依赖 session JSON。
基于这个引擎,Zagens 的 Harness 各层门禁得以可靠地挂载在 turn 循环的各个退出点上。
4. 三层组合式 Harness 架构
Zagens 的完成度门禁系统是三层可组合的:
#mermaid-svg-Mx7ct2rBjbEpmPyJ{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Mx7ct2rBjbEpmPyJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .error-icon{fill:#552222;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .marker.cross{stroke:#333333;}#mermaid-svg-Mx7ct2rBjbEpmPyJ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Mx7ct2rBjbEpmPyJ p{margin:0;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .cluster-label text{fill:#333;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .cluster-label span{color:#333;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .cluster-label span p{background-color:transparent;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .label text,#mermaid-svg-Mx7ct2rBjbEpmPyJ span{fill:#333;color:#333;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .node rect,#mermaid-svg-Mx7ct2rBjbEpmPyJ .node circle,#mermaid-svg-Mx7ct2rBjbEpmPyJ .node ellipse,#mermaid-svg-Mx7ct2rBjbEpmPyJ .node polygon,#mermaid-svg-Mx7ct2rBjbEpmPyJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .rough-node .label text,#mermaid-svg-Mx7ct2rBjbEpmPyJ .node .label text,#mermaid-svg-Mx7ct2rBjbEpmPyJ .image-shape .label,#mermaid-svg-Mx7ct2rBjbEpmPyJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .rough-node .label,#mermaid-svg-Mx7ct2rBjbEpmPyJ .node .label,#mermaid-svg-Mx7ct2rBjbEpmPyJ .image-shape .label,#mermaid-svg-Mx7ct2rBjbEpmPyJ .icon-shape .label{text-align:center;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .node.clickable{cursor:pointer;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .arrowheadPath{fill:#333333;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Mx7ct2rBjbEpmPyJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Mx7ct2rBjbEpmPyJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Mx7ct2rBjbEpmPyJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .cluster text{fill:#333;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .cluster span{color:#333;}#mermaid-svg-Mx7ct2rBjbEpmPyJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Mx7ct2rBjbEpmPyJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .icon-shape,#mermaid-svg-Mx7ct2rBjbEpmPyJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .icon-shape p,#mermaid-svg-Mx7ct2rBjbEpmPyJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .icon-shape .label rect,#mermaid-svg-Mx7ct2rBjbEpmPyJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Mx7ct2rBjbEpmPyJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Mx7ct2rBjbEpmPyJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Mx7ct2rBjbEpmPyJ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
graph_complete 候选时(原子执行)
运行中(全程)
checklist 全绿
Layer 1: 模型自驱plan + checklist + nudge 继续
Stub 门 · 文件扫描
Layer 2: 硬验收门 · 退出码 Oracle
Layer 3: 交付物对账 · path/glob
✅ 真实完成
组合方式(可独立开关):
- Layer 1 仅 = 原始效果(模型自驱 + 防早停);
- Layer 1+2 = 纯粹的退出码门禁(最确定、最便宜);
- Layer 1+2+3 = 完整组合,能捕获欠分解场景。
4.1 门禁在何时触发
§4 的流程图容易误读为「L1 跑完再跑 L2」。实际时序如下:
Layer 3
Layer 2
Stub 门
graph_complete 候选
Layer 1 (LHT)
模型
Layer 3
Layer 2
Stub 门
graph_complete 候选
Layer 1 (LHT)
模型
#mermaid-svg-JUCBsLgmAwKFcCMV{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JUCBsLgmAwKFcCMV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JUCBsLgmAwKFcCMV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JUCBsLgmAwKFcCMV .error-icon{fill:#552222;}#mermaid-svg-JUCBsLgmAwKFcCMV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JUCBsLgmAwKFcCMV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JUCBsLgmAwKFcCMV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JUCBsLgmAwKFcCMV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JUCBsLgmAwKFcCMV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JUCBsLgmAwKFcCMV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JUCBsLgmAwKFcCMV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JUCBsLgmAwKFcCMV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JUCBsLgmAwKFcCMV .marker.cross{stroke:#333333;}#mermaid-svg-JUCBsLgmAwKFcCMV svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JUCBsLgmAwKFcCMV p{margin:0;}#mermaid-svg-JUCBsLgmAwKFcCMV .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-JUCBsLgmAwKFcCMV text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-JUCBsLgmAwKFcCMV .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-JUCBsLgmAwKFcCMV .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-JUCBsLgmAwKFcCMV .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-JUCBsLgmAwKFcCMV .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-JUCBsLgmAwKFcCMV #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-JUCBsLgmAwKFcCMV .sequenceNumber{fill:white;}#mermaid-svg-JUCBsLgmAwKFcCMV #sequencenumber{fill:#333;}#mermaid-svg-JUCBsLgmAwKFcCMV #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-JUCBsLgmAwKFcCMV .messageText{fill:#333;stroke:none;}#mermaid-svg-JUCBsLgmAwKFcCMV .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-JUCBsLgmAwKFcCMV .labelText,#mermaid-svg-JUCBsLgmAwKFcCMV .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-JUCBsLgmAwKFcCMV .loopText,#mermaid-svg-JUCBsLgmAwKFcCMV .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-JUCBsLgmAwKFcCMV .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-JUCBsLgmAwKFcCMV .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-JUCBsLgmAwKFcCMV .noteText,#mermaid-svg-JUCBsLgmAwKFcCMV .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-JUCBsLgmAwKFcCMV .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-JUCBsLgmAwKFcCMV .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-JUCBsLgmAwKFcCMV .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-JUCBsLgmAwKFcCMV .actorPopupMenu{position:absolute;}#mermaid-svg-JUCBsLgmAwKFcCMV .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-JUCBsLgmAwKFcCMV .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-JUCBsLgmAwKFcCMV .actor-man circle,#mermaid-svg-JUCBsLgmAwKFcCMV line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-JUCBsLgmAwKFcCMV :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
alt
[graph.incomplete]
loop
[整个任务周期]
alt
[缺交付物]
[全绿]
alt
[退出码 ≠ 0]
[全绿]
alt
[发现 todo!/unimplemented!]
[通过]
无工具调用 / step 耗尽 / loop_guard 等
注入 nudge,继续
plan + checklist 均无可办项
纯文件扫描(先于 L2/L3)
阻断,强制返工
Harness 主动执行 verify
强制返工
路径/glob 对账
missing_deliverables + 返工
✅ 真实完成
要点: Layer 1 贯穿全程;Layer 2/3(及 Stub 门)仅在 graph_complete 候选时原子执行,同轮内 L2 全绿后才进入 L3。
4.2 案例:MicroStack02 欠分解假绿
MicroStack 框架压测(代号 MICROSTACK)规定 24 类交付物、四门验收 + [verify:] 纪律。一次典型失败跑(MicroStack02):
| UI / 节点 | checklist 100%、incomplete_stop=0、gate_skip graph_complete ×3 | — |
| 规模 | 声称完成 | 仅 ~7045 行(目标 15–40K) |
| 覆盖率 | checklist 项已勾 | app 16.3%、orm 4.7% |
| 欠分解 | 任务图全绿 | gzip 中间件、cmd/microstack/main.go、Router trie 重构从未进 checklist |
各层分别拦住了什么?
| Layer 1 | ✅ 无早停;但 checklist 全绿 → 放行候选 | 同左 |
| Layer 2 | — | ✅ 覆盖率门、gofmt 真门可拦「测试红/未格式化」 |
| Layer 3 | — | ✅ middleware/gzip.go、**/*trie*.go 等 manifest 项抓到「从未分解进清单」的交付物 |
根因代码定位:maybe_continue_incomplete_code_task 只看模型自产 plan + checklist——完成度上界 = 模型自拆清单完整度。Layer 3 把「模型欠分解」平移为「操作者预写 manifest」,但 manifest 可离线审查、可回归,远比每次现场分解稳定。
下面逐层深入。
5. Layer 1:强制继续(LHT)—— 不让模型用散文结束
Layer 1 解决的核心问题:模型在多步骤任务中途以文字总结结束,不再调用任何工具。
5.1 问题根因
源码定位在 crates/runtime-server/src/long_horizon/mod.rs 的 maybe_continue_incomplete_code_task:
graph = CodeTaskGraph::from_snapshots(plan, checklist)
if graph.is_empty() -> Skip("graph_empty")
if !graph.incomplete() -> Skip("graph_complete")
完成判定完全依赖模型自产的 plan + checklist 快照。如果模型在初始分解时就遗漏了关键交付物,「open_items == 0」就是一个虚假的完成信号。
5.2 强制继续机制
maybe_continue_incomplete_code_task 被挂载在 no_tool_uses.rs 的分支链中(audit 之后、Break 之前):
#mermaid-svg-VVwsRXdLLQIgrGvO{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-VVwsRXdLLQIgrGvO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VVwsRXdLLQIgrGvO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VVwsRXdLLQIgrGvO .error-icon{fill:#552222;}#mermaid-svg-VVwsRXdLLQIgrGvO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VVwsRXdLLQIgrGvO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VVwsRXdLLQIgrGvO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VVwsRXdLLQIgrGvO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VVwsRXdLLQIgrGvO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VVwsRXdLLQIgrGvO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VVwsRXdLLQIgrGvO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VVwsRXdLLQIgrGvO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VVwsRXdLLQIgrGvO .marker.cross{stroke:#333333;}#mermaid-svg-VVwsRXdLLQIgrGvO svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VVwsRXdLLQIgrGvO p{margin:0;}#mermaid-svg-VVwsRXdLLQIgrGvO .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-VVwsRXdLLQIgrGvO .cluster-label text{fill:#333;}#mermaid-svg-VVwsRXdLLQIgrGvO .cluster-label span{color:#333;}#mermaid-svg-VVwsRXdLLQIgrGvO .cluster-label span p{background-color:transparent;}#mermaid-svg-VVwsRXdLLQIgrGvO .label text,#mermaid-svg-VVwsRXdLLQIgrGvO span{fill:#333;color:#333;}#mermaid-svg-VVwsRXdLLQIgrGvO .node rect,#mermaid-svg-VVwsRXdLLQIgrGvO .node circle,#mermaid-svg-VVwsRXdLLQIgrGvO .node ellipse,#mermaid-svg-VVwsRXdLLQIgrGvO .node polygon,#mermaid-svg-VVwsRXdLLQIgrGvO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VVwsRXdLLQIgrGvO .rough-node .label text,#mermaid-svg-VVwsRXdLLQIgrGvO .node .label text,#mermaid-svg-VVwsRXdLLQIgrGvO .image-shape .label,#mermaid-svg-VVwsRXdLLQIgrGvO .icon-shape .label{text-anchor:middle;}#mermaid-svg-VVwsRXdLLQIgrGvO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VVwsRXdLLQIgrGvO .rough-node .label,#mermaid-svg-VVwsRXdLLQIgrGvO .node .label,#mermaid-svg-VVwsRXdLLQIgrGvO .image-shape .label,#mermaid-svg-VVwsRXdLLQIgrGvO .icon-shape .label{text-align:center;}#mermaid-svg-VVwsRXdLLQIgrGvO .node.clickable{cursor:pointer;}#mermaid-svg-VVwsRXdLLQIgrGvO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VVwsRXdLLQIgrGvO .arrowheadPath{fill:#333333;}#mermaid-svg-VVwsRXdLLQIgrGvO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VVwsRXdLLQIgrGvO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VVwsRXdLLQIgrGvO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VVwsRXdLLQIgrGvO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VVwsRXdLLQIgrGvO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VVwsRXdLLQIgrGvO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VVwsRXdLLQIgrGvO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VVwsRXdLLQIgrGvO .cluster text{fill:#333;}#mermaid-svg-VVwsRXdLLQIgrGvO .cluster span{color:#333;}#mermaid-svg-VVwsRXdLLQIgrGvO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-VVwsRXdLLQIgrGvO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VVwsRXdLLQIgrGvO rect.text{fill:none;stroke-width:0;}#mermaid-svg-VVwsRXdLLQIgrGvO .icon-shape,#mermaid-svg-VVwsRXdLLQIgrGvO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VVwsRXdLLQIgrGvO .icon-shape p,#mermaid-svg-VVwsRXdLLQIgrGvO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VVwsRXdLLQIgrGvO .icon-shape .label rect,#mermaid-svg-VVwsRXdLLQIgrGvO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VVwsRXdLLQIgrGvO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VVwsRXdLLQIgrGvO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VVwsRXdLLQIgrGvO :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
是
否
是
否
是
否
是
否
是
否
是
否
模型无工具调用no_tool_uses 路径
1. scratchpad_summary+ pending steers?
Continue
2. pending steers?
Continue
3. sub-agentcompletions?
Continue
4. REPL blocks?
Continue / Break
5. incompleteaudit continue?
Continue(audit 独占)
6. ★ LHTgraph.incomplete?
Continue(注入 nudge)
Break
当模型在工具调用后只输出文字总结,引擎走 no_tool_uses 路径 → 第 6 分支触发 → 注入一条强制继续的 nudge 消息:
长程代码任务尚未完成 — 请勿仅用文字总结结束本轮。
目标:将 auth 模块重构为基于 trait 的后端
进度:████░░░░░░ 42%(plan 1/3 阶段;checklist 2/5 项未完成)
仍待完成:
– [plan ◎] 引入 AuthBackend trait
– [todo ○] 更新集成测试
请继续用工具完成当前 in_progress 项,验证(如 cargo check/test),再 checklist_update / update_plan。
5.3 NudgeTracker:防死循环
为防止模型在同一个 item 上无限循环,Zagens 实现了 NudgeTracker:
#mermaid-svg-TKmBecJsMiLk8491{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TKmBecJsMiLk8491 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TKmBecJsMiLk8491 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TKmBecJsMiLk8491 .error-icon{fill:#552222;}#mermaid-svg-TKmBecJsMiLk8491 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TKmBecJsMiLk8491 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TKmBecJsMiLk8491 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TKmBecJsMiLk8491 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TKmBecJsMiLk8491 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TKmBecJsMiLk8491 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TKmBecJsMiLk8491 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TKmBecJsMiLk8491 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TKmBecJsMiLk8491 .marker.cross{stroke:#333333;}#mermaid-svg-TKmBecJsMiLk8491 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TKmBecJsMiLk8491 p{margin:0;}#mermaid-svg-TKmBecJsMiLk8491 defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-TKmBecJsMiLk8491 g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-TKmBecJsMiLk8491 g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-TKmBecJsMiLk8491 g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-TKmBecJsMiLk8491 g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-TKmBecJsMiLk8491 g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-TKmBecJsMiLk8491 .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-TKmBecJsMiLk8491 .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-TKmBecJsMiLk8491 .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-TKmBecJsMiLk8491 .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-TKmBecJsMiLk8491 .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-TKmBecJsMiLk8491 .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-TKmBecJsMiLk8491 .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-TKmBecJsMiLk8491 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TKmBecJsMiLk8491 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TKmBecJsMiLk8491 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TKmBecJsMiLk8491 .edgeLabel .label text{fill:#333;}#mermaid-svg-TKmBecJsMiLk8491 .label div .edgeLabel{color:#333;}#mermaid-svg-TKmBecJsMiLk8491 .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-TKmBecJsMiLk8491 .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-TKmBecJsMiLk8491 .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-TKmBecJsMiLk8491 .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-TKmBecJsMiLk8491 .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-TKmBecJsMiLk8491 .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TKmBecJsMiLk8491 .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TKmBecJsMiLk8491 #statediagram-barbEnd{fill:#333333;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TKmBecJsMiLk8491 .cluster-label,#mermaid-svg-TKmBecJsMiLk8491 .nodeLabel{color:#131300;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-TKmBecJsMiLk8491 .note-edge{stroke-dasharray:5;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-note text{fill:black;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram-note .nodeLabel{color:black;}#mermaid-svg-TKmBecJsMiLk8491 .statediagram .edgeLabel{color:red;}#mermaid-svg-TKmBecJsMiLk8491 #dependencyStart,#mermaid-svg-TKmBecJsMiLk8491 #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-TKmBecJsMiLk8491 .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TKmBecJsMiLk8491 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
in_progress_id 被 nudge
有实质进展 → 重置计数
同一 item nudge 3 次无进展
同一 item nudge 5 次(硬上限)
连续 8 turn 无工具调用
long_horizon_blocked
用户消息恢复
请用户引导
Nudging
Blocked
WaitUser
AskUser
上图为状态机概览;阈值如下:
| 同一 in_progress_id 被 nudge 3 次而无实质进展 | long_horizon_blocked |
| 同一 item 被 nudge 5 次(硬上限) | 停止 nudge,等待用户消息恢复 |
| in_progress_id 变化 | 重置计数 |
| 连续 8 个助手 turn 无工具调用 | nudge 变为「请用户引导」,不再机械继续 |
5.4 进展判定
「有进展吗?」需要客观信号,而非正则的玄学判断:
| edit_file / write_file / apply_patch 成功 | 工具返回 success | 客观 |
| exec_shell + 退出码 0 + 匹配验证正则 | success + 匹配 | 启发式 |
| checklist_update / update_plan 成功 | 状态机迁移 | 客观 |
| git working-tree 变化 | git status –porcelain 签名变化 | 客观,语言无关 |
其中 git working-tree 信号(Phase 2.x 引入)解决了非主流语言项目中验证正则列表不全的问题——只要工作区文件发生了实际变化,就算进展。
5.5 演进中的关键修补
LHT 并非一次性设计完成。经过 DEMO3–DEMO6 四次实证压力测试,团队修复了多个隐蔽的早停泄漏路径:
| Step budget 耗尽 | 模型在 100 step 后 break,无任何 nudge | maybe_continue_at_step_limit 给予新的预算窗口(最多 3 次续命) |
| loop_guard 截停 | 同一工具连续失败 8 次,直接 Break | maybe_continue_after_loop_guard_halt 清除失败计数 + 建议切换方案 |
| 上下文溢出 | 上下文超出模型窗口,强制 Failed | maybe_cycle_handoff_on_context_overflow 强制一次 cycle 交接 |
| 欠分解导致的虚假完成 | checklist 全绿但关键交付物未写 | 交给 Layer 2+3 解决(见 §4.2) |
每个泄漏路径都对应一个 run.rs 中的 break 出口。团队做了系统性审计:每个 turn 退出点都必须经过 LHT 门禁,否则就是一个新的早停泄漏。
#mermaid-svg-agHLwLPuuqODKMDX{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-agHLwLPuuqODKMDX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-agHLwLPuuqODKMDX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-agHLwLPuuqODKMDX .error-icon{fill:#552222;}#mermaid-svg-agHLwLPuuqODKMDX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-agHLwLPuuqODKMDX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-agHLwLPuuqODKMDX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-agHLwLPuuqODKMDX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-agHLwLPuuqODKMDX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-agHLwLPuuqODKMDX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-agHLwLPuuqODKMDX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-agHLwLPuuqODKMDX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-agHLwLPuuqODKMDX .marker.cross{stroke:#333333;}#mermaid-svg-agHLwLPuuqODKMDX svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-agHLwLPuuqODKMDX p{margin:0;}#mermaid-svg-agHLwLPuuqODKMDX .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-agHLwLPuuqODKMDX .cluster-label text{fill:#333;}#mermaid-svg-agHLwLPuuqODKMDX .cluster-label span{color:#333;}#mermaid-svg-agHLwLPuuqODKMDX .cluster-label span p{background-color:transparent;}#mermaid-svg-agHLwLPuuqODKMDX .label text,#mermaid-svg-agHLwLPuuqODKMDX span{fill:#333;color:#333;}#mermaid-svg-agHLwLPuuqODKMDX .node rect,#mermaid-svg-agHLwLPuuqODKMDX .node circle,#mermaid-svg-agHLwLPuuqODKMDX .node ellipse,#mermaid-svg-agHLwLPuuqODKMDX .node polygon,#mermaid-svg-agHLwLPuuqODKMDX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-agHLwLPuuqODKMDX .rough-node .label text,#mermaid-svg-agHLwLPuuqODKMDX .node .label text,#mermaid-svg-agHLwLPuuqODKMDX .image-shape .label,#mermaid-svg-agHLwLPuuqODKMDX .icon-shape .label{text-anchor:middle;}#mermaid-svg-agHLwLPuuqODKMDX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-agHLwLPuuqODKMDX .rough-node .label,#mermaid-svg-agHLwLPuuqODKMDX .node .label,#mermaid-svg-agHLwLPuuqODKMDX .image-shape .label,#mermaid-svg-agHLwLPuuqODKMDX .icon-shape .label{text-align:center;}#mermaid-svg-agHLwLPuuqODKMDX .node.clickable{cursor:pointer;}#mermaid-svg-agHLwLPuuqODKMDX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-agHLwLPuuqODKMDX .arrowheadPath{fill:#333333;}#mermaid-svg-agHLwLPuuqODKMDX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-agHLwLPuuqODKMDX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-agHLwLPuuqODKMDX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-agHLwLPuuqODKMDX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-agHLwLPuuqODKMDX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-agHLwLPuuqODKMDX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-agHLwLPuuqODKMDX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-agHLwLPuuqODKMDX .cluster text{fill:#333;}#mermaid-svg-agHLwLPuuqODKMDX .cluster span{color:#333;}#mermaid-svg-agHLwLPuuqODKMDX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-agHLwLPuuqODKMDX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-agHLwLPuuqODKMDX rect.text{fill:none;stroke-width:0;}#mermaid-svg-agHLwLPuuqODKMDX .icon-shape,#mermaid-svg-agHLwLPuuqODKMDX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-agHLwLPuuqODKMDX .icon-shape p,#mermaid-svg-agHLwLPuuqODKMDX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-agHLwLPuuqODKMDX .icon-shape .label rect,#mermaid-svg-agHLwLPuuqODKMDX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-agHLwLPuuqODKMDX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-agHLwLPuuqODKMDX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-agHLwLPuuqODKMDX :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
早停泄漏路径(DEMO3–6 修补)
Step budget 耗尽
maybe_continue_at_step_limit最多 3 次续命
loop_guard 截停
maybe_continue_after_loop_guard_halt清除失败计数
上下文溢出
maybe_cycle_handoff_on_context_overflow强制 cycle 交接
欠分解虚假完成
Layer 2+3 机器门禁
每个 break 出口必须经过 LHT 门禁
6. Layer 2:硬验收门 —— Harness 主动执行,退出码当法官
Layer 1 只能保证「模型没提前停」,但不能保证「做对了」。Layer 2 扭转了判决权力:不再相信模型说「我跑过了,通过了」,Harness 重新跑一遍,看退出码。
6.1 设计铁律
不能用 LLM 当法官。 用 LLM 审计者「读一遍然后说 LGTM」是一个软的、非确定性的、可说服的、不能离线回放的裁决。
正确的分工(下图);硬验收门与交付物覆盖均由机器 Oracle 裁决,不由 LLM 散文判断:
#mermaid-svg-DCYfhpD42b0MN23r{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DCYfhpD42b0MN23r .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DCYfhpD42b0MN23r .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DCYfhpD42b0MN23r .error-icon{fill:#552222;}#mermaid-svg-DCYfhpD42b0MN23r .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DCYfhpD42b0MN23r .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DCYfhpD42b0MN23r .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DCYfhpD42b0MN23r .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DCYfhpD42b0MN23r .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DCYfhpD42b0MN23r .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DCYfhpD42b0MN23r .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DCYfhpD42b0MN23r .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DCYfhpD42b0MN23r .marker.cross{stroke:#333333;}#mermaid-svg-DCYfhpD42b0MN23r svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DCYfhpD42b0MN23r p{margin:0;}#mermaid-svg-DCYfhpD42b0MN23r .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-DCYfhpD42b0MN23r .cluster-label text{fill:#333;}#mermaid-svg-DCYfhpD42b0MN23r .cluster-label span{color:#333;}#mermaid-svg-DCYfhpD42b0MN23r .cluster-label span p{background-color:transparent;}#mermaid-svg-DCYfhpD42b0MN23r .label text,#mermaid-svg-DCYfhpD42b0MN23r span{fill:#333;color:#333;}#mermaid-svg-DCYfhpD42b0MN23r .node rect,#mermaid-svg-DCYfhpD42b0MN23r .node circle,#mermaid-svg-DCYfhpD42b0MN23r .node ellipse,#mermaid-svg-DCYfhpD42b0MN23r .node polygon,#mermaid-svg-DCYfhpD42b0MN23r .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DCYfhpD42b0MN23r .rough-node .label text,#mermaid-svg-DCYfhpD42b0MN23r .node .label text,#mermaid-svg-DCYfhpD42b0MN23r .image-shape .label,#mermaid-svg-DCYfhpD42b0MN23r .icon-shape .label{text-anchor:middle;}#mermaid-svg-DCYfhpD42b0MN23r .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DCYfhpD42b0MN23r .rough-node .label,#mermaid-svg-DCYfhpD42b0MN23r .node .label,#mermaid-svg-DCYfhpD42b0MN23r .image-shape .label,#mermaid-svg-DCYfhpD42b0MN23r .icon-shape .label{text-align:center;}#mermaid-svg-DCYfhpD42b0MN23r .node.clickable{cursor:pointer;}#mermaid-svg-DCYfhpD42b0MN23r .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DCYfhpD42b0MN23r .arrowheadPath{fill:#333333;}#mermaid-svg-DCYfhpD42b0MN23r .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DCYfhpD42b0MN23r .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DCYfhpD42b0MN23r .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DCYfhpD42b0MN23r .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DCYfhpD42b0MN23r .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DCYfhpD42b0MN23r .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DCYfhpD42b0MN23r .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DCYfhpD42b0MN23r .cluster text{fill:#333;}#mermaid-svg-DCYfhpD42b0MN23r .cluster span{color:#333;}#mermaid-svg-DCYfhpD42b0MN23r div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DCYfhpD42b0MN23r .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DCYfhpD42b0MN23r rect.text{fill:none;stroke-width:0;}#mermaid-svg-DCYfhpD42b0MN23r .icon-shape,#mermaid-svg-DCYfhpD42b0MN23r .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DCYfhpD42b0MN23r .icon-shape p,#mermaid-svg-DCYfhpD42b0MN23r .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DCYfhpD42b0MN23r .icon-shape .label rect,#mermaid-svg-DCYfhpD42b0MN23r .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DCYfhpD42b0MN23r .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DCYfhpD42b0MN23r .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DCYfhpD42b0MN23r :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
✅ 机器 Oracle
❌ 禁止
软 · 不可回放
LLM 审计者读一遍说 LGTM
退出码法官Harness 主动执行 manifest
路径对账法官预声明交付物扫描
不放行
通过 / 不通过
6.2 验收 Manifest
操作者在 ~/.zagens/config.toml 中声明验收门列表:
[long_horizon.completion_gate]
mode = "enforce"
max_manifest_rounds = 5
[[long_horizon.completion_gate.verify]]
id = "build"
cmd = "go build ./…"
[[long_horizon.completion_gate.verify]]
id = "contracts_stable"
cmd = "git diff –exit-code contracts/"
[[long_horizon.completion_gate.verify]]
id = "coverage_app"
shell = "none"
argv = ["zagens", "coverage-gate", "–pkg", "app", "–min", "75"]
关键约束:
- shell = "none" + argv:跨平台(Windows 无 bash),避免引用语义漂移;
- 退出码不是 0 就判不通过,强制模型返工;
- 区分断言失败与基础设施错误:exit_class 分 assertion(测试红)和 infra(命令找不到、超时),连续 N 次 infra 则诚实宣布 audit_unmet;
- 只信任用户全局配置/内置测试夹具中的可执行命令,工作区配置/模型生成文件只能走 observe 模式(记录但不阻塞)。
6.3 任务无关的通用验收门
Layer 2 有三类 verify 来源;其中 操作者 manifest(§6.2)适合回归夹具与强约束任务,另有两类零 per-task 配置、全局开关即覆盖所有代码任务的通用来源:
| 操作者 manifest | completion_gate.mode | 手写的 [[verify]] 列表 | 受信任全局配置 |
| 模型 [verify:] 回放 | auto_verify_replay | 扫描已完成 checklist 项,Harness 主动重跑 | 无需额外信任 |
| 工具链探测门 | toolchain_gate | 探测 go.mod/Cargo.toml/package.json 等 | 内置固定命令 |
三类来源按归一化命令合并去重(优先级 operator > toolchain > model),一次跑完。日常任务可在 ~/.zagens/config.toml 中只开全局开关,无需 per-task manifest:
[long_horizon.completion_gate]
auto_verify_replay = "enforce" # 主动复跑模型声明的 [verify:]
toolchain_gate = "observe" # 工具链探测 build/test
如此设计后,Layer 2 的价值核心不再是「每个任务写一份 manifest」,而是**「Harness 主动执行、退出码当法官」**——大多数日常任务打开上述开关即可。
#mermaid-svg-iHEI6X0tNxnJXqEV{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-iHEI6X0tNxnJXqEV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-iHEI6X0tNxnJXqEV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-iHEI6X0tNxnJXqEV .error-icon{fill:#552222;}#mermaid-svg-iHEI6X0tNxnJXqEV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-iHEI6X0tNxnJXqEV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-iHEI6X0tNxnJXqEV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-iHEI6X0tNxnJXqEV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-iHEI6X0tNxnJXqEV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-iHEI6X0tNxnJXqEV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-iHEI6X0tNxnJXqEV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-iHEI6X0tNxnJXqEV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-iHEI6X0tNxnJXqEV .marker.cross{stroke:#333333;}#mermaid-svg-iHEI6X0tNxnJXqEV svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-iHEI6X0tNxnJXqEV p{margin:0;}#mermaid-svg-iHEI6X0tNxnJXqEV .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-iHEI6X0tNxnJXqEV .cluster-label text{fill:#333;}#mermaid-svg-iHEI6X0tNxnJXqEV .cluster-label span{color:#333;}#mermaid-svg-iHEI6X0tNxnJXqEV .cluster-label span p{background-color:transparent;}#mermaid-svg-iHEI6X0tNxnJXqEV .label text,#mermaid-svg-iHEI6X0tNxnJXqEV span{fill:#333;color:#333;}#mermaid-svg-iHEI6X0tNxnJXqEV .node rect,#mermaid-svg-iHEI6X0tNxnJXqEV .node circle,#mermaid-svg-iHEI6X0tNxnJXqEV .node ellipse,#mermaid-svg-iHEI6X0tNxnJXqEV .node polygon,#mermaid-svg-iHEI6X0tNxnJXqEV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-iHEI6X0tNxnJXqEV .rough-node .label text,#mermaid-svg-iHEI6X0tNxnJXqEV .node .label text,#mermaid-svg-iHEI6X0tNxnJXqEV .image-shape .label,#mermaid-svg-iHEI6X0tNxnJXqEV .icon-shape .label{text-anchor:middle;}#mermaid-svg-iHEI6X0tNxnJXqEV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-iHEI6X0tNxnJXqEV .rough-node .label,#mermaid-svg-iHEI6X0tNxnJXqEV .node .label,#mermaid-svg-iHEI6X0tNxnJXqEV .image-shape .label,#mermaid-svg-iHEI6X0tNxnJXqEV .icon-shape .label{text-align:center;}#mermaid-svg-iHEI6X0tNxnJXqEV .node.clickable{cursor:pointer;}#mermaid-svg-iHEI6X0tNxnJXqEV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-iHEI6X0tNxnJXqEV .arrowheadPath{fill:#333333;}#mermaid-svg-iHEI6X0tNxnJXqEV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-iHEI6X0tNxnJXqEV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-iHEI6X0tNxnJXqEV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iHEI6X0tNxnJXqEV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-iHEI6X0tNxnJXqEV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iHEI6X0tNxnJXqEV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-iHEI6X0tNxnJXqEV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-iHEI6X0tNxnJXqEV .cluster text{fill:#333;}#mermaid-svg-iHEI6X0tNxnJXqEV .cluster span{color:#333;}#mermaid-svg-iHEI6X0tNxnJXqEV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-iHEI6X0tNxnJXqEV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-iHEI6X0tNxnJXqEV rect.text{fill:none;stroke-width:0;}#mermaid-svg-iHEI6X0tNxnJXqEV .icon-shape,#mermaid-svg-iHEI6X0tNxnJXqEV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iHEI6X0tNxnJXqEV .icon-shape p,#mermaid-svg-iHEI6X0tNxnJXqEV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-iHEI6X0tNxnJXqEV .icon-shape .label rect,#mermaid-svg-iHEI6X0tNxnJXqEV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iHEI6X0tNxnJXqEV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-iHEI6X0tNxnJXqEV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-iHEI6X0tNxnJXqEV :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
发现 todo!/unimplemented!
通过
是
否
graph_complete 候选
Stub 门纯文件扫描
立即阻止
Layer 2 硬验收门
操作者 manifest
[verify:] 回放
工具链探测门go.mod / Cargo.toml / package.json
退出码 = 0?
Layer 3 交付物对账
强制返工
6.4 Stub 门(规则独立的接地信号)
Green build 可能掩盖缺失的功能实现——todo!() 编译能通过,但运行就崩。Zagens 在 Layer 2 之前插入一个纯文件扫描的 stub 门:
- 阻塞级(enforce):todo!()、unimplemented!()、NotImplementedError、throw/panic!/raise + “not implemented” 句式 → 立即阻止完成;
- 记录级:纯 TODO/FIXME 注释 → 从不阻塞,仅计 telemetry。
这层门在 graph_complete 候选时先于 Layer 2/3 执行——纯文件扫描几乎零开销,如果发现 stub 就没必要花几分钟跑构建了。
7. Layer 3:交付物对账 —— 抓到模型从未分解进 checklist 的项
Layer 2 能阻止「测试没过但模型声称过了」,但它不能捕获「模型从未写在 checklist 里的交付物」——这才是 MicroStack02 的核心失败模式。
Layer 3 在 Layer 2 全绿后,用纯 Rust 同步扫描(非 agent_spawn、非 LLM)对工作区做 path/glob/tracked 对账,可选每项跑 optional_verify_cmd:
#mermaid-svg-WuGhqxA1bnb0hMVa{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WuGhqxA1bnb0hMVa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WuGhqxA1bnb0hMVa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WuGhqxA1bnb0hMVa .error-icon{fill:#552222;}#mermaid-svg-WuGhqxA1bnb0hMVa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WuGhqxA1bnb0hMVa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WuGhqxA1bnb0hMVa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WuGhqxA1bnb0hMVa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WuGhqxA1bnb0hMVa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WuGhqxA1bnb0hMVa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WuGhqxA1bnb0hMVa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WuGhqxA1bnb0hMVa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WuGhqxA1bnb0hMVa .marker.cross{stroke:#333333;}#mermaid-svg-WuGhqxA1bnb0hMVa svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WuGhqxA1bnb0hMVa p{margin:0;}#mermaid-svg-WuGhqxA1bnb0hMVa .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-WuGhqxA1bnb0hMVa .cluster-label text{fill:#333;}#mermaid-svg-WuGhqxA1bnb0hMVa .cluster-label span{color:#333;}#mermaid-svg-WuGhqxA1bnb0hMVa .cluster-label span p{background-color:transparent;}#mermaid-svg-WuGhqxA1bnb0hMVa .label text,#mermaid-svg-WuGhqxA1bnb0hMVa span{fill:#333;color:#333;}#mermaid-svg-WuGhqxA1bnb0hMVa .node rect,#mermaid-svg-WuGhqxA1bnb0hMVa .node circle,#mermaid-svg-WuGhqxA1bnb0hMVa .node ellipse,#mermaid-svg-WuGhqxA1bnb0hMVa .node polygon,#mermaid-svg-WuGhqxA1bnb0hMVa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WuGhqxA1bnb0hMVa .rough-node .label text,#mermaid-svg-WuGhqxA1bnb0hMVa .node .label text,#mermaid-svg-WuGhqxA1bnb0hMVa .image-shape .label,#mermaid-svg-WuGhqxA1bnb0hMVa .icon-shape .label{text-anchor:middle;}#mermaid-svg-WuGhqxA1bnb0hMVa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WuGhqxA1bnb0hMVa .rough-node .label,#mermaid-svg-WuGhqxA1bnb0hMVa .node .label,#mermaid-svg-WuGhqxA1bnb0hMVa .image-shape .label,#mermaid-svg-WuGhqxA1bnb0hMVa .icon-shape .label{text-align:center;}#mermaid-svg-WuGhqxA1bnb0hMVa .node.clickable{cursor:pointer;}#mermaid-svg-WuGhqxA1bnb0hMVa .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WuGhqxA1bnb0hMVa .arrowheadPath{fill:#333333;}#mermaid-svg-WuGhqxA1bnb0hMVa .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WuGhqxA1bnb0hMVa .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WuGhqxA1bnb0hMVa .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WuGhqxA1bnb0hMVa .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WuGhqxA1bnb0hMVa .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WuGhqxA1bnb0hMVa .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WuGhqxA1bnb0hMVa .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WuGhqxA1bnb0hMVa .cluster text{fill:#333;}#mermaid-svg-WuGhqxA1bnb0hMVa .cluster span{color:#333;}#mermaid-svg-WuGhqxA1bnb0hMVa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WuGhqxA1bnb0hMVa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WuGhqxA1bnb0hMVa rect.text{fill:none;stroke-width:0;}#mermaid-svg-WuGhqxA1bnb0hMVa .icon-shape,#mermaid-svg-WuGhqxA1bnb0hMVa .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WuGhqxA1bnb0hMVa .icon-shape p,#mermaid-svg-WuGhqxA1bnb0hMVa .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WuGhqxA1bnb0hMVa .icon-shape .label rect,#mermaid-svg-WuGhqxA1bnb0hMVa .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WuGhqxA1bnb0hMVa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WuGhqxA1bnb0hMVa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WuGhqxA1bnb0hMVa :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
否
是
退出码 ≠ 0
通过
操作者预声明交付物 manifest
纯 Rust 同步扫描非 agent_spawn · 非 LLM
路径/glob存在?
missing_deliverables
可选 verify命令
不通过
pass: true
结构化 JSON 输出离线可回放
操作者在 ~/.zagens/config.toml 中声明 [[long_horizon.completion_gate.deliverable]](完整回归夹具见 fixtures/harness/microstack-completion-gate.toml):
[[long_horizon.completion_gate.deliverable]]
id = "gzip_middleware"
path = "middleware/gzip.go"
[[long_horizon.completion_gate.deliverable]]
id = "deliverable_24_refactor"
glob = "**/*trie*.go"
optional_verify_cmd = "go test ./… -run Refactor"
[[long_horizon.completion_gate.deliverable]]
id = "contracts_frozen"
path = "contracts/server.go"
tracked = true # 须 git 仓库且已 commit,否则无基线
扫描完成后输出结构化 JSON,例如:
{
"pass": false,
"missing_deliverables": [
{"id": "gzip_middleware", "what": "middleware/gzip.go does not exist", "evidence": "workspace path missing"},
{"id": "deliverable_24_refactor", "what": "Router trie refactor not executed", "evidence": "glob router/*trie* zero hits"}
],
"manifest_round": 2
}
pass 只取决于退出码和路径命中——不依赖任何 LLM 的「感觉」,纯函数输出,离线可回放,可做快照回归。
诚实上限
三层门禁各自有界计数器:max_manifest_rounds、max_audit_rounds。如果耗尽而门仍未全绿,不会无限循环,而是记录 audit_unmet + 未达标门列表,不产生虚假绿灯。
8. Cycle & Handoff:可信的回合间交接
长程任务往往单次会话的上下文窗口不够。Zagens 通过 **Cycle(循环)**机制实现上下文无缝交接。
8.1 触发条件
| 活动输入 token ≥ 阈值 | 768K(约 1M 窗口的 75%) |
| 无飞行中的工具/流/审批 | in_flight: false |
| LHT 增强 | 在 75–85% 警告带内,优先在 checklist item 完成时触发,避开编辑中途 |
8.2 交接内容
每次 cycle 交接有两层:
#mermaid-svg-LHX50Y1WgE3w1f6F{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LHX50Y1WgE3w1f6F .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LHX50Y1WgE3w1f6F .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LHX50Y1WgE3w1f6F .error-icon{fill:#552222;}#mermaid-svg-LHX50Y1WgE3w1f6F .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LHX50Y1WgE3w1f6F .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LHX50Y1WgE3w1f6F .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LHX50Y1WgE3w1f6F .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LHX50Y1WgE3w1f6F .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LHX50Y1WgE3w1f6F .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LHX50Y1WgE3w1f6F .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LHX50Y1WgE3w1f6F .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LHX50Y1WgE3w1f6F .marker.cross{stroke:#333333;}#mermaid-svg-LHX50Y1WgE3w1f6F svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LHX50Y1WgE3w1f6F p{margin:0;}#mermaid-svg-LHX50Y1WgE3w1f6F .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-LHX50Y1WgE3w1f6F .cluster-label text{fill:#333;}#mermaid-svg-LHX50Y1WgE3w1f6F .cluster-label span{color:#333;}#mermaid-svg-LHX50Y1WgE3w1f6F .cluster-label span p{background-color:transparent;}#mermaid-svg-LHX50Y1WgE3w1f6F .label text,#mermaid-svg-LHX50Y1WgE3w1f6F span{fill:#333;color:#333;}#mermaid-svg-LHX50Y1WgE3w1f6F .node rect,#mermaid-svg-LHX50Y1WgE3w1f6F .node circle,#mermaid-svg-LHX50Y1WgE3w1f6F .node ellipse,#mermaid-svg-LHX50Y1WgE3w1f6F .node polygon,#mermaid-svg-LHX50Y1WgE3w1f6F .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LHX50Y1WgE3w1f6F .rough-node .label text,#mermaid-svg-LHX50Y1WgE3w1f6F .node .label text,#mermaid-svg-LHX50Y1WgE3w1f6F .image-shape .label,#mermaid-svg-LHX50Y1WgE3w1f6F .icon-shape .label{text-anchor:middle;}#mermaid-svg-LHX50Y1WgE3w1f6F .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LHX50Y1WgE3w1f6F .rough-node .label,#mermaid-svg-LHX50Y1WgE3w1f6F .node .label,#mermaid-svg-LHX50Y1WgE3w1f6F .image-shape .label,#mermaid-svg-LHX50Y1WgE3w1f6F .icon-shape .label{text-align:center;}#mermaid-svg-LHX50Y1WgE3w1f6F .node.clickable{cursor:pointer;}#mermaid-svg-LHX50Y1WgE3w1f6F .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LHX50Y1WgE3w1f6F .arrowheadPath{fill:#333333;}#mermaid-svg-LHX50Y1WgE3w1f6F .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LHX50Y1WgE3w1f6F .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LHX50Y1WgE3w1f6F .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LHX50Y1WgE3w1f6F .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LHX50Y1WgE3w1f6F .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LHX50Y1WgE3w1f6F .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LHX50Y1WgE3w1f6F .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LHX50Y1WgE3w1f6F .cluster text{fill:#333;}#mermaid-svg-LHX50Y1WgE3w1f6F .cluster span{color:#333;}#mermaid-svg-LHX50Y1WgE3w1f6F div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LHX50Y1WgE3w1f6F .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LHX50Y1WgE3w1f6F rect.text{fill:none;stroke-width:0;}#mermaid-svg-LHX50Y1WgE3w1f6F .icon-shape,#mermaid-svg-LHX50Y1WgE3w1f6F .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LHX50Y1WgE3w1f6F .icon-shape p,#mermaid-svg-LHX50Y1WgE3w1f6F .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LHX50Y1WgE3w1f6F .icon-shape .label rect,#mermaid-svg-LHX50Y1WgE3w1f6F .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LHX50Y1WgE3w1f6F .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LHX50Y1WgE3w1f6F .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LHX50Y1WgE3w1f6F :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
层 2: Carry Forward(模型手写)
长程目标(一行)
待办 item ids
上次验证命令与结果
正在编辑的文件路径
失败方案 / 约束
层 1: StructuredState(自动保留)
模式 / 工作区 / cwd
plan → 阶段列表 + 状态标记
checklist → 进度 + 未完成项
working set → 最近读写文件
sub-agent → id + role + objective
audit scratchpad → run_id
Cycle 触发条件
活动 token ≥ 768K
in_flight: false
LHT: 优先在 checklist item 完成时
Cycle 交接
新 Cycle 会话
层 1(StructuredState)由引擎确定性保留;层 2(carry_forward)由模型在 cycle 边界手写。Carry forward 模板示例:
Also include in <carry_forward>:
– Long-horizon objective (one line)
– Open checklist/plan item ids or labels still pending
– Last verification command and outcome (pass/fail/not run)
– Files currently being edited (paths only)
– Failed approaches / constraints
8.3 可视化的 Cycle 时间线
下图仅为示意,不代表真实耗时。
#mermaid-svg-dsCYwX4WAwpnZlzZ{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dsCYwX4WAwpnZlzZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dsCYwX4WAwpnZlzZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dsCYwX4WAwpnZlzZ .error-icon{fill:#552222;}#mermaid-svg-dsCYwX4WAwpnZlzZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dsCYwX4WAwpnZlzZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dsCYwX4WAwpnZlzZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dsCYwX4WAwpnZlzZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dsCYwX4WAwpnZlzZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dsCYwX4WAwpnZlzZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dsCYwX4WAwpnZlzZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dsCYwX4WAwpnZlzZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dsCYwX4WAwpnZlzZ .marker.cross{stroke:#333333;}#mermaid-svg-dsCYwX4WAwpnZlzZ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dsCYwX4WAwpnZlzZ p{margin:0;}#mermaid-svg-dsCYwX4WAwpnZlzZ .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-dsCYwX4WAwpnZlzZ .cluster-label text{fill:#333;}#mermaid-svg-dsCYwX4WAwpnZlzZ .cluster-label span{color:#333;}#mermaid-svg-dsCYwX4WAwpnZlzZ .cluster-label span p{background-color:transparent;}#mermaid-svg-dsCYwX4WAwpnZlzZ .label text,#mermaid-svg-dsCYwX4WAwpnZlzZ span{fill:#333;color:#333;}#mermaid-svg-dsCYwX4WAwpnZlzZ .node rect,#mermaid-svg-dsCYwX4WAwpnZlzZ .node circle,#mermaid-svg-dsCYwX4WAwpnZlzZ .node ellipse,#mermaid-svg-dsCYwX4WAwpnZlzZ .node polygon,#mermaid-svg-dsCYwX4WAwpnZlzZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dsCYwX4WAwpnZlzZ .rough-node .label text,#mermaid-svg-dsCYwX4WAwpnZlzZ .node .label text,#mermaid-svg-dsCYwX4WAwpnZlzZ .image-shape .label,#mermaid-svg-dsCYwX4WAwpnZlzZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-dsCYwX4WAwpnZlzZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dsCYwX4WAwpnZlzZ .rough-node .label,#mermaid-svg-dsCYwX4WAwpnZlzZ .node .label,#mermaid-svg-dsCYwX4WAwpnZlzZ .image-shape .label,#mermaid-svg-dsCYwX4WAwpnZlzZ .icon-shape .label{text-align:center;}#mermaid-svg-dsCYwX4WAwpnZlzZ .node.clickable{cursor:pointer;}#mermaid-svg-dsCYwX4WAwpnZlzZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dsCYwX4WAwpnZlzZ .arrowheadPath{fill:#333333;}#mermaid-svg-dsCYwX4WAwpnZlzZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dsCYwX4WAwpnZlzZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dsCYwX4WAwpnZlzZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dsCYwX4WAwpnZlzZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dsCYwX4WAwpnZlzZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dsCYwX4WAwpnZlzZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dsCYwX4WAwpnZlzZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dsCYwX4WAwpnZlzZ .cluster text{fill:#333;}#mermaid-svg-dsCYwX4WAwpnZlzZ .cluster span{color:#333;}#mermaid-svg-dsCYwX4WAwpnZlzZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dsCYwX4WAwpnZlzZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dsCYwX4WAwpnZlzZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-dsCYwX4WAwpnZlzZ .icon-shape,#mermaid-svg-dsCYwX4WAwpnZlzZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dsCYwX4WAwpnZlzZ .icon-shape p,#mermaid-svg-dsCYwX4WAwpnZlzZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dsCYwX4WAwpnZlzZ .icon-shape .label rect,#mermaid-svg-dsCYwX4WAwpnZlzZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dsCYwX4WAwpnZlzZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dsCYwX4WAwpnZlzZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dsCYwX4WAwpnZlzZ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
token ≥ 768K
再次触线
Cycle 1实现 + 工具调用
交接StructuredState + carry_forward
Cycle 2继续实现
交接
Cycle 3收尾验证
用户在 LongHorizonPanel 的 Cycle 标签页中可以看到:
- 当前 cycle 编号 + 时间线;
- 每轮 carry_forward 摘要(可展开预览);
- 768K 警告线与当前上下文使用量的对比。
9. 宏观循环(Phase 4):LHT ↔ CRAFT 交替
何时启用: 默认长程任务 Layer 1–3 + Cycle 即可。Macro Loop 面向 15K–20K 行级超大重构,在实现与 QA 之间交替多轮;回归基线见 fixtures/harness/lht-eval-arms/lht_long_refactor.toml。
CRAFT(Implementer + Reviewer + Verifier 多代理段)负责质量闭环与缺口识别,没有 graph_complete 放行权——最终仍由 Layer 2/3 机器门裁决。
Zagens 实现了 Phase 4 Macro Loop——在 LHT 实现段和 CRAFT QA 段之间交替:
#mermaid-svg-nCOAot3bcCPdEJm2{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nCOAot3bcCPdEJm2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nCOAot3bcCPdEJm2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nCOAot3bcCPdEJm2 .error-icon{fill:#552222;}#mermaid-svg-nCOAot3bcCPdEJm2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nCOAot3bcCPdEJm2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nCOAot3bcCPdEJm2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nCOAot3bcCPdEJm2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nCOAot3bcCPdEJm2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nCOAot3bcCPdEJm2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nCOAot3bcCPdEJm2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nCOAot3bcCPdEJm2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nCOAot3bcCPdEJm2 .marker.cross{stroke:#333333;}#mermaid-svg-nCOAot3bcCPdEJm2 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nCOAot3bcCPdEJm2 p{margin:0;}#mermaid-svg-nCOAot3bcCPdEJm2 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-nCOAot3bcCPdEJm2 .cluster-label text{fill:#333;}#mermaid-svg-nCOAot3bcCPdEJm2 .cluster-label span{color:#333;}#mermaid-svg-nCOAot3bcCPdEJm2 .cluster-label span p{background-color:transparent;}#mermaid-svg-nCOAot3bcCPdEJm2 .label text,#mermaid-svg-nCOAot3bcCPdEJm2 span{fill:#333;color:#333;}#mermaid-svg-nCOAot3bcCPdEJm2 .node rect,#mermaid-svg-nCOAot3bcCPdEJm2 .node circle,#mermaid-svg-nCOAot3bcCPdEJm2 .node ellipse,#mermaid-svg-nCOAot3bcCPdEJm2 .node polygon,#mermaid-svg-nCOAot3bcCPdEJm2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nCOAot3bcCPdEJm2 .rough-node .label text,#mermaid-svg-nCOAot3bcCPdEJm2 .node .label text,#mermaid-svg-nCOAot3bcCPdEJm2 .image-shape .label,#mermaid-svg-nCOAot3bcCPdEJm2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-nCOAot3bcCPdEJm2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nCOAot3bcCPdEJm2 .rough-node .label,#mermaid-svg-nCOAot3bcCPdEJm2 .node .label,#mermaid-svg-nCOAot3bcCPdEJm2 .image-shape .label,#mermaid-svg-nCOAot3bcCPdEJm2 .icon-shape .label{text-align:center;}#mermaid-svg-nCOAot3bcCPdEJm2 .node.clickable{cursor:pointer;}#mermaid-svg-nCOAot3bcCPdEJm2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nCOAot3bcCPdEJm2 .arrowheadPath{fill:#333333;}#mermaid-svg-nCOAot3bcCPdEJm2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nCOAot3bcCPdEJm2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nCOAot3bcCPdEJm2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nCOAot3bcCPdEJm2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nCOAot3bcCPdEJm2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nCOAot3bcCPdEJm2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nCOAot3bcCPdEJm2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nCOAot3bcCPdEJm2 .cluster text{fill:#333;}#mermaid-svg-nCOAot3bcCPdEJm2 .cluster span{color:#333;}#mermaid-svg-nCOAot3bcCPdEJm2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nCOAot3bcCPdEJm2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nCOAot3bcCPdEJm2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-nCOAot3bcCPdEJm2 .icon-shape,#mermaid-svg-nCOAot3bcCPdEJm2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nCOAot3bcCPdEJm2 .icon-shape p,#mermaid-svg-nCOAot3bcCPdEJm2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nCOAot3bcCPdEJm2 .icon-shape .label rect,#mermaid-svg-nCOAot3bcCPdEJm2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nCOAot3bcCPdEJm2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nCOAot3bcCPdEJm2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nCOAot3bcCPdEJm2 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
代码实现
识别缺口
Layer 1–3
验证通过
auto_continue
CRAFT QA 段
Implementer
Reviewer
Verifier
LHT 实现段
Layer 1 防早停
Layer 2 退出码门
Layer 3 交付物对账
LHT 修复段
完成 / 下一轮
每轮 LHT 段使用 Layer 1–3 门禁推进代码实现;CRAFT 段使用多代理(Implementer + Reviewer + Verifier)做质量闭环。Macro Loop 的 auto_continue 机制让这个过程可以无人值守地跑多个回合。
这个宏循环的回归基线固定在 fixtures/harness/lht-eval-arms/lht_long_refactor.toml 中,作为 CI 的定期验证夹具。
10. 对抗审计器:Agent 独立的缺口枚举器
可选扩展: 默认 Stub 门 + Layer 2/3 已覆盖大多数场景。对抗审计在 config.toml 中 opt-in 启用,用于 Stub 扫不到的「无标记占位实现」或「规格有、清单无」的缺口枚举。
Layer 2 的 stub 门(正则扫描)只能捕获标记明确的残缺实现。对「函数体返回 return Ok(()) 占位但没有标记」或「整个模块从未进入 checklist」这类情况,需要另一个 Agent 来发现。
但这里有一个微妙的设计边界:「法官」vs「缺口枚举器」。
| 权力 | 直接判 pass/fail,放行或阻塞 | 没有放行/否决权;只输出「疑似缺口」候选 |
| 输出 | “LGTM/不通过” 散文 | 机器可测试的断言:{file:line, 缺什么, 建议的 [verify: cmd]} |
| 谁最终裁决 | 自身(软的、可说服的、不可回放) | 仍然是机器 Oracle——候选注入后,stub 门/退出码/路径对账来裁决 |
| 失败模式 | 审计者-建设者共谋盖章 | 最坏情况「报几个假缺口」,机器门一跑就驳回了 |
对抗审计器的输出永远不直接进入 graph_complete 的放行/阻塞判断;它只能扩展机器的门禁检查面。最终绿灯仍然由退出码和路径命中决定。
#mermaid-svg-u0dNAROFnExZFVEG{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-u0dNAROFnExZFVEG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-u0dNAROFnExZFVEG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-u0dNAROFnExZFVEG .error-icon{fill:#552222;}#mermaid-svg-u0dNAROFnExZFVEG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-u0dNAROFnExZFVEG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-u0dNAROFnExZFVEG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-u0dNAROFnExZFVEG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-u0dNAROFnExZFVEG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-u0dNAROFnExZFVEG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-u0dNAROFnExZFVEG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-u0dNAROFnExZFVEG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-u0dNAROFnExZFVEG .marker.cross{stroke:#333333;}#mermaid-svg-u0dNAROFnExZFVEG svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-u0dNAROFnExZFVEG p{margin:0;}#mermaid-svg-u0dNAROFnExZFVEG .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-u0dNAROFnExZFVEG .cluster-label text{fill:#333;}#mermaid-svg-u0dNAROFnExZFVEG .cluster-label span{color:#333;}#mermaid-svg-u0dNAROFnExZFVEG .cluster-label span p{background-color:transparent;}#mermaid-svg-u0dNAROFnExZFVEG .label text,#mermaid-svg-u0dNAROFnExZFVEG span{fill:#333;color:#333;}#mermaid-svg-u0dNAROFnExZFVEG .node rect,#mermaid-svg-u0dNAROFnExZFVEG .node circle,#mermaid-svg-u0dNAROFnExZFVEG .node ellipse,#mermaid-svg-u0dNAROFnExZFVEG .node polygon,#mermaid-svg-u0dNAROFnExZFVEG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-u0dNAROFnExZFVEG .rough-node .label text,#mermaid-svg-u0dNAROFnExZFVEG .node .label text,#mermaid-svg-u0dNAROFnExZFVEG .image-shape .label,#mermaid-svg-u0dNAROFnExZFVEG .icon-shape .label{text-anchor:middle;}#mermaid-svg-u0dNAROFnExZFVEG .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-u0dNAROFnExZFVEG .rough-node .label,#mermaid-svg-u0dNAROFnExZFVEG .node .label,#mermaid-svg-u0dNAROFnExZFVEG .image-shape .label,#mermaid-svg-u0dNAROFnExZFVEG .icon-shape .label{text-align:center;}#mermaid-svg-u0dNAROFnExZFVEG .node.clickable{cursor:pointer;}#mermaid-svg-u0dNAROFnExZFVEG .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-u0dNAROFnExZFVEG .arrowheadPath{fill:#333333;}#mermaid-svg-u0dNAROFnExZFVEG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-u0dNAROFnExZFVEG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-u0dNAROFnExZFVEG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-u0dNAROFnExZFVEG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-u0dNAROFnExZFVEG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-u0dNAROFnExZFVEG .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-u0dNAROFnExZFVEG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-u0dNAROFnExZFVEG .cluster text{fill:#333;}#mermaid-svg-u0dNAROFnExZFVEG .cluster span{color:#333;}#mermaid-svg-u0dNAROFnExZFVEG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-u0dNAROFnExZFVEG .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-u0dNAROFnExZFVEG rect.text{fill:none;stroke-width:0;}#mermaid-svg-u0dNAROFnExZFVEG .icon-shape,#mermaid-svg-u0dNAROFnExZFVEG .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-u0dNAROFnExZFVEG .icon-shape p,#mermaid-svg-u0dNAROFnExZFVEG .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-u0dNAROFnExZFVEG .icon-shape .label rect,#mermaid-svg-u0dNAROFnExZFVEG .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-u0dNAROFnExZFVEG .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-u0dNAROFnExZFVEG .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-u0dNAROFnExZFVEG :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
全绿
未通过
禁止直连
对抗审计 Agent缺口枚举器
输出候选file:line · 缺什么 · verify 建议
注入门禁检查面
Stub 门扫描
退出码 Oracle
路径/glob 对账
机器裁决
✅ graph_complete
返工 / audit_unmet
❌ 直接放行/阻塞
11. 可视化:让完成度可见
Harness 产生事实,可视化让事实可见。
Zagens 的桌面 UI 中有一个 2×2 的 Harness Grid:
#mermaid-svg-4Y3urxoutt3zmRWs{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4Y3urxoutt3zmRWs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4Y3urxoutt3zmRWs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4Y3urxoutt3zmRWs .error-icon{fill:#552222;}#mermaid-svg-4Y3urxoutt3zmRWs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4Y3urxoutt3zmRWs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4Y3urxoutt3zmRWs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4Y3urxoutt3zmRWs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4Y3urxoutt3zmRWs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4Y3urxoutt3zmRWs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4Y3urxoutt3zmRWs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4Y3urxoutt3zmRWs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4Y3urxoutt3zmRWs .marker.cross{stroke:#333333;}#mermaid-svg-4Y3urxoutt3zmRWs svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4Y3urxoutt3zmRWs p{margin:0;}#mermaid-svg-4Y3urxoutt3zmRWs .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-4Y3urxoutt3zmRWs .cluster-label text{fill:#333;}#mermaid-svg-4Y3urxoutt3zmRWs .cluster-label span{color:#333;}#mermaid-svg-4Y3urxoutt3zmRWs .cluster-label span p{background-color:transparent;}#mermaid-svg-4Y3urxoutt3zmRWs .label text,#mermaid-svg-4Y3urxoutt3zmRWs span{fill:#333;color:#333;}#mermaid-svg-4Y3urxoutt3zmRWs .node rect,#mermaid-svg-4Y3urxoutt3zmRWs .node circle,#mermaid-svg-4Y3urxoutt3zmRWs .node ellipse,#mermaid-svg-4Y3urxoutt3zmRWs .node polygon,#mermaid-svg-4Y3urxoutt3zmRWs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4Y3urxoutt3zmRWs .rough-node .label text,#mermaid-svg-4Y3urxoutt3zmRWs .node .label text,#mermaid-svg-4Y3urxoutt3zmRWs .image-shape .label,#mermaid-svg-4Y3urxoutt3zmRWs .icon-shape .label{text-anchor:middle;}#mermaid-svg-4Y3urxoutt3zmRWs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4Y3urxoutt3zmRWs .rough-node .label,#mermaid-svg-4Y3urxoutt3zmRWs .node .label,#mermaid-svg-4Y3urxoutt3zmRWs .image-shape .label,#mermaid-svg-4Y3urxoutt3zmRWs .icon-shape .label{text-align:center;}#mermaid-svg-4Y3urxoutt3zmRWs .node.clickable{cursor:pointer;}#mermaid-svg-4Y3urxoutt3zmRWs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4Y3urxoutt3zmRWs .arrowheadPath{fill:#333333;}#mermaid-svg-4Y3urxoutt3zmRWs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4Y3urxoutt3zmRWs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4Y3urxoutt3zmRWs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4Y3urxoutt3zmRWs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4Y3urxoutt3zmRWs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4Y3urxoutt3zmRWs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4Y3urxoutt3zmRWs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4Y3urxoutt3zmRWs .cluster text{fill:#333;}#mermaid-svg-4Y3urxoutt3zmRWs .cluster span{color:#333;}#mermaid-svg-4Y3urxoutt3zmRWs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4Y3urxoutt3zmRWs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4Y3urxoutt3zmRWs rect.text{fill:none;stroke-width:0;}#mermaid-svg-4Y3urxoutt3zmRWs .icon-shape,#mermaid-svg-4Y3urxoutt3zmRWs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4Y3urxoutt3zmRWs .icon-shape p,#mermaid-svg-4Y3urxoutt3zmRWs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4Y3urxoutt3zmRWs .icon-shape .label rect,#mermaid-svg-4Y3urxoutt3zmRWs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4Y3urxoutt3zmRWs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4Y3urxoutt3zmRWs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4Y3urxoutt3zmRWs :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
下排
LongHorizonPanelTask Graph · Cycles · Context门禁状态 · 768K 阈值
AgentPanelSub-agents / CRAFT
上排
ChecklistPanel计划与 checklist 进度
AuditScratchpadPanel审计草稿与恢复区
LongHorizonPanel 有三个子标签页:Task Graph(计划/checklist/门禁摘要)、Cycle(时间线与 carry_forward)、Context(768K 阈值 vs 上限)。
读屏场景:如何判断「真完成」?
| Task Graph 100% + 门禁全绿 | Layer 2/3 已通过 | ✅ 可信任完成 |
| Checklist 100% + 门禁琥珀色「有条件完成」 | checklist 全勾但 manifest 未绿或 observe 缺口 | 继续让模型返工或检查 config |
| Nodes 有 gate_skip graph_complete 但无 manifest_gate_result | 未启用 completion_gate | 考虑打开 Layer 2/3 |
| Nodes 有 audit_unmet | 有界轮次耗尽 | 人工介入,不假绿 |
Nodes 标签页记录 Harness 决策流:
#mermaid-svg-X6WFUvcdg3NGGIfn{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-X6WFUvcdg3NGGIfn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-X6WFUvcdg3NGGIfn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-X6WFUvcdg3NGGIfn .error-icon{fill:#552222;}#mermaid-svg-X6WFUvcdg3NGGIfn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-X6WFUvcdg3NGGIfn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-X6WFUvcdg3NGGIfn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-X6WFUvcdg3NGGIfn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-X6WFUvcdg3NGGIfn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-X6WFUvcdg3NGGIfn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-X6WFUvcdg3NGGIfn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-X6WFUvcdg3NGGIfn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-X6WFUvcdg3NGGIfn .marker.cross{stroke:#333333;}#mermaid-svg-X6WFUvcdg3NGGIfn svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-X6WFUvcdg3NGGIfn p{margin:0;}#mermaid-svg-X6WFUvcdg3NGGIfn .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-X6WFUvcdg3NGGIfn .cluster-label text{fill:#333;}#mermaid-svg-X6WFUvcdg3NGGIfn .cluster-label span{color:#333;}#mermaid-svg-X6WFUvcdg3NGGIfn .cluster-label span p{background-color:transparent;}#mermaid-svg-X6WFUvcdg3NGGIfn .label text,#mermaid-svg-X6WFUvcdg3NGGIfn span{fill:#333;color:#333;}#mermaid-svg-X6WFUvcdg3NGGIfn .node rect,#mermaid-svg-X6WFUvcdg3NGGIfn .node circle,#mermaid-svg-X6WFUvcdg3NGGIfn .node ellipse,#mermaid-svg-X6WFUvcdg3NGGIfn .node polygon,#mermaid-svg-X6WFUvcdg3NGGIfn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-X6WFUvcdg3NGGIfn .rough-node .label text,#mermaid-svg-X6WFUvcdg3NGGIfn .node .label text,#mermaid-svg-X6WFUvcdg3NGGIfn .image-shape .label,#mermaid-svg-X6WFUvcdg3NGGIfn .icon-shape .label{text-anchor:middle;}#mermaid-svg-X6WFUvcdg3NGGIfn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-X6WFUvcdg3NGGIfn .rough-node .label,#mermaid-svg-X6WFUvcdg3NGGIfn .node .label,#mermaid-svg-X6WFUvcdg3NGGIfn .image-shape .label,#mermaid-svg-X6WFUvcdg3NGGIfn .icon-shape .label{text-align:center;}#mermaid-svg-X6WFUvcdg3NGGIfn .node.clickable{cursor:pointer;}#mermaid-svg-X6WFUvcdg3NGGIfn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-X6WFUvcdg3NGGIfn .arrowheadPath{fill:#333333;}#mermaid-svg-X6WFUvcdg3NGGIfn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-X6WFUvcdg3NGGIfn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-X6WFUvcdg3NGGIfn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-X6WFUvcdg3NGGIfn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-X6WFUvcdg3NGGIfn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-X6WFUvcdg3NGGIfn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-X6WFUvcdg3NGGIfn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-X6WFUvcdg3NGGIfn .cluster text{fill:#333;}#mermaid-svg-X6WFUvcdg3NGGIfn .cluster span{color:#333;}#mermaid-svg-X6WFUvcdg3NGGIfn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-X6WFUvcdg3NGGIfn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-X6WFUvcdg3NGGIfn rect.text{fill:none;stroke-width:0;}#mermaid-svg-X6WFUvcdg3NGGIfn .icon-shape,#mermaid-svg-X6WFUvcdg3NGGIfn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-X6WFUvcdg3NGGIfn .icon-shape p,#mermaid-svg-X6WFUvcdg3NGGIfn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-X6WFUvcdg3NGGIfn .icon-shape .label rect,#mermaid-svg-X6WFUvcdg3NGGIfn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-X6WFUvcdg3NGGIfn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-X6WFUvcdg3NGGIfn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-X6WFUvcdg3NGGIfn :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-X6WFUvcdg3NGGIfn .green>*{fill:#dfd!important;stroke:#3a3!important;}#mermaid-svg-X6WFUvcdg3NGGIfn .green span{fill:#dfd!important;stroke:#3a3!important;}#mermaid-svg-X6WFUvcdg3NGGIfn .yellow>*{fill:#ffd!important;stroke:#fa0!important;}#mermaid-svg-X6WFUvcdg3NGGIfn .yellow span{fill:#ffd!important;stroke:#fa0!important;}#mermaid-svg-X6WFUvcdg3NGGIfn .red>*{fill:#fee!important;stroke:#c33!important;}#mermaid-svg-X6WFUvcdg3NGGIfn .red span{fill:#fee!important;stroke:#c33!important;}#mermaid-svg-X6WFUvcdg3NGGIfn .neutral>*{fill:#eef!important;stroke:#36c!important;}#mermaid-svg-X6WFUvcdg3NGGIfn .neutral span{fill:#eef!important;stroke:#36c!important;}
Nodes 决策流(颜色编码)
continue_injected
step_limit_continue
gate_skip
blocked
incomplete_stop
audit_unmet
verify_gate 裁决
背景:DEMO3–6 压测序列
| DEMO3 | ~2W 行 Go Monkey 解释器 | unverified_acceptance 软提示→软门禁;[verify:] 纪律 |
| DEMO4 | 同上 | step budget 耗尽无声早停 → maybe_continue_at_step_limit |
| DEMO5 | 20K 行解释器 | plan/checklist 双计数、verify_gate 文本匹配误报、cycle 阈值 mid-turn 不评估 |
| DEMO6 | Monkey 双后端 | checklist_write 批量更新绕过 verify_gate |
12. 经验教训与演化
Zagens Harness 不是纸面设计——它在 DEMO3–DEMO6 四次实证压力测试中暴露出许多隐蔽问题,并逐一修补。以下是几个有普适性的教训:
12.1 所有 turn 退出点都必须是 LHT 门禁
最初 LHT 只挂载在 no-tool-uses 路径上。但 step budget 耗尽、loop_guard 截停、上下文溢出——每个外循环 break 路径都可能产生虚假的 Completed,必须系统性审计每个退出点。
12.2 进展判定不能依赖文本匹配
最初用 result_contains_success 检查 "exit code: 0" 子串来判定验证命令是否成功,但 exec_shell 成功路径返回的是裸 stdout(ok monkey/lexer 0.078s),根本不包含退出码信息。修复很简单:删除多余的文本检查,success 布尔值就是退出码 0 的权威信号。
12.3 checklist 和 plan 不能算两份工作量
DEMO5 中,模型创建了 12 个 plan 项但全部放弃(pending),同时用 checklist 推进了 19 项全部完成。原来的进度算法将两方面相加,结果 12 + 19 = 31 总项、12 项 pending,进度卡在 61%。修复:当 checklist 非空时,以 checklist 为完成度的权威来源。
12.4 [verify:] 纪律是基础
模型的 checklist 项经常把「可运行的验收」退化为「创建文件」项——“create example scripts” 在 checklist 中标记完成只是创建了文件,但从未真正跑过。Zagens 在 base.md 中强化了 checklist 写作纪律:任何需要运行的验收项必须写作 [verify: <command>] <label>,并在引擎层做了判断强化。
12.5 门禁系统的天花板 = manifest 的完整性
这是一个诚实的边界声明。Layer 3 保证「manifest 中的交付物不会漏掉」,但不能保证「规范中写了但 manifest 中没写的」。这本质上是把「模型欠分解」变成了「操作者欠写 manifest」。但 manifest 可以离线审查、可回归、可复用——比模型每次现场分解稳定得多。
13. 测试与回归架
Zagens Harness 的验证体系包括:
#mermaid-svg-DYkYfzMaD8OdcdIW{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DYkYfzMaD8OdcdIW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DYkYfzMaD8OdcdIW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DYkYfzMaD8OdcdIW .error-icon{fill:#552222;}#mermaid-svg-DYkYfzMaD8OdcdIW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DYkYfzMaD8OdcdIW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DYkYfzMaD8OdcdIW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DYkYfzMaD8OdcdIW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DYkYfzMaD8OdcdIW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DYkYfzMaD8OdcdIW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DYkYfzMaD8OdcdIW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DYkYfzMaD8OdcdIW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DYkYfzMaD8OdcdIW .marker.cross{stroke:#333333;}#mermaid-svg-DYkYfzMaD8OdcdIW svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DYkYfzMaD8OdcdIW p{margin:0;}#mermaid-svg-DYkYfzMaD8OdcdIW .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-DYkYfzMaD8OdcdIW .cluster-label text{fill:#333;}#mermaid-svg-DYkYfzMaD8OdcdIW .cluster-label span{color:#333;}#mermaid-svg-DYkYfzMaD8OdcdIW .cluster-label span p{background-color:transparent;}#mermaid-svg-DYkYfzMaD8OdcdIW .label text,#mermaid-svg-DYkYfzMaD8OdcdIW span{fill:#333;color:#333;}#mermaid-svg-DYkYfzMaD8OdcdIW .node rect,#mermaid-svg-DYkYfzMaD8OdcdIW .node circle,#mermaid-svg-DYkYfzMaD8OdcdIW .node ellipse,#mermaid-svg-DYkYfzMaD8OdcdIW .node polygon,#mermaid-svg-DYkYfzMaD8OdcdIW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DYkYfzMaD8OdcdIW .rough-node .label text,#mermaid-svg-DYkYfzMaD8OdcdIW .node .label text,#mermaid-svg-DYkYfzMaD8OdcdIW .image-shape .label,#mermaid-svg-DYkYfzMaD8OdcdIW .icon-shape .label{text-anchor:middle;}#mermaid-svg-DYkYfzMaD8OdcdIW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DYkYfzMaD8OdcdIW .rough-node .label,#mermaid-svg-DYkYfzMaD8OdcdIW .node .label,#mermaid-svg-DYkYfzMaD8OdcdIW .image-shape .label,#mermaid-svg-DYkYfzMaD8OdcdIW .icon-shape .label{text-align:center;}#mermaid-svg-DYkYfzMaD8OdcdIW .node.clickable{cursor:pointer;}#mermaid-svg-DYkYfzMaD8OdcdIW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DYkYfzMaD8OdcdIW .arrowheadPath{fill:#333333;}#mermaid-svg-DYkYfzMaD8OdcdIW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DYkYfzMaD8OdcdIW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DYkYfzMaD8OdcdIW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DYkYfzMaD8OdcdIW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DYkYfzMaD8OdcdIW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DYkYfzMaD8OdcdIW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DYkYfzMaD8OdcdIW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DYkYfzMaD8OdcdIW .cluster text{fill:#333;}#mermaid-svg-DYkYfzMaD8OdcdIW .cluster span{color:#333;}#mermaid-svg-DYkYfzMaD8OdcdIW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DYkYfzMaD8OdcdIW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DYkYfzMaD8OdcdIW rect.text{fill:none;stroke-width:0;}#mermaid-svg-DYkYfzMaD8OdcdIW .icon-shape,#mermaid-svg-DYkYfzMaD8OdcdIW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DYkYfzMaD8OdcdIW .icon-shape p,#mermaid-svg-DYkYfzMaD8OdcdIW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DYkYfzMaD8OdcdIW .icon-shape .label rect,#mermaid-svg-DYkYfzMaD8OdcdIW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DYkYfzMaD8OdcdIW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DYkYfzMaD8OdcdIW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DYkYfzMaD8OdcdIW :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
CI: verify-workspace.sh+ verify-lint.sh
kernel-v3-replay/
microstack-completion-gate.toml
lht-harness-baseline.json
strict-task-seed/
lht_long_refactor.toml
夹具路径均在 fixtures/harness/ 下;设计规格见 docs/harness/COMPOSABLE_HARNESS.md。
14. 结语
Zagens 的 Harness 工程回答了一个核心问题:当 AI Agent 说「我做完了」时,你怎么知道它是真的做完了?
答案不是信任模型,而是构建一整套独立于模型的机器门禁系统:
#mermaid-svg-ZmDB5QhshjFC06El{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZmDB5QhshjFC06El .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZmDB5QhshjFC06El .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZmDB5QhshjFC06El .error-icon{fill:#552222;}#mermaid-svg-ZmDB5QhshjFC06El .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZmDB5QhshjFC06El .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZmDB5QhshjFC06El .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZmDB5QhshjFC06El .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZmDB5QhshjFC06El .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZmDB5QhshjFC06El .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZmDB5QhshjFC06El .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZmDB5QhshjFC06El .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZmDB5QhshjFC06El .marker.cross{stroke:#333333;}#mermaid-svg-ZmDB5QhshjFC06El svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZmDB5QhshjFC06El p{margin:0;}#mermaid-svg-ZmDB5QhshjFC06El .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZmDB5QhshjFC06El .cluster-label text{fill:#333;}#mermaid-svg-ZmDB5QhshjFC06El .cluster-label span{color:#333;}#mermaid-svg-ZmDB5QhshjFC06El .cluster-label span p{background-color:transparent;}#mermaid-svg-ZmDB5QhshjFC06El .label text,#mermaid-svg-ZmDB5QhshjFC06El span{fill:#333;color:#333;}#mermaid-svg-ZmDB5QhshjFC06El .node rect,#mermaid-svg-ZmDB5QhshjFC06El .node circle,#mermaid-svg-ZmDB5QhshjFC06El .node ellipse,#mermaid-svg-ZmDB5QhshjFC06El .node polygon,#mermaid-svg-ZmDB5QhshjFC06El .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZmDB5QhshjFC06El .rough-node .label text,#mermaid-svg-ZmDB5QhshjFC06El .node .label text,#mermaid-svg-ZmDB5QhshjFC06El .image-shape .label,#mermaid-svg-ZmDB5QhshjFC06El .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZmDB5QhshjFC06El .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZmDB5QhshjFC06El .rough-node .label,#mermaid-svg-ZmDB5QhshjFC06El .node .label,#mermaid-svg-ZmDB5QhshjFC06El .image-shape .label,#mermaid-svg-ZmDB5QhshjFC06El .icon-shape .label{text-align:center;}#mermaid-svg-ZmDB5QhshjFC06El .node.clickable{cursor:pointer;}#mermaid-svg-ZmDB5QhshjFC06El .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZmDB5QhshjFC06El .arrowheadPath{fill:#333333;}#mermaid-svg-ZmDB5QhshjFC06El .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZmDB5QhshjFC06El .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZmDB5QhshjFC06El .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZmDB5QhshjFC06El .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZmDB5QhshjFC06El .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZmDB5QhshjFC06El .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZmDB5QhshjFC06El .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZmDB5QhshjFC06El .cluster text{fill:#333;}#mermaid-svg-ZmDB5QhshjFC06El .cluster span{color:#333;}#mermaid-svg-ZmDB5QhshjFC06El div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZmDB5QhshjFC06El .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZmDB5QhshjFC06El rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZmDB5QhshjFC06El .icon-shape,#mermaid-svg-ZmDB5QhshjFC06El .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZmDB5QhshjFC06El .icon-shape p,#mermaid-svg-ZmDB5QhshjFC06El .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZmDB5QhshjFC06El .icon-shape .label rect,#mermaid-svg-ZmDB5QhshjFC06El .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZmDB5QhshjFC06El .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZmDB5QhshjFC06El .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZmDB5QhshjFC06El :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
Zagens Harness 全景
上下文续命
超大型重构
扩展检查面
Layer 1 · LHT防早停 · nudge 继续
Layer 2 · 硬验收门退出码 Oracle
Layer 3 · 交付物对账路径/glob 扫描
Cycle 交接StructuredState + Carry Forward
Macro LoopLHT ↔ CRAFT 交替
对抗审计缺口枚举 → 机器门裁决
可审计 · 可回放 · 真实完成
这套系统的设计哲学可以浓缩为一句话:Harness 不替模型做事,它只负责检查模型有没有把事做完。检查的手段是机器可回放的、可审计的、不依赖模型自身表达的。
本文基于 Zagens v0.8.2 的公开设计文档与源码。作品名称:Zagens(MIT 协议),开源地址:github.com/didclawapp-ai/zagens




