## [ERR-20260510-003] `bash long-test.sh | tail -N` 假性 137 + 报错被吞

**日期**: 2026-05-10
**类别**: shell / pipe / 测试调试
**严重度**: 中（误导调试方向，可能浪费数小时）

### 现象

`bash scripts/dev/agent-pool/tests/run-tests.sh 2>&1 | tail -60` 退出码 **137 + 零输出**。

包 `timeout 90` 也是 137 + 零输出。多次重启 session 复现。看着像系统 SIGKILL（OOM / 磁盘满 / sandbox 限制），但 `free -h`、`df -h`、`bash -n` 语法、单独跑 T0 / init 段都 OK。

### 根因

**不是 137，是 pipe 交互被信号杀**：

1. `run-tests.sh` 内部某步 `set -e` 失败（实际是泄漏 worktree 让 `git worktree add pool/slot-2` 撞引用冲突）
2. trap cleanup EXIT 触发，cleanup 函数遍历 N 个 slot 跑 `git worktree remove` / `git branch -D`
3. `tail -60` 提前满足 60 行只读末尾 → close pipe → 上游 bash 收 SIGPIPE → set -e 模式下 bash 整体被 wait 掉变 137 表征
4. 关键：**报错信息（pipe 上游 stderr）被 SIGPIPE 链同时吞掉**，包括真正的 `fatal: 'pool/slot-2' is already used by worktree at '/tmp/agent-pool-test.Y8fQLG/slot-2'`

### 调试解法

**遇到 long-running script | tail/head + 137 + 零输出，立刻换文件重定向**：

```bash
# ❌ 看不到错误
bash test.sh 2>&1 | tail -60

# ✅ 错误完整保留
bash test.sh > /tmp/out 2> /tmp/err
echo "exit: $?"
tail -60 /tmp/out
[ -s /tmp/err ] && tail -20 /tmp/err
```

判断标志：

| 现象 | 真凶倾向 |
|---|---|
| 137 + 完全零输出 | pipe SIGPIPE 链；先换文件重定向再判断 |
| 137 + 部分输出 | 可能真 OOM / 监控杀；用 `dmesg \| grep -i kill` 验证 |
| timeout 90 都 137 + 零输出 | 强证 pipe 问题（timeout 杀进程会吐 stderr） |

### 这次的真正 bug

修完 pipe 误导后看到真因：另一个 session 留下的泄漏 worktree `/tmp/agent-pool-test.Y8fQLG/slot-2` 占着 `pool/slot-2` 分支引用。`pool-init` `git worktree add` 撞冲突 → 测试失败。

清理动作：

```bash
rm -rf /tmp/agent-pool-test.*
git worktree prune -v
git branch -D pool/slot-1 pool/slot-2 ... test/branch-*
```

### 工作流改进

`tests/run-tests.sh` cleanup 函数建议加 `git -C "${REPO_ROOT}" worktree prune -v 2>/dev/null || true` 兜底，防止 SIGKILL（trap 不触发）后下次跑撞引用冲突。

### 参考

- 修复 PR：#288（heartbeat 自动同步 task_branch + T12 测试）
- 同一次会话还看到 stash 漏沉淀 4 个 / patch-id 比对找内容已发布的本地僵尸分支等
