---
name: doctor
description: >
  本机环境体检：一条命令问清这台机器上哪些流程能跑、哪些会降级（缺 Python 包、git、node、gh，
  traces/ 能否解析，知识库索引在不在），并给出每项缺失的修法。任务开始前环境可疑、换机器、
  内网新部署、或流程中途以一句 import 报错退出时用。可反复执行：同一台机器两次跑结论一致。
---

# Doctor（本机环境体检）

依赖缺了不在开单时报，而在任务中途以一句 traceback 出现。实测：缺 PyYAML 的机器上点「导出交接包」，
面板只回一句「导出脚本没有给出 JSON 结果」。根因在 traceback 的最后一行，读者要自己认。
全仓有一批脚本在 import 阶段就依赖 PyYAML，缺一个包会同时断掉几条流程。

本 skill 的动作一件：**跑体检器，然后按它给的顺序修一项、重跑一次**。

## 何时触发

- 用户问「这台机器能不能用」「装了什么」「为什么报缺依赖」；
- 流程中途出现 `ModuleNotFoundError`、`command not found`，或面板报「没有给出 JSON 结果」这类只有结果没有原因的错误；
- 换机器、换解释器、内网新部署第一次用；
- 修完一项要复验。

## 只跑一条命令

```bash
python3 scripts/doctor.py          # 人读三段：结论 / 证据 / 下一步
python3 scripts/doctor.py --json   # 面板或脚本消费
```

退出码：`0` 无阻断、`2` 有阻断项、`3` 不在 ascend-sleuth 检出里、`4` 命令行参数写错。

不要自己另写探测命令。手敲 `python3 -c "import yaml"` 只验一个包，也漏掉解释器不一致这一层。
体检器扫的是 `scripts/` 下全部脚本的 import，新增第三方包会被它自动发现；能力表写错 id 时它会自报。

## 怎么读输出

三段各回答一个问题。

| 段 | 回答 | 用法 |
|---|---|---|
| 结论 | 哪些流程能跑、降级、不能跑 | 第一屏转述这三行，不让用户自己读全表 |
| 证据 | 每项缺什么、影响几个脚本、修法原值 | 修的时候照抄「修：」后面那条命令 |
| 下一步 | 按影响面排序的修复动作 | 一次只做第一条 |

报告末尾那行「体检用的解释器」要带上。面板与终端可能不是同一个解释器：Windows 上按 `python3` →
`python` → `py -3` 的顺序探活。把包装到另一个解释器上，体检结论不会变。

解释器低于 3.10 时，Python 那一行会标降级：标准库名单在那个版本不存在，依赖判定只能按路径推断，
可能多报。先升级解释器再判结论。

## 修复循环

1. 读结论段，记下第一条阻断项。
2. 只修那一项，命令照抄证据段给的「修：」原值。
3. 重跑同一条命令。
4. 阻断项清零后，再处理降级项。
5. 结论与上一次不一致时先停。同一台机器两次跑出不同结果，说明环境在变（PATH、解释器、代理），
   先查这个再继续修。

## 硬规则

- 没跑就不许说「环境没问题」。结论只从脚本输出里取。
- 不许为了让检查变绿去改体检器或绕开它。它是判据，不是待办清单。
- 阻断与降级的判据不同。缺 Python 包是**阻断**：相关脚本在 import 阶段退出。缺 `node`、`gh`、
  `git` 是**降级**：对应流程退化，其余照跑。先修阻断项。
- 修不了的项照实说。内网装不了包就给出带 wheel 的离线装法，不再给一条本机执行不了的联网命令。
- 降级项不挡流程时不要顺手修。一次只动一项，修完重跑，否则下一轮分不清是谁改好了。
- **「演进模式」那一行是部署声明，不是缺陷**。`record-only` 属于正常项（只做内容沉淀的部署的
  预期形态：只记信号不产卡），不要为了让它变绿去改成 `full`。声明写坏时它报降级，修的是
  `deployment.yaml` 里的 `evolution.mode`，不是体检器。

## 它不负责什么

- **内容门禁**：索引新鲜度、结构校验、面板契约由各自的检查脚本判，体检器不碰内容。
- **一次跑完所有 CI 命令**：那是 `python3 scripts/rehearse_evolve_loop.py`（逐条复跑 CI 的 `run:`）。
  体检器只在「下一步」里指出该跑哪一条，不抄那份清单。
- **装包与改配置**：它只读。装包是人的决定，装法由它给出、人执行。
