# DSH 失败归因与消融设计（交接给 Codex 对话）

> 来源：DSH 会话（Harbor 评测研究）基于 `/Users/lizhao/Documents/ChatGPT/swe` 的实验产物做的离线分析，2026-10-27。
> 用法：在 Codex 对话里说“读取 `reports/dsh-failure-attribution-and-ablation-20261027.md`，按 §4/§7 的优先级继续”，即可接续。
> 边界：本文件不改动任何原始实验记录与报告；所有结论均标注证据路径，可复核。

## 给 Codex 的接续指令（可直接复制）

1. 先读本文件 §1–§3，确认归因口径（9 题 + igel = 11 次主样本；35 次 DSH 运行含消融）。
2. 优先做 §7 的 S0（仪表化：DSH system prompt / 请求 messages / 采样参数落盘），**不要先跑模型**。
3. 再按 §7 的 S1（采样对齐）→ S2（loop 契约注入）→ S3（commit checkpoint）顺序做单变量实验；S4（预算×2）只在前面都失败时做。
4. 每轮实验用独立目录，冻结原基线；先 Oracle 再 Agent；保留所有原始结果与失败。
5. 报告更新时把“归因类别”和“机制”分两列写，避免 budget 标签吞掉 implementation 失败。

---

# DSH 失败完整归因 + 消融实验设计

> 2026-10-27 · 数据源：IQuest-Q1 × DeepSWE 9 题基线 + igel 专题 + 契约/循环消融，共 35 次 dsh-minimal 运行
> 结论口径：这是**项目预算/协议口径下**的归因，不是官方 DeepSWE 榜单结论

## 0. 一句话

DSH 的失败不是单一原因，而是 **5 种失败模式** 叠加 **3 个系统性因素**（预算单位错配、提交策略、随机方差）；其中“预算耗尽”只是表层的停止原因，真正的可行动问题有三个：**编辑到最后一刻才想起来提交**、**同一命令重复数百次不换策略**、**文本工具调用让 DSH 提前判完成**。

## 1. 主样本逐 trial 归因（9 题 + igel = 11 次运行）

| 任务 | 预算上限 | 实际请求 | 编辑 | commit | patch | F2P | 结束 | 失败模式 |
|---|---:|---:|---:|---:|---:|---:|---|---|
| meriyah | 406 | 412 | 77 | 0 | 0 | 0/49 | error(429) | **M2 编辑到死，从不提交**（最后编辑在 100% 预算） |
| query | 450 | 456 | 20 | 0 | 0 | 0/8 | error | **M2**（62% 后进入测试，仍不提交） |
| helm | 446 | 452 | **0** | 0 | 0 | 0/5 | error | **M1 零编辑循环**（同一命令重复 318 次） |
| anko | 286 | 292 | 172 | 0 | 0 | 0/9 | error | **M2**（最后编辑在 100% 预算） |
| fastapi | 428 | 297 | 8 | 2 | 54,391 | 137/137 | completed | **M4 通过**（commit@291/292，98% 预算处） |
| scc | 344 | 153 | 8 | 0 | 0 | 0/31 | completed | **M5 协议提前完成**（44% 预算就 completed，无提交） |
| katex（主/重试） | 362 | 368 | **0** | 0 | 0 | 0/94 | error | **M1 零编辑循环**（同一命令重复 190 / 315 次） |
| arktype | 370 | 376 | 148 | 5 | 24,252 | 0/25 | error | **M3 提交了但测试不过** |
| vulture | 312 | 318 | 67 | 2 | 30,928 | 11/24 | error | **M3**（commit@302/303，97% 预算处） |
| igel | 256 | 262 | 193 | 0 | 0 | 0/24 | error | **M2**（最后编辑在 100% 预算） |

模式计数：**M1=3、M2=4、M3=2、M4=1、M5=1**（katex 两次运行均 M1）。

## 2. 系统性因素（跨 trial 的量化证据）

### 2.1 预算单位错配（结构性）

同题同模型下 DSH 的请求数是 codex/mini 的 **1.2–5.6 倍（中位 ~3 倍）**：

| 任务 | codex | mini | DSH | DSH/mini |
|---|---:|---:|---:|---:|
| meriyah | 168 | 156 | 412 | 2.6× |
| query | 146 | 148 | 456 | 3.1× |
| helm | 189 | 148 | 452 | 3.1× |
| anko | 52 | 81 | 292 | 3.6× |
| fastapi | 100 | 89 | 297 | 3.3× |
| scc | 99 | 129 | 153 | 1.2× |
| katex | 81 | 104 | 368 | 3.5× |
| arktype | 77 | 263 | 376 | 1.4× |
| vulture | 246 | 118 | 318 | 2.7× |

而预算 = **官方 top20 每任务最大 n_agent_steps × 1.2**，是给官方 harness 的步数语义定的；DSH 的 SDK minimal 循环（只有 bash 一个工具，`tool_count=1`）粒度更细 → **9/11 次运行精确打满请求上限**（406/450/446/286/370/312/362/368/256），预算在多数题上是 binding 的。

### 2.2 提交策略（最可行动）

- 只有 **3/11** 有 patch；其中 fastapi commit 在 98% 预算、vulture 在 97%，即“踩线提交”
- **4 次 M2 运行**：第一处编辑在预算的 4–14% 就发生了，最后一处编辑在 95–100% 预算 —— 说明它们**一直在改，但从不 checkpoint commit**；prompt 里明明写了 “Make checkpoint commits… Only committed changes are scored”
- 结果：77–193 条编辑命令的工作量，因未提交而 patch=0 → 按 pristine base 评分 = 0
- 推论：DSH 的 0 分里有相当一部分是**提交协议失败**，不是“没干活”

### 2.3 病态循环（task-dependent）

- helm：同一命令重复 **318 次**（`grep get-release-template …`），**零编辑**
- katex：同一命令重复 **315 / 190 次**，零编辑
- loop 消融里甚至出现 **636 次**精确重复
- 修正 Codex 报告的一处说法：“重复命令最多 6 次”只对 meriyah 成立；helm/katex 是数百次精确重复
- 这类循环一旦发生，预算必死且不会产生 patch

### 2.4 协议/格式（SCC 专属）

- SCC 基线：`finish_reason=completed` 于 153 步（44% 预算），final response 是 `<iquestcoder_tool_call>…` 文本 XML，DSH 视为无 tool_call → 提前结束、无提交
- 契约消融的 completed 运行（H1-2/H1-3/H2-1/…）大多有 patch 且 **F2P 28/31** —— 说明 SCC 只要正常提交，能到 28/31；那 3 个测试是**稳定的实现缺口**，不是随机
- 反馈触发数确实为 0（日志与轨迹双重核对），所以“反馈机制效果”本轮没测到；但 H0 vs H1-H3 的差异更可能是**运行间方差**（H0 恰好都 error，H 组恰好有 completed）

### 2.5 随机方差（被低估的关键因素）

同配置重复运行差异极大：

| 组 | 3 次运行的 F2P |
|---|---|
| helm-L0 | 0/5, 2/5, 0/5（其中一次有 62KB patch，另两次 0 patch） |
| katex-L0 | 4/94, 0/94, 0/94（一次有 patch，两次无） |
| loop L1 | helm 0/5, 1/5, **5/5**；katex 0/94, 82/94, 0/94 |

→ 单次运行的归因/排名不可靠；3 次/组也不足以检验效应。

## 3. 对 Codex 原结论的修订

| 原说法 | 修订 |
|---|---|
| “7 题预算耗尽，主要未提交” | 拆成：5 未提交（4 M2 + 1 M1）+ 2 提交未过（M3）+ 1 协议（M5）；M2 是“编辑到最后未提交”，不是“没做成” |
| “重复命令最多 6 次” | 仅 meriyah 成立；helm/katex/loop 有 190–636 次精确重复 |
| “不能归因反馈机制” | 成立；且 H0 vs H1-3 差异可用方差解释，不应视为干预效果 |
| “模型能力失败” | 只能作“项目预算口径下的能力失败”；预算单位与 harness 步数语义不匹配，需预算敏感性实验才能外推 |

## 4. 消融实验设计

### 阶段 0 · 离线/仪表化（不跑模型，0.5 天）

| ID | 内容 | 产出 |
|---|---|---|
| I1 | 用现有 35 次运行重算：模式分类、重复计数、commit 尝试、预算使用点 | 逐 trial 归因表（本文件 §1） |
| I2 | 在 runner 里补埋点：`git status --porcelain`（结束前判断是否 dirty）、exact-command hash 重复计数、first/last edit 预算占比、finish_reason、合成反馈次数、**DSH system prompt 落盘** | 后续所有实验可自动归因 |
| I3 | 修 contract/loop 消融的统计口径：把 H0 vs H1-H3、L0 vs L1 的差异先与方差基线比较 | 判断哪些“效果”是噪声 |

### 阶段 1 · 决定性实验（1–2 天，约 12–16 次 trial）

| ID | 假设 | 干预（单变量） | 任务 × n | 主指标 / 判定 |
|---|---|---|---|---|
| **E1** | 预算绑定 | step_limit ×2（meriyah 812、helm 892） | meriyah×2, helm×2 | commit/patch 出现 → 预算绑定；helm 仍循环 → M1 独立 |
| **E2** | 提交策略 | 预算 50%/80% 时若 dirty 或无新 commit，注入 “commit now” 提醒（max 2 次） | meriyah×3 | patch 率、commit 步位置、F2P |
| **E3** | 病态循环 | 精确重复 ≥6 次 → 注入“换策略或提交”提醒 | helm×3, katex×2 | max exact repeat、编辑数、patch |
| **E4** | 协议错位 | 把 `<iquestcoder_tool_call>` 归一化为结构化 tool_call 或注入格式反馈 | scc×3 | 提前完成率、patch、F2P（预期 28/31） |
| **E5** | 提示词（非 SP 全文） | runtime prompt 加 3 条规则：每完成一处改动就 checkpoint commit / 禁止重复同一命令 / 只用结构化 bash 工具 | meriyah×2, helm×2 | patch 率、重复数、F2P |

> E2/E3/E5 都是 prompt/harness 级干预，必须与原基线分开目录、原记录不动；每轮先 Oracle，再跑，跑完核对清理。

### 阶段 2 · 量化与澄清（0.5–1 天）

| ID | 内容 | 目的 |
|---|---|---|
| E6 | meriyah 预算曲线：×1 / ×2 / ×3，每档 2–3 次 | 把“预算 vs 能力”画成曲线，回答 DSH 分数在什么预算下才稳定 |
| E7 | DSH vs mini 轨迹离线对比（同题同模型）：命令/步、token/步、编辑/commit 节奏 | 解释为什么都是 bash-only，mini 却只用 1/3 步数（SP/观测格式/步进粒度） |
| E8 | 方差基线：meriyah/helm 各 3 次原配置 | 给后续实验定最小样本量 |

### 判定树

```
E1 (预算×2)
 ├─ meriyah 出现 commit/patch → 预算绑定是 M2 主因 → 报告改口径 + E6 画曲线
 └─ 仍不提交 → 进 E2（提交提醒）
helm:
 ├─ E1 仍 0 编辑循环 → E3（循环熔断）→ 仍失败 → E5（提示词）
scc:
 └─ E4（协议归一化）→ 若仍 28/31 → 3 个测试是真实实现缺口，另立攻坚
```

## 5. 成本与风险

- 模型免费（IQuest 口径），沙箱单 trial 约 0.1–0.4 元，阶段 1 约 12–16 次 → 总成本 < 10 元，主要是时间（单 trial 10–20 分钟，并发 2）
- 风险：①改 runner 会改变基线 → 必须独立目录、保留原记录；②E2/E3 的提醒可能“教会”模型而非修复机制 → 报告时区分“能力 vs 协议”；③n 小 → 每阶段先看方差，别把一次成功当结论

## 6. 需要拍板

1. 先做 **E1（预算×2）+ E4（SCC 协议）** 这条最短路径，还是先做 E2/E3？
2. 允许改 runner/预算吗（独立目录、原基线冻结）？
3. 接受每阶段 n=2–3 的方向性结论，还是要 n≥5 的统计结论（成本 ×2）？

---

## 7. 附：mini vs DSH 源码级配对分析（2026-10-27 补充）

配对任务：helm / meriyah / scc（同模型 IQuest-Q1、同任务、同 runtime prompt；mini 成功、DSH 失败）

| 维度 | mini-swe-agent（源码：upstream/mini-swe-agent-fc） | dsh-minimal（SDK 0.1.5rc1，wrapper+runner 在 upstream/deepseek-v41-evaluation/dsh-minimal.patch） |
|---|---|---|
| 系统提示 | `mini.yaml`：workflow 6 步 + “每轮至少一个 bash tool call” + 显式提交命令 `echo COMPLETE_TASK_AND_SUBMIT_FINAL_OUTPUT` | SDK 内置 profile，**未记录**（ATIF 首步是 user，无 system step） |
| 终止/提交 | 环境检测命令输出首行 == 哨兵 → `Submitted` 异常；模型不能静默结束 | `finish_reason=completed` 即结束；runner 接受 completed/max-tokens，其余 exit 1 → Pier 记 NonZeroAgentExitCodeError |
| 格式错误恢复 | `max_consecutive_format_errors=3`，每次注入格式错误反馈并继续 | 无等价机制：模型若把工具调用写成文本（`<iquestcoder_tool_call>`），SDK 视为无 tool call → completed |
| 观测渲染 | 10k 截断 + 明确 warning/head/tail/elided 提示 | 未在本地源码；轨迹里只有工具输出+`[Command finished with exit code 0]` |
| 步数限制 | `step_limit` 在 agent 内 → `LimitsExceeded`（软结束） | 推理代理 `model_request_limit` → HTTP 429 + SDK 重试 5 次 → error（硬结束，无收尾机会） |
| 推理/文本记录 | trajectory 含 content/ reasoning | ATIF 里 assistant 文本几乎为空（helm 30/447、meriyah 8/407），reasoning 0 条 → 无法看模型意图 |
| 采样参数 | 显式 temperature=1.0 / top_p=.95 / top_k=20 | 只有 reasoning_effort=max / max_tokens=256000，**temperature 等未显式设置** → 与 mini 不可直接比 |

### 配对 case 证据

- **helm**：mini 156 次调用完成 编辑→测试→commit（msg 275/324，约 85%）→ 提交哨兵 → 5/5 通过；DSH 452 次调用、**0 次编辑**、从 ~step 120 起同一 grep 重复 **319 次**（观测输出正常且相同），最后连续 5 次 429 后 error。
- **meriyah**：两边都 `git checkout -b feat/using-declarations`；mini 在 85% 处 commit；DSH 到 90% 仍在 `git diff/log`，直到预算耗尽从未 `git add/commit`。
- **scc**：DSH `finish_reason=completed`（153/344 步）时 final_response 是 `<iquestcoder_tool_call>` 文本 XML，无提交；mini 的格式错误机制会把这类输出当作 invalid action 重试，而非结束。

### 结论

“SP 不对”更准确的表述是：**DSH 与 mini 的差异不是一段 SP，而是 agent-loop 契约**（显式提交、每轮至少一个动作、格式错误恢复、预算软/硬结束）+ 采样参数 + 未记录的 SDK 系统提示。要闭合因果，先补三项仪表化（DSH system prompt / 请求 messages / 采样参数），再做采样对齐与契约注入实验。
