# AI Review 必须把 PR description body 喂给 LLM，否则会反复指控已 ack 项

**Date**: 2026-05-14
**Tags**: ai-review, prompt-engineering, gitea, false-positive
**Related**: #373（需求工单）/ #371（触发实例）/ #259（AI review 工作流系统）

## 症状

PR #371 的 6 轮 ai-review，每一轮都把"PRD 写 3 件事独立 PR 但本 PR 合并第 1+2 件事"列为 suggestion，即便作者已在 PR description 的「与 PRD 范围的差异」段清楚解释为何合并合理。

## 元根因

`scripts/ops/ai-review-runner.sh` 的 prompt 只输入 **diff + 关联文档 + 代码**，**不输入 PR description body**。LLM 看不到作者已经写下的 rationale → 每轮重新发现同一"客观事实"（如"高风险路径合并"）→ 每轮新列一遍。

state 增量去重（#259）只能去重**上一轮 LLM 自己列过的 finding**，无法处理"作者已在 body 解释但 LLM 从未看到的事实"。

## 修复

`scripts/ops/ai-review-runner.sh` 提取 PR_JSON.body，构建 `PR_BODY_CONTEXT` 块注入到 prompt（在 PR 元信息之后、探查方式之前）。配套规则：

- 合理解释 → 不列 finding（视作 ack）；如需提示降级为 suggestion 并加 "PR body 已 ack：<原话>" 前缀
- 牵强解释 → 仍列 finding，message 必须引用 body 原话说明为何 rationale 不成立
- body 是作者**声明**，不是契约面事实源——冲突时仍以 docs/ 和代码为准

防御性截断 12000 字符（实测 PR body 多在 2-8K，覆盖绝大多数）。

附带加 `AI_REVIEW_DUMP_PROMPT=1` 短路，本地秒级 dump 最终 prompt 不调 claude，用于 prompt 调试。

## 反向校验

故意写一个牵强的 rationale（如"我觉得没事"），review 应识别为"解释不足"，仍列 finding 并引用作者原话。这点靠 prompt 规则约束 + 后续观察。

## 教训：prompt 缺什么比 prompt 写什么更致命

state 去重做得再精致，没把作者声明喂进去就解决不了"已 ack 项重复出现"。每加一条结构化输入前先问：**作者已经说过什么？这层信息有没有进 prompt？**

类似盲点可能还在：commit messages（intent 信号）、关联 issue body（需求约束）、上次 review 的作者回复（dialog 上下文）。

## 验证

```bash
# 本地 dump prompt 看 PR_BODY 是否被注入
AI_REVIEW_DUMP_PROMPT=1 PR_NUMBER=371 AI_REVIEW_MODE=hard-rules-block \
  GITEA_API_TOKEN=$GITEA_API_TOKEN bash scripts/ops/ai-review-runner.sh \
  | grep -A2 'PR description body'
```

实测 PR #371 next round review，"为何合并 1+2 件事"应不再作为 finding 出现（merge 本 PR 后下次 review 自验）。
