Skip to content

Latest commit

 

History

History
347 lines (246 loc) · 7.7 KB

File metadata and controls

347 lines (246 loc) · 7.7 KB

实战案例:修复 LobsterPress v1.2.4 统计 Bug

本示例展示如何使用 GitHub Development Standard 修复真实 Bug。


背景

Issue: SonicBotMan/lobster-press#56

问题: content_preserved 统计错误


Step 1: 读 Issue

原始 Issue 内容

Bug #1 (高危): Shell summary 变量覆盖

问题:compress() 中,summary 变量在循环中被覆盖,导致最终只保留最后一个工具的摘要。

位置:scripts/lobster_press_v152.py 第 148 行

代码:
for tool in tools:
    summary = tool['summary']  # 每次循环都覆盖

影响:summary 变量只保留最后一个工具的摘要,前面的全部丢失。

修复方案:改用 summary_parts = [],循环中 append,最后 "\n".join()

Step 2: 写"5行任务卡"

【任务类型】Bug 修复
【目标】修复 summary 变量覆盖问题
【边界】只修改 compress() 函数中的 summary 相关代码
【非目标】不重构其他函数,不修改 CLI,不改变其他统计逻辑
【影响范围】scripts/lobster_press_v152.py compress() 函数

Step 3: 确定基线版本

# 检查当前版本
git tag | grep v1.2 | sort -V | tail -3
# v1.2.3
# v1.2.4-beta
# v1.2.4

# 基于 v1.2.4 开始
git checkout v1.2.4
git checkout -b fix/issue-56-summary-overwrite

# 创建新版本文件
cp scripts/lobster_press_v152.py scripts/lobster_press_v124.py

Step 4: 列改动点

需要修改

  1. scripts/lobster_press_v124.py compress() 函数
    • 第 148 行:summary = tool['summary'] 改为 summary_parts.append(tool['summary'])
    • 第 160 行:print(summary) 改为 print("\n".join(summary_parts))

不应修改

  • ❌ 不修改 _generate_summary() 函数
  • ❌ 不修改 CLI 参数
  • ❌ 不修改其他统计变量
  • ❌ 不修改 parser 结构

风险点

  • ✅ summary_parts 需要在循环前初始化
  • ✅ 所有使用 summary 的地方都要检查

Step 5: 编码

修改前(第 145-150 行)

# 统计各工具结果
for tool in tools:
    summary = tool['summary']  # ❌ 每次循环都覆盖
    stats[tool['name']] = tool['stats']

修改后

# 统计各工具结果
summary_parts = []  # ✅ 改为列表收集
for tool in tools:
    summary_parts.append(tool['summary'])  # ✅ 追加而非覆盖
    stats[tool['name']] = tool['stats']

# 最后合并
summary = "\n".join(summary_parts)

完整 diff

--- a/scripts/lobster_press_v152.py
+++ b/scripts/lobster_press_v124.py
@@ -145,8 +145,11 @@ def compress(input_file, output_file, strategy='standard', dry_run=False):
     
     # 统计各工具结果
-    for tool in tools:
-        summary = tool['summary']
+    summary_parts = []
+    for tool in tools:
+        summary_parts.append(tool['summary'])
         stats[tool['name']] = tool['stats']
     
-    print(summary)
+    summary = "\n".join(summary_parts)
+    print(summary)

Step 6: 本地验证(4 层)

Layer 1: 语法验证

python3 -m py_compile scripts/lobster_press_v124.py
# 无输出 = 通过

Layer 2: 导入验证

python3 -c "from scripts.lobster_press_v124 import compress; print('导入成功')"
# 输出:导入成功

Layer 3: 行为验证

# test_summary_fix.py
import sys
sys.path.insert(0, '.')
from scripts.lobster_press_v124 import compress
import tempfile
import json

# 创建测试数据
test_data = [
    {"role": "user", "content": "Hello"},
    {"role": "assistant", "content": "World"}
]

# 写入临时文件
with tempfile.NamedTemporaryFile(mode='w', suffix='.jsonl', delete=False) as f:
    for msg in test_data:
        f.write(json.dumps(msg) + '\n')
    input_file = f.name

output_file = input_file.replace('.jsonl', '_compressed.jsonl')

# 调用
try:
    compress(input_file, output_file, strategy='light', dry_run=True)
    print("✅ 行为验证通过")
except Exception as e:
    print(f"❌ 行为验证失败: {e}")
    raise

Layer 4: 回归验证

# 运行已有测试
python3 tests/test_lobster_press.py

# 手动测试核心流程
python3 scripts/lobster_press_v124.py sessions/example.jsonl -o /tmp/test.jsonl --strategy light

Step 7: 看 diff

检查改动量

git diff --stat scripts/lobster_press_v124.py
# scripts/lobster_press_v124.py | 8 +++++++-
# 1 file changed, 8 insertions(+), 1 deletion(-)

# 总共 9 行,符合"修 1 个小 bug"的预期(5-30 行)

检查改动范围

git diff scripts/lobster_press_v124.py | grep "^+" | grep -v "^+++"
# 只有 3 行新增:
# + summary_parts = []
# + summary_parts.append(tool['summary'])
# + summary = "\n".join(summary_parts)

# ✅ 没有改到其他函数
# ✅ 没有改到 CLI
# ✅ 没有重构其他代码

Step 8: 写发布说明

Commit Message

fix: 修复 summary 变量覆盖问题 (Issue #56)

问题:
- compress() 循环中 summary 变量被覆盖
- 只保留最后一个工具的摘要
- 前面工具的摘要全部丢失

修复:
- 改用 summary_parts 列表收集
- 循环结束后合并为字符串

影响范围:
- scripts/lobster_press_v124.py compress() 函数
- 第 145-155 行

验证:
- ✅ 语法检查通过
- ✅ 导入检查通过
- ✅ 行为验证通过
- ✅ 回归测试通过

非修改:
- 不修改 CLI 参数
- 不修改其他函数
- 不修改 parser 结构

Closes #56

Release Note

## v1.2.4-hotfix1 (2026-03-11)

### 修复内容

- **Bug #1 (高危)**: 修复 summary 变量覆盖问题
  - 问题:compress() 循环中 summary 变量被覆盖
  - 影响:只保留最后一个工具的摘要,前面的全部丢失
  - 修复:改用列表收集,最后合并
  - 位置:scripts/lobster_press_v124.py compress() 函数

### 影响范围

- scripts/lobster_press_v124.py
- compress() 函数(第 145-155 行)

### 验证

- ✅ 语法检查通过
- ✅ 导入检查通过
- ✅ 行为验证通过(构造最小样例)
- ✅ 回归测试通过

### 已知不变更

- 不修改 CLI 参数
- 不修改其他统计逻辑
- 不修改摘要生成函数
- 不新增文件

### 升级指南

```bash
# 直接替换旧版本文件
cp scripts/lobster_press_v124.py scripts/lobster_press_v152.py

# 无需其他配置修改

---

## Step 9: 最后复盘

### 做得好的地方

1. ✅ **最小修改** - 只改了 9 行代码
2. ✅ **目标明确** - 只修 Bug #1,没有夹带私货
3. ✅ **验证完整** - 4 层验证全部通过
4. ✅ **文档同步** - commit message + release note 清晰

### 可以改进的地方

1. ⚠️ **测试用例** - 可以添加单元测试,避免未来回归
2. ⚠️ **代码注释** - 可以在 summary_parts 初始化处添加注释

### 学到的经验

- **变量覆盖很隐蔽** - 在循环中赋值同一变量很容易出错
- **列表收集更安全** - 用 list.append() + join() 避免 overwriting
- **Diff 审查很重要** - 通过看 diff 确认没有改过头

---

## 总结

**本次修复严格遵守 GitHub Development Standard:**

| 步骤 | 状态 | 说明 |
|------|------|------|
| 1. 读 issue | ✅ | 理解 Bug #1 的 summary 覆盖问题 |
| 2. 写5行任务卡 | ✅ | 目标/边界/非目标明确 |
| 3. 确定基线版本 | ✅ | 基于v1.2.4 |
| 4. 列改动点 | ✅ | 只改 compress() summary 相关代码 |
| 5. 编码 | ✅ | 9 行代码,最小修改 |
| 6. 本地验证(4层) | ✅ | 语法/导入/行为/回归全部通过 |
| 7. 看 diff | ✅ | 确认改动量合理(9行) |
| 8. 写发布说明 | ✅ | commit message + release note 清晰 |
| 9. 最后复盘 | ✅ | 总结经验教训 |

**改动量统计**:
- 修改文件:1 个
- 修改行数:9 行
- 修改函数:1 个
- 修改类型:Bug 修复

**✅ 发布成功!**