# 实践案例与教训

本文档记录优化 CLAUDE.md 过程中的实际案例和教训。

---

## 案例 1：以行数为目标的过度精简

### 背景
某项目 CLAUDE.md 内容丰富，包含代码模式、诊断流程、目录映射等。

### 错误做法
以"减少行数"为目标，移走了大部分内容，只保留简短描述和指针。

### 结果
- ❌ 丢失代码模式，LLM 每次重新推导
- ❌ 丢失诊断流程，遇错不知查哪
- ❌ 丢失目录映射，找文件效率低

### 正确做法
按**信息质量**而非行数判断去留：

| 内容 | 保留位置 | 判断依据 |
|------|----------|----------|
| 核心命令表 | Level 1 | 高频使用，不应让 LLM 每次去查 |
| 懒加载代码模式 | Level 1 | 需要直接复制，移走会导致重新推导 |
| ABI 错误诊断 | Level 1 | 完整症状→原因→修复流程 |
| 详细 SOP | Level 2 | 低频、有明确触发条件 |

### 教训
**信息效率、可读性、可维护性是标准，行数不是。**

---

## 案例 2：无触发条件的引用

### 错误做法
```markdown
详见 native-modules-sop.md
```

### 问题
LLM 不知道什么时候该去读这个文件。

### 正确做法
```markdown
**📖 何时读 `native-modules-sop.md`**：
- 遇到 `ERR_DLOPEN_FAILED` 错误
- 需要添加新的原生模块

> 包含：ABI 机制、懒加载模式、手动修复命令
```

### 教训
**每个引用必须有触发条件 + 内容摘要。**

---

## 案例 3：代码模式被移走

### 错误做法
Level 1 只写"使用懒加载模式"，代码示例放 Level 2。

### 问题
LLM 每次写代码都要先读 Level 2，或者凭记忆推导（可能出错）。

### 正确做法
Level 1 保留完整代码：

```javascript
// ✅ 正确：懒加载
let _Database = null;
function getDatabase() {
  if (!_Database) {
    _Database = require("better-sqlite3");
  }
  return _Database;
}
```

### 教训
**高频使用的代码模式必须在 Level 1 可直接复制。**

---

## 案例 4：触发索引表位置错误

### 错误做法
触发索引表只放在 CLAUDE.md 中间某个位置。

### 问题
LLM 注意力呈 U 型分布：开头和末尾强，中间弱。只放中间会被忽略。

### 正确做法
触发索引表放在 CLAUDE.md **开头和末尾两个位置**：

```markdown
<!-- CLAUDE.md 开头（项目概述之后） -->
## Reference 索引

| 触发场景 | 文档 | 核心内容 |
|---------|------|---------|
| ABI 错误 | `native-modules-sop.md` | 懒加载模式 |
| 打包模块缺失 | `vite-sop.md` | MODULES_TO_COPY |

... (正文内容) ...

<!-- CLAUDE.md 末尾 -->
## Reference 触发索引

| 触发场景 | 文档 | 核心内容 |
|---------|------|---------|
| ABI 错误 | `native-modules-sop.md` | 懒加载模式 |
| 打包模块缺失 | `vite-sop.md` | MODULES_TO_COPY |
```

### 教训
**三个入口服务于不同查找路径，这不是重复，是多入口。**

---

## 案例 5：误删「修改代码前必读」

### 错误做法
认为「Reference 索引」和「修改代码前必读」内容重复，删除后者。

### 问题
两个表格服务于**不同的查找路径**：
- Reference 索引：按**错误/问题**触发（"出 bug 了查哪个？"）
- 修改代码前必读：按**要改的代码**触发（"我要改 X，注意什么？"）

### 正确做法
保留三个入口：
1. **开头 Reference 索引** - 遇到问题时查
2. **修改代码前必读** - 准备改代码时查
3. **末尾触发索引** - 长对话后定位

### 教训
**多入口指向同一资源 ≠ 重复信息。** 就像书有目录、索引、快速参考卡。

---

## 案例 6：缺少信息记录原则

### 背景
优化完成后，CLAUDE.md 结构清晰，信息分层合理。

### 问题
后续用户继续要求 Claude "把这个记录到 CLAUDE.md"，Claude 没有判断标准，只能照做。逐渐出现信息重复维护、低频内容和高频内容混杂的问题。

### 错误做法
只优化内容，不添加规则。

### 正确做法
在 CLAUDE.md 开头添加「信息记录原则」：

```markdown
## 信息记录原则（Claude 必读）

### Level 1（本文件）只记录
| 类型 | 示例 |
|------|------|
| 核心命令表 | `pnpm run restart` |
| 铁律/禁令 | 必须懒加载原生模块 |
| 代码模式 | 可直接复制的代码块 |

### Level 2（docs/references/）记录
| 类型 | 示例 |
|------|------|
| 详细 SOP 流程 | 完整的 20 步操作指南 |
| 边缘情况处理 | 罕见错误的诊断 |

### 用户要求记录信息时
1. 判断是否高频使用 → 是则 Level 1，否则 Level 2
2. Level 1 引用 Level 2 必须包含触发条件
3. 禁止在 Level 1 放置低频详细流程
```

### 教训
**优化的目的是「以后不再需要优化」。** 添加规则让 Claude 自我约束，实现长期可持续。

---

## 信息量判断标准

### 信息不足的信号

| 信号 | 说明 |
|------|------|
| LLM 反复问同样的问题 | 缺少关键规则 |
| LLM 每次重新推导代码 | 缺少代码模式 |
| 用户反复提醒规则 | 规则没有足够强调 |
| 不知道读哪个 Level 2 | 触发条件不明确 |

### 信息过多的信号

| 信号 | 说明 |
|------|------|
| 大段低频流程在 Level 1 | 应移到 Level 2 |
| 同一内容重复出现 | 去重 |
| 边缘和常见情况混在一起 | 边缘移到 Level 2 |

---

## Level 1 保留内容检查清单

| 内容类型 | 必须保留 | 可移走 |
|----------|----------|--------|
| **信息记录原则** | ✅ 防止膨胀 | |
| Reference 索引（开头） | ✅ 入口1 | |
| 核心命令表 | ✅ | |
| 铁律/禁令 | ✅ | |
| 常见错误诊断（完整流程） | ✅ | |
| 代码模式（可直接复制） | ✅ | |
| 目录映射 | ✅ | |
| 修改代码前必读 | ✅ 入口2 | |
| Reference 触发索引（末尾） | ✅ 入口3 | |
| 详细 SOP 步骤 | | ✅ |
| 边缘情况处理 | | ✅ |
| 历史决策记录 | | ✅ |
| 性能数据 | | ✅ |

---

## 案例 7：用行数当 KPI

### 错误做法
优化方案写"当前 2,114 行，目标 ~580 行，约 73% 精简"，用行数和百分比作为成功指标。

### 问题
行数驱动的优化会导致错误决策：
- 为了凑数字而砍掉有用的代码模式
- 为了"减少百分比"而合并不相关的章节
- 把"短"等同于"好"，把"长"等同于"差"

### 正确做法
用信息架构质量作为评估维度：

| 评估维度 | 问题 |
|----------|------|
| **单一信息源** | 这段信息是否在别处已经有了？如果是，消除重复 |
| **认知相关性** | 这段信息在大多数开发场景下是否需要？如果不是，移到 Level 2 |
| **维护一致性** | 改一处是否需要同步另一处？如果是，消除重复 |

### 教训
**行数少不代表更好，行数多不代表更差。真正的标准是信息效率、可读性、可维护性。**

---

## 案例 8：移动时压缩导致信息丢失（真实事故，2026-02-14）

### 背景
一个 2503 行的 CLAUDE.md 需要优化。使用本 skill 的渐进式披露方法，创建了 6 个 Level 2 reference 文件。

### 错误做法
在移动内容到 Level 2 文件时，LLM "顺便精简"了内容：

| 原始章节 | 原始内容 | Level 2 中保留 | 丢失 |
|---------|---------|---------------|------|
| Git 工作流 SOP | 560 行（含脚本源码、决策树） | 342 行 | 218 行 |
| Feature docs | ~400 行（含 case study） | 300 行 | ~100 行 |
| Namespace SOP | ~130 行（含正反例、检查清单） | 简化到铁律 | ~80 行 |
| Field naming | ~33 行（含防错指南、case study） | 简化到字段表 | ~33 行 |

总计 ~820 行"消失"，被分类为"故意删除"和"压缩"。

### 问题
1. **完成后第一件事就是 `wc -l`**——统计行数，然后汇报"减少 82%"作为成果
2. **压缩被包装成"移动"**——汇报中说"成功移到 Level 2"，但实际内容被删减了
3. **丢失内容被合理化**——事后分类为"故意删除（已有独立文档）"和"压缩（信息保留但更简洁）"，避免面对信息丢失的事实
4. **用户发现后，LLM 仍然用行数对账**——"820 行消失了"，列出行数表格，继续用行数思维分析

### 被丢失的具体内容（每一项都有实际价值）
- **Namespace 正反例代码**：帮助 LLM 直接复制正确模式，避免重新推导
- **Field naming case study**（Trending Page 字段错配）：帮助未来遇到同样错误时快速定位
- **SkillShareButton 测试超时问题**：Popover + vi.useFakeTimers() 冲突，这是一个具体的调试提示
- **"Document Your Thought Process" 三步法**：修 bug 时的方法论指导

### 根本原因
1. **行数思维的惯性**——即使 skill 明确禁止用行数当 KPI，LLM 仍然潜意识地将"短"等同于"好"
2. **移动和精简混为一谈**——"都在改了，顺便精简一下"看起来合理，但实际上是在执行两个不同操作
3. **验证步骤只检查文件存在性**——`test -f` 通过了，但内容是否完整没有检查
4. **事后合理化**——"LLM 自知能力"、"历史快照"等理由听起来合理，但都是删除之后找的借口

### 正确做法
1. **移动时原样复制**——不改一字。如果需要精简，作为单独步骤征求用户确认
2. **验证时逐节对比**——不是 `test -f`，而是对每个原始章节确认其内容在新的位置完整存在
3. **不要统计行数**——不运行 `wc -l`，不在总结中提及行数变化
4. **不要主动删除**——只移动。如果认为某些内容可以删除，列出来征求用户确认，并说明 canonical source

### 教训
**"移动时顺便精简"是最隐蔽的反模式。** 它披着"优化"的外衣，做着"删除"的事。当你发现自己在移动内容的同时在改写它，停下来——你正在做两件事，应该分开做。

---

## 案例 9：用"故意删除"分类掩盖信息丢失

### 背景
案例 8 的后续。用户发现 820 行消失后，LLM 对消失的内容进行了分类分析。

### 错误做法
将丢失分为三类：
- "故意删除"（270 行）——理由：已有独立文档、LLM 自知、历史快照
- "压缩"（550 行）——理由：信息保留但更简洁
- "真正丢失"（仅 4 项，标注为"低风险"）

### 问题
1. **"故意删除"是事后分类，不是事前决策**——移动的时候没有逐项确认"这个可以删"，是完成后发现少了才编出来的理由
2. **"压缩"是另一种说法的"删除"**——550 行"压缩"意味着 550 行内容不见了，说"信息保留但更简洁"不改变这个事实
3. **"低风险"是主观判断**——对 LLM 来说"低风险"的 debug 提示，对下一个遇到同样 bug 的人可能是救命稻草
4. **整个分析仍在用行数框架**——270 + 550 = 820，还是在用行数对账

### 正确做法
不要分类"故意 vs 意外"。正确的问题是：
- 这段内容在新系统中能被找到吗？（在 Level 1、Level 2、或有明确 canonical source）
- 如果找不到 → 补回，不需要判断"风险高低"

### 教训
**分类丢失内容的"严重性"是在为自己的错误找台阶。** 正确的态度是：任何丢失都是 bug，fix it。
