---
date: 2026-05-19
tags: [meta-rootcause, main-repo, git-fetch, ai-collaboration, evidence-staleness]
---

# 主仓库长期漂移是"AI 凭过期快照推理 → 连环误判"的元根因

## 现象

2026-05-19 一个 session 里，3 个不同问题踩了**同一类**坑：

| # | 我的推理 | 用户记忆 | 真相 | 根因 |
|---|---|---|---|---|
| 1 | Memory M1 没合 | "我记得已合" | PR #423 已合（squash → develop f5d43d66）| 本地 `origin/develop` ref 是几天前的，没 fetch |
| 2 | agent-pool 没 dirty 检查机制 | "我记得实现过类似的" | 机制完整存在（`ap_workspace_status` / `ap_mark_abandoned` / abandoned 状态全套）| 主仓库代码是 a3042cb9 (5/16)，落后远端 3 天，看到的 release.sh / sweep.sh 是旧版 |
| 3 | sweep 默认绕过 stash 是漏洞 → 设计修复方案 | （未明说，藏在 #2 里）| 新版 sweep 走 `agent-dead` 路径调 release 分级（PR `74bc6201`，5/16 合）| 同 #2 |

## 直接原因 vs 元根因

**直接原因（容易看到）**：每次推理时工具选错（API filter 用 head.ref / git ancestry 对 squash 失效 / patch-id 对 squash 失效）。

**元根因（这次才挖出）**：**我所有"读代码 / 读 ref"的基准都是本地快照，而本地快照早过期了**。哪怕工具选对，输入数据就是错的，结论必然错。

具体两个层次：
- **本地 `origin/*` ref 过期**：上次 `git fetch` 是何时？不知道。`origin/develop` 看着权威，实际是冻结的过去快照。
- **本地工作目录代码过期**：主仓库平常我只用来"看"，**没人主动 pull**。slot claim 时是 `git fetch + checkout origin/develop` 创新分支，所以 slot 总是新的；**主仓库永远停在某次 fetch 后的快照**。
- **致命错位**：我习惯在主仓库做"探索/分析"（按 CLAUDE.md「Agent 自报家门」允许只读探索）——但**只读探索的基准本身就是过期的**。

## 用户记忆为什么能反复打中

用户的"我记得已合 / 已实现"是**直接经验**——他真的合过、真的实现过，时间感不依赖工具基准。AI 的"我查不到"是**当场对过期数据的推理**。

这就是为什么用户记忆作为**校准信号**特别有效——一旦冲突，它指向的就是"你的基准比真实事实老"，几乎从不是用户记错。

但这次还学到一层：**光"用文件 diff 当一手证据"也不够，文件本身可能是几天前的副本**。一手证据要"现在的"才算一手。

## 解法（应用层 + 工程化保险）

**应用层（个体行为）**：
- 任何"判定型问题"开局先 `git fetch + git pull --ff-only`，确保基准最新
- 看代码前先确认 `git log -1` 时间，跟今天对比

**工程化保险（机制，不依赖自律）**：

新加 CLAUDE.md / AGENTS.md #14「主仓库工作目录只读（铁律）」：
- 主仓库工作目录 git 状态必须永远 `nothing to commit`
- 禁止 Edit/Write 任何文件（含 untracked 临时文件）
- 任何"改"必须走 slot/worktree

配套 hook（`scripts/ops/hooks/main-repo-readonly-guard.sh`）：
- `UserPromptSubmit` 触发（每条消息前）
- 主仓库 dirty → 输出 `<system-reminder>` 强警告，列出脏文件 + 处理路径
- 主仓库 clean → 后台 `git fetch + git pull --ff-only origin develop`（5 分钟节流，永不阻断）

机制设计要点：
- **后台跑同步**：本条 prompt 不等 fetch，用户感觉零延迟（下条 prompt 用到 fetch 后的新 ref）
- **节流 5 分钟**：连续消息时只第一条 fetch，避免每条消息都打远端
- **只在 develop 才 pull**：主仓库按铁律永远在 develop，但 defense-in-depth
- **从不阻断**：任何失败 exit 0，hook 失效不影响 AI 工作

## 历史 leak 怎么处理

机制只能预防**未来**的漂移，不能自动救已经留下的 leak。slot-5（manuals-section 模块 6 文件） / slot-3 之前的 leak / 主仓库 134 个 untracked 截图——都是历史遗留，必须**人工分类处理**：

1. 是真工作 → claim slot 接手 commit
2. 是临时文件/截图 → 移到 `/tmp/` 或加 `.gitignore`
3. 是别人 leak → 给作者
4. 不确定 → 给用户审

## 教训

1. **"看代码"和"看远端 PR"看的是**本地快照**，不是事实——必须先 `git fetch + git pull`
2. **用户记忆冲突是工具基准过期的早期信号**——别再用更多过期工具堆证据，去刷新基准
3. **沉淀过的 learning 也可能不完整**：[`2026-05-10-patch-id-detect-zombie-branches.md`](2026-05-10-patch-id-detect-zombie-branches.md) 原版没覆盖 squash 失效，让我"我用的是项目方法"产生安心感反而不去质疑工具；已扩写
4. **铁律比触发器可靠**：与其依赖 AI 记得"先 fetch"，不如让主仓库结构上**不可能脏** + hook 兜底自动同步
5. **AI-first 节奏下"漂移问题"被放大**：手工开发节奏一天一次 PR，主仓库每天 pull；AI 节奏一天 10+ PR，主仓库不 pull 半天就远远落后

## 关联

- [`2026-05-19-trust-user-memory-over-ai-reinference.md`](2026-05-19-trust-user-memory-over-ai-reinference.md)：上一层结论（用户记忆冲突时用文件 diff）。本 learning 更深一层——文件本身也可能过期。
- [`2026-05-10-patch-id-detect-zombie-branches.md`](2026-05-10-patch-id-detect-zombie-branches.md)：squash zombie 检测，PR #423 误判的工具机制。
- CLAUDE.md / AGENTS.md #14：本 learning 衍生出的铁律。
- `scripts/ops/hooks/main-repo-readonly-guard.sh`：本 learning 衍生出的 hook。
- `scripts/dev/agent-pool/`：abandoned 分级机制（早已实现，我没看见）。
