# #09 Rebuttal 流程自动化 + 目标一致性 Gate

> 版本: v1.1
> 日期: 2026-06-03
> 作者: 庞统（副军师）
> 状态: 待评审（v1.1）
> 前置: #04 黑板协作（@mention）+ #08 Classify Outcome
> 关联: T4 审查体系完善
> 变更: v1.1 纳入司马懿评审反馈 — verdict 读 reviews 表 + rebuttal mention spawn 带 on_complete 回调

## 讨论决策记录

### D1: 庞统持续 session
**结论**：不做 openclaw 层面的持续 session（受 openclaw 机制限制）。改为两个场景确保目标一致性：
1. Round review（已实现 ✅）— 子任务完成后庞统审查
2. 过程中 agent 沟通（本设计覆盖）— agent 遇到问题问庞统时，庞统保持和目标高度一致，防止需求降级

### D2: 动态规划 / Replan
**结论**：不需要专门的 replan 模块。在当前架构中 replan 已通过自然组合实现：
- Task 失败 → crash_limit 标 failed → round review → 庞统看全局后决定调整
- Task 产出改变理解 → agent 自主读黑板（#05 上下文注入）→ agent 自己判断调整
- 发现新依赖 → 庞统在 round review 中发现 → 创建新子任务
- 依赖链自动推进 → `_advance_dependencies`（blocked→pending）
- Per-task timeout + crash limit → `_check_timeouts`（deadline 优先，默认 30m，crash 3/30m 标 failed）

不做独立的 replan 代码模块。

### D3: Rebuttal 触发方式
**结论**：靠 agent 自主 + @mention 现有机制，不做 daemon 层面的自动触发。原因：
1. 减少系统复杂度
2. Agent 有自主判断能力（#05 上下文注入）
3. @mention 机制已成熟（#04）

### D4: B8 BUG-7 planning 暂停
**结论**：`planning` 状态已从状态机中移除，BUG 不再存在。但前端 resume 映射为 `executing`（非法状态），应改为恢复到 `resumed_from` 记录的状态。记为后续前端修复项。

### D5: 司马懿评审反馈（v1.0 → v1.1）

**问题1：verdict 读取方式** → on_complete 回调中从 reviews 表查最新 verdict（`SELECT verdict FROM reviews WHERE task_id=? ORDER BY created_at DESC LIMIT 1`），和 ticker `_recover_review_task` 一致。

**问题2：review 保持状态不会被重复 dispatch** → 确认无问题，`_dispatch_reviews` 已有 `if reviews: continue` 保护。

**问题3：rebuttal @mention 缺 on_complete** → 选方案 1：mention spawn 带回调。触发条件：task status=review + comment_type=rebuttal → spawn 时带 `_review_on_complete` 回调。改动点在 `_process_mentions`，约 10 行。

**问题4：assignee 而非 current_agent** → 确认 @mention 对象用 assignee（执行者），不用 current_agent（审查者）。

**MAX_ROUNDS 确认**：`RebuttalManager.MAX_ROUNDS = 2`，rebuttal round 1（司马懿重审）+ rebuttal round 2（庞统仲裁）= 2 轮。对齐。

---

## 一、问题陈述

### 1.1 Rebuttal 缺失

当前审查流程：

```
Agent 完成 → review → 司马懿审查 → verdict(approved/rejected/needs_revision) → 结束
```

**问题**：审查结论是单方面的。Agent 对 rejected/needs_revision 没有反驳渠道。尤其是：
- 复杂设计方案，司马懿可能误判
- 需求降级场景，agent 认为自己做了正确的事但被 reviewer 要求改回去
- 没有 1-2 轮辩论，结论质量无法保证

**已有基础**：
- `RebuttalManager` 类已实现（2 轮反驳，round 1→司马懿重审，round 2→庞统仲裁）
- `comment_type` 支持 `rebuttal`、`rebuttal_response`、`debate_argument` 等
- `reviews` 表结构完整

**缺什么**：ticker/dispatcher 层面没有自动串联 rebuttal 流程。`submit_rebuttal` 存在但无人调用。

### 1.2 目标一致性 Gate

当前 agent 遇到需求不清晰时：
- executor prompt 说"不确定时停下来问（黑板 comment）"
- @mention 机制可以把庞统 spawn 起来

**缺什么**：
1. executor/reviewer prompt 没有明确指引"需求不清晰时 @pangtong-fujunshi 提问"
2. 庞统收到提问时，没有注入原始任务目标和验收标准来校准回答
3. 庞统的回复可能无意中做了需求降级（"这个太复杂了，简化一下吧"）

---

## 二、设计方案

### 2.1 Rebuttal 自动化流程

#### 流程图

```
Agent 完成任务 → review
  → 司马懿审查 → verdict
    ├─ approved → done（无争议）
    ├─ rejected/needs_revision → 通知被审 agent
    │   → Agent 选择：
    │     ├─ 接受 verdict → 按 verdict 修改 → 重新提交 review
    │     └─ 反驳 → submit_rebuttal（黑板 comment_type=rebuttal）
    │       → Ticker 检测到 rebuttal → spawn 司马懿重审（round 2）
    │         ├─ 司马懿改判 → done/needs_revision
    │         └─ 司马懿坚持 → 通知庞统仲裁（round 3，最终轮）
    │           → 庞统裁决 → done/needs_revision/创建新任务
    └─ （rebuttal 最多 2 轮，超限庞统最终裁决）
```

#### 触发机制

**关键设计决策：谁触发 rebuttal？**

不是 daemon 自动触发，而是 **agent 自主选择**。流程：

1. 司马懿审查完成 → verdict 写入 reviews 表 + comment_type=review
2. Ticker 检测到新 review verdict → 通知被审 agent（@mention agent）
3. Agent 看到 verdict + 自己的产出 → 决定接受或反驳
4. 如果反驳 → agent 写 comment_type=rebuttal + @simayi-challenger
5. Ticker 的 mention 处理循环 spawn 司马懿重审
6. 司马懿重审后如果坚持 → @pangtong-fujunshi 请求仲裁
7. 庞统仲裁 → 最终结论

**这个流程几乎不需要新代码**——主要靠 @mention 现有机制 + prompt 引导。

#### 需要改的代码

| 文件 | 改动 | 说明 |
|------|------|------|
| `dispatcher.py` `_task_on_complete` | 修改 | review completed → 读 verdict → approved 标 done / 非 approved @mention assignee |
| `ticker.py` `_process_mentions` | 修改 | rebuttal mention spawn 时带 `_review_on_complete` 回调 |
| `prompt_templates/executor.md` | 修改 | 加入“需求不清晰时 @pangtong-fujunshi 提问” |
| `prompt_templates/reviewer.md` | 修改 | 加入 rebuttal 流程指引 |
| `prompt_templates/review_pangtong.md` | 修改 | 加入仲裁指引 + 目标一致性检查 |
| `prompt_templates/review_simayi.md` | 修改 | 加入 rebuttal 处理指引 |

#### _task_on_complete 改动细节（dispatcher.py）

当前逻辑（L244-250）：review completed → 直接标 done。

改为：
```python
if _is_review:
    if outcome in ("completed", "session_revived"):
        # 读 verdict
        review = conn.execute(
            "SELECT verdict FROM reviews WHERE task_id=? ORDER BY created_at DESC LIMIT 1",
            (_task_id,)
        ).fetchone()
        if review and review["verdict"] == "approved":
            _dispatcher._mark_task_status(_task_db, _task_id, "done")
        else:
            # 非 approved → @mention 被审 agent（用 assignee，非 current_agent）
            task = conn.execute("SELECT assignee FROM tasks WHERE id=?", (_task_id,)).fetchone()
            if task and task["assignee"]:
                bb.add_comment(_task_id, "daemon",
                    f"@{task['assignee']} 审查结论: {review['verdict'] if review else '未知'}，请查看详情并决定接受或反驳",
                    comment_type="review")
            # 不标 done，保持 review
    else:
        # crash/error → 保持 review 等 ticker 处理
        pass
```

#### _process_mentions 改动细节（ticker.py）

当前 mention spawn 不带 on_complete。rebuttal 场景需要带，否则新 verdict 无人处理。

触发条件：task status=review + mention 的 comment_type 包含 rebuttal

```python
# 在 mention spawn 时检查：如果是 rebuttal 场景
has_rebuttal = any(
    item.get("comment_type") == "rebuttal"
    for item in items
)
task_status = bb.get_task(items[0]["task_id"]).status if items else None

if has_rebuttal and task_status == "review":
    # rebuttal 重审：带 on_complete 回调处理新 verdict
    result = await self.spawner.spawn_full_agent(
        agent_id=agent_id,
        message=prompt,
        task_id=tid,
        use_main_session=True,
        on_complete=_review_on_complete,  # 处理新 verdict
    )
else:
    # 普通 mention：不带回调
    result = await self.spawner.spawn_full_agent(
        agent_id=agent_id,
        message=prompt,
        task_id=tid,
        use_main_session=True,
    )
```

其中 `_review_on_complete` 复用 dispatcher 中 review verdict 的处理逻辑（读 verdict → approved 标 done / 非 approved @mention）。

#### 防止无限循环

- RebuttalManager.MAX_ROUNDS = 2（已有，rebuttal round 1 司马懿重审 + round 2 庞统仲裁）
- 超过 2 轮 → 庞统最终裁决
- 每个 review 记录在 reviews 表中，rebuttal_count 可追溯
- `_dispatch_reviews` 已有 `if reviews: continue` 保护，有 review 结论的任务不会被重复 dispatch

### 2.2 目标一致性 Gate

#### Agent 端

**executor.md 改动**：

在"工作方式"和"约束"之间新增一节：

```markdown
## 需求不清晰时的处理
- 任务描述有歧义、验收标准不明确、多个理解方式 → @pangtong-fujunshi 提问
- 不要自行假设。宁可多问一句，也不要做错方向
- 提问时：列出你的理解、可能的选项、你倾向的方案，让庞统确认
- 庞统回复后，以回复为准继续执行
```

#### 庞统端

**review_pangtong.md 改动**：

新增"代理提问处理"部分：

```markdown
## 回答 Agent 提问时的原则
- 对照原始任务目标和验收标准回答，不做需求降级
- 如果 agent 觉得目标太难 → 讨论替代方案，但必须说清楚代价（缩小的范围、降低的质量）
- 如果原始目标确实不可行 → 升级用户，不要自己做主降级
- 回答要具体到可操作，不要给模糊方向
```

#### Bootstrap 注入

当庞统被 @mention spawn 回答问题时，bootstrap 已经会注入任务上下文（#05 L2 层）。不需要额外改动。

### 2.3 司马懿 Rebuttal 处理

**reviewer.md / review_simayi.md 改动**：

```markdown
## Rebuttal 处理
- 被反驳时，重新审视自己的结论
- 如果 agent 的反驳有理有据 → 改判
- 如果坚持原判 → 给出更具体的理由，不要只说"我认为不行"
- Rebuttal 不是对抗，是共同追求正确答案
- 第 2 轮 rebuttal 如果仍无法达成一致 → @pangtong-fujunshi 请求仲裁
```

---

## 三、改动总览

| 文件 | 改动 | 行数 |
|------|------|------|
| `src/daemon/ticker.py` | review verdict 非 approved 时 @mention 被审 agent | ~15 行 |
| `prompt_templates/executor.md` | 新增"需求不清晰时 @pangtong-fujunshi" | ~8 行 |
| `prompt_templates/reviewer.md` | 新增 rebuttal 处理指引 | ~8 行 |
| `prompt_templates/review_pangtong.md` | 新增仲裁指引 + 反需求降级 | ~10 行 |
| `prompt_templates/review_simayi.md` | 新增 rebuttal 处理指引 | ~8 行 |
| **净增** | | **~49 行** |

---

## 四、验收标准

1. 司马懿审完 rejected/needs_revision → 自动 @mention 被审 agent
2. Agent prompt 明确引导"需求不清晰 → @pangtong-fujunshi"
3. 庞统回复时对照原始目标，不做需求降级
4. Rebuttal 最多 2 轮，超限庞统裁决
5. 现有测试不 regression

---

## 五、不做的事

- 不做 daemon 层面的自动 rebuttal 触发（靠 agent 自主 + @mention）
- 不做专门的 rebuttal API 端点（复用 comment + mention）
- 不做 rebuttal 状态机扩展（复用 RebuttalManager 已有逻辑）
