# Troubleshooting

更新时间：2026-09-13。

本文只给出当前 checkout 已实现的诊断入口和有界回退路径。先确认实际加载的 Pi、SoL-Pi 来源和配置，再判断某个机制是否真的执行；不要用 HUD 绿色、工具名存在或普通日志 marker 代替执行证据。

## 先收集只读信息

在仓库根目录运行以下检查。它们不会修改项目文件，也不会发起模型调用：

```bash
node --version
npm --version
pi --version
node scripts/check-pi-compat.mjs
node scripts/check-sol-pi-config.mjs \
  --config /absolute/path/to/effective/sol-pi.json
```

如果正在 Pi session 内，依次使用：

```text
/sol doctor
/sol status
/sol explain
/sol evidence
```

`/sol doctor` 显示配置路径和 scope、有效配置、Pi 版本/模式/能力、工具数量和四机制状态；`/sol status` 显示 HUD 同源的每机制状态和最近摘要；`/sol explain` 显示未解决原因；`/sol evidence` 只列出最近事件关联的 evidence id。输出只包含短元数据，不应包含 provider payload、凭据或完整命令输出。

修改 `sol-pi.json` 后必须重启 Pi。`/sol hud show`、`/sol hud standard` 等显示命令不会重新加载配置。

## 没有持久会话

### 现象

HUD 或诊断显示 `NO_SESSION`，或命令使用了 `--no-session`。ObservationPack/EPR/OCC 的归档、状态保存和续跑能力可能显示为回退。

### 处理

- 需要归档、`obs_recall`、Reducer 原文核对或 OCC 计划恢复时，使用有持久 session 的 Pi 启动方式，不要使用 `--no-session`；
- 需要无 session 的启动 smoke 时，可以验证扩展不崩溃，但不能把它当作证据归档或压缩验收；
- ObservationPack 会保留全文，不创建新的替换引用；
- EPR 不调用 reducer model，原始 tool result 保持不变；
- OCC 在 session append 失败时保留原生策略，不自动安排续跑；
- Action Fusion 是否能执行 `then_run` 与 session 持久化无关，仍要单独检查活动 bash backend。

对应合同为 `tests/compat/no-session.test.ts`。该测试证明的是独立降级，不证明无 session 支持完整四机制。

## Action Fusion 的 then_run 没有执行

先区分观察边界：

1. `/sol status` 显示 Action Fusion 是否入口可达；
2. `/sol doctor` 检查工具数量和宿主能力；
3. 查看结构化回执中的 `[then_run:succeeded]`、`[then_run:failed]` 或 `[then_run:skipped]`，不要只搜普通日志；
4. 确认 provider 最终 payload 是否真的带有 `then_run`，再确认 `execute` 是否收到它。

常见原因：

| 现象/原因码 | 含义 | 处理 |
| --- | --- | --- |
| `FUSION_TOOL_SHADOWED` | edit/write 被其它扩展或宿主工具提供 | 检查 `pi list --approve`、加载顺序和活动工具；不能把其它扩展的工具当作 SoL-Pi Fusion |
| `TOOL_SURFACE_UNVERIFIED` | 宿主没有给出足够的工具来源/活动快照 | 保留当前未知状态；不要强行开启或把工具名当成功 |
| `THEN_RUN_ARGUMENT_LOST` | schema 或 execute 观察到 `then_run` 在链路中消失 | 保存 provider payload、工具 schema、prepare/execute 观察结果，按边界定位 |
| `EXECUTION_BACKEND_UNSUPPORTED` | bash 缺失、未激活或不是 Pi 内置来源 | 提供同 backend 的显式 execution adapter；不要让 SoL-Pi 在本机偷偷启动回退命令 |
| `THEN_RUN_NOT_REQUESTED` | 本次工具调用没有请求后续验证 | 这是正常跳过，不是兼容错误 |
| `MUTATION_FAILED` | 文件修改没有完成 | 验证不会启动；先修复目标文件/权限/参数 |
| `VALIDATION_FAILED` / `VALIDATION_TIMEOUT` | 修改已保留，但指定验证失败或超时 | 读取结构化回执和验证原文，修复后重新发起明确的验证 |
| `WORKSPACE_CHANGED_DURING_VALIDATION` | 验证前后目标文件被外部进程改写 | 停止并确认并发写入，不能复用旧回执 |

当前实现只在活动 `bash` 来源为 Pi 内置工具时默认使用 Pi bash。SSH、container 或其它远程扩展必须提供显式同 backend 委托；配置文件没有这个路由开关。

## ObservationPack 召回和完整性

### `RECALL_UNAVAILABLE`

这表示 `obs_recall` 不在活动工具集合、来源不可信、对象路径不可读或存储结构异常。SoL-Pi 会停止新的全文替换，并尽量保留原文；它不会制造一个无法读取的新引用。已有引用在对象仍存在且通过校验时可以继续读取。

检查顺序：

1. `/sol doctor` 查看 `publicToolDefinitions` 和工具集合；
2. `/sol status` 查看“历史打包”原因；
3. 确认 Pi session directory 未被清理、移动或替换为符号链接；
4. 确认对象是普通文件，父目录不是符号链接；
5. 对已有 id 使用 `obs_recall` 从上一个 `next_offset` 继续，而不是猜新的 offset。

### 完整性失败

召回会核对对象的 SHA-256、字节数、字符数、行数和有限文件指纹。出现 `HASH_MISMATCH`、`SOURCE_CHANGED_DURING_READ`、`SYMLINK_NOT_ALLOWED` 或元数据错误时，保留失败状态，不把对象显示成可信证据。

新对象的 sidecar 在正文写入、fsync、校验后发布。旧对象若没有 sidecar，召回结果会显示 `integrity=unverified`；这表示可读取，不表示完整性已确认。不要手工修改正文或 sidecar 来“修复” hash，正确做法是保留原证据、重新产生一次完整归档并记录旧 id。

## Reducer 没有提取或回退原文

按以下顺序判断：

- 输出短于最小阈值：`SOURCE_UNDER_MIN_BYTES`，正常保留原文；
- 日志超过提取上限：`REDUCER_BUDGET_EXHAUSTED`，正常回退；
- 内容疑似包含 key、token、authorization 等敏感值：`REMOTE_REDUCTION_NOT_ALLOWED`，不远程发送；
- 远程开关未显式打开：`REMOTE_REDUCTION_NOT_ALLOWED`，确定性提取仍可能先尝试；
- provider/model 不可用、调用取消/超时、回执 schema/引用/失败覆盖不合格：回退原文；
- 摘录不比原文短：保留原文，不把“调用过模型”写成节省。

配置检查：

```bash
node scripts/check-sol-pi-config.mjs \
  --config /absolute/path/to/effective/sol-pi.json
```

这只能证明字段结构合法。它不能证明 Pi 已配置对应 provider 凭据，也不能证明真实模型会返回可核对回执。启用远程 reducer 前应先阅读 [SECURITY.md](../SECURITY.md)，并确认日志允许离开本机。

## OCC 没有压缩或没有续跑

OCC 只在计划边界、上下文增长、窗口能力和经济条件都可核对时行动。以下情况属于保守跳过或回退：

- 计划没有可确认的完成边界；
- native cut、context window、缓存比率或其它边界未知；
- 预期释放不足以抵偿压缩/缓存代价；
- session append 失败或没有持久 session；
- 用户取消、输入 correction、Pi 退出或 native compaction 回调失败。

成功压缩后才会安排一次隐藏 reminder 续跑；取消或失败不会自动重启任务。`cacheWriteReadRatio` 不是账单价格，修改它需要写入配置并重启新 session。

## 配置覆盖和冲突

### 配置看起来没有生效

1. 运行 `/sol doctor`，记录实际 `path` 和 `scope`；
2. 确认项目 trusted 状态；
3. 确认项目配置和全局配置没有被误认为合并；
4. 用 `check-sol-pi-config.mjs` 检查 doctor 显示的同一文件；
5. 完全退出并重启 Pi，再运行 `/sol status`。

项目配置优先时，全局配置不会补齐项目中省略的字段；省略字段按默认关闭。无效项目配置不会静默回退到一个“看起来可用”的全局配置，而应显示加载错误。

### 工具冲突

如果其它扩展替换了 edit/write 或 bash：

- 不要通过重复安装同一 checkout、修改 Pi 源码或手工改工具名解决；
- 保留 `FUSION_TOOL_SHADOWED` 或 `EXECUTION_BACKEND_UNSUPPORTED` 证据；
- 检查扩展加载来源、scope、活动工具和相对加载顺序；
- 若需要组合支持，新增真实宿主冲突测试后再改变支持结论。

## 暂停、回滚和重新开启

临时停止新的写侧优化：

```text
/sol off
```

恢复：

```text
/sol on
```

暂停不会删除已有对象、sidecar、ledger 或 session log；已有证据仍可读。它也不会把正在进行的外部命令伪装成已取消。

仅隐藏 HUD：

```text
/sol hud hide
/sol hud show
```

这不等于暂停机制。若配置变更导致启动失败，先关闭 Pi，再把 `sol-pi.json` 恢复到最后一个已验证副本，重新运行 `check-sol-pi-config.mjs`，然后启动 Pi。v2 转 v1 前应保留原始 v2 文件和显式 `.v2.backup`；不要覆盖已有备份，也不要在没有可回读证据时删除旧 session 归档。

安装或版本回滚必须保持上游 Pi 未修改，并按 [agents-install.md](../agents-install.md) 的 scope、`pi list`、配置 preflight、离线启动和 all-mechanisms 检查逐项重做。一次 `npm test` 或旧 HUD 录屏不能替代回滚后的真实宿主确认。

## 仍需外部证据的问题

当前仓库不能仅靠本地测试回答：

- 真实模型在普通任务中是否自然选择 `then_run`、召回、Reducer 或 OCC；
- 不同 provider 的实际 usage、成本、延迟和质量；
- 0.84.2 全部宿主模式、第三方 widget/footer 和远程 backend；
- 持久 session 重启、分叉、模型切换后的完整 HUD 历史重建；
- 四机制 16 组合和正式安装 scope 的完整发布结论。

这些项目要使用真实目标项目、干净 checkout、明确 provider/模型和授权成本范围执行，不能用夹具、dry-run 或配置文件替代。
