# TiDB 源码辅助诊断设计

**Date:** 2026-05-07
**Status:** Design draft
**Scope:** TiDB 诊断过程中的按需源码分析能力

---

## 1. 设计目标

在 TiDB Cloud 诊断过程中增加一个按需源码分析能力：当现有 evidence 已经指向具体组件、版本、日志、profile symbol、SQL planner 行为或疑似 bug 时，agent 可以进一步检索 TiDB/TiKV/PD/TiFlash 源码，辅助确认机制或版本差异。

这个能力不是 `Add Sources`，也不是 workspace source。源码分析属于诊断编排中的一个 Action，由 `clinic-cli` 提供组件版本事实，由源码检索工具消费这些事实。

核心原则：

1. **组件版本来自 Clinic API**，不是源码工具自己猜。
2. **image tag 到源码 ref 的翻译不能靠猜测**，必须先确认权威 source of truth。
3. **源码分析是 evidence-driven deep dive**，不是每次诊断默认执行。
4. **现场版本和后续修复必须分开表达**，不能用 `main` / `master` 冒充故障现场代码。

---

## 2. Current Design

当前 `clinic-cli cluster-metadata --include-components` 已经是合适的组件信息入口。它通过 Clinic cluster metadata 查询拿到 cluster detail，并在 resource pool / Premium / BYOC 相关场景下查询组件清单。

组件清单来自 Clinic API：

```text
GET /clinic/api/v1/orgs/{org_id}/clusters/{cluster_or_parent_id}/resource-pool/components
```

调用时应继续使用 Investibook/Clinic 内部 API key 的 Bearer auth，不使用浏览器 cookie / CSRF 会话。

示例字段形态：

```json
{
  "component_type": "TIDB_WORKER",
  "version": "v8.5.4",
  "phase": "AVAILABLE",
  "cpu": 8,
  "memory_gi": 16,
  "node_count": 1,
  "max_node_count": 8,
  "min_node_count": 1,
  "image": {
    "repo": "tidbcloud-prod-registry.example.com/tidbcloud/tidb",
    "tag": "v8.5.4-nextgen.202510.20"
  }
}
```

这些组件信息应该持久化到 workspace 的 raw evidence，例如：

```text
evidences/cluster_meta.json
```

`cluster_meta.json` 是后续源码分析的 canonical component inventory。

---

## 3. Target Contract

### 3.1 Clinic Component Inventory

`clinic-cli cluster-metadata --include-components` 应输出并持久化规范化组件清单：

- `component_type`
- `version`
- `image.repo`
- `image.tag`
- `cpu`
- `memory_gi`
- `node_count`
- `min_node_count`
- `max_node_count`
- `phase`
- `storages`
- `components_source.endpoint`
- `components_source.resource_pool_scope`
- `components_source.queried_cluster_id`

对 Premium / BYOC / resource pool 场景，`queried_cluster_id` 必须明确记录实际查询的是 tenant cluster 还是 parent resource pool。源码工具不能重新猜测这个范围。

### 3.2 Source Code Evidence

源码检索工具只消费 `evidences/cluster_meta.json`，不自己查询或推断组件版本。

源码证据写入：

```text
evidences/source_code/<query_id>.json
```

每条源码证据必须包含：

- `component_type`
- `repo`
- `requested_version`
- `image_repo`
- `image_tag`
- `resolved_ref`
- `ref_source`
- `ref_confidence`
- `operation`
- `query`
- `matches`
- `truncated`
- `errors`

如果无法确定 image tag 对应的源码 ref，必须返回 `unknown`，不能 fallback 到最新分支。

### 3.3 Report Boundary

诊断 report 只引用源码证据摘要，不内嵌大段源码。

允许进入 report 的信息：

- repo / ref / path / line range
- 为什么该 ref 与现场版本匹配
- 该代码片段支持或反驳了哪个诊断判断

不允许进入 report 的信息：

- 大段源码 payload
- 大量 grep 原始结果
- 未确认版本映射下的强结论

---

## 4. Image Tag 翻译规则

`image tag -> code ref` 不应该通过字符串规则猜测。v1 的权威解析路径是读取镜像 config labels，从 OCI metadata / build labels 中提取源码仓库和 commit。

示例命令：

```bash
crane config <image_repo>:<image_tag> | jq '.config.Labels'
```

其中 `<image_repo>` 和 `<image_tag>` 来自 `clinic-cli cluster-metadata --include-components` 持久化的 component inventory，例如 `image.repo` 和 `image.tag`。

优先使用的 labels：

| Label | 用途 |
| --- | --- |
| `org.opencontainers.image.source` | 源码仓库 URL，例如 `https://github.com/tikv/tikv.git` |
| `org.opencontainers.image.revision` | OCI 标准源码 revision，作为首选 commit |
| `net.pingcap.tibuild.git-sha` | PingCAP build metadata 中的 git sha，用于交叉校验 |
| `org.opencontainers.image.ref.name` | 镜像构建 ref / image tag 辅助信息 |

解析规则：

1. 对 `image.repo:image.tag` 调用 `crane config`。
2. 从 `org.opencontainers.image.source` 解析 repo，并做 allowlist / normalization。
3. 从 `org.opencontainers.image.revision` 解析 commit。
4. 如果 `net.pingcap.tibuild.git-sha` 存在，必须与 `org.opencontainers.image.revision` 一致；不一致时返回 `unknown` 并记录冲突。
5. 如果 `source` 或 `revision` 缺失，不能用 tag 字符串猜测 commit。
6. 只有在 label 解析失败但用户明确需要“后续修复线索”时，才允许使用 release tag / release branch 做低置信补充查询，并明确标记不是现场代码。

示例 image tag：

```text
v8.5.4-nextgen.202510.20
v8.5.4-nextgen.202510.26
```

这些 tag 只能作为 image identity，不能直接作为源码 ref。现场源码 ref 应来自 image labels 中的 commit。

仍需确认的问题：

1. 不同组件是否都稳定写入同一组 labels：
   - TiDB
   - TiKV
   - PD
   - TiFlash
2. 内部 patch image 是否可能指向非公开 repo 或不可访问 commit？
3. `org.opencontainers.image.source` 是否总是 GitHub repo，还是可能是内部 mirror。
4. 如果 registry 访问失败，是否有 Clinic / build service API 能返回同样的 source / revision metadata？
5. Premium / BYOC / Dedicated 是否存在不同 build pipeline 或 label 写入规则？

在这些问题没有完全确认前，源码 ref resolver 只能对 label 完整且一致的镜像返回 `high confidence`；其他情况返回 `unknown` 或低置信补充线索。

---

## 5. Implementation Direction

### 5.1 扩展 clinic-cli

保留现有命令：

```bash
python3 .opencode/skills/builtin/clinic-cli/scripts/clinic_cli.py cluster-metadata \
  --cluster-id <cluster_id> \
  --include-components
```

需要补强：

- 规范化 `resource-pool/components` payload。
- 持久化 `components_source` provenance。
- 对 Dedicated、Premium current、Premium parent 三类 scope 建测试。
- 保持 raw evidence 写入由 `clinic-cli` 负责。

### 5.2 新增源码检索能力

新增一个诊断工具能力，例如 `tidb-source-code`：

- 读取 `evidences/cluster_meta.json`。
- 根据 `component_type` 映射 repo。
- 用 `crane config <image_repo>:<image_tag>` 读取 image labels，解析 `org.opencontainers.image.source` 和 `org.opencontainers.image.revision`。
- 用 `net.pingcap.tibuild.git-sha` 交叉校验 revision。
- 用本地 code cache 执行 `grep` / `show` / `diff` / `log`。
- 写入 `evidences/source_code/*.json`。
- stdout 只返回 compact summary 和 evidence 文件路径。

### 5.3 Code Cache

后端本地缓存建议：

```text
/data/code-cache/repos/<repo>.git
/data/code-cache/worktrees/<repo>/<ref>/
```

规则：

- repo 缓存使用 bare mirror。
- 每个 `repo@ref` 使用独立只读 worktree 或 archive view。
- 禁止多个 workspace 共用一个 mutable checkout 后反复 `git switch`。
- fetch/update 必须加文件锁。
- 设置缓存大小上限和 GC 策略。

`gh` 只用于 PR / issue / release metadata，不作为主要源码 grep/search 工具。

### 5.4 Repo-local Agent Instructions

源码 repo 本身可能带有 `AGENTS.md` 和 `.agents/skills/`，例如 TiDB repo 的 root `AGENTS.md` 会定义 repo-wide agent 规则、路径级 precedence、测试/验证约束和 subsystem map。

源码分析工具在读取源码前必须先解析同一个 `repo@resolved_ref` 下的 repo-local instructions：

1. 读取 root `AGENTS.md`。
2. 如果目标源码路径的父目录链上存在更深层 `AGENTS.md`，按从 root 到 leaf 的顺序加载，越深的文件对该 subtree 优先级越高。
3. 如果 `AGENTS.md` 指向 `.agents/skills` 或 `docs/agents/*`，只读取与当前源码问题相关的入口索引或明确引用文件，不全量加载整个 skill tree。
4. 如果当前 `resolved_ref` 下没有 `AGENTS.md`，记录 `instructions_status=missing`，不能 fallback 到 `master` / `main` 的 AGENTS 作为现场版本规则。

Instruction 解析结果应成为源码证据的 provenance：

- `instructions_ref`
- `loaded_instruction_files`
- `instruction_hashes`
- `instructions_status`
- `instruction_limitations`

这些 repo-local instructions 用来约束源码解读方式，例如术语、subsystem 边界、生成代码注意事项、测试语义和“不要猜测”的规则。它们不替代 Investibook 的诊断 evidence，也不允许工具因为读到外部 repo 的 build/test 规则就自动执行高成本验证。

### 5.5 Source Interpretation Cache

源码分析不应该每次都从零开始重新读代码。需要把 cache 分成三层：

1. **Repo / ref cache**：缓存仓库 mirror 和 `repo@ref` worktree，避免重复 clone / checkout。
2. **Search result cache**：缓存确定性检索结果，例如同一个 `repo@ref + operation + query + path_filter` 的 `grep` / `show` / `diff` 输出。
3. **Instruction cache**：缓存同一个 `repo@ref` 下已解析的 `AGENTS.md` / `.agents/skills` 相关指引。
4. **Interpretation cache**：缓存 AI 对源码片段的机制解读，避免同一个版本、同一段代码、同一类诊断问题反复消耗上下文和模型调用。

Interpretation cache 的 key 必须包含：

- `repo`
- `resolved_ref`
- `component_type`
- `file_path`
- `line_range`
- `code_blob_hash`
- `instruction_hashes`
- `diagnosis_question_hash`
- `analysis_prompt_version`
- `tool_contract_version`

其中 `code_blob_hash` 是防止同一路径/行号在不同 ref 下内容变化；`instruction_hashes` 是防止 repo-local agent rules 变化后复用旧解读；`analysis_prompt_version` 和 `tool_contract_version` 是防止 prompt 或输出契约变化后继续复用旧解读。

Interpretation cache 的 value 应保持小而结构化：

- `summary`
- `mechanism`
- `relevant_symbols`
- `supports`
- `contradicts`
- `limitations`
- `source_refs`

复用规则：

- 同一个 `repo@ref`、同一段代码、同一个问题类型可以复用。
- 如果 diagnosis question 只是实例名、时间窗口不同，但源码问题相同，可以命中同一类 interpretation。
- 如果现场版本不同、代码 hash 不同、prompt/contract 版本不同，必须重新解读。
- 缓存命中只能作为源码机制解释的起点；最终诊断仍必须回到当前 workspace 的 evidence 做关联。

不缓存：

- 用户敏感 SQL 全文。
- 包含租户、表名、业务字段的原始问题。
- 未脱敏日志全文。
- 没有 source ref provenance 的自由文本判断。

缓存位置建议：

```text
/data/code-cache/search-results/
/data/code-cache/instructions/
/data/code-cache/interpretations/
```

workspace 内只保存本次诊断实际引用的源码证据摘要，不复制全局 interpretation cache。

### 5.6 Diagnosis Action

在诊断编排中新增 Action：

```text
inspect-source-code
```

触发条件：

- 已有 evidence 指向具体组件。
- 已有明确 hypothesis。
- 已有版本或 image tag。
- 有具体搜索入口，例如 log message、profile symbol、planner 行为、function name、issue / PR 线索。

不触发场景：

- 首轮泛化诊断。
- 只有模糊 CPU/latency 指标，没有具体源码问题。
- 组件版本无法解析且没有必要查后续修复。

---

## 6. Component Repo Registry

初始 registry 只表达组件到仓库的方向，不表达 image tag 到 commit 的猜测：

| component_type | repo |
| --- | --- |
| `TIDB_WORKER` | `pingcap/tidb` |
| `TIKV` | `tikv/tikv` |
| `TIKV_WORKER` | `tikv/tikv` |
| `COPROCESSOR_WORKER` | `tikv/tikv` |
| `PD` | `tikv/pd` |
| `PD_TSO` | `tikv/pd` |
| `PD_SCHEDULING` | `tikv/pd` |
| `TIFLASH_COMPUTE` | TiFlash repo |
| `TIFLASH_WRITE` | TiFlash repo |
| `TIFLASH_LEARNER` | TiFlash repo |
| `TIFLASH_COMPUTE_LEARNER` | TiFlash repo |

具体 ref 必须由 image tag 翻译规则、build metadata 或版本元数据决定。

---

## 7. Risks

- `version` 不等于 exact source commit，尤其是 `nextgen` image tag。
- Premium / BYOC 的组件可能在 parent resource pool 下，不能只查 tenant cluster。
- PD / TiFlash / worker 拆分后，component type 到 repo 的映射不能硬编码在 prompt 里。
- 内部 image 可能包含 patch，不一定对应公开 GitHub tag。
- 源码分析不能阻塞基础诊断；Clinic 或 GitHub 不可用时应返回 `unknown`。

---

## 8. Verification Checklist

- `clinic-cli cluster-metadata --include-components` 能持久化 resource-pool components。
- `cluster_meta.json` 中组件字段稳定、可测试。
- `components_source` 能说明 endpoint、scope 和 queried cluster id。
- image tag 无翻译规则时，源码工具返回 `unknown`。
- exact commit、release tag、release branch 三类 ref 解析分别有测试。
- 源码工具从同一个 `repo@resolved_ref` 加载 root / path-specific `AGENTS.md`，不会 fallback 到 `main` / `master` 的 instructions。
- instruction hash 变化后，旧 interpretation cache 不会被复用。
- 并发两个 workspace 查不同 ref，不会互相污染 checkout。
- grep 大结果会截断并落文件。
- report 只引用源码证据摘要，不内嵌大段源码。
