# 前言

最新阅读地址：

* 当前公开站点（旧版 GitBook，待同步本仓库 RC 内容）：[code-visualization.shawnxie.top](https://code-visualization.shawnxie.top/)
* 本地预览（本仓库最新）：`npm run serve` → <http://localhost:4000/>
* 部署说明：[`docs/github-pages-deploy.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/github-pages-deploy.md)

## 这本书讲什么

代码可视化不是简单画图，而是一套软件理解方法。它把源码结构、程序行为、变更历史和组织信息转化为可观察、可查询、可验证的结构化事实，并服务人类开发者、Reviewer 和 AI Agent。

软件系统里有大量“不可见但关键”的事实：

* 调用链与依赖关系
* 控制流与数据流
* 测试覆盖与运行时 Trace
* 变更历史与 Owner
* 架构边界与约束

当这些事实只散落在源码、日志、文档、PR、测试平台和人的经验里时，开发者只能靠阅读、搜索和询问来拼接上下文。代码可视化要做的，是把这些事实采集出来、组织起来，并以图、路径、矩阵、报告或查询接口的方式服务工程决策。

在 AI 时代，这件事更重要。AI 可以更快地生成和修改代码，但也带来新的问题：

* 它是否找对了修改位置？
* 它是否理解了调用链和模块边界？
* 它是否遗漏了相关测试？
* 它是否破坏了架构约束？
* 它是否引入了安全、性能或数据一致性风险？
* 人类 Reviewer 如何验证它的修改？

这些问题不能只靠自然语言解释解决。它们需要结构化证据：调用关系、影响面、测试覆盖、运行时路径、架构规则和历史变更。因此，代码可视化应升级为软件理解基础设施：它既帮助人理解复杂系统，也为 AI Agent 提供上下文、边界、证据和验证能力。

## 本书结构

全书按“原理先行，再推进到工程场景和 AI 应用”组织：

1. 源码如何被结构化：AST、符号、类型、IR、CFG、DFG
2. 程序事实如何被分析与融合：静态分析、动态分析、变更分析
3. 代码事实如何建模为图谱：节点、边、属性、查询
4. 三个核心工程场景：代码库理解、变更影响分析、架构理解与遗留系统改造
5. AI 时代应用：Agent 上下文、图谱查询、Review 证据、辅助重构
6. 实践闭环：采集、建图、分析、可视化、Agent 查询、验证报告

## 本书主线

全书围绕下面这条链路展开：

```mermaid
flowchart LR
 Problem[工程问题] --> Source[源码结构化]
 Source --> Analysis[静态/动态/变更分析]
 Analysis --> Graph[代码图谱]
 Graph --> Viz[可视化与查询]
 Viz --> Scene[核心工程场景]
 Graph --> Agent[AI Agent 上下文]
 Scene --> Review[Review 与验证证据]
 Agent --> Review
```

![全书主线：从工程问题到 Agent 验证](/files/tCXtRSak13vx7MVM1isC)

> 后续 AI 配图备注：可生成一张“人类开发者 + AI Agent 共同围绕代码图谱工作的主视觉图”，适合作为首页头图。画面重点是源码、运行时、测试、PR、Agent 汇聚到一张软件理解地图，风格应偏技术书籍封面，不要做营销海报。

读完这本书，你应该能够：

1. 理解 AST、符号表、CFG、DFG、Call Graph、Trace、Coverage 等概念如何服务代码理解。
2. 判断不同工程问题需要采集哪些代码数据。
3. 设计一个小型代码图谱和可视化查询系统。
4. 理解 AI Agent 修改代码时需要什么上下文、约束和验证证据。

## 本书适合谁

* 想系统理解代码可视化、程序分析和代码图谱的开发者。
* 经常接手大型代码库、遗留系统或跨团队项目的工程师。
* 关注研发效能、质量治理、架构治理和影响面分析的技术负责人。
* 想把 AI 编程工具引入真实工程流程，但担心上下文、测试和 Review 风险的团队。
* 对“人和 AI 如何共同理解代码库”感兴趣的读者。
* 正在建设 AI Coding / AI Agent 工具，需要结构化上下文与验证证据层的工程师。

## 阅读方式

全书主线为：原理 → 图谱 → 三个核心场景 → AI 应用 → 实践闭环。附录提供术语表、贯穿案例、版本勘误与资料卡索引。

如果你更关注原理，建议按目录顺序阅读前 3 篇；如果你更关注工程落地，可以重点阅读“代码库理解与上下文构建”“变更影响分析与验证”“架构理解与遗留系统改造”；如果你关注 AI 编程工具，则可以在理解代码图谱基础后阅读第 5 篇。

实践部分会构建一个最小代码理解系统，目标不是做一个完整商业平台，而是把“源码解析 -> 图谱构建 -> 影响面分析 -> 可视化展示 -> Agent 查询接口 -> 验证报告”这条链路跑通。

全书统一使用模拟案例 `mini-shop`（见 `examples/mini-shop/` 与 [`docs/sample-case/README.md`](/fu-lu/sample-case)）贯穿原理、图谱、影响面和 Agent 上下文，不引入真实业务仓库。建议先按案例中的“全书跟做主线”走完 PR-42，再进入分章精读。

## 术语、案例与版本

* 术语表：[`docs/glossary.md`](/fu-lu/glossary)
* 贯穿案例：[`docs/sample-case/README.md`](/fu-lu/sample-case) · [`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)
* 版本与勘误：[`docs/changelog.md`](/fu-lu/changelog)
* 资料卡索引：[`docs/research-cards/README.md`](/fu-lu/research-cards)
* 完成标准（编辑用）：[`docs/definition-of-done.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/definition-of-done.md)

发现错误请在勘误入口记录章节与复现句；修正后写入 changelog。

## 延伸阅读与参考资料

* [ANTLR](https://www.antlr.org/)：语法分析器生成工具，可用于理解 Lexer、Parser 和语法规则。
* [Tree-sitter](https://tree-sitter.github.io/tree-sitter/)：面向代码编辑器和代码分析场景的增量解析器。
* [OpenTelemetry Traces](https://opentelemetry.io/docs/concepts/signals/traces/)：理解 Trace、Span 和运行时链路观测的官方资料。
* [CodeQL Data Flow Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/)：理解数据流和污点分析的官方资料。
* [GitHub Copilot: Explore a codebase](https://docs.github.com/en/copilot/tutorials/explore-a-codebase)：AI 辅助代码库探索的官方教程。
* [SWE-bench](https://github.com/swe-bench/SWE-bench)：仓库级软件工程任务评测基准。

## 交流联系

* Email: <xiexiao064@gmail.com>
* WeChat: ShawnLFF
* 公众号：肖恩聊技术

<img src="/files/SxLtwbp9KjBAmHZTGGtC" alt="公众号二维码" width="400">


# 第一篇：代码可视化的目标与边界


# 为什么需要代码可视化

## 本章要解决的问题

为什么复杂代码库不能只靠搜索、文档和经验理解？代码可视化到底解决什么工程问题？

## 读者读完应获得什么

1. 能说明大型代码库理解困难的真实来源。
2. 能区分“画一张大图”和“围绕问题组织可验证事实”。
3. 能用一次跨模块改动说明：没有结构化事实时，人和 AI 都会误判影响面。

## 本章不讲什么

* 不介绍具体绘图库用法。
* 不展开完整程序分析算法。
* 不把代码可视化窄化为 UI 美化。

***

软件系统的复杂性并不只来自代码行数。一个中型项目可能只有几万到几十万行代码，但它同时包含业务入口、框架约定、模块依赖、数据库访问、异步任务、配置开关、测试用例、部署脚本和历史包袱。开发者真正需要理解的，不是某个文件里的语句，而是这些语句如何和整个系统发生关系。

代码可视化的价值也不只是“把代码画成图”。如果只是把所有类、方法和调用关系铺到一张图上，结果往往比源代码更难读。真正有用的代码可视化，是把隐藏在代码里的事实提取出来，并围绕具体问题组织成可观察、可查询、可验证的表达。

## 大型代码库为什么难理解

代码难理解通常不是因为某一段代码写得特别复杂，而是因为读者缺少上下文。一个方法可能只有十几行，但你需要知道它被谁调用、在哪个请求路径里执行、依赖哪些配置、修改后影响哪些测试、是否被线上流量频繁触达。

大型代码库常见的理解障碍包括：

* 入口分散：HTTP 接口、消息消费、定时任务、命令行任务、测试入口分布在不同位置。
* 调用链深：业务逻辑跨越多层服务、公共库和中间件。
* 隐式约定多：框架注解、反射、配置和生成代码让文本搜索失效。
* 演进历史长：当前结构是多次补丁、迁移和妥协的结果。
* 责任边界模糊：Owner、模块边界和架构规则不在源码字面中显式出现。

文档能帮助建立心智模型，但文档会过期。搜索能定位关键字，但无法稳定表达结构和关系。同事经验很有效，但不可复制、不可审计。

## 一个跨模块改动的例子

以全书案例 `mini-shop` 为例。看起来只是改一行折扣：

```java
// DiscountPolicy.apply
return amount * 0.85; // 原为 0.9
```

但工程上它至少牵动：

1. `PricingService.calculateTotal` 的计算结果
2. `OrderService.createOrder` 的订单总价
3. `PaymentClient.charge` 的支付金额
4. `PricingServiceTest` 与 `OrderServiceTest` 的断言

如果只靠搜索 `0.9` 或阅读单个文件，很容易漏掉调用方和测试。可视化与代码理解系统要回答的，正是这类问题：

> 这次改动看起来很小，但它真正碰到了哪些实体、路径和验证点？

```mermaid
flowchart LR
 Change["改 DiscountPolicy.apply"] --> Pricing["PricingService.calculateTotal"]
 Pricing --> Order["OrderService.createOrder"]
 Order --> API["OrderController.create"]
 Order --> Pay["PaymentClient.charge"]
 Pricing --> T1["PricingServiceTest"]
 Order --> T2["OrderServiceTest"]
```

## 文档、搜索和经验的边界

| 方式       | 擅长              | 不足           |
| -------- | --------------- | ------------ |
| 文档       | 说明意图和设计背景       | 容易过期，缺少可执行证据 |
| 文本搜索     | 快速定位关键字         | 误报漏报多，不懂结构   |
| IDE 跳转   | 单点定义/引用导航       | 难以形成全局影响面和报告 |
| 同事经验     | 解释历史和隐式约定       | 不可复制、不可审计    |
| 代码可视化/图谱 | 组织结构、关系、行为与演进事实 | 依赖数据采集与建模质量  |

代码可视化不是取代这些方式，而是把其中可结构化的部分沉淀成系统能力。

## AI 时代为什么更需要它

AI 编程工具加快了生成和修改，但也放大了验证压力：

* 它是否找对了修改位置？
* 它是否理解模块边界？
* 它是否更新了相关测试？
* Reviewer 如何审计它的结论？

如果没有结构化事实层，人和 AI 都只能用自然语言“感觉相关”。有了代码理解系统，改动可以对应到实体、路径、测试和规则，形成可检查证据。

## 代码可视化真正服务的问题

围绕工程问题，而不是围绕图表类型，常见问题包括：

1. 这个功能从入口到实现经过哪些代码？
2. 这次 PR 可能影响哪些模块和测试？
3. 哪些热点文件经常一起变更？
4. 架构边界是否被破坏？
5. 给 Agent 的上下文应该包含哪些符号和约束？

图、路径、矩阵、报告和查询接口，都只是回答这些问题的表达形式。

## 阅读本书时请带着决策问题

建议你在后续每一章都问同一个问题：

> 这套事实最终帮人/AI 做了哪个决定？要不要改、改哪里、还看谁、如何证明？

如果一章读完只能复述术语，却说不出决策，说明还停留在概念层。`mini-shop` 的折扣变更会反复出现，不是因为业务重要，而是因为它足够小，却能逼出完整决策链。

## 从“看见”到“可决策”

有用的代码可视化最终要落到决策：

1. 要不要改
2. 改哪里
3. 还要看谁/测谁
4. 如何向 Reviewer 证明

因此本书后文不会把“生成大图”当终点，而会把图、路径、报告和查询都视为**决策界面**。对 AI Agent 同样如此：没有决策所需事实，生成再快也只是加速不确定。

## 局限

* 可视化不能自动保证正确理解；数据质量和模型边界决定上限。
* 全量大图通常不可读；必须按问题裁剪子图。
* 没有工程集成时，图只是展览，不是工作流能力。

## 小结

1. 代码库难理解，主要因为上下文分散，而不是单段代码难读。
2. 文档、搜索和经验都有边界，需要结构化事实层补齐。
3. 有用的代码可视化围绕工程问题组织证据，而不是堆砌大图。
4. AI 加速修改后，影响面判断和验证证据变得更关键。

下一章将回答：既然要可视化，到底应该把哪些事实作为对象。

## 工程决策清单：什么时候必须上代码理解系统

当出现以下信号中的任意两项，通常就值得建设结构化代码理解能力，而不是继续只靠搜索和经验：

1. 跨模块缺陷占比高，定位时间显著长于修改时间
2. AI/自动化改码开始进入主干，但 Review 只能抽样
3. 架构规则写在文档里，却经常在 PR 中被无意识破坏
4. 测试很多，却说不清一次变更该跑哪些
5. 关键路径缺乏 Owner，事故复盘靠“谁熟谁上”

`mini-shop` 虽小，但已经具备这些信号的缩影：折扣一行变更，会穿过计价、订单与支付，并打坏两份断言。若把它放大到真实多仓系统，缺少事实层的成本会指数上升。

## 与本书其余章节的接口

* 第二篇回答“结构事实从哪来”
* 第三篇回答“如何融合成图谱与证据”
* 第四篇回答“工程上怎么用”
* 第五篇回答“AI 如何被约束与审计”
* 第六篇给出可跟做闭环

## 关键要点复盘

围绕「为什么需要代码可视化」，读者离开本章前应能做到：

1. 解释“大图≠理解”与结构化事实的区别
2. 用 PR-42 列出搜索会漏的调用方/测试
3. 说明 AI 加速修改为何放大验证压力
4. 指出全量大图与无 ID 图两类失败
5. 衔接到“可视化对象”章

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 失败模式：把“可视化”做成展览

| 失败模式   | 表现             | 后果            | 纠正        |
| ------ | -------------- | ------------- | --------- |
| 全仓大图   | 默认渲染所有类与调用     | 不可读、不可决策      | 按任务裁剪子图   |
| 无实体 ID | 图上只有文件名字符串     | 无法对接影响面/Agent | 稳定符号 ID   |
| 无验证出口  | 只有图，没有测试/规则    | Review 仍靠感觉   | 报告与检查清单   |
| 与工作流脱节 | 图在 wiki，PR 看不到 | 无人使用          | 集成到 PR/CI |

`PR-42` 的正确起点不是“画全仓”，而是从 `method:DiscountPolicy#apply` 展开路径、测试与风险。

## 练习

1. 用 `mini-shop` 的 VIP 折扣修改，列出只靠文本搜索可能漏掉的 3 类影响。
2. 对比“文档 / 搜索 / 同事经验 / 代码图谱”在该修改上的优劣。
3. 写一段 5 行说明：为什么 AI 修改速度上升会放大验证压力。

## 本章导航

* 上一章：无（本书起始章）
* 下一章：[代码可视化到底可视化什么](/di-yi-pian-dai-ma-ke-shi-hua-de-mu-biao-yu-bian-jie/what-to-visualize)
* 相关章：[代码图谱：节点、边与属性](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/code-graph-model)

## 延伸阅读与参考资料

* [SWE-bench](https://github.com/swe-bench/SWE-bench)：仓库级软件工程任务说明“改对代码”需要仓库上下文与验证。资料卡：`../docs/research-cards/rc-swe-bench.md`
* [GitHub Copilot: Explore a codebase](https://docs.github.com/en/copilot/tutorials/explore-a-codebase)：官方代码库探索路径。资料卡：`../docs/research-cards/rc-github-copilot-explore.md`
* [IEEE 关于软件维护成本的经典讨论综述入口](https://ieeexplore.ieee.org/)（检索 software maintenance cost）：理解“理解成本”长期存在。
* [Git documentation](https://git-scm.com/doc)：变更是软件事实的基础来源之一。
* [OpenTelemetry Traces](https://opentelemetry.io/docs/concepts/signals/traces/)：运行时事实补充结构理解。资料卡：`../docs/research-cards/rc-opentelemetry-traces.md`
* 本书案例：[`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md) 与 [`docs/sample-case/README.md`](/fu-lu/sample-case)。


# 代码可视化到底可视化什么

## 本章要解决的问题

代码可视化的对象到底是什么？是图表类型，还是代码背后的事实？

## 读者读完应获得什么

1. 能把可视化对象分成结构、关系、行为、演进、组织五类事实。
2. 能把一个功能从入口追踪到代码、测试和 Owner 的事实链。
3. 能为后续代码图谱建模准备实体清单。

## 本章不讲什么

* 不比较各类前端图库。
* 不把“选哪种图”当成主问题。

***

初次接触代码可视化，会想到类图、调用图、依赖图、控制流图、火焰图。这些图重要，但如果只从图表类型出发，容易误以为代码可视化就是为代码选一种图形表达。

更准确的理解是：代码可视化可视化的不是代码文本，而是代码背后的事实。图只是表达方式之一；查询、报告、矩阵、列表和路径解释同样属于代码理解系统。

## 五类可视化对象

```mermaid
flowchart TB
 S[结构 Structure] --> G[代码事实层]
 R[关系 Relation] --> G
 B[行为 Behavior] --> G
 E[演进 Evolution] --> G
 O[组织 Organization] --> G
 G --> V[图 / 路径 / 报告 / 查询]
```

### 结构：代码由哪些实体组成

* 仓库、模块、包、目录
* 文件、类、接口、枚举
* 方法、字段、参数、配置项
* 测试文件与测试用例

在 `mini-shop` 中，结构实体至少包括：

```
module: order / pricing / payment
class: OrderService, PricingService, DiscountPolicy, PaymentClient
method: createOrder, calculateTotal, apply, charge
test: OrderServiceTest, PricingServiceTest
```

### 关系：实体如何连接

* 包含、依赖、调用、继承、实现
* 读写、配置引用、测试覆盖

例如：

```
OrderService.createOrder -> PricingService.calculateTotal
PricingService.calculateTotal -> DiscountPolicy.apply
OrderServiceTest covers OrderService.createOrder
```

### 行为：系统实际怎么运行

* 控制流与数据流
* 运行时 Trace / Span
* 覆盖率、性能热点、错误路径

静态关系说明“可能怎样连接”，行为事实说明“实际怎样发生”。

### 演进：系统如何变化

* Diff、Commit、PR
* 变更频率、共变文件、缺陷历史

`PR-42` 把 `DiscountPolicy.apply` 中的折扣从 `0.9` 改为 `0.85`，这就是演进事实；它需要映射回结构实体后才能做影响面分析。

### 组织：谁负责、边界在哪

* Owner、团队、服务目录
* 架构规则与模块边界

例如规则：`pricing` 不得直接依赖 `payment`。组织事实让可视化不仅服务代码阅读，也服务治理。

## 从对象到事实链

以“创建 VIP 订单”为例，完整事实链可以是：

1. 入口：`OrderController.create`
2. 业务编排：`OrderService.createOrder`
3. 计价：`PricingService.calculateTotal`
4. 折扣：`DiscountPolicy.apply`
5. 支付：`PaymentClient.charge`
6. 测试：`OrderServiceTest.shouldCreateVipOrderWithDiscount`
7. 规则：订单总价变更会影响支付金额

可视化系统要能把这条链查出来，而不是只展示一张静态类图。

## 表达方式不止图

| 事实类型 | 常见表达                 |
| ---- | -------------------- |
| 结构   | 目录树、符号列表、代码大纲        |
| 关系   | 调用图、依赖图、引用矩阵         |
| 行为   | 路径图、火焰图、覆盖热区         |
| 演进   | 变更耦合图、热点文件列表         |
| 组织   | 服务目录、Owner 地图、规则违规列表 |

选择表达方式的标准是：它是否帮助回答当前问题，并保留可回跳源码的证据。

## 和代码图谱的过渡

当五类事实需要统一查询时，自然会进入代码图谱：

* 节点 = 实体
* 边 = 关系
* 属性 = 证据来源、位置、置信度、时间

后面章节会把这些对象落实为可存储、可查询的模型。

## 事实优先级

不是所有事实都要同时可视化。可按任务裁剪：

| 任务       | 优先事实              |
| -------- | ----------------- |
| 定位功能入口   | 结构 + 调用关系         |
| 评估 PR    | 变更实体 + 调用方 + 测试   |
| 架构治理     | 模块依赖 + 规则 + 热点    |
| Agent 修改 | 符号 + 边界 + 测试 + 轨迹 |

这能避免“全量大图”既慢又不可读。

可视化真正难的不是“画什么形状”，而是决定哪些对象配得上进入事实层。对象选错，后面图谱再精美也只是噪音放大器：目录树看起来完整，却回答不了一次折扣变更会影响谁；全仓调用大图看起来震撼，却让 Reviewer 在 30 秒内找不到变更点。

因此本章把“可视化什么”拆成事实分类问题。你先学会给工程问题贴标签——它缺的是结构、关系、行为、演进还是组织事实——再谈图、表、报告哪种表达更合适。`mini-shop` 的价值在于：同一个 VIP 下单问题，五类事实都能各举一例，而且少一类就会在某个决策上失明。

## 局限

* 不是所有事实都能高精度自动提取。
* 组织与业务语义常需人工规则补充。
* 事实过多会噪声化，必须按任务裁剪。

选定对象之后，团队其实是在选定“哪些争论可以被数据结束”。若你坚持只可视化目录和类名，那么关于支付是否受折扣影响的争论就永远停留在会议上；若你把调用边、测试边和规则纳入事实层，争论就可以变成一次查询。这是可视化对象选择的工程含义，而不仅是信息架构偏好。

## 小结

1. 可视化的对象是事实，不是图本身。
2. 结构、关系、行为、演进、组织构成基本事实分类。
3. 工程问题需要事实链，而不是孤立节点。
4. 统一事实层是走向代码图谱的前提。

## 对象选择的反模式

1. **只可视化目录树**：看不到调用与变更，对 PR 几乎无帮助。
2. **只可视化全量调用大图**：信息过载，决策成本更高。
3. **只可视化运行时大盘**：无法回跳到可修改的代码实体。
4. **只可视化组织架构**：缺少代码事实时，治理会变成形式主义。

正确做法是任务驱动的对象组合：先问题，后事实，再表达。

## 五类事实的最小字段建议

| 事实类 | 最小字段                                 |
| --- | ------------------------------------ |
| 结构  | id, name, file, line range           |
| 关系  | from, to, type, confidence, evidence |
| 行为  | entity\_id, trace/test id, timestamp |
| 演进  | entity\_id, commit/pr, change\_type  |
| 组织  | entity\_id, owner, rule\_id, status  |

## mini-shop 五类事实速查

| 事实类 | mini-shop 例子                                            |
| --- | ------------------------------------------------------- |
| 结构  | `class:DiscountPolicy`、`method:DiscountPolicy#apply`    |
| 关系  | `calculateTotal calls apply`、`createOrder calls charge` |
| 行为  | 测试执行命中 VIP 分支；（扩展）下单 trace                              |
| 演进  | `PR-42` 修改 `apply` 字面量 0.9→0.85                         |
| 组织  | 规则 `pricing-no-payment`；pricing/order/payment 模块边界      |

若只能列出其中一类，说明对象选择仍停留在“会画一种图”，还不是“会组织事实链”。

## 从问题反推对象

问题：`VIP 折扣变更是否影响支付金额？`

最小对象集：

1. 变更实体 `DiscountPolicy.apply`
2. 调用路径到 `PaymentClient.charge`
3. 相关测试断言
4. 是否存在绕过计价的支付入口（如有）

没有路径与测试，只看 diff 一行，不足以回答该问题。

## 关键要点复盘

围绕「代码可视化到底可视化什么」，读者离开本章前应能做到：

1. 列举结构/关系/行为/演进/组织五类事实
2. 为 VIP 下单写出五类事实各一例
3. 说明 AST 单独拿不到的两类事实
4. 给出任务驱动选对象的反模式
5. 衔接到软件理解系统五层

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 练习

1. 把“创建 VIP 订单”写成结构/关系/行为/演进/组织五类事实清单。
2. 指出哪两类事实无法仅靠 AST 获得。
3. 为代码图谱列出至少 6 个节点类型候选。

## 常见问题：可视化对象

### 是不是把所有事实都画出来最好？

不是。应先问题后对象；事实过多会噪声化。

### 只要 AST 够不够？

不够。行为、演进、组织事实通常需要其他来源。

## 本章检查清单

1. 能否按五类事实分类任意一个工程问题
2. 是否避免“只画目录树/只画全仓大图”
3. 是否为 PR-42 写出最小对象集

## 本章导航

* 上一章：[为什么需要代码可视化](/di-yi-pian-dai-ma-ke-shi-hua-de-mu-biao-yu-bian-jie/why-code-visualization)
* 下一章：[从图形展示到软件理解系统](/di-yi-pian-dai-ma-ke-shi-hua-de-mu-biao-yu-bian-jie/software-understanding-system)
* 相关章：[代码图谱：节点、边与属性](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/code-graph-model)

## 延伸阅读与参考资料

* [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/)：组织与服务元数据如何目录化。资料卡：`../docs/research-cards/rc-backstage-catalog.md`
* [OpenTelemetry Traces](https://opentelemetry.io/docs/concepts/signals/traces/)：行为事实中的路径信号。资料卡：`../docs/research-cards/rc-opentelemetry-traces.md`
* [GitHub docs: About the dependency graph](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-the-dependency-graph)：依赖关系作为结构/关系事实。
* [Language Server Protocol](https://microsoft.github.io/language-server-protocol/)：符号与引用作为可查询结构事实。资料卡：`../docs/research-cards/rc-lsp.md`
* [Git diff](https://git-scm.com/docs/git-diff)：演进事实的基础输入。资料卡：`../docs/research-cards/rc-git-diff.md`
* 本书案例：[`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)。


# 从图形展示到软件理解系统

## 本章要解决的问题

为什么代码可视化应升级为持续更新的软件理解系统，而不是一次性画图？

## 读者读完应获得什么

1. 能描述数据采集、程序分析、图谱建模、查询表达、工程集成五层结构。
2. 能说明一次 PR 分析如何在系统中闭环。
3. 能判断一个“可视化能力”是否只是展示层，还是已具备系统能力。

## 本章不讲什么

* 不展开某个平台的完整安装手册。
* 不比较所有商业工具。

***

代码可视化经常被误解为“生成几张图”。类图、依赖图、调用图和火焰图都有价值，但它们只是最终表达层。真正能支撑工程决策的，是一套持续更新的软件理解系统。

软件理解系统的目标，是把代码、运行时、变更历史和工程上下文转化为可查询、可解释、可验证的事实。图形展示只是输出之一；其他输出还包括影响面报告、测试推荐、风险说明、Agent 上下文包和 Review 检查清单。

```mermaid
flowchart TB
 Data[数据采集层] --> Analysis[程序分析层]
 Analysis --> Graph[图谱建模层]
 Graph --> Query[可视化与查询层]
 Query --> Workflow[工程集成层]
 Workflow --> Feedback[反馈更新]
 Feedback --> Data
```

![软件理解系统分层（精确技术图）](/files/RTKGnbJA6yG34dozsbGX)

> 后续 AI 配图备注：可生成软件理解系统分层架构图，体现五层闭环。

## 数据采集层

没有可靠数据，后续分析都会变成猜测。常见来源：

| 数据源   | 例子             | 用途      |
| ----- | -------------- | ------- |
| 源码与构建 | 文件、AST、依赖锁     | 结构与候选关系 |
| 运行时   | Trace、日志、覆盖率   | 真实路径与热点 |
| 变更    | Git Diff、PR、缺陷 | 演进与风险   |
| 组织    | Owner、服务目录、规则  | 治理与边界   |

在 `mini-shop` 中，最小采集至少包括 Java 源码、测试文件和 `PR-42` Diff。

## 程序分析层

分析层把原始数据变成工程事实：

* AST / 符号 / 类型
* 调用图、依赖图
* CFG / DFG
* Trace 到方法映射
* Diff 到实体映射

这一层决定系统“知道什么”和“不确定什么”。

## 图谱建模层

图谱层统一存放节点、边、属性和证据来源。对 `mini-shop`，可以把 `OrderService.createOrder`、`PricingService.calculateTotal`、`DiscountPolicy.apply` 及 `tests` 关系放进同一模型，供影响面和 Agent 查询复用。

参考样例：[`examples/mini-shop/artifacts/code-graph.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/code-graph.json)

## 可视化与查询层

输出不应只有大图，还应包括：

* 子图探索
* 路径解释
* 影响面报告
* 符号/调用/测试查询 API

查询层是人和 AI 共用的接口。

## 工程集成层

系统只有进入工作流才有持续价值：

* IDE：跳转、解释、局部影响
* CI/PR：变更影响、测试建议、规则检查
* APM：运行时证据回灌
* AI Agent：上下文包与验证报告

## 一次 PR 闭环

以 `PR-42` 为例：

```
采集 DiscountPolicy 源码
 -> 解析 apply 方法
 -> 映射 Diff 到 method:DiscountPolicy#apply
 -> 反向调用得到 calculateTotal / createOrder / create
 -> 关联 PricingServiceTest / OrderServiceTest
 -> 输出影响面报告与验证建议
 -> 进入 PR Review
```

这就是从“图形展示”到“软件理解系统”的差别：结果可复用、可审计、可更新。

## 系统能力成熟度

| 级别    | 特征             | 典型产出      |
| ----- | -------------- | --------- |
| L1 展示 | 手工导出静态图        | 一次分享用的架构图 |
| L2 分析 | 可重复抽取结构/调用     | 调用图、依赖图   |
| L3 图谱 | 多源事实统一查询       | 影响面、上下文包  |
| L4 集成 | 进入 PR/CI/Agent | 自动报告与审计轨迹 |

本书后续内容按 L2 到 L4 逐步展开。

“系统”一词在这里不是为了显得宏大。它强调闭环：事实要被采集、被更新、被查询、被写回工程动作。只有展示层的代码可视化，就像只有仪表盘没有传感器——演示时好看，PR 到来时帮不上忙。

读本章时请把每一层都映射到 `PR-42`：采集如何认出 `DiscountPolicy.apply`，分析如何生成路径，图谱如何保存边，查询如何被人/Agent 使用，集成如何把报告贴进 PR。缺一层，整条证据链就会在那一层断开。

## 局限

* 系统建设有成本，应从最小闭环开始。
* 多源融合会引入冲突，需要证据优先级。
* 过度自动化可能制造虚假确定感。

## 小结

1. 图是表达，系统才是能力。
2. 软件理解系统由采集、分析、图谱、查询、集成构成闭环。
3. PR 影响面是检验系统是否有用的典型场景。
4. AI Agent 和 Reviewer 都依赖同一套事实层。

## 反馈环：系统如何持续变准

软件理解系统不是一次索引。关键反馈包括：

1. 测试结果回写覆盖与可靠性
2. Review 决策回写规则是否过严/过松
3. 运行时热点回写路径优先级
4. Agent 轨迹回写上下文策略是否有效

没有反馈环，图谱会在两周内过时，重新退化成“又一个静态站点”。

## 平台边界

系统应清楚自己不替代：

* 业务需求分析
* 最终合并责任
* 生产变更审批制度
* 完整可观测性平台

它提供的是事实、查询与证据，而不是自动免责。

## 关键要点复盘

围绕「从图形展示到软件理解系统」，读者离开本章前应能做到：

1. 画出采集-分析-图谱-查询-集成闭环
2. 把 PR-42 产物映射到五层
3. 说明缺采集/集成时系统如何断裂
4. 给出一周版最小系统清单
5. 衔接到编译/程序分析原理篇

若任一做不到，请先复习本章例子与练习，再继续向后读。

## PR-42 在五层中的产物映射

| 层      | PR-42 对应产物/动作                          |
| ------ | -------------------------------------- |
| 采集     | 解析 `DiscountPolicy` 等方法与候选调用           |
| 分析     | Diff→变更实体；反向调用；相关测试                    |
| 图谱     | `code-graph.json` 中的 nodes/edges/rules |
| 查询/可视化 | 影响路径视图、节点详情、报告页                        |
| 集成     | PR 评论/CI 检查/Agent 工具响应                 |

缺任一层，系统会在该层断开：例如有图谱无集成，则只存在于演示环境；有集成无采集，则报告会过期。

## 最小可行系统（一周版）

1. JSON 图谱 + 手写/半自动采集
2. 一个 `impact_analysis` 脚本
3. Markdown 验证报告
4. PR 模板强制粘贴报告摘要

先闭环，再平台化。

## 练习

1. 用五层模型标出 `PR-42` 影响面报告分别经过哪些层。
2. 说明为什么只有展示层、没有采集/图谱层时系统不可持续。
3. 给你们团队的现状自评：L1-L4 哪一级，缺什么。

## 常见问题：软件理解系统

### 有图是不是就有系统？

不是。缺采集、图谱更新与工程集成时，图只是展览。

### 必须一开始就做平台吗？

不必。先跑通最小闭环，再平台化。

## 本章导航

* 上一章：[代码可视化到底可视化什么](/di-yi-pian-dai-ma-ke-shi-hua-de-mu-biao-yu-bian-jie/what-to-visualize)
* 下一章：[编译器视角下的代码结构](/di-er-pian-yuan-ma-jie-gou-hua-yuan-li/compiler-view)
* 相关章：[代码图谱：节点、边与属性](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/code-graph-model)

## 延伸阅读与参考资料

* [OpenTelemetry](https://opentelemetry.io/docs/concepts/signals/traces/)：运行时信号如何进入事实层。资料卡：`../docs/research-cards/rc-opentelemetry-traces.md`
* [Backstage](https://backstage.io/docs/overview/what-is-backstage/)：工程门户与目录集成视角。资料卡：`../docs/research-cards/rc-backstage-catalog.md`
* [CodeQL documentation](https://codeql.github.com/docs/)：静态分析事实如何服务安全与理解。
* [Internal Developer Platform concepts](https://internaldeveloperplatform.org/)：平台化集成的工程语境。
* [GitHub Actions / checks 概念](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/about-status-checks)：工程集成层中的 PR 检查位。
* 本书案例：[`examples/mini-shop/artifacts/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/README.md)。


# 第二篇：源码结构化原理


# 编译器视角下的代码结构

## 本章要解决的问题

为什么理解代码需要借用编译器视角？词法、语法、语义和 IR 各自贡献什么结构事实？

## 读者读完应获得什么

1. 能画出编译器前端到中端的基本流水线。
2. 能说明哪些阶段对代码可视化最重要。
3. 能把 `mini-shop` 中的方法映射到“源码文本 -> 结构事实”的过程。

## 本章不讲什么

* 不实现完整编译器或优化器。
* 不深入寄存器分配、指令选择等后端主题。

***

代码可视化工具和 IDE、静态分析器有一个共同基础：它们都在某种程度上复用编译器前端思想。编译器要理解程序才能生成目标代码；代码理解系统要理解程序才能建图、查询和验证。差别在于目标不同，但结构分解方式高度相似。

## 编译器基本流水线

```mermaid
flowchart LR
 Src[源码字符] --> Lex[词法分析 Lexer]
 Lex --> Tokens[Token 流]
 Tokens --> Parse[语法分析 Parser]
 Parse --> AST[AST]
 AST --> Sema[语义分析]
 Sema --> IR[中间表示 IR]
 IR --> Opt[优化/分析]
```

| 阶段      | 输入    | 输出        | 对可视化的价值         |
| ------- | ----- | --------- | --------------- |
| 词法分析    | 字符流   | Token     | 稳定切分标识符、关键字、字面量 |
| 语法分析    | Token | AST       | 得到声明、语句、表达式结构   |
| 语义分析    | AST   | 符号与类型信息   | 连接定义与引用         |
| IR / 分析 | 结构化程序 | CFG/DFG 等 | 路径、数据依赖、更深层分析   |

## 为什么不能停在文本

对 `PricingService.calculateTotal`：

```java
double total = discountPolicy.apply(customerType, amount);
System.out.println("calculate total for " + customerType);
```

文本层看到两个 `calculate`，结构层却看到：

* 一次方法调用表达式 `apply`
* 一次字符串字面量 `"calculate total for ..."`

编译器视角的意义，就是强制系统先承认“语言结构”，再谈搜索、重构和 Agent 修改。

## 各阶段与代码理解的对应

### 词法与语法：结构骨架

* 类、方法、参数列表从哪里来
* 调用表达式如何被识别
* 源码位置如何保留

详见下一章“从字符到 AST”。

### 语义：名字与类型

* `discountPolicy` 指向字段还是局部变量
* `apply` 绑定到哪个方法定义
* 重载与继承如何消解

详见“符号表、作用域与类型关系”。

### IR 与图：路径和依赖

* 分支如何形成控制流
* 数据如何从参数流到返回值
* 调用边如何进入调用图

详见 “IR、SSA、CFG 与 DFG”。

## 对 AI 与工程工具的启示

AI Coding 工具如果只有文本窗口，相当于跳过了编译器前端。更稳妥的链路是：

```
源码 -> AST/符号/图事实 -> 上下文包/影响面 -> 生成修改 -> 再解析校验
```

第一层结构事实越扎实，后面的 Agent 定位和 Review 证据越可信。

## 贯穿例子：一笔 VIP 订单

`mini-shop` 中一次 `createOrder` 在编译器视角下至少经过：

1. 解析 `OrderService` 与 `PricingService` 的方法声明
2. 识别 `calculateTotal` 与 `apply` 调用表达式
3. 结合符号信息确认调用目标
4. 为后续影响面分析提供实体 ID

没有这些步骤，`PR-42` 只能停留在“某文件某行变了”，无法升级为“某个方法实体及其调用链变了”。

编译器视角对软件理解的启发，不在于你要重写 javac，而在于它证明了一件事：源码文本必须先变成结构化对象，后续一切分析才站得住。词法、语法、符号、中间表示这些阶段，对应的是不同粒度的事实，而不是教科书上的过场动画。

本书后面的 AST、符号表、CFG/DFG，本质上都是在借用编译前端的“分层诚实”：每一层只声称自己能保证的东西，并把不确定性显式留到下一层或属性字段里。对 AI Agent 同样如此——跳过结构层直接“读字符串改代码”，等于跳过编译器前端直接猜机器码。

## 局限

* 编译器视角不等于要自研编译器。
* 不同语言前端能力差异很大，动态语言语义更难。
* 生成代码、反射和框架魔法仍会留下盲区。

## 小结

1. 代码理解系统与编译器前端共享结构分解思路。
2. 词法/语法给结构，语义给绑定，IR/分析给路径与依赖。
3. 可视化应建立在结构事实上，而不是纯文本外观上。
4. AI 修改同样需要这层事实作为定位与校验基础。

## 编译器阶段与代码理解任务映射

把编译器阶段直接映射到工程任务，有助于避免“学编译器”跑偏：

| 工程任务      | 主要依赖阶段    | 典型输出               |
| --------- | --------- | ------------------ |
| 生成类/方法大纲  | 语法分析      | AST 声明节点           |
| 跳转到定义     | 语义/符号     | resolves\_to 边     |
| 候选调用图     | 语法 + 初步符号 | calls 边            |
| 影响面中的路径解释 | 调用图 + CFG | 路径列表               |
| AI 补丁语法校验 | 词法/语法     | parse success/fail |

对 `mini-shop` 而言，VIP 折扣修改首先落在语法树中的数值字面量节点；要判断它是否影响订单入口，则必须进入符号绑定与调用关系，而不是停在 Token 序列。

## 常见误解

1. **“有了大模型就不需要 parser”**：模型可以猜结构，但不能稳定提供可审计位置与类型绑定。
2. **“上了 IR 才能做代码理解”**：很多工程问题在 AST+符号层即可；IR 用于更深路径/数据流。
3. **“解析失败就整仓不可用”**：生产采集必须失败隔离，否则一次坏文件拖垮全索引。

## 工作示例：一笔 VIP 订单穿过编译器视角

源码片段：

```java
double total = pricingService.calculateTotal(quantity, unitPrice, customerType);
```

逐层看：

1. **词法**：`pricingService` / `calculateTotal` / 参数列表被识别为标识符与分隔符
2. **语法**：形成 MethodCall 表达式，隶属于 `createOrder` 方法体
3. **语义**：`pricingService` 绑定到字段类型 `PricingService`，从而把调用候选收敛到该类方法
4. **后续分析**：该调用成为影响面与 Agent 上下文中的关键边

如果只做文本搜索 `calculateTotal`，日志与注释会制造噪声；编译器视角的价值，正是把“像不像”升级成“是不是某种语法结构/绑定”。

## 关键要点复盘

围绕「编译器视角下的代码结构」，读者离开本章前应能做到：

1. 说明编译前端阶段与本书章节映射
2. 区分“借用编译思想”与“实现完整编译器”
3. 指出 AST/符号/IR 各解决什么问题
4. 说明为何代码理解优先前端事实
5. 衔接到源码→AST

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 编译流水线与本书章节映射

| 编译阶段      | 产出         | 本书落点         |
| --------- | ---------- | ------------ |
| Lex/Parse | Token/AST  | 源码到 AST      |
| 符号/类型     | 绑定关系       | 符号表章         |
| IR/优化相关表示 | CFG/DFG 基础 | IR/CFG/DFG 章 |
| 后端        | 机器码等       | 非本书重点        |

代码理解系统借用编译前端思想，但不等于实现完整编译器。目标是可查询事实，而不是生成可执行程序。

## 练习

1. 画出 `calculateTotal` 从字符到可分析结构的阶段图。
2. 说明词法、语法、语义各解决什么问题，缺一会发生什么误判。
3. 解释为何 AI 补丁后应重新 parse/校验，而不是只看文本 diff。

## 常见问题：编译视角

### 是否需要实现完整编译器？

不需要。本书借用前端思想提取可查询事实。

### 后端代码生成重要吗？

对代码理解主线次要；优先 AST/符号/IR 事实。

## 本章检查清单

1. 能否映射词法/语法/符号/IR 到本书章节
2. 是否区分编译器目标与理解系统目标
3. 是否知道后续从 AST 章开始深入

## 本章导航

* 上一章：[从图形展示到软件理解系统](/di-yi-pian-dai-ma-ke-shi-hua-de-mu-biao-yu-bian-jie/software-understanding-system)
* 下一章：[从字符到 AST](/di-er-pian-yuan-ma-jie-gou-hua-yuan-li/source-to-ast)
* 相关章：[静态分析](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/static-analysis)；[采集源码结构](/di-liu-pian-shi-jian-xiang-mu/collect-source-structure)

## 延伸阅读与参考资料

* [Java Language Specification](https://docs.oracle.com/javase/specs/jls/se17/html/index.html)：语言规则一级来源。
* [Tree-sitter](https://tree-sitter.github.io/tree-sitter/)：实用解析器视角。资料卡：`../docs/research-cards/rc-tree-sitter.md`
* [ANTLR](https://www.antlr.org/)：Lexer/Parser 规则教学。资料卡：`../docs/research-cards/rc-antlr.md`
* [LLVM Language Reference](https://llvm.org/docs/LangRef.html)：IR 作为分析友好表示的工业参考。
* [TypeScript Compiler API](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API)：语言服务/编译器 API 路线。
* 本书案例：[`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)。


# 从字符到 AST

## 本章要解决的问题

为什么全文搜索和正则匹配无法稳定理解代码？AST 提供了什么结构化事实，又故意不提供什么？

## 读者读完应获得什么

1. 能解释 Token、Lexer、Parser、AST 在代码理解流水线中的位置。
2. 能对一个真实函数画出最小 AST，并说明哪些节点对可视化有用。
3. 能判断：哪些问题适合用 AST 解决，哪些必须交给符号表、调用图、运行时或测试证据。
4. 能说明 AI Agent 为什么不能只靠“读文本改文本”，而需要 AST 层结构事实。

## 本章不讲什么

* 不实现完整编译器或完整语言前端。
* 不展开所有 Parser 算法（递归下降、LR、GLR 等）。
* 不在本章解决符号绑定、类型推断、动态分派和运行时路径。
* 不把工具评测当主题；工具只作为可复现入口。

***

AST 是很多代码可视化系统和代码理解基础设施的第一层数据基础。它把源码从线性文本变成树形结构，让工具可以稳定定位声明、表达式、语句和调用。

如果说上一章建立了编译器视角，那么本章关注其中最常用的一段链路：

```
字符流 -> Token 流 -> AST -> 后续分析输入
```

理解 AST 之后，后面讲符号解析、调用图、影响面分析和 Agent 上下文构建都会更自然。

本章使用全书贯穿案例 `mini-shop` 中的 `PricingService.calculateTotal` 作为主例子。完整源码见 [`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)。

## 为什么不能只做字符串搜索

假设我们要找出所有“真正调用 `calculateTotal`”的位置，或者判断某次修改是否动到了方法调用。最直接的方式是全文搜索 `calculate` 或 `calculateTotal(`，但很快会遇到误报和漏报。

`mini-shop` 里同时存在这些片段：

```java
// 真实方法声明
public double calculateTotal(int quantity, double unitPrice, String customerType) { ... }

// 真实方法调用
double total = pricingService.calculateTotal(quantity, unitPrice, customerType);

// 日志文本，不是调用
System.out.println("calculate total for " + customerType);

// 可能被字符串搜索误伤的注释
// TODO: calculate total offline for batch jobs
```

字符串搜索可能：

1. 把日志和注释当成调用。
2. 因换行、空格、链式调用漏掉真实调用。
3. 无法区分“方法声明”和“方法调用”。
4. 无法知道调用发生在哪个方法体内。

AST 的意义就在于：工具不再猜文本，而是基于语言结构识别：

* 这是一次方法调用表达式。
* 这是一个字符串字面量。
* 这是一个方法声明。
* 该节点位于哪个文件、哪一行、哪个父节点之下。

对 AI Agent 来说，这一点尤其关键。Agent 如果只靠文本片段做修改，很容易“改到了字面量，却以为改到了调用”。AST 层事实能把这类错误降到语法结构层面。

## 从字符到 Token

词法分析器（Lexer）把字符流切成 Token。Token 是语言的最小语法单元。

以 `calculateTotal` 方法签名中的片段为例：

```java
public double calculateTotal(int quantity, double unitPrice, String customerType)
```

词法分析会得到类似序列：

| Token 文本         | 大致类别   |
| ---------------- | ------ |
| `public`         | 关键字    |
| `double`         | 类型/关键字 |
| `calculateTotal` | 标识符    |
| `(`              | 分隔符    |
| `int`            | 类型/关键字 |
| `quantity`       | 标识符    |
| `,`              | 分隔符    |
| `double`         | 类型/关键字 |
| `unitPrice`      | 标识符    |
| `...`            | ...    |

Token 已经比裸字符串稳定：注释和空白通常不会进入核心 Token 序列，标识符和关键字也被分开了。但 Token 仍不足以表达程序结构，因为你还不知道：

* 哪些 Token 组成一个方法声明
* 哪些 Token 组成参数列表
* 哪些 Token 属于方法体里的表达式

因此还需要 Parser。

## 从 Token 到 AST

Parser 按语言语法规则把 Token 组织成树。不同工具可能生成不同形态：

* 更完整的语法树：保留大量标点和细粒度语法节点
* 更抽象的 AST：压缩对分析无用的细节，保留语义上重要的节点

对代码理解系统而言，通常更关心后一类：方法、参数、调用、返回、分支、字面量等。

`PricingService.calculateTotal` 的核心源码如下：

```java
public double calculateTotal(int quantity, double unitPrice, String customerType) {
 double amount = quantity * unitPrice;
 double total = discountPolicy.apply(customerType, amount);
 System.out.println("calculate total for " + customerType);
 return total;
}
```

它的最小 AST 可以画成：

```mermaid
flowchart TB
 M["MethodDeclaration: calculateTotal"] --> RT["ReturnType: double"]
 M --> P1["Parameter: quantity:int"]
 M --> P2["Parameter: unitPrice:double"]
 M --> P3["Parameter: customerType:String"]
 M --> B["Block"]
 B --> V1["VariableDeclaration: amount"]
 V1 --> Mul["BinaryExpression: *"]
 Mul --> Q["Name: quantity"]
 Mul --> U["Name: unitPrice"]
 B --> V2["VariableDeclaration: total"]
 V2 --> Call1["MethodCall: discountPolicy.apply"]
 Call1 --> A1["Arg: customerType"]
 Call1 --> A2["Arg: amount"]
 B --> Call2["MethodCall: System.out.println"]
 Call2 --> Str["StringLiteral: calculate total for ..."]
 B --> Ret["ReturnStatement: total"]
```

![源码到 AST 的结构链路（精确技术图）](/files/GMcr5FjtK2yDgfe3V1md)

> 后续 AI 配图备注：可生成一张“源码文本到 Token 再到 AST 树”的教学插图。左侧是 `calculateTotal` 源码，中间是 Token 列表，右侧是 AST 节点树；用颜色区分“方法调用节点”和“字符串字面量节点”，强调日志文本不是调用。

这棵树表达的是结构，不是排版。工具可以从根向下遍历，也可以按节点类型查询：

* 找所有 `MethodDeclaration`：得到方法列表
* 找所有 `MethodCall`：得到候选调用
* 找所有 `StringLiteral`：得到字符串常量，而不是调用

因此，日志里的 `"calculate total for ..."` 会落在字符串节点，而 `discountPolicy.apply(...)` 会落在方法调用节点。这就是 AST 相对字符串搜索的第一层优势。

## AST 节点里应保留什么

如果只把 AST 当“树长什么样”来看，后续系统仍然难用。面向代码图谱和可视化时，每个关键节点至少应保留：

```
node_type
name / operator / literal_value
parent_relation
file_path
start_line / end_line
start_column / end_column
```

以方法调用 `discountPolicy.apply(customerType, amount)` 为例，抽取结果可以是：

```json
{
 "node_type": "MethodCall",
 "expression": "discountPolicy.apply",
 "method_name": "apply",
 "receiver": "discountPolicy",
 "arguments": ["customerType", "amount"],
 "file_path": "src/main/java/com/minishop/pricing/PricingService.java",
 "start_line": 14,
 "end_line": 14
}
```

这些字段看起来简单，却决定了后续能力：

1. 可视化需要行号，才能把图节点回跳到源码。
2. 影响面分析需要方法名和所属文件，才能把 Diff 映射到实体。
3. Agent 上下文需要结构化位置，才能说明“我改的是哪一个调用”。
4. Review 证据需要可追溯路径，而不是“模型认为相关”的模糊描述。

## AST 能回答的问题

AST 最适合回答结构性问题：

* 一个文件包含哪些类、方法和字段
* 一个方法的参数和返回类型文本是什么
* 方法体里有哪些变量声明、分支、循环和调用表达式
* 哪些地方使用了注解、装饰器或特定语法模式
* 哪些节点是字符串字面量，哪些节点是真正调用

在 `mini-shop` 上，仅凭 AST 就可以稳定得到：

```
PricingService
 method calculateTotal(...)
 calls discountPolicy.apply(...)
 calls System.out.println(...)
 returns total
```

在可视化中，这些事实可以直接生成：

* 代码大纲 / 类结构树
* 方法内表达式树
* 候选调用列表
* 语法模式命中结果

它们也是后续构建调用图、数据流和变更实体映射的输入，而不是终点。

## AST 在自动化修改中的价值

AST 不只是“读代码”的数据源，也能用于更安全的自动修改。

对比两种改法：

| 方式     | 做法                                     | 风险                |
| ------ | -------------------------------------- | ----------------- |
| 字符串替换  | 全局替换 `0.9` 或 `calculate`               | 容易误改注释、日志、文档、其他数字 |
| AST 修改 | 定位 `DiscountPolicy.apply` 方法体中的数值字面量节点 | 修改目标明确，可保留格式和周围结构 |

常见基于 AST 的能力包括：

* 批量修改 API 调用
* 自动迁移语法
* 识别危险模式
* 生成代码结构报告
* 做局部、可回放的重构

在 AI 时代，这一层更加重要。AI 生成补丁后，系统可以用 AST 做第一道校验：

1. 修改后文件是否仍能解析
2. 目标节点是否真的从声明/调用集合中发生变化
3. 是否误改了字符串字面量或其他无关节点

这不会证明业务正确，但能先挡住大量“语法级误改”。

## 一个最小抽取流程

对 `mini-shop` 做 AST 采集时，最小流程可以是：

```
1. 扫描 src/main/java 与 src/test/java 下的 .java 文件
2. 对每个文件做 parse，失败则记录错误并继续
3. 遍历 AST，提取：
 - 类 / 接口声明
 - 方法声明
 - 方法调用表达式
 - 字面量（至少先保留字符串和数字）
4. 为每个节点附上 file_path 与行列位置
5. 输出 JSON，供图谱构建使用
```

一个面向后续图谱的最小方法节点可以长这样：

```json
{
 "id": "method:com.minishop.pricing.PricingService#calculateTotal",
 "type": "method",
 "name": "calculateTotal",
 "qualified_name": "com.minishop.pricing.PricingService.calculateTotal",
 "file_path": "src/main/java/com/minishop/pricing/PricingService.java",
 "start_line": 11,
 "end_line": 16,
 "parameters": [
 {"name": "quantity", "type_text": "int"},
 {"name": "unitPrice", "type_text": "double"},
 {"name": "customerType", "type_text": "String"}
 ],
 "return_type_text": "double",
 "calls": [
 {
 "method_name": "apply",
 "receiver_text": "discountPolicy",
 "line": 14
 },
 {
 "method_name": "println",
 "receiver_text": "System.out",
 "line": 15
 }
 ]
}
```

注意这里的 `calls` 还只是“候选调用”，不是已解析完成的精确调用边。`apply` 最终指向哪个方法定义，需要符号表和类型信息；本章只负责把调用表达式稳定挖出来。

## 权威定义与工程现实

在编译原理中，词法分析与语法分析把源程序变成可处理结构；AST 是后续语义分析与工具处理的常用起点。工程上，语言工具往往不会“从零手写完整编译器”，而是复用：

1. 语言官方 Compiler API（如 TypeScript）
2. 成熟 Parser 框架（ANTLR、tree-sitter）
3. 生态解析库（JavaParser）

对代码理解系统，关键不是复刻编译器后端，而是稳定获得：

* 节点类型
* 层级关系
* 源码位置
* 可遍历/可查询接口

因此本书把 AST 定义为**结构事实层的第一公民**，并要求后续图谱节点能回跳到 AST 位置证据。

## 局限

AST 很有用，但不是完整语义。它无法单独可靠回答：

1. 一个名字到底绑定到哪个定义 `discountPolicy` 是字段、参数还是局部变量？需要符号表和作用域。
2. 一个调用最终可能分派到哪些实现 接口、继承、重载会让“同名方法”有多条可能路径。
3. 某次调用是否在生产路径上真实发生 这需要 Trace、日志或覆盖率等运行时证据。
4. 某次改动的工程影响有多大 需要把 Diff 映射到实体，再沿调用图、测试关系和历史风险传播。
5. 用户输入是否经过校验后进入敏感操作 这通常需要数据流 / 污点分析，而不是纯 AST 遍历。

所以正确位置是：

```
AST = 结构事实层
符号/类型 = 名字与关系层
CFG/DFG/Call Graph = 路径与依赖层
Trace/Coverage/Git = 行为与演进证据层
```

AI Agent 如果停在 AST，它可能知道“这里有一个调用节点”，但仍不知道“该不该改、改完影响谁、该跑哪些测试”。

## 常见工具选择

不同生态有不同入口，选择标准应优先“可讲解、可复现”，而不是“最完整”：

| 工具                                                        | 适合什么                   | 需要注意              |
| --------------------------------------------------------- | ---------------------- | ----------------- |
| [Tree-sitter](https://tree-sitter.github.io/tree-sitter/) | 多语言、增量解析、编辑器/扫描器场景     | 语义信息较少，常需额外查询     |
| [JavaParser](https://javaparser.org/)                     | Java 教学和 Java 项目抽取     | 主要服务 Java 生态      |
| [ANTLR](https://www.antlr.org/)                           | 讲解 Lexer/Parser 规则如何工作 | 自己维护语法成本更高        |
| TypeScript Compiler API                                   | TS/JS 项目中的结构与类型信息      | 更接近语言服务，而不只是纯 AST |
| Babel                                                     | JS/TS 变换与工程化改造         | 更偏转换管线            |

本书实践部分默认用 Java + 易解释的 AST 抽取路径，因为 `mini-shop` 的类型和声明结构足够清楚，方便从 AST 过渡到符号与调用图。

## 和 AI Agent 的关系

把 AST 放进 AI 编程链路，不是为了让模型“多看一点树”，而是为了提供可审计的结构约束。

对 `mini-shop` 的典型 Agent 任务“调整 VIP 折扣”：

错误路径：

```
搜索文本 "0.9" 或 "calculate"
 -> 可能改到日志、注释或其他数字
 -> 不知道调用方和测试
```

更合理的路径：

```
定位 DiscountPolicy.apply 的方法声明节点
 -> 确认数值字面量节点
 -> 提取相关调用表达式
 -> 后续再查符号、调用方、测试
 -> 生成可回放的修改与验证证据
```

因此，AST 在 AI 时代至少承担四类角色：

1. **定位层**：找到真正要改的语法节点
2. **校验层**：修改后是否仍可解析、目标节点是否变化
3. **抽取层**：为图谱和上下文包提供结构实体
4. **解释层**：向人和 Reviewer 说明“改的是声明还是字面量，还是调用”

AST 不会替代测试，也不会替代影响面分析；它只是让 Agent 从“文本补丁机”变成“能操作结构事实的修改器”的第一步。

## 小结

1. 字符串搜索处理的是文本外观；AST 处理的是语言结构。
2. Lexer 把字符变成 Token，Parser 把 Token 变成可遍历树。
3. 对代码理解系统而言，AST 节点必须带上类型、名称和源码位置。
4. AST 能稳定回答“有哪些声明和表达式”，但不能单独回答“名字指向谁、运行时是否走到、影响面多大”。
5. 在 AI 时代，AST 是 Agent 定位、校验和证据抽取的基础层，而不是完整的代码理解系统。

下一章将在 AST 之上补上名字与类型：符号表、作用域和引用关系。到那时，我们才能把 `discountPolicy.apply(...)` 从“一个调用表达式”推进到“一次指向具体定义的引用”。

## 关键要点复盘

围绕本章，读者离开前应能做到：

1. 说明为何不能只靠字符串搜索
2. 走通 Token→AST 与最小抽取流程
3. 在 mini-shop 上指出 AST 能/不能回答的问题
4. 选择 parser 时权衡增量与语义
5. 衔接到符号与类型

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 练习

1. 打开 `PricingService.java`，列出 `calculateTotal` 的方法声明、变量声明、方法调用、字符串字面量节点。
2. 说明日志文本为何不应进入调用图候选边。
3. 设计 3 条 AST 级校验规则，用于检查 Agent 是否误改字符串字面量。
4. 对比 Tree-sitter 与 JavaParser 在“教学可复现/Java 语义便利”上的取舍（参考资料卡）。

## 常见问题：AST

### AST 能直接当调用图吗？

不能。调用边通常还要符号消解与类型信息。

### 选 Tree-sitter 还是 JavaParser？

看目标语言与是否需要语义；教学可用其一讲清流程。

## 本章检查清单

1. 能否说明字符串搜索的失败模式
2. 能否描述 Token→AST 最小流程
3. 能否指出 AST 对 PR-42 的边界

## 本章导航

* 上一章：[编译器视角下的代码结构](/di-er-pian-yuan-ma-jie-gou-hua-yuan-li/compiler-view)
* 下一章：[符号表、作用域与类型关系](/di-er-pian-yuan-ma-jie-gou-hua-yuan-li/symbols-scopes-types)
* 相关章：[静态分析](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/static-analysis)；[采集源码结构](/di-liu-pian-shi-jian-xiang-mu/collect-source-structure)

## 延伸阅读与参考资料

* [Tree-sitter](https://tree-sitter.github.io/tree-sitter/)：增量解析与具体语法树。资料卡：`../docs/research-cards/rc-tree-sitter.md`
* [ANTLR](https://www.antlr.org/)：语法规则驱动的前端构建。资料卡：`../docs/research-cards/rc-antlr.md`
* [JavaParser](https://javaparser.org/)：Java AST 访问、修改与位置信息。资料卡：`../docs/research-cards/rc-javaparser.md`
* [TypeScript Compiler API](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API)：结构与类型信息更接近语言服务。
* [Aho et al., Compilers (Dragon Book) 相关概念](https://www.amazon.com/Compilers-Principles-Techniques-Tools-2nd/dp/0321486811)：词法/语法分析经典教材背景（概念级）。
* [Eclipse JDT / Java model 文档入口](https://www.eclipse.org/jdt/)：IDE 结构模型的工程参考。
* 本书案例：[`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)；资料卡目录：[`../docs/research-cards/`](/fu-lu/research-cards)。


# 符号表、作用域与类型关系

## 本章要解决的问题

为什么有了 AST 还不够？名字、作用域和类型如何把“表达式”变成“可导航关系”？

## 读者读完应获得什么

1. 能解释符号、定义、引用、作用域、类型的基本关系。
2. 能说明 IDE“跳转到定义”背后需要哪些查询。
3. 能在 `mini-shop` 上区分同名文本与真实绑定。

## 本章不讲什么

* 不完整实现类型推断算法。
* 不覆盖所有 OOP/泛型边角。

***

![定义-引用绑定示意](/files/onYKCtxViKResQFBfMBl)

AST 告诉我们“这里有一个名字、一次调用”，但还不能稳定回答：

* 这个名字定义在哪里？
* 它在当前作用域是否可见？
* 调用应绑定到哪个方法？

符号表、作用域和类型系统补的就是这一层。

如果把 AST 比作“看见了哪些语法构件”，符号与类型就是“这些构件在名字世界上如何彼此指认”。没有这一层，调用图只能靠文本猜，影响面会把同名方法搅在一起，Agent 也会在重构时改错目标。IDE 的“跳转到定义”之所以可靠，并不是编辑器更聪明，而是语言服务维护了定义-引用关系。

## 定义与引用

以 `mini-shop` 为例：

```java
private final DiscountPolicy discountPolicy;

double total = discountPolicy.apply(customerType, amount);
```

* 定义：字段 `discountPolicy` 的声明
* 引用：方法体中的 `discountPolicy`
* 调用引用：`apply` 应绑定到 `DiscountPolicy.apply`

如果只有 AST，你只知道有一个标识符；有了符号信息，才能建立：

```
ref:discountPolicy --resolves_to--> field:PricingService.discountPolicy
call:apply --resolves_to--> method:DiscountPolicy#apply
```

## 作用域

作用域决定名字可见性。常见层次：

```
编译单元/文件
 -> 类/接口
 -> 方法
 -> 语句块
```

同名变量可以在不同作用域合法共存。代码理解系统必须按作用域解析，而不能全局字符串匹配。

## 类型关系

类型帮助消解重载、继承和接口实现：

* 方法参数类型影响重载选择
* 接口引用可能指向多个实现
* 泛型擦除/推断影响静态确定性

对可视化与影响面来说，类型关系至少应支持：

| 关系                   | 用途        |
| -------------------- | --------- |
| extends / implements | 架构与层次图    |
| typed\_as            | 字段/参数/返回值 |
| overrides            | 多态调用候选    |
| resolves\_to         | 精确或候选定义   |

## IDE 跳转背后的查询

“跳转到定义”通常不是魔法，而是：

```
1. 定位光标处 AST 节点
2. 取标识符与上下文类型
3. 查符号表得到候选定义
4. 按作用域/类型排序消解
5. 跳到定义节点源码位置
```

“查找引用”则是反向索引：从定义找所有 resolves\_to 边。

## 对调用图的影响

未做符号消解时，`apply(` 只能得到候选调用；完成消解后，`mini-shop` 可得到较可靠边：

```
PricingService.calculateTotal -> DiscountPolicy.apply
OrderService.createOrder -> PricingService.calculateTotal
```

这对 `PR-42` 影响面分析是前提：变更实体必须能连到真实调用方。

## 和 AI Agent 的关系

Agent 若只搜索 `apply` 文本，可能误伤无关方法。更稳妥的上下文应包含：

* 目标符号 ID
* 定义位置
* 直接引用与调用方
* 类型与模块边界

也就是把符号层事实写进上下文包，而不是只贴源码片段。

## 最小符号表 schema（教学可用）

把符号层事实落成可查询记录时，不必一上来做完整编译器。最小表可以是：

```json
{
  "symbols": [
    {
      "id": "method:DiscountPolicy#apply",
      "kind": "method",
      "name": "apply",
      "owner": "class:DiscountPolicy",
      "file": "src/main/java/com/minishop/pricing/DiscountPolicy.java",
      "start_line": 3,
      "end_line": 10,
      "signature": "apply(String customerType, double amount) -> double"
    }
  ],
  "refs": [
    {
      "id": "ref:PricingService#calculateTotal:discountPolicy",
      "name": "discountPolicy",
      "file": "src/main/java/com/minishop/pricing/PricingService.java",
      "line": 12,
      "resolves_to": "field:PricingService#discountPolicy",
      "confidence": "high"
    },
    {
      "id": "call:PricingService#calculateTotal->DiscountPolicy#apply",
      "name": "apply",
      "file": "src/main/java/com/minishop/pricing/PricingService.java",
      "line": 13,
      "resolves_to": "method:DiscountPolicy#apply",
      "confidence": "high",
      "receiver_type": "DiscountPolicy"
    }
  ]
}
```

关键字段解释：

| 字段                            | 作用                       |
| ----------------------------- | ------------------------ |
| `id`                          | 稳定符号 ID，供图谱与 Agent 上下文引用 |
| `owner`                       | 所属类/文件，支持作用域导航           |
| `resolves_to`                 | 定义-引用边的目标                |
| `confidence`                  | 绑定把握；中低置信必须保留，不可静默丢弃     |
| `signature` / `receiver_type` | 帮助重载与多态消解                |

这张表直接支撑：

1. 跳转到定义
2. 查找引用
3. 调用图边
4. `PR-42` 变更实体定位

## 失败模式对照

| 错误做法            | 症状          | 正确做法                    |
| --------------- | ----------- | ----------------------- |
| 全局字符串匹配 `apply` | 误绑无关方法      | 按作用域 + 接收者类型消解          |
| 忽略 shadowing    | 内层变量被当成外层字段 | 从内向外查作用域链               |
| 把候选当唯一          | 影响面漏路径或假精确  | 输出候选集 + confidence      |
| 只存名字不存 ID       | 重命名后历史断链    | 稳定 ID + 限定名             |
| Agent 上下文只贴源码   | 改错同名符号      | 附 `symbol_id` 与 callers |

## 工作示例：从 AST 到可导航边

输入：`PricingService.calculateTotal` 中的 `discountPolicy.apply(...)`。

处理步骤：

1. AST 识别 `MethodCallExpr` 与 `NameExpr`
2. 作用域解析 `discountPolicy` → 字段定义
3. 取字段类型 `DiscountPolicy`
4. 在 `DiscountPolicy` 中按签名匹配 `apply`
5. 写出 `calls` 边与 `resolves_to` 边

输出（简化）：

```
field:PricingService#discountPolicy  typed_as  class:DiscountPolicy
call@PricingService:13  resolves_to  method:DiscountPolicy#apply
method:PricingService#calculateTotal  calls  method:DiscountPolicy#apply
```

没有第 2-4 步，就只剩“看到了 apply 三个字符”。

## 常见问题：符号与类型

### 为什么 IDE 能跳转，我的脚本却不行？

IDE 背后通常有完整语言服务（符号表 + 类型 + 索引）。脚本若只扫 AST 文本，缺少绑定层。

### 动态代理 / DI 注入怎么办？

静态层给候选与置信度；运行时/配置事实可在后续动态分析章补充，而不是假装静态唯一。

### 是否必须实现完整类型推断？

教学与影响面第一阶段不需要。优先做定义-引用、简单类型与方法绑定，再按场景加深。

## 局限

* 动态语言、反射、依赖注入会降低静态绑定精度。
* 跨项目/生成代码需要额外索引。
* 多实现多态时往往只能给候选集，不能假装唯一确定。

也可以反过来看：符号层的质量决定了自动化的上限。调用图、重构、精准测试、Agent 定位，全都默认“名字可以被正确绑定”。绑定错了，后面每一层都会以更高效率犯同一个错。因此在工具链不成熟时，宁可输出候选与置信度，也不要假装唯一精确。

## 小结

1. AST 给结构，符号与类型给绑定。
2. 作用域是正确解析名字的前提。
3. 定义-引用关系是 IDE、调用图和影响面的共同基础。
4. Agent 上下文应使用符号 ID，而不是裸字符串。

## 解析不确定时的工程策略

当静态绑定无法唯一确定时，系统不应假装唯一：

```
resolves_to candidates = [ImplA.m, ImplB.m]
confidence = medium
reason = polymorphic_receiver
```

对影响面，这意味着路径要按候选集合扩展；对 Agent，这意味着修改前要更高确认级别。把不确定性藏起来，比“查不到”更危险。

## mini-shop 中的绑定练习

* `discountPolicy`：字段定义在 `PricingService`
* `apply`：绑定到 `DiscountPolicy.apply`
* `save`：绑定到 `OrderRepository.save`，不能与日志文本混淆

这三条是后续调用图与 PR-42 影响面的前提。

## 关键要点复盘

围绕「符号表、作用域与类型关系」，读者离开本章前应能做到：

1. 解释 AST 为何不够，需要定义-引用
2. 在 mini-shop 标出 discountPolicy 绑定
3. 说明同名 apply 不能直接当精确边
4. 写出不确定绑定时的 confidence 策略
5. 衔接到 IR/CFG/DFG

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 练习

1. 在 `PricingService` 中标出 `discountPolicy` 的定义点与引用点。
2. 说明为何“同名 apply”不能直接当精确调用边。
3. 用 LSP 的 go-to-definition / find-references 类比，写出图谱应支持的两条查询。

## 本章检查清单

1. 定义与引用是否能落到稳定 ID
2. 是否处理同名/多态的 confidence
3. Agent 上下文是否带 symbol\_id 而非裸字符串

## 本章导航

* 上一章：[从字符到 AST](/di-er-pian-yuan-ma-jie-gou-hua-yuan-li/source-to-ast)
* 下一章：[IR、SSA、CFG 与 DFG](/di-er-pian-yuan-ma-jie-gou-hua-yuan-li/ir-ssa-cfg-dfg)
* 相关章：[静态分析](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/static-analysis)；[采集源码结构](/di-liu-pian-shi-jian-xiang-mu/collect-source-structure)

## 延伸阅读与参考资料

* [JLS §6 Names](https://docs.oracle.com/javase/specs/jls/se17/html/jls-6.html)：名称与作用域一级规则。资料卡：`../docs/research-cards/rc-jls-names.md`
* [Language Server Protocol](https://microsoft.github.io/language-server-protocol/)：定义/引用查询的协议化。资料卡：`../docs/research-cards/rc-lsp.md`
* [TypeScript Compiler API](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API)：类型与符号信息工程入口。
* [JavaParser Symbol Solver 相关文档](https://javaparser.org/)：Java 符号解析实践。
* [Oracle Java Tutorials: Packages/Names](https://docs.oracle.com/javase/tutorial/java/package/index.html)：包与可见性基础。
* 本书案例：[`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)。


# IR、SSA、CFG 与 DFG

## 本章要解决的问题

如何表达程序路径和数据传播？CFG/DFG 对代码理解与 AI Review 有什么用？

## 读者读完应获得什么

1. 能解释 IR、SSA、CFG、DFG 的基本含义与关系。
2. 能对小函数画出控制流并指出数据依赖。
3. 能说明这些图如何服务风险路径与验证，而不是替代测试。

## 本章不讲什么

* 不讲完整编译优化流程。
* 不实现工业级指针分析。

***

AST 与符号回答“程序由什么构成、名字指向谁”。要回答“执行可能怎么走、数据如何传播”，需要控制流图（CFG）与数据流图（DFG），它们通常建立在中间表示（IR）之上。

## 概念地图

```mermaid
flowchart LR
 AST[AST/符号] --> IR[IR]
 IR --> CFG[CFG 控制流]
 IR --> SSA[SSA 形式]
 SSA --> DFG[DFG 数据流]
 CFG --> PDG[程序依赖]
 DFG --> PDG
```

![VIP 折扣 CFG 示意](/files/y6HdleIHC3RNJDNtiKpD)

| 概念  | 回答的问题              |
| --- | ------------------ |
| IR  | 用更适合分析的形式表示程序      |
| CFG | 哪些基本块，如何分支/汇合      |
| SSA | 每个变量赋值如何唯一命名，便于数据流 |
| DFG | 值从哪里产生，流到哪里        |

## 最小例子：折扣计算

```java
public double apply(String customerType, double amount) {
 if ("VIP".equals(customerType)) {
 return amount * 0.85;
 }
 return amount;
}
```

简化 CFG：

```mermaid
flowchart TD
 E[Entry] --> C{customerType == VIP?}
 C -->|yes| R1[return amount * 0.85]
 C -->|no| R2[return amount]
 R1 --> X[Exit]
 R2 --> X
```

数据依赖上：

* 返回值依赖 `amount`
* VIP 分支还依赖字面量 `0.85`
* 条件依赖 `customerType`

当 `PR-42` 修改 `0.9 -> 0.85` 时，变更点落在 VIP 分支的数据流上；相关测试正是在验证这条路径的输出。

## 为何对可视化有用

1. **路径解释**：展示“从入口到敏感操作”的可能路径
2. **影响细化**：区分改的是死代码还是热路径
3. **安全/校验审查**：DFG 支持污点传播直觉（输入是否到达危险点）
4. **AI Review 证据**：说明模型修改落在哪条路径的数据依赖上

## 与调用图的分工

| 图   | 粒度    | 典型用途      |
| --- | ----- | --------- |
| 调用图 | 方法间   | 影响面、上下文扩展 |
| CFG | 方法内控制 | 分支覆盖、路径风险 |
| DFG | 值依赖   | 数据传播、常量影响 |

`mini-shop` 的跨模块影响面主要靠调用图；单方法内折扣逻辑变化，则可用 CFG/DFG 解释“为什么测试断言会变”。

## 和 AI Agent 的关系

Agent 修改条件或字面量时，系统可附加：

* 受影响分支
* 相关返回值依赖
* 建议覆盖的测试路径

这比只说“改了一行”更可审。

当问题从“谁调用了这个方法”推进到“这条分支会不会走到、这个值会不会流到支付金额”，调用就不够了。CFG 回答控制可能，DFG 回答数据依赖；它们让影响面解释从“改了某方法”细化为“改了返回值的数据依赖”或“改了分支条件”。

`PR-42` 是很好的分度尺：字面量 `0.9→0.85` 主要是数据依赖变化，VIP 判断本身没动。能把这一点写进报告，Reviewer 才会明白为什么测试断言必须改、为什么支付入参会变。IR/SSA 则是让这些图在工程上可计算的表示选择，而不是目标本身。

## 局限

* 精确 CFG/DFG 代价高，别名与异常路径复杂。
* 动态分派让过程间分析变难。
* 对很多工程场景，先做好调用图 + 测试关联，再按需加深数据流。

更深分析有机会成本。CFG/DFG 更强，也更贵、更易受别名和动态特性影响。工程上应把它们当成可升级能力：默认调用图服务大多数 PR，关键金额/权限/分支逻辑再打开路径与数据依赖解释。这与“为每个函数生成完整形式化证明”是两条路。

## 小结

1. IR 为深度分析提供稳定表示。
2. CFG 描述控制可能，DFG 描述数据依赖。
3. 它们补全 AST/符号无法回答的路径问题。
4. 在 AI Review 中，路径与数据依赖是重要证据类型。

## 何时升级到 CFG/DFG

不是每个任务都要上控制流/数据流。建议阈值：

| 场景          | 是否需要 CFG/DFG |
| ----------- | ------------ |
| 找方法调用方      | 通常否，调用图即可    |
| 解释分支相关 bug  | 需要 CFG       |
| 输入是否到达敏感点   | 需要 DFG/污点    |
| 字面量/条件影响返回值 | 轻量 DFG 有帮助   |
| 仅更新测试断言     | 可能否          |

`PR-42` 改的是 VIP 分支字面量，用 CFG 标注分支、用数据依赖解释返回值变化，是合适深度；不必一上来上完整过程间指针分析。

## 工作示例：折扣字面量的数据依赖

对 VIP 分支：

```
amount --DFG--> mul(amount, 0.85) --DFG--> return
customerType --CFG condition--> VIP branch
```

因此：

* 改 `0.85`：改变返回值数据依赖
* 改 VIP 判断条件：改变控制依赖
* 两者都会逼迫测试更新，但解释路径不同

在验证报告中写清“数据依赖变化”还是“控制依赖变化”，能帮助 Reviewer 更快抓住重点。

## 与调用图联合使用

CFG/DFG 解释方法内部，调用图解释方法之间。`PR-42` 的完整解释通常是：

```
DFG: 0.9/0.85 -> apply return
CallGraph: apply <- calculateTotal <- createOrder <- create
Tests: PricingServiceTest, OrderServiceTest
```

## 关键要点复盘

围绕「IR、SSA、CFG 与 DFG」，读者离开本章前应能做到：

1. 区分 CFG 与 DFG 的问题域
2. 对 PR-42 字面量变化写出数据依赖
3. 说明何时不必上完整过程间分析
4. 把 CFG/DFG 与调用图拼成完整解释
5. 衔接到静态分析

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 教学用 CFG/DFG 记录格式

不必先上工业分析器，可用 JSON 记录方法内事实：

```json
{
  "method": "method:DiscountPolicy#apply",
  "cfg_blocks": [
    {"id": "B0", "text": "entry"},
    {"id": "B1", "text": "if VIP"},
    {"id": "B2", "text": "return amount * 0.85"},
    {"id": "B3", "text": "return amount"}
  ],
  "cfg_edges": [
    {"from": "B0", "to": "B1"},
    {"from": "B1", "to": "B2", "label": "VIP"},
    {"from": "B1", "to": "B3", "label": "else"}
  ],
  "dfg_edges": [
    {"from": "param:amount", "to": "mul:amount*0.85"},
    {"from": "mul:amount*0.85", "to": "return:B2"},
    {"from": "param:amount", "to": "return:B3"}
  ]
}
```

对 `PR-42`：

* 变更落在 `B2` 的字面量
* DFG 解释返回值变化
* 调用图解释谁消费该返回值

## 常见误解

| 误解              | 澄清                    |
| --------------- | --------------------- |
| CFG 就是流程图装饰     | CFG 是可达控制事实，服务路径与测试选择 |
| DFG 等于完整程序证明    | DFG 受别名/反射限制，是证据不是定理  |
| 有了调用图就不需要 CFG   | 调用图跨方法，CFG 管方法内分支     |
| AI 可读源码所以不需要 IR | IR/路径事实让审计可机器检查       |

## 练习

1. 为 `DiscountPolicy.apply` 画出 CFG，并标出 VIP 分支上的数据依赖。
2. 说明 `PR-42` 修改字面量时，影响的是控制结构还是数据依赖（或两者）。
3. 举一个“有调用边但需要 DFG 才能解释风险”的例子（可用安全数据流直觉）。

## 常见问题：CFG/DFG

### 每个 PR 都要上 DFG 吗？

否。调用图 + 测试常先够用；分支/污点场景再加深。

### CFG 和调用图重复吗？

不重复：CFG 方法内，调用图方法间。

## 本章检查清单

1. 能区分 CFG/DFG 问题域
2. 能为 PR-42 字面量写数据依赖
3. 知道何时升级分析深度

## 本章导航

* 上一章：[符号表、作用域与类型关系](/di-er-pian-yuan-ma-jie-gou-hua-yuan-li/symbols-scopes-types)
* 下一章：[静态分析：不运行代码时能知道什么](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/static-analysis)
* 相关章：[静态分析](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/static-analysis)；[采集源码结构](/di-liu-pian-shi-jian-xiang-mu/collect-source-structure)

## 延伸阅读与参考资料

* [CodeQL Data Flow Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/)：数据流分析官方说明。资料卡：`../docs/research-cards/rc-codeql-dataflow.md`
* [LLVM LangRef](https://llvm.org/docs/LangRef.html)：IR/SSA 工业参考。
* [Static Program Analysis (Møller & Schwartzbach)](https://cs.au.dk/~amoeller/spa/)：静态分析教材级公开资源。
* [Muchnick, Advanced Compiler Design & Implementation 概念](https://www.elsevier.com/books/advanced-compiler-design-implementation/muchnick/978-1-55860-320-2)：CFG/数据流经典背景。
* [WALA / analysis frameworks overview](https://github.com/wala/WALA)：过程间分析工程参考。
* 本书案例：[`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)。


# 第三篇：程序分析与代码图谱


# 静态分析：不运行代码时能知道什么

## 本章要解决的问题

静态分析能提取哪些事实，边界在哪里？它如何为代码图谱提供边？

## 读者读完应获得什么

1. 能列举静态分析的典型产出与误差来源。
2. 能说明调用图、依赖图、规则检查与测试无关路径的差异。
3. 能在 `mini-shop` 上给出静态可得的关系集合。

## 本章不讲什么

* 不测评具体商业工具。
* 不展开完整抽象解释理论。

***

静态分析在不执行程序的情况下，从源码、字节码或 IR 推导事实。它是代码可视化最常用的事实来源之一：结构稳定、可重复、可在 CI 中运行。

## 静态分析能知道什么

| 类别 | 例子          | 工程用途    |
| -- | ----------- | ------- |
| 结构 | 类/方法/字段     | 大纲、图谱节点 |
| 依赖 | import、模块依赖 | 架构图     |
| 调用 | 直接调用边       | 影响面     |
| 规则 | 分层违规、禁用 API | 治理      |
| 度量 | 复杂度、耦合      | 热点辅助    |

对 `mini-shop`，静态阶段至少能得到：

```
OrderController.create -> OrderService.createOrder
OrderService.createOrder -> PricingService.calculateTotal
PricingService.calculateTotal -> DiscountPolicy.apply
OrderService.createOrder -> PaymentClient.charge
```

以及模块依赖：`order -> pricing`、`order -> payment`。

## 基本流程

```mermaid
flowchart LR
 Src[源码/字节码] --> Parse[解析]
 Parse --> Model[程序模型]
 Model --> Rules[规则/查询]
 Model --> Graph[导出节点与边]
 Rules --> Report[告警/报告]
```

![多源事实融合到代码图谱](/files/m0S5Bh6bHRWqqHXWkc45)

## 误报与漏报

静态分析必须诚实面对不确定性：

* **漏报**：反射、依赖注入、动态代理让调用不可见
* **误报**：保守分析把不会发生的路径标成可能

因此图谱边最好带属性：

```
confidence: high | medium | low
source: static
evidence: file:line
```

## 在 PR 与 AI 中的位置

`PR-42` 不需要运行系统，也能先做：

1. 变更实体定位
2. 反向调用静态追踪
3. 规则检查（pricing 是否错误依赖 payment）

AI Review 可以先消费这些静态证据，再决定是否要求补充运行时或测试结果。

## 静态分析在工程叙事里的位置

静态分析常被窄化成“找 bug 的工具”。在本书主线里，它更基础的角色是**生产结构与关系事实**：谁调用谁、谁依赖谁、哪些调用尚未解析。告警只是这些事实之上的一种规则消费方式。

对 AI 工作流，这个区分很关键。Agent 不需要你每次都丢给它一份安全扫描长文；它更需要可查询的 `calls` 边、`unresolved` 列表和 limitations。没有事实层，扫描报告也无法接到影响面与上下文包。

`PR-42` 上静态分析的正确贡献是：把 diff 锚到 `DiscountPolicy.apply`，再给出反向调用事实，而不是直接宣布“无安全问题所以可合并”。

## 局限

* 不知真实流量是否走到某路径
* 难证明性能与并发问题
* 框架魔法需要专用规则补充

## 小结

1. 静态分析提供可重复的结构与关系事实。
2. 调用/依赖/规则是代码图谱的核心输入。
3. 必须标注置信度，避免虚假确定。
4. 它是影响面与 Agent 上下文的第一层来源。

## 进阶要点：把规则变成可查询事实

静态规则只有进入图谱或报告，才会成为持续能力。例如：

```
rule:pricing-no-payment
if exists edge depends_on(pricing, payment): fail
```

对 `mini-shop`，当前应通过。若 Agent 为“复用支付费率”而让 pricing 依赖 payment，系统应在验证报告中直接 fail，而不是等人工读 diff 才发现。

## 静态分析输出如何服务 AI

给 Agent 的不应是“告警洪水”，而是可操作子集：

1. 与当前任务符号相交的告警
2. 架构规则结果
3. 高置信调用边
4. 需要人工确认的低置信候选

若把全量静态告警塞进上下文，模型会过载并忽略关键约束。静态分析要会做**任务裁剪**。

## 工作示例：规则检查输出

```json
{
 "rule_id": "pricing-no-payment",
 "status": "pass",
 "evidence": [],
 "checked_modules": ["pricing", "payment"]
}
```

若失败：

```json
{
 "rule_id": "pricing-no-payment",
 "status": "fail",
 "evidence": [
 {"from": "class:PricingService", "to": "class:PaymentClient", "via": "import_or_call"}
 ]
}
```

该输出应同时进入：架构治理面板、PR 检查、Agent 验证报告。同一规则，三处消费，避免多套口径。

## 常见问题：静态分析

### 静态分析能证明没 bug 吗？

不能。它提供事实与候选问题，不是完备证明。

### 误报多是不是没用？

关键是分置信度与任务裁剪，不是放弃。

### 和测试什么关系？

互补：静态广覆盖，测试给行为证据。

## 本章检查清单

1. 是否区分漏报误报
2. 是否标注置信度
3. 是否支持规则查询
4. 是否服务 PR/Agent 裁剪

## 关键要点复盘

围绕「静态分析：不运行代码时能知道什么」，读者离开本章前应能做到：

1. 说明静态分析产出关系事实而不只是告警
2. 写出 calls 边与 unresolved 列表契约
3. 解释 limitations 字段为何必须保留
4. 把静态事实接到影响面输入
5. 衔接到动态分析

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 静态分析输出契约（教学）

一次静态分析 run 至少应留下可机器消费的结果：

```json
{
  "analyzer": "mini-static",
  "target": "method:DiscountPolicy#apply",
  "findings": [],
  "facts": {
    "calls": [
      {"from": "method:PricingService#calculateTotal", "to": "method:DiscountPolicy#apply", "confidence": "high"}
    ],
    "unresolved_calls": []
  },
  "limitations": ["no reflection", "no dynamic proxies"]
}
```

注意：`findings` 为空不等于“无风险”；它只说明规则集未触发。影响面仍要结合调用图与测试。

## 工作示例：PR-42 上的静态事实

1. Diff 定位变更方法 `DiscountPolicy.apply`
2. 静态调用图给出反向路径到 `OrderController.create`
3. 未发现 `pricing -> payment` 依赖边
4. 输出给影响面模块，而不是直接宣称“安全”

## 常见失败

| 失败              | 后果        | 缓解               |
| --------------- | --------- | ---------------- |
| 只报 bug 不产图谱事实   | 无法服务影响面   | 同时输出关系事实         |
| 把 unresolved 丢掉 | 假完整       | 保留 unresolved 列表 |
| 规则集过小却写“全面扫描”   | 误导 Review | 明确 limitations   |

## 练习

1. 列出 `mini-shop` 仅靠静态分析可得的 5 条边。
2. 给出 1 个会漏报、1 个会误报的场景，并说明如何在图谱中标注置信度。
3. 写一条架构规则检查：`pricing` 不得依赖 `payment`。

## 本章导航

* 上一章：[IR、SSA、CFG 与 DFG](/di-er-pian-yuan-ma-jie-gou-hua-yuan-li/ir-ssa-cfg-dfg)
* 下一章：[动态分析：运行起来之后才能知道什么](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/dynamic-analysis)
* 相关章：[变更影响分析与验证](/di-si-pian-san-ge-he-xin-gong-cheng-chang-jing/change-impact-verification)；[构建代码图谱](/di-liu-pian-shi-jian-xiang-mu/build-code-graph)

## 延伸阅读与参考资料

* [CodeQL docs](https://codeql.github.com/docs/)：查询式静态分析。资料卡：`../docs/research-cards/rc-codeql-dataflow.md`
* [Semgrep docs](https://semgrep.dev/docs/)：模式化静态规则。
* [SpotBugs](https://spotbugs.github.io/)：字节码级缺陷模式检测。
* [Error Prone](https://errorprone.info/)：编译期静态检查实践。
* [ArchUnit](https://www.archunit.org/)：架构规则测试化。
* 本书案例：[`examples/mini-shop/artifacts/code-graph.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/code-graph.json)。


# 动态分析：运行起来之后才能知道什么

## 本章要解决的问题

运行时证据补足了哪些静态分析盲区？如何把 Trace/Coverage 连回代码实体？

## 读者读完应获得什么

1. 能说明 Log、Trace、Profile、Coverage 的分工。
2. 能设计“请求路径 -> 方法实体”的关联方式。
3. 能判断何时必须引入动态证据。

## 本章不讲什么

* 不讲具体 APM 产品选型大全。
* 不部署完整观测平台。

***

静态分析回答“可能怎样”，动态分析回答“实际怎样”。对代码理解系统，动态事实用于验证、降噪和风险判断。

## 主要动态信号

| 信号           | 说明       | 连回代码的关键字段    |
| ------------ | -------- | ------------ |
| Log          | 事件与错误信息  | logger 名称、堆栈 |
| Trace/Span   | 分布式请求链路  | span 名、代码属性  |
| Coverage     | 测试/线上覆盖  | 文件行号、方法      |
| Profile      | CPU/内存热点 | 栈帧符号         |
| Runtime call | 实际调用采样   | 调用对          |

## 与静态事实融合

```mermaid
flowchart TB
 Static[静态调用图] --> Merge[事实融合]
 Trace[Trace/Coverage] --> Merge
 Merge --> Graph[代码图谱属性更新]
 Graph --> Use[影响面/热点/Agent 证据]
```

示例：静态显示 `createOrder -> calculateTotal -> apply` 可能发生；若集成测试覆盖了 VIP 订单路径，则可为这些边标记 `covered_by_test=true`。

## 关联方法

要把 Span 连到 `mini-shop` 方法，常见做法：

1. 约定 span 名与方法全名一致
2. 使用 OpenTelemetry code 属性
3. 通过堆栈采样映射符号
4. 用覆盖率行号映射到方法区间

没有稳定映射，动态数据就只是另一套孤立监控，无法进入代码图谱。

## 何时必须用动态证据

* 静态调用不可见（反射、插件）
* 需要知道生产热路径
* 评估“改动是否落在高频路径”
* 验证 AI 修改后行为是否保持

对 `PR-42`，本地测试覆盖已能提供强证据；若在生产调整折扣策略，还应用 Trace/业务指标观察支付金额分布变化。

## mini-shop 的动态证据示例

假设为 `OrderServiceTest.shouldCreateVipOrderWithDiscount` 打开覆盖率，可得到：

```
covered methods:
 OrderService.createOrder
 PricingService.calculateTotal
 DiscountPolicy.apply
 PaymentClient.charge
```

于是在图谱中可为这些方法/边写入：

```json
{
 "coverage": {
 "test": "test:OrderServiceTest#shouldCreateVipOrderWithDiscount",
 "covered_entities": [
 "method:OrderService#createOrder",
 "method:PricingService#calculateTotal",
 "method:DiscountPolicy#apply",
 "method:PaymentClient#charge"
 ]
 }
}
```

当 `PR-42` 修改 `apply` 时，动态/测试证据能说明：该变更不仅静态可达，而且已被现有测试路径执行到。这对 AI 修改后的验证特别有价值。

动态分析的独特价值是“发生过”。它不能证明所有可能，但能给静态猜测提供硬证据：这条下单路径确实走到了 `charge`；这个测试确实覆盖了 VIP 分支。把动态结果并入图谱时，关键不是替换静态边，而是带上 `source=dynamic` 与 trace/coverage 引用，让合并策略可审计。

在 AI 改码场景里，动态证据常被误用成“测试绿了就结束”。更稳妥的叙事是：动态结果提高置信度，静态路径保证没跑到的可能仍被看见，二者一起服务 Review，而不是互相取消。

## 局限

* 覆盖受输入与环境限制，未见不等于不可能
* 采样有偏差
* 运行时探针有成本

## 小结

1. 动态分析补齐真实路径与热点。
2. 关键是把运行时信号映射回代码实体。
3. 与静态图融合后才能服务影响面和治理。
4. AI 验证常需“静态影响面 + 动态/测试证据”组合。

## 动态事实进入图谱的最小 schema

建议至少写入这些属性：

```json
{
 "edge_id": "calls:createOrder->calculateTotal",
 "runtime": {
 "seen_in_trace": true,
 "trace_ids": ["tr_demo_001"],
 "covered_by_tests": ["test:OrderServiceTest#shouldCreateVipOrderWithDiscount"],
 "last_seen_at": "2026-07-22T10:00:00Z"
 }
}
```

没有这些字段，动态数据就只是另一套监控面板，无法与 PR 影响面、Agent 上下文共用。

## 与 AI 验证的结合

Agent 修改后，除了静态影响面，还应尽量给出：

1. 相关测试是否执行到变更实体
2. 若有预发 Trace，热路径是否包含变更方法
3. 若无动态证据，报告需显式写“动态证据缺失”

对 `PR-42`，本地测试覆盖已能形成强证据；缺少线上 Trace 并不阻断合并，但应降低“生产无影响”的表述强度。

## 工作示例：测试覆盖回写

执行 `OrderServiceTest` 后：

```
covered:
 OrderController? no (单测直接调 service)
 OrderService.createOrder yes
 PricingService.calculateTotal yes
 DiscountPolicy.apply yes
 PaymentClient.charge yes
```

于是 `PR-42` 相关测试推荐不应只给 pricing 单测，也应包含 order 单测——因为行为断言建立在链路上。动态/测试证据纠正了“只看变更文件”的偏见。

## 关键要点复盘

围绕「动态分析：运行起来之后才能知道什么」，读者离开本章前应能做到：

1. 说明动态事实如何以 source=dynamic 入库
2. 给出静态/动态合并四条策略
3. 用下单路径解释支付副作用
4. 指出“未见≠不可能”
5. 衔接到变更分析

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 动态事实如何并入图谱

Trace/Coverage 不应替换静态图，而应作为带证据的边/属性：

```json
{
  "type": "calls",
  "from": "method:OrderService#createOrder",
  "to": "method:PaymentClient#charge",
  "source": "dynamic",
  "confidence": "high",
  "evidence_refs": ["trace:order-create-001"]
}
```

合并策略建议：

1. 静态有、动态无：保留静态，confidence 不变
2. 动态有、静态无：新增边，标记 dynamic
3. 两边都有：提升 confidence，并记录双来源
4. 冲突：保留冲突项，供人/Agent 审查，不静默覆盖

## mini-shop 示例

下单路径的动态证据可确认：

```
createOrder -> calculateTotal -> apply
createOrder -> charge(total)
```

这对解释 `PR-42` 很关键：折扣变化会传导到支付金额，即使 diff 只改了定价文件。

## 练习

1. 说明如何把一次订单请求 Trace 映射到 `createOrder -> calculateTotal -> apply`。
2. 若 Coverage 显示 VIP 测试覆盖了 `apply`，对 `PR-42` 风险判断有何帮助？
3. 讨论采样 Trace 的主要偏差来源。

## 常见问题：动态分析

### 动态覆盖能替代静态图吗？

不能。动态证明“发生过”，静态描述“可能”。

### 测试没跑到是否表示不可能？

否。未见不等于不可能。

## 本章检查清单

1. 动态边是否带 source/evidence
2. 是否定义静动态合并策略
3. 是否用路径解释支付副作用

## 本章导航

* 上一章：[静态分析：不运行代码时能知道什么](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/static-analysis)
* 下一章：[变更分析：系统是如何演进的](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/change-analysis)
* 相关章：[变更影响分析与验证](/di-si-pian-san-ge-he-xin-gong-cheng-chang-jing/change-impact-verification)；[构建代码图谱](/di-liu-pian-shi-jian-xiang-mu/build-code-graph)

## 延伸阅读与参考资料

* [OpenTelemetry Traces](https://opentelemetry.io/docs/concepts/signals/traces/)：Trace/Span 概念。资料卡：`../docs/research-cards/rc-opentelemetry-traces.md`
* [W3C Trace Context](https://www.w3.org/TR/trace-context/)：分布式追踪上下文标准。
* [Jaeger architecture](https://www.jaegertracing.io/docs/latest/architecture/)：追踪系统结构参考。
* [Istanbul coverage](https://istanbul.js.org/)：覆盖率事实来源之一。
* [OpenTelemetry code attributes 相关文档](https://opentelemetry.io/docs/)：将 span 关联到代码实体的方向。
* 本书案例：[`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)。


# 变更分析：系统是如何演进的

## 本章要解决的问题

Git/PR 历史如何成为代码理解事实？如何识别热点与变更耦合？

## 读者读完应获得什么

1. 能把 Diff/Commit/PR 映射到代码实体。
2. 能解释变更频率、共变和风险的基本用法。
3. 能用 `PR-42` 说明演进事实如何进入影响面。

## 本章不讲什么

* 不做完整代码考古产品。
* 不依赖真实公司仓库数据。

***

代码理解不只看“现在是什么”，还要看“如何变成这样”。变更分析把版本历史变成可查询事实。

## 核心对象

| 对象           | 字段例子                           | 用途     |
| ------------ | ------------------------------ | ------ |
| Commit       | author, time, message          | 责任与时间线 |
| Diff         | file, line range, type         | 映射变更实体 |
| PR           | reviewers, labels, checks      | 流程上下文  |
| EntityChange | method/class change count      | 热点     |
| CoChange     | files/methods changed together | 隐式耦合   |

## 从 Diff 到实体

`PR-42` Diff：

```diff
- return amount * 0.9;
+ return amount * 0.85;
```

映射结果：

```
changed_entity = method:DiscountPolicy#apply
file = DiscountPolicy.java
line = 6
```

只有映射到实体，后续才能沿调用图扩展影响面。样例见 [`examples/mini-shop/artifacts/pr-42.diff`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/pr-42.diff)。

## 变更耦合与热点

若历史中 `DiscountPolicy` 与 `PricingServiceTest` 经常同 PR 修改，说明存在验证耦合；这可以提示 Agent：改折扣时默认带上测试文件。

可视化上常用：

* 热点文件柱状/热力
* 共变矩阵
* 实体变更时间线

## 风险直觉

高风险常来自组合信号：

1. 变更落在核心调用链
2. 相关测试少或断言脆弱
3. 历史缺陷密集
4. 跨模块共变突然增加

`PR-42` 虽是单字面量修改，但落在金额链路上，因此风险不是“低到可忽略”。

## 和 AI 的关系

Agent 可用变更事实做：

* 优先阅读近期共变文件
* 避开长期稳定且无测试的高危区时提高确认级别
* 在验证报告中引用历史缺陷密度（若有）

## 变更分析流水线

```mermaid
flowchart LR
 Diff[git diff / PR-42.diff] --> Map[映射到变更实体]
 Map --> Hist[关联历史提交/共变]
 Hist --> Facts[演进事实入库]
 Facts --> Impact[供影响面分析使用]
```

对 `PR-42`，映射金标是 `method:DiscountPolicy#apply`，而不是停在文件路径。

变更分析把时间维引进来。没有它，图谱只是当前快照；有了它，你才能问“谁总是和折扣逻辑一起改”“这次 diff 到底碰到了哪个方法实体”。工程上最容易偷懒的一步，是停留在文件级变更——`DiscountPolicy.java` 被改了——却不映射到 `method:DiscountPolicy#apply`。后面的影响面、测试选择和 Agent 上下文都会因此变粗。

`pr-42.diff` 之所以适合做金标，是因为它足够小，却逼你完成“行 → 实体 → 关系”的完整映射。做不到这一步，所谓演进分析只是 git log 美化。

## 局限

* 历史噪声大，重命名会切断实体轨迹
* 提交质量影响信号
* 需要实体稳定 ID 与重命名追踪

## 小结

1. 变更是一等事实，不只是日志。
2. Diff 必须映射到代码实体。
3. 热点与共变帮助发现隐式结构。
4. 影响面与 Agent 上下文都应消费演进信号。

## 进阶要点：实体稳定 ID 与重命名

演进分析最怕实体 ID 漂移。推荐：

1. 优先 `package.Class#method` 这类逻辑 ID
2. 保留文件路径与行号作证据，不把路径当唯一身份
3. 检测重命名事件时，建立 old\_id -> new\_id 映射

否则“热点方法”时间序列会在一次 rename 后归零，误导治理判断。

## 工作示例：PR-42 的演进事实记录

建议把一次 PR 记为：

```json
{
 "pr": "PR-42",
 "entity_changes": [
 {"entity": "method:DiscountPolicy#apply", "change": "literal_update", "from": 0.9, "to": 0.85}
 ],
 "likely_cochange": [
 "test:PricingServiceTest#shouldApplyVipDiscount",
 "test:OrderServiceTest#shouldCreateVipOrderWithDiscount"
 ]
}
```

下一次若有人再次修改折扣策略，系统应提示：历史共变显示测试几乎总是一起改。这对 Agent 上下文选择是强信号。

## 演进度量（教学用最小集）

1. 实体变更频率
2. 共变对支持度
3. 缺陷关联次数（若有）
4. 最近变更年龄

不必一开始就上复杂算法；先让这些字段进图谱。

## 常见问题：变更分析

### Commit 消息能否代替结构映射？

不能。消息不可靠，必须映射到实体。

### 重命名怎么处理？

需要 old\_id 到 new\_id 的映射，否则热点统计失真。

### 变更耦合高一定是坏味道吗？

不一定，但要能解释；无解释的高耦合常是隐式架构。

## 本章检查清单

1. Diff 是否映射实体
2. 是否记录共变
3. 是否保留 PR 元数据
4. ID 是否稳定
5. 能否服务影响面与上下文

## 关键要点复盘

围绕「变更分析：系统是如何演进的」，读者离开本章前应能做到：

1. 把 diff 映射到方法级变更实体
2. 给出 PR-42 金标实体 ID
3. 区分行为变更与纯重构
4. 说明演进事实如何服务影响面
5. 衔接到代码图谱模型

若任一做不到，请先复习本章例子与练习，再继续向后读。

## Diff 到变更实体算法骨架

```
input: pr-42.diff, code-graph.json
for each changed file/hunk:
  map lines -> enclosing method/class via graph or AST ranges
  emit changed_entity {id, change_type, file, lines}
dedupe entities
attach related edges for downstream impact
```

对 `PR-42`，金标输出应包含且优先聚焦：

```json
{"id": "method:DiscountPolicy#apply", "change_type": "modified"}
```

若只输出文件级 `DiscountPolicy.java`，后续影响面与测试关联会变粗，Review 成本上升。

## 变更分类

| 类型     | 例子       | 影响面策略      |
| ------ | -------- | ---------- |
| 行为字面量  | 0.9→0.85 | 必做路径+测试    |
| 纯重构重命名 | 变量改名     | 重点看绑定保持    |
| 注释/格式  | 无语义      | 可降级        |
| 测试更新   | 断言调整     | 核对是否覆盖变更路径 |

## 练习

1. 把 `pr-42.diff` 映射为变更实体，并写出实体 ID。
2. 设计两个变更耦合指标，解释它们对 Agent 上下文选择的帮助。
3. 说明重命名如何破坏“实体稳定 ID”，以及如何缓解。

## 本章导航

* 上一章：[动态分析：运行起来之后才能知道什么](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/dynamic-analysis)
* 下一章：[代码图谱：节点、边与属性](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/code-graph-model)
* 相关章：[变更影响分析与验证](/di-si-pian-san-ge-he-xin-gong-cheng-chang-jing/change-impact-verification)；[构建代码图谱](/di-liu-pian-shi-jian-xiang-mu/build-code-graph)

## 延伸阅读与参考资料

* [Git diff](https://git-scm.com/docs/git-diff)：行级变更输入。资料卡：`../docs/research-cards/rc-git-diff.md`
* [Conventional Commits](https://www.conventionalcommits.org/)：提交语义化（可选增强）。
* [CodeScene hotspots 概念](https://codescene.com/blog/hotspot-analysis/)：热点与演进可视化思路。
* [GitHub pull request docs](https://docs.github.com/en/pull-requests)：PR 作为协作与检查载体。
* [Software evolution / mining repositories 研究入口](https://ieeexplore.ieee.org/)（检索 MSR mining software repositories）。
* 本书案例：[`examples/mini-shop/artifacts/pr-42.diff`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/pr-42.diff)。


# 代码图谱：节点、边与属性

## 本章要解决的问题

代码事实如何被建模成统一图谱？最小模型需要哪些节点与边？

## 读者读完应获得什么

1. 能为 `mini-shop` 定义节点、边和关键属性。
2. 能写出 3 到 5 个有工程价值的查询。
3. 能在 JSON/SQLite 与图数据库之间做取舍。

## 本章不讲什么

* 不绑定唯一图数据库产品。
* 不追求一次覆盖所有语言语义。

***

代码图谱是软件理解系统的核心数据层。它把结构、关系、行为、演进和组织事实放到可查询模型中。

## 最小 schema

### 节点类型

* `module` / `file` / `class` / `method` / `test`
* 可扩展：`route`、`config`、`pr`、`owner`

### 边类型

* `contains`、`calls`、`tests`、`depends_on`
* 可扩展：`covers`、`owns`、`changed_in`

### 关键属性

```
id, name, qualified_name
file_path, start_line, end_line
source, confidence, updated_at
```

## mini-shop 实例

完整样例：[`examples/mini-shop/artifacts/code-graph.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/code-graph.json)

核心调用链：

```mermaid
flowchart LR
 OC[OrderController.create] --> OS[OrderService.createOrder]
 OS --> PS[PricingService.calculateTotal]
 PS --> DP[DiscountPolicy.apply]
 OS --> PC[PaymentClient.charge]
```

![mini-shop 核心调用图谱（精确技术图）](/files/6B00Dz2URA70Tnr64rXW)

## 有工程价值的查询

1. **find\_symbol** `DiscountPolicy.apply` 定义在哪？
2. **find\_callers** 谁调用了 `DiscountPolicy.apply`？
3. **impact\_analysis** 从变更方法出发的反向路径与入口？
4. **related\_tests** 哪些测试覆盖该调用链？
5. **architecture\_rules** `pricing` 是否依赖 `payment`？

这些查询直接服务 PR 影响面和 Agent 上下文包。

## 存储取舍

| 方案      | 优点           | 适用      |
| ------- | ------------ | ------- |
| JSON 文件 | 简单可讲解        | 教学与最小原型 |
| SQLite  | 可 SQL 查询、易分发 | 本地工具    |
| 图数据库    | 深层路径与图算法     | 大规模扩展   |

本书实践优先 JSON/SQLite 讲清模型，图数据库作为扩展。

## 多源融合原则

同一条 `calls` 边可能来自静态解析或动态观测。属性中应保留：

* `source`
* `confidence`
* `evidence_refs`

冲突时按策略合并，而不是静默覆盖。

## 从样例 JSON 读模型

`examples/mini-shop/artifacts/code-graph.json` 中的一条调用边应能直接回答“谁调用谁”：

```json
{
  "type": "calls",
  "from": "method:PricingService#calculateTotal",
  "to": "method:DiscountPolicy#apply",
  "source": "static",
  "confidence": "high"
}
```

一条测试边应能直接回答“谁锁住该行为”：

```json
{
  "type": "tests",
  "from": "test:PricingServiceTest#shouldApplyVipDiscount",
  "to": "method:DiscountPolicy#apply"
}
```

一条架构规则应能被自动判定：

```json
{
  "id": "pricing-no-payment",
  "description": "pricing must not depend on payment",
  "from_module": "pricing",
  "forbidden_to_module": "payment"
}
```

如果这些字段缺失，图谱就只是“能画”，还不能“能审”。

## 稳定 ID 约定

推荐：

```
file:<path>
class:<SimpleName>
method:<Class>#<method>
test:<Class>#<method>
```

要求：

1. 同一实体在采集、图谱、影响面、上下文包中 ID 一致
2. 重命名时显式迁移 ID 映射，而不是静默生成新 ID
3. 低置信解析不得覆盖高置信 ID

`PR-42` 变更实体 `method:DiscountPolicy#apply` 必须与图谱、报告全文一致。

代码图谱不是另一种画法，而是软件理解的数据层合同。节点、边、属性一旦约定不稳，UI、影响面、Agent 工具和验证报告会各自发明一套 ID，最后数字对不上。教学上我们用 JSON 讲清合同；生产上你可以换 SQLite 或图数据库，但合同本身不应推倒重来。

请把“五条金标查询”当成模型验收，而不是附录练习。若 `find_callers(apply)` 和 `related_tests(apply)` 都不能稳定回答，图谱再大也只是库存节点，不是理解系统。

## 局限

* 模型过粗会丢关键语义，过细会难维护
* ID 稳定性决定演进分析能否成立
* 查询性能与增量更新需要工程投入

## 小结

1. 代码图谱用节点/边/属性统一软件事实。
2. 最小模型即可支撑影响面与 Agent 查询。
3. 查询设计应先于可视化炫技。
4. 存储选择服务可复现，而不是先追求规模。

## 查询体验的最低标准

图谱是否成功，不看节点数，而看能否在 3 次查询内回答：

1. 这个符号在哪？
2. 谁调用它？
3. 哪些测试锁住它？

对 `DiscountPolicy.apply`，金标答案应稳定可复现。若三次查询仍要靠全文搜索碰运气，说明模型或索引未达标。

## 工作示例：五个金标查询

| 查询                                 | 期望                                   |
| ---------------------------------- | ------------------------------------ |
| find\_symbol(DiscountPolicy.apply) | method 节点 + 文件行号                     |
| find\_callers(apply)               | calculateTotal                       |
| find\_callees(createOrder)         | calculateTotal, charge, save         |
| related\_tests(apply)              | PricingServiceTest, OrderServiceTest |
| architecture\_rules(pricing)       | pricing-no-payment = pass            |

把这五条做成自动化契约测试，实践项目就不会“看起来有图、却不可用”。

## 常见问题：代码图谱模型

### 必须上图数据库吗？

教学与早期不必；模型正确优先。

### 边太多怎么办？

分层、过滤、任务子图，而不是一次画完。

### 如何防止假精确？

低置信与 unresolved 必须保留。

## 本章检查清单

1. 节点/边/属性是否完整
2. 是否有证据字段
3. 金标查询是否可过
4. 存储取舍是否说明

## 关键要点复盘

围绕「代码图谱：节点、边与属性」，读者离开本章前应能做到：

1. 写出最小节点/边/属性 schema
2. 完成 5 条金标查询
3. 解释稳定 ID 约定
4. 说明 JSON/SQLite/图库取舍
5. 衔接到证据可视化

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 练习

1. 为 `mini-shop` 写出 5 个查询及其预期结果。
2. 设计 `calls` 边的属性：source/confidence/evidence。
3. 比较 JSON 与 SQLite 在教学原型中的优劣。

## 本章导航

* 上一章：[变更分析：系统是如何演进的](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/change-analysis)
* 下一章：[可视化表达：从图到证据](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/visualization-as-evidence)
* 相关章：[变更影响分析与验证](/di-si-pian-san-ge-he-xin-gong-cheng-chang-jing/change-impact-verification)；[构建代码图谱](/di-liu-pian-shi-jian-xiang-mu/build-code-graph)

## 延伸阅读与参考资料

* [Neo4j data modeling](https://neo4j.com/docs/getting-started/data-modeling/)：图建模基础。资料卡：`../docs/research-cards/rc-neo4j-modeling.md`
* [SQLite docs](https://www.sqlite.org/docs.html)：本地可查询存储。资料卡：`../docs/research-cards/rc-sqlite.md`
* [Joern Code Property Graph](https://docs.joern.io/code-property-graph/)：代码属性图概念。
* [Graph Data models overview (academic/engineering surveys)](https://neo4j.com/blog/)：图模型取舍补充阅读。
* [LSP](https://microsoft.github.io/language-server-protocol/)：符号索引与查询能力对照。资料卡：`../docs/research-cards/rc-lsp.md`
* 本书样例：[`examples/mini-shop/artifacts/code-graph.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/code-graph.json)。


# 可视化表达：从图到证据

## 本章要解决的问题

怎样让可视化成为可审计证据，而不是装饰性图表？

## 读者读完应获得什么

1. 能定义“证据型可视化”的标准。
2. 能把图、路径、表格、报告组合成证据包。
3. 能说明 AI 输出为何必须可回跳事实层。

## 本章不讲什么

* 不教授设计美学教程。
* 不比较所有前端可视化库。

***

代码可视化的失败模式很常见：图很漂亮，但无法回答“所以呢”。证据型可视化要求每个视觉元素都能追溯到数据，并能支持决策。

## 证据标准

一条可视化结论应可检查：

1. **来源**：来自静态/动态/变更哪一层
2. **定位**：对应哪个文件/符号/行号
3. **路径**：如何从问题走到该节点
4. **置信度**：确定还是候选
5. **动作**：建议测试、Review 关注点或回滚条件

## 表达组合

| 表达   | 适合           |
| ---- | ------------ |
| 子图   | 局部关系探索       |
| 路径列表 | 影响链解释        |
| 表格   | 测试、风险、规则     |
| 报告   | PR/Agent 交付物 |
| 查询轨迹 | AI 审计        |

`PR-42` 的证据包不应只有一张调用图，而应包含：

* 变更实体表
* 影响路径
* 相关测试表
* 风险说明
* 查询轨迹

见 [`examples/mini-shop/artifacts/verification-report-pr-42.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/verification-report-pr-42.md)。

## 从“看见”到“证明”

```mermaid
flowchart LR
 Q[工程问题] --> Query[图谱查询]
 Query --> Subgraph[相关子图]
 Query --> Paths[路径]
 Query --> Tables[测试/规则表]
 Subgraph --> Evidence[证据包]
 Paths --> Evidence
 Tables --> Evidence
 Evidence --> Decision[合并/修改/补测/回滚]
```

![从查询到证据包](/files/epcnadw1GD8gk810dMbW)

## 对 AI 输出的要求

模型可以说“可能影响订单总价”，但系统应附上：

```
path: apply -> calculateTotal -> createOrder -> create
tests: PricingServiceTest, OrderServiceTest
rule_check: pricing-no-payment = pass
```

否则 Reviewer 只能选择相信或放弃，无法审计。

## 设计原则

1. 默认展示任务相关子图，不丢全库大图
2. 节点可点击回源码
3. 边显示来源与置信度
4. 先摘要后下钻
5. 报告与图共享同一查询结果

图可以是插图，也可以是证据。差别在于：读者能否从一张图回到实体 ID、源码位置、置信度与查询轨迹，并据此做合并决策。没有这些，颜色再醒目也只是装饰；有了这些，哪怕只是路径列表加测试表，也比全仓力导向大图更像 Review 材料。

本章的七步法是为了对抗“先画图再找故事”的习惯。正确顺序永远是：先有主张，再绑实体，再选最小表达。`PR-42` 的三件套（路径、测试、规则）就是这个顺序的最小完备例。

## 局限

* 证据链过长会淹没重点
* 低置信度边展示不当会造成误导
* 需要产品化的信息层级，而不是一次画完

## 小结

1. 可视化的目标是证据，不是装饰。
2. 图、路径、表、报告应组成可审计证据包。
3. AI 结论必须回跳到图谱事实。
4. 好的表达服务于决策动作。

## 证据包模板（可直接复用）

```
# Evidence Pack
Claim: ...
Entities: ...
Paths: ...
Tests: ...
Rules: ...
Confidence: ...
Query Trace: ...
Suggested Action: ...
```

AI 生成的自然语言说明只能作为 `Claim` 的草稿，不能替换后六项。

## 工作示例：同一结论的两种呈现

弱呈现：

> 这张图显示订单和定价有关系，所以可能有风险。

强呈现：

> 变更实体 `DiscountPolicy.apply`；影响路径 `apply -> calculateTotal -> createOrder -> create`；相关测试 2 个将失败；架构规则通过；查询轨迹 4 步可回放。

出版级终稿要求全书默认使用强呈现：每个重要视觉结论都能改写成强呈现段落。

## 常见问题：证据可视化

### 为什么不直接给最大图？

全图不可决策，证据需要裁剪与解释。

### 颜色编码可以使用吗？

可以，但必须有图例，并服务信息而非装饰。

### AI 插画能当证据吗？

不能。证据必须可回跳数据。

## 本章检查清单

1. 结论能否改写成强呈现
2. 是否有来源与置信度
3. 是否可回源码
4. 是否服务明确动作

## 关键要点复盘

围绕「可视化表达：从图到证据」，读者离开本章前应能做到：

1. 陈述证据七步法
2. 用 PR-42 组装路径+测试+规则三件套
3. 拒绝无 ID/无轨迹的插图
4. 说明颜色与 AI 插画的边界
5. 衔接到工程场景篇

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 证据图判定标准

一张图要成为证据，必须同时满足：

1. **可追溯**：节点/边能回到源码或产物 ID
2. **可复现**：给定同一输入可再生成
3. **有任务边界**：说明查询条件/过滤
4. **有置信度**：低置信不可画成实线“事实”

反例：无过滤的全仓力导向图、无来源标签的调用箭头、与报告数字不一致的截图。

## PR-42 证据三件套

1. 影响路径图：`apply -> calculateTotal -> createOrder -> create`
2. 测试表：两测需更新断言
3. 规则结果：`pricing-no-payment = pass`

三者缺一，就从“证据”退回“插图”。

## 如何把结论做成证据（操作步骤）

1. **锁定主张**：先写一句话结论（例如：`PR-42` 会改变 VIP 订单总价并影响支付入参）。
2. **绑定实体 ID**：把结论落到 `method:DiscountPolicy#apply` 等稳定 ID，而不是“某个折扣文件”。
3. **选择最少表达**：路径图 + 测试表 + 规则结果；默认不渲染全仓大图。
4. **标注来源与置信度**：边/结论标明 static/dynamic 与 high/medium/low。
5. **提供回跳**：每个关键节点可定位文件与行号，或指向 artifacts。
6. **保留查询轨迹**：记录 `find_symbol` / `find_callers` / `related_tests` 等步骤，使结论可复现。
7. **分级展示**：阻断/重要/提示分层，避免证据过载。

```
claim
 -> entities
 -> minimal views (path/table/rule)
 -> confidence + source
 -> source jump
 -> query_trace
 -> reviewer decision
```

这套步骤是方法，不只是版式建议。缺步骤 2/4/6 的图，通常只能算插图。

## 练习

1. 把 `verification-report-pr-42.md` 拆成“图/路径/表/轨迹”四类证据。
2. 指出一张“很好看但不可审计”的图可能缺少哪些字段。
3. 为 AI 结论设计必须附带的最小证据包字段。

## 本章导航

* 上一章：[代码图谱：节点、边与属性](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/code-graph-model)
* 下一章：[代码库理解与上下文构建](/di-si-pian-san-ge-he-xin-gong-cheng-chang-jing/codebase-understanding)
* 相关章：[变更影响分析与验证](/di-si-pian-san-ge-he-xin-gong-cheng-chang-jing/change-impact-verification)；[构建代码图谱](/di-liu-pian-shi-jian-xiang-mu/build-code-graph)

## 延伸阅读与参考资料

* [Nielsen Norman Group: Minimize Cognitive Load](https://www.nngroup.com/articles/minimize-cognitive-load/)：信息呈现与认知负荷。
* [OpenTelemetry visualization of traces](https://opentelemetry.io/docs/concepts/signals/traces/)：路径可视化直觉。
* [SARIF](https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html)：机器可读分析结果交换。资料卡：`../docs/research-cards/rc-sarif.md`
* [GitHub PR checks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/about-status-checks)：证据进入工作流的位置。
* [D3 graph interaction patterns](https://d3js.org/)：交互探索参考（实现可选）。
* 本书样例：[`examples/mini-shop/artifacts/verification-report-pr-42.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/verification-report-pr-42.md)。


# 第四篇：三个核心工程场景


# 代码库理解与上下文构建

## 本章要解决的问题

面对陌生代码库，如何系统构建上下文，而不是盲目搜索？

## 读者读完应获得什么

1. 能按入口、模块、调用链、测试、Owner 分层建立理解。
2. 能用代码图谱加速“这功能怎么走”的问题。
3. 能为人和 Agent 输出可复用的上下文摘要。

## 本章不讲什么

* 不讲具体业务域知识学习法。
* 不承诺自动生成完美架构文档。

***

代码库理解是所有后续场景的基础。无论是排查问题、做变更，还是给 Agent 派任务，第一步都是构建正确上下文。

## 理解任务的分层

```mermaid
flowchart TB
 Q[问题] --> L1[入口与边界]
 L1 --> L2[模块与依赖]
 L2 --> L3[关键调用链]
 L3 --> L4[测试与运行证据]
 L4 --> L5[Owner 与演进]
```

| 层级  | 问题     | mini-shop 例子                                     |
| --- | ------ | ------------------------------------------------ |
| 入口  | 从哪里进来  | `OrderController.create`                         |
| 模块  | 责任如何切分 | order / pricing / payment                        |
| 调用链 | 关键路径   | create -> createOrder -> calculateTotal -> apply |
| 测试  | 如何验证   | Order/Pricing tests                              |
| 演进  | 最近如何变  | PR-42 折扣调整                                       |

## 从问题到查询

不要先“把仓库读完”。先把问题翻译成查询：

1. 功能入口是什么？
2. 核心实体/服务是什么？
3. 写路径与读路径分别经过谁？
4. 哪些测试锁定行为？
5. 有哪些架构规则不能破？

对“VIP 订单如何计价”：

```
find_symbol(OrderController.create)
find_callees(OrderService.createOrder)
find_path(createOrder, DiscountPolicy.apply)
related_tests(calculateTotal)
```

## 上下文摘要模板

给人与 Agent 共用的最小摘要：

```
# 功能：VIP 订单计价
入口：OrderController.create
核心路径：createOrder -> calculateTotal -> apply
关键不变量：VIP 总价 = quantity * unitPrice * 0.85
测试：PricingServiceTest, OrderServiceTest
规则：pricing 不依赖 payment
```

这比丢给模型 20 个无关文件更有效。

## 可视化怎么帮

* 模块依赖图：先看边界
* 调用子图：只展开任务相关路径
* 测试覆盖视图：看哪些行为被锁住
* 热点图：避免先钻冷代码

## 交接与 onboarding

代码库理解系统可以把“老人经验”沉淀为：

* 入口目录
* 标准查询
* 架构规则
* 常见变更检查单

新人与 Agent 都从同一事实层开始。

## 理解是可交接的工作产品

“我大概看懂了”不能进入团队流程。代码库理解的产出必须是可交接的：入口列表、主路径、不变量、测试锁、规则与未知点。只有这样，下一个人或 Agent 才能在同一事实层上继续，而不是重新从搜索框开始。

这也是为什么本章强调 30 分钟流程和摘要模板——它们不是形式主义，而是把个人阅读变成组织资产。

## 局限

* 缺少运行时数据时，理解偏静态
* 业务语义仍需领域补充
* 自动摘要可能过时，需与变更分析联动刷新

如果只能带走一个习惯，请带走这个：每次理解代码库都留下一页上下文摘要。它比“我看过了”更可验证，也比直接让 Agent 开改更安全。摘要里的未知点同样宝贵——它们告诉下一步该查图还是该问领域专家。

## 小结

1. 代码库理解是分层构建上下文，不是随机阅读。
2. 先问题后查询，再决定看哪些子图。
3. 上下文摘要应同时服务人和 Agent。
4. 图谱让理解过程可重复、可交接。

## 上下文构建操作手册（可复用）

面对陌生仓库，建议固定 30 分钟流程：

1. **定位入口**（5 分钟） 搜索 Controller/router/main，确认外部入口集合。
2. **画模块边界**（5 分钟） 先看目录与依赖方向，不先看算法细节。
3. **抽一条主路径**（10 分钟） 选一个代表用例，沿着调用走到数据/外部依赖。
4. **锁测试**（5 分钟） 找到表征该行为的测试，记录断言。
5. **写上下文摘要**（5 分钟） 产出可交给同事或 Agent 的一页纸。

把这五步工具化后，就接近“代码库理解系统”的最小产品形态。

## mini-shop 示例摘要

```
功能：VIP 订单计价
入口：OrderController.create
主路径：createOrder -> calculateTotal -> apply
支付副作用：createOrder -> charge(total)
不变量：VIP total = qty * unitPrice * discount
测试：PricingServiceTest / OrderServiceTest
规则：pricing 不依赖 payment
```

## 工作示例：Issue 到上下文包

Issue：`VIP 用户投诉折扣不对`

查询序列：

1. 搜索关键字 VIP/discount → `DiscountPolicy`
2. find\_callers(apply) → calculateTotal / createOrder
3. related\_tests → 两测
4. 生成上下文摘要交给人或 Agent

30 分钟内应能定位，而不是在 payment 与 order 目录来回猜。

## 关键要点复盘

围绕「代码库理解与上下文构建」，读者离开本章前应能做到：

1. 复述 30 分钟上下文构建流程
2. 填写上下文摘要模板
3. 对 VIP 计价问题给出查询序列
4. 指出只搜关键字的失败
5. 衔接到变更影响分析

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 上下文摘要模板（人/Agent 共用）

```markdown
# Context Brief: <question>
## Entry points
- ...
## Primary path
- ...
## Key symbols
- id / file / why relevant
## Invariants
- ...
## Tests locking behavior
- ...
## Architecture rules
- ...
## Unknowns / low-confidence edges
- ...
## Suggested next queries
1. ...
2. ...
```

把该模板填完，才算“理解了这段代码”，而不是“读过几个文件”。

## 失败模式

1. **从细节开始**：先抠算法实现，却不知道入口与模块边界。
2. **只搜关键字**：命中日志字符串，漏掉真实调用链。
3. **不记测试**：改完无法证明行为。
4. **给 Agent 一大段无关源码**：噪音压过结构事实。

## 练习

1. 针对“VIP 订单如何计价”写出 5 条图谱查询顺序。
2. 生成一份给人与 Agent 共用的上下文摘要（10 行内）。
3. 说明为何“先通读仓库”通常不是最优策略。

## 常见问题：代码库理解

### 和新手 onboarding 文档什么关系？

文档给意图，图谱给可验证事实；二者互补。

### 30 分钟流程可以跳过测试吗？

不建议。没有表征测试，后续改造缺少护栏。

## 本章检查清单

1. 是否完成入口→路径→测试→摘要
2. 是否使用上下文摘要模板
3. 是否避免只搜关键字

## 本章导航

* 上一章：[可视化表达：从图到证据](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/visualization-as-evidence)
* 下一章：[变更影响分析与验证](/di-si-pian-san-ge-he-xin-gong-cheng-chang-jing/change-impact-verification)
* 相关章：[AI 生成代码的 Review 证据层](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/ai-code-review-evidence)；[构建变更影响分析](/di-liu-pian-shi-jian-xiang-mu/build-change-impact-analysis)

## 延伸阅读与参考资料

* [GitHub Copilot: Explore a codebase](https://docs.github.com/en/copilot/tutorials/explore-a-codebase)。资料卡：`../docs/research-cards/rc-github-copilot-explore.md`
* [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/)。资料卡：`../docs/research-cards/rc-backstage-catalog.md`
* [Sourcegraph code search docs](https://docs.sourcegraph.com/)：大规模代码导航参考。
* [LSP](https://microsoft.github.io/language-server-protocol/)：符号级导航能力。资料卡：`../docs/research-cards/rc-lsp.md`
* [SWE-bench](https://github.com/swe-bench/SWE-bench)：仓库级任务难度背景。资料卡：`../docs/research-cards/rc-swe-bench.md`
* 本书案例：[`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)。


# 变更影响分析与验证

## 本章要解决的问题

如何从一次 Diff 推导影响范围，并形成可进入 PR 的验证策略？

## 读者读完应获得什么

1. 能把行级 Diff 映射为代码实体变更。
2. 能沿调用图做反向追踪，并关联测试与风险分级。
3. 能输出一份可审计的影响面报告，并说明它在 PR 流程中的位置。

## 本章不讲什么

* 不承诺零误报的完美影响面。
* 不展开所有测试选择算法细节。
* 不依赖真实公司仓库。

***

行级 Diff 告诉你“哪些行变了”，工程决策需要的是“可能影响什么”。变更影响分析的任务，就是把 Diff 转成影响路径、相关测试和风险说明。

本章以 `mini-shop` 的 `PR-42` 为完整例子：把 VIP 折扣从 `0.9` 调整为 `0.85`。

```mermaid
flowchart LR
 Diff[Git Diff] --> Entities[变更实体]
 Entities --> Callers[反向调用链]
 Callers --> Entries[入口/资源]
 Entities --> Tests[相关测试]
 Callers --> Tests
 Entries --> Risk[风险分级]
 Tests --> Risk
 Risk --> Report[影响面报告]
 Report --> PR[PR Review / CI]
```

![PR-42 影响路径（精确技术图）](/files/GZYMw2iw0sD2azPqa8BR)

> 后续 AI 配图备注：可生成“PR 页面中的影响面分析报告”界面 mockup，突出变更实体、影响路径、建议测试和风险标签。

## 跟做剧本：读完 PR-42 的 20 分钟

把下面步骤当作本章主线，后文概念都是在解释这些步骤为何必要。

1. **只看 diff（2 分钟）**\
   打开 `examples/mini-shop/artifacts/pr-42.diff`。你只知道一行数字变了。此时还不能回答：谁调用它？支付会不会变？哪条测试会红？
2. **映射变更实体（3 分钟）**\
   把 hunk 映射到 `method:DiscountPolicy#apply`，而不是停在文件名。实体 ID 是后续一切查询的种子。
3. **反向路径（5 分钟）**\
   从图谱得到： `apply -> calculateTotal -> createOrder -> create`\
   并意识到 `charge(total)` 会消费新的总价，即使 diff 没碰 payment 文件。
4. **相关测试（5 分钟）**\
   定位 `PricingServiceTest` / `OrderServiceTest` 中 `180.0` 断言，标记为“需更新到 170.0”，而不是“测试全绿所以安全”。
5. **风险与动作（5 分钟）**\
   风险 medium：金额语义变化 + 测试过期 + 入口路径受影响。\
   动作：更新断言、跑相关测试、在 PR 附路径与轨迹。

完整 JSON 金标见 `examples/mini-shop/artifacts/impact-report-pr-42.json`。后文各节是在把上述五步工程化。

## 为什么 Diff 不够

`PR-42` 的实质变更只有一行：

```diff
- return amount * 0.9;
+ return amount * 0.85;
```

如果只看 Diff：

* 不知道它属于 `DiscountPolicy.apply`
* 不知道 `PricingService.calculateTotal` 会用到它
* 不知道订单入口和支付金额间接受影响
* 不知道两份测试仍断言 `180.0`

影响面分析要补的，正是这些工程语义。

## 从 Diff 到变更实体

步骤：

1. 解析 Diff，得到文件与行号
2. 用源码索引定位行号落入的方法/类
3. 生成变更实体列表

结果：

```json
{
 "changed_entities": [
 {
 "id": "method:DiscountPolicy#apply",
 "file": "src/main/java/com/minishop/pricing/DiscountPolicy.java",
 "lines": [6],
 "change_type": "modified"
 }
 ]
}
```

没有实体映射，就无法查询调用方，也无法稳定跟踪历史。

## 调用链反向追踪

从变更方法出发，沿 `calls` 边反向扩展：

```
DiscountPolicy.apply
 <- PricingService.calculateTotal
 <- OrderService.createOrder
 <- OrderController.create
```

同时记录同层副作用：

```
OrderService.createOrder -> PaymentClient.charge
```

因此金额字面量变化会传导到支付入参。

完整图数据见 [`examples/mini-shop/artifacts/code-graph.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/code-graph.json)。

## 依赖传播和资源影响

除了调用方，还要看：

* 模块依赖是否变化
* 配置/资源是否变化
* 对外 API 契约是否变化

`PR-42` 中：

* 模块依赖未变
* 对外方法签名未变
* 行为契约变了：VIP 订单总价从 `180` 变为 `170`（数量 2、单价 100）

行为契约变化必须进入报告，否则 Reviewer 会误判为“纯内部常量”。

## 关联测试与覆盖率

相关测试可通过以下信号发现：

1. 直接 `tests` 边
2. 测试代码调用了变更方法或其调用方
3. 覆盖率显示测试执行了变更行

`mini-shop` 中至少应关联：

| 测试                                                  | 原因            |
| --------------------------------------------------- | ------------- |
| `PricingServiceTest.shouldApplyVipDiscount`         | 直接验证 VIP 折扣总价 |
| `OrderServiceTest.shouldCreateVipOrderWithDiscount` | 经过订单链路验证总价    |

两者当前都断言 `180.0`，在折扣改为 `0.85` 后应更新为 `170.0`。

## 风险分级

可用一个可解释的规则集，而不是黑盒分数：

| 信号             | PR-42                          |
| -------------- | ------------------------------ |
| 是否在核心业务链路      | 是（下单计价）                        |
| 是否影响金额/权限等敏感语义 | 是                              |
| 相关测试是否存在       | 是，但会失败需更新                      |
| 是否跨模块传播        | 是（pricing -> order/payment 入参） |
| 架构规则是否破坏       | 否                              |

综合等级：**中**。 单行修改不等于低风险。

## 影响面报告设计

最小报告字段：

```
pr / title
changed_entities
impact_paths
related_tests
risk.level + reasons
recommended_actions
query_trace
```

`PR-42` 样例：

* JSON：[`examples/mini-shop/artifacts/impact-report-pr-42.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/impact-report-pr-42.json)
* Markdown：[`examples/mini-shop/artifacts/verification-report-pr-42.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/verification-report-pr-42.md)

报告示例片段：

```markdown
## 影响路径
apply -> calculateTotal -> createOrder -> create

## 建议
1. 更新定价与订单测试期望值
2. 运行 pricing/order 测试
3. Review 支付金额是否随总价变化
```

## 在 PR 流程中的位置

建议接入点：

1. **开发本地**：提交前预览影响面
2. **CI**：对 PR Diff 自动生成报告注释
3. **Review**：Reviewer 先看路径/测试/风险，再看代码
4. **合并后**：必要时结合线上指标观察

它不替代测试，而是帮助决定“测什么、看什么、问什么”。

## AI 时代的影响面验证

当修改由 Agent 生成时，影响面报告还要回答：

1. Agent 是否改到了声称的实体
2. 是否漏掉相关测试更新
3. 查询轨迹是否支持其上下文选择
4. 是否违反架构规则

也就是说，影响面分析既是给人类的，也是给 AI 变更的验证层。

## 方法依据

影响面分析并不是“凭感觉扩文件”，其工程基础通常包括：

1. **变更定位**：由版本控制 diff 提供行级变化（见 Git 文档）。
2. **实体映射**：把行映射到方法/类等可索引对象。
3. **依赖传播**：沿调用/依赖关系扩展候选影响集。
4. **测试选择**：按变更选择相关测试（Test Impact Analysis 思路）。
5. **风险解释**：用可检查信号解释为何是中/高风险，而不是黑盒分数。

因此，报告里的每一条路径和测试建议，都应能回跳到图谱边或 diff 证据。

## 局限

* 静态反向调用可能漏掉反射/配置入口
* 测试关联可能不完整
* 风险规则需要团队校准
* 不能证明“无影响”，只能提供证据与候选范围

## 小结

1. Diff 必须先映射到代码实体。
2. 影响面 = 变更实体 + 反向路径 + 测试 + 风险。
3. 报告应可进入 PR，并可审计。
4. 对 AI 修改，影响面是关键验证证据层。

## 关键要点复盘

围绕本章，读者离开前应能做到：

1. 从 diff 走到影响面报告字段
2. 解释 PR-42 风险为何 medium
3. 列出相关测试与更新断言
4. 说明 AI 时代影响面在 PR 中的位置
5. 衔接到架构与遗留改造

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 练习

1. 基于 `pr-42.diff` 手工写出变更实体、影响路径、相关测试、风险等级。
2. 解释为何 `PaymentClient` 未改文件仍可能受影响。
3. 若删除 `OrderServiceTest`，风险等级与建议动作如何变化？
4. 把影响面报告改写成 PR 评论的 8 行摘要。

## 常见问题：影响面

### Diff 绿了是不是就没影响？

否。影响在调用路径与测试，不只在 diff 行。

### 风险 medium 如何决策？

金额语义变化需测更新与人工确认业务值。

## 本章检查清单

1. 变更实体是否方法级
2. 路径/测试/规则是否齐全
3. 报告是否可进入 PR

## 本章导航

* 上一章：[代码库理解与上下文构建](/di-si-pian-san-ge-he-xin-gong-cheng-chang-jing/codebase-understanding)
* 下一章：[架构理解与遗留系统改造](/di-si-pian-san-ge-he-xin-gong-cheng-chang-jing/architecture-and-legacy-modernization)
* 相关章：[AI 生成代码的 Review 证据层](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/ai-code-review-evidence)；[构建变更影响分析](/di-liu-pian-shi-jian-xiang-mu/build-change-impact-analysis)

## 延伸阅读与参考资料

* [Git diff](https://git-scm.com/docs/git-diff)。资料卡：`../docs/research-cards/rc-git-diff.md`
* [Test Impact Analysis](https://learn.microsoft.com/en-us/azure/devops/pipelines/test/test-impact-analysis)。资料卡：`../docs/research-cards/rc-test-impact.md`
* [GitHub code scanning / checks](https://docs.github.com/en/code-security)：PR 中的自动检查位。
* [Codecov docs](https://docs.codecov.com/docs)：覆盖与 PR 反馈参考。
* [CodeQL](https://codeql.github.com/docs/)：深度静态证据补充。
* [Launchable / TIA industry practice](https://www.launchableinc.com/)：测试选择工程化参考（产品文档，次级）。
* 本书样例：[`impact-report-pr-42.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/impact-report-pr-42.json)、[`verification-report-pr-42.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/verification-report-pr-42.md)。


# 架构理解与遗留系统改造

## 本章要解决的问题

如何用代码事实理解架构边界，并安全推进遗留系统改造？

## 读者读完应获得什么

1. 能区分“宣称架构”和“事实架构”。
2. 能用依赖/调用/变更耦合发现边界侵蚀。
3. 能把改造拆成可验证的小步，并保留对比证据。

## 本章不讲什么

* 不提供某行业遗留系统迁移剧本全集。
* 不鼓吹一次性重写。

***

架构图常常描述系统“应该怎样”，代码图谱和变更历史描述系统“实际怎样”。遗留改造要先对齐这两层。

遗留系统真正难的地方，往往不是“不会写新代码”，而是不知道旧边界在哪里、哪些依赖是历史偶然、哪些测试其实只是端到端护身符。改造失败很少死在语法上，更多死在：改完后没人能证明“系统还是原来那个系统”。

因此本章把架构理解当成**地图工作**，而不是画一张更漂亮的框线图。地图要同时回答三件事：现在实际怎么连、业务主路径怎么走、哪些规则绝不能破。`mini-shop` 虽小，但已经足够演示“README 写分层、代码却偷偷跨层”的经典张力。

## 宣称架构 vs 事实架构

以 `mini-shop` 的简化架构为例：

```
order -> pricing
order -> payment
pricing -/-> payment (禁止)
```

若某次改造让 `pricing` 直接调用 `payment` 查费率，事实架构就破坏了分层，即使 README 仍写“pricing 纯计算”。

```mermaid
flowchart LR
 Order --> Pricing
 Order --> Payment
 Pricing -. 禁止 .-> Payment
```

## 发现边界问题的信号

1. 模块依赖违规
2. 跨层调用增多
3. 变更耦合显示无关模块总被一起改
4. 入口过多、公共工具包膨胀
5. 测试只能做端到端，无法局部验证

## 改造前地图

改造前至少准备：

| 地图    | 内容       |
| ----- | -------- |
| 模块依赖图 | 当前方向与违规  |
| 关键路径  | 业务主入口调用链 |
| 测试地图  | 哪些行为被锁住  |
| 热点图   | 高风险改动区   |
| 规则集   | 允许/禁止依赖  |

没有地图就开改，等于在迷雾中拆迁。

## 为什么大爆炸重写会反复失败

大爆炸重写的诱惑很明确：旧代码脏、新框架香、一次换掉似乎更痛快。但在缺少事实架构与表征测试时，团队会同时失去三样东西：

1. **对照系**：不知道新系统是否保持了旧行为
2. **回滚点**：出问题只能继续硬推
3. **局部验证**：任何改动都要靠全链路碰运气

Strangler 思路不是保守，而是把风险切成可证明的小步。对 AI 尤其重要：Agent 擅长在允许范围内做机械改动，却很不擅长在无地图时做边界判断。

## 小步改造策略

以“把折扣策略独立配置化”为例：

1. 先加表征测试锁住 VIP/非 VIP 价格
2. 抽取配置点，不改外部行为
3. 对比调用图：对外路径应保持
4. 再切换实现
5. 输出迁移前后依赖与测试对比报告

AI 可以辅助改代码，但每一步都要有行为保持证据。

## 验证清单

* 架构规则是否仍通过
* 关键路径是否保持
* 相关测试是否全绿
* 性能/错误率是否回归（如有动态证据）
* 回滚点是否明确

## 和 AI 的协作方式

适合交给 Agent 的：

* 样板式移动/重命名
* 补测试骨架
* 生成依赖差异报告

不适合无约束交给 Agent 的：

* 无测试的大爆炸重写
* 边界未定义的跨模块重构

## 局限

* 事实架构受分析精度限制
* 业务语义与组织权力结构不在图中
* 改造成功取决于节奏与验证，不只是工具

遗留改造最终是治理问题：谁有权改边界、何种违规可临时豁免、豁免如何过期。图谱与规则检查提供事实，ADR 与发布策略提供决策记录。没有治理，工具只会反复报告同一类跨层依赖，然后被大家“先合并再说”。

## 小结

1. 先用事实架构对齐真实边界。
2. 改造前需要地图与规则，而不是直接开改。
3. 小步 + 对比证据是安全默认策略。
4. AI 适合加速受约束改造，不适合替代架构判断。

## 改造看板最小字段

| 字段                      | 说明               |
| ----------------------- | ---------------- |
| target\_boundary        | 目标模块边界           |
| current\_violations     | 当前违规依赖           |
| characterization\_tests | 表征测试集合           |
| step\_plan              | 小步序列             |
| rollback                | 回滚点              |
| exit\_metrics           | 退出标准（违规=0/关键路径绿） |

没有看板的“AI 重构”，通常只是把混乱从一个目录搬到另一个目录。

## 工作示例：禁止依赖的守护测试

可用 ArchUnit 风格伪代码表达：

```
no classes in package "..pricing.."
 should depend on classes in "..payment.."
```

把它纳入 CI 后，AI 重构若引入反向依赖，会在证据层直接失败。遗留改造的“地图 + 守护”比“一次性画目标架构图”更重要。

## 常见问题：架构与改造

### 目标架构图画完是否算完成？

否。要有事实架构、守护规则与小步验证。

### AI 适合哪类改造？

机械且边界清晰的小步；不适合无测试大爆炸。

### 如何防止越改越乱？

看板 + 规则 + 表征测试 + 回滚点。

## 本章检查清单

1. 宣称vs事实
2. 规则可执行
3. 小步计划
4. 退出指标

## 关键要点复盘

围绕「架构理解与遗留系统改造」，读者离开本章前应能做到：

1. 区分事实架构与宣称架构
2. 用 pricing-no-payment 做规则检查
3. 说明 Strangler 小步与大爆炸差异
4. 把规则接入 AI 改造护栏
5. 衔接到 AI 时代动机章

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 架构规则与改造步的耦合

改造每一步都要能回答：

1. 依赖方向是否仍满足规则？
2. 主路径是否仍有表征测试？
3. 新旧实现是否可并存（Strangler）？
4. 回滚点在哪？

`mini-shop` 中的金标规则：

```
pricing must not depend on payment
```

任何“为了方便复用费率”而让 pricing 依赖 payment 的 AI 改动，应在合并前被规则检查拦截。

## 练习

1. 对比 `mini-shop` 的宣称架构与事实架构，写出一条可自动检查的规则。
2. 用 Strangler Fig 思路，把“折扣配置化”拆成 3 个可验证小步。
3. 列出改造前最小地图：依赖、关键路径、测试、规则。

## 本章导航

* 上一章：[变更影响分析与验证](/di-si-pian-san-ge-he-xin-gong-cheng-chang-jing/change-impact-verification)
* 下一章：[为什么 AI 时代更需要代码理解](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/why-code-understanding-matters-in-ai-era)
* 相关章：[AI 生成代码的 Review 证据层](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/ai-code-review-evidence)；[构建变更影响分析](/di-liu-pian-shi-jian-xiang-mu/build-change-impact-analysis)

## 延伸阅读与参考资料

* [Strangler Fig Application](https://martinfowler.com/bliki/StranglerFigApplication.html)。资料卡：`../docs/research-cards/rc-strangler-fig.md`
* [Architecture Decision Records](https://adr.github.io/)。资料卡：`../docs/research-cards/rc-adr.md`
* [ArchUnit](https://www.archunit.org/)：架构规则可执行化。
* [Backstage](https://backstage.io/docs/features/software-catalog/)：服务/Owner 目录。资料卡：`../docs/research-cards/rc-backstage-catalog.md`
* [Fitness Function-driven architecture](https://www.thoughtworks.com/insights/articles/fitness-function-driven-development)：架构守护思路。
* 本书案例：[`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)。


# 第五篇：AI 时代的新应用


# 为什么 AI 时代更需要代码理解

## 本章要解决的问题

AI 让写代码更快之后，为什么代码理解反而更重要？

## 读者读完应获得什么

1. 能说明生成加速与验证压力之间的不对称。
2. 能列出 Agent 修改代码时必需的结构化能力。
3. 能把本书主线重新收束到“理解、约束、验证”。

## 本章不讲什么

* 不争论模型排名。
* 不把 AI 写成万能或无用。

## 本章与邻章边界

* 本章只回答“为什么 AI 时代更需要代码理解”。
* 不展开上下文包字段、图谱查询接口或 Review 报告模板；这些分别见后续章节。

***

AI 编程降低了“写出一段代码”的成本，但没有自动消除：

* 找对位置
* 保持架构边界
* 更新测试
* 证明改动安全

相反，当 Agent 可以跨文件批量修改时，错误也会以更高速度扩散。代码理解因此从“高级团队加分项”变成“AI 工程基础设施”。

可以把今天的研发流程想成两条传送带。一条是生成：补全、多文件编辑、自动开 PR；另一条是理解与验证：读调用链、找测试、审架构、做回归。AI 显著加速了第一条，却没有自动加速第二条。于是组织会看到一种新的“繁荣式过载”——提交很多，但每个人都更忙于解释这些提交到底改了什么。

本书主张的不是放慢 AI，而是给第二条传送带装上结构化事实层：让定位、约束、扩展影响和证明不再完全依赖个人记忆。

## 速度不对称

```mermaid
flowchart LR
 Gen[生成/修改速度上升] --> Gap[不对称扩大]
 Val[理解/验证速度不足] --> Gap
 Gap --> Risk[缺陷、返工、Review 过载]
```

如果生成快、验证慢，团队会陷入：

1. 大量 PR 等待人工理解
2. Reviewer 只能抽样看
3. 回归靠运气被测到

## Agent 失败的典型原因

结合 `mini-shop` 任务“改 VIP 折扣”：

| 失败              | 原因         | 缺什么            |
| --------------- | ---------- | -------------- |
| 只改常量不改测试        | 无相关测试查询    | related\_tests |
| 改到日志文本          | 无 AST/符号定位 | 结构事实           |
| 不知订单/支付受影响      | 无调用图       | 影响面            |
| 无法向 Reviewer 解释 | 无查询轨迹      | 证据层            |

## 一个反直觉的结论

更强的模型并不能替代代码理解基础设施。模型更强时，它更能“看起来合理”地讲故事；如果缺少可回跳的实体、路径和轨迹，Reviewer 反而更难一眼识破问题。证据层的价值，正是把“说服力”从文笔转回可检查事实。

对 `PR-42` 这种一行折扣变更，人类专家靠经验也能猜到要改测试；但当 Agent 一天提 20 个类似 PR 时，靠猜和靠熟人都不可扩展。那时你需要的不是更长的 prompt，而是稳定查询。

## 代码理解提供的四类能力

1. **定位**：改哪里
2. **约束**：不能越哪些边界
3. **扩展**：还要看谁、测谁
4. **证明**：如何验证与审计

这四类能力对应本书的图谱、场景、上下文与报告。

## 对人与对 AI 是同一套事实

不要建设两套系统：

* 给人看图
* 给 AI 另做黑盒检索

而应共享代码图谱：

* 人用可视化与报告
* Agent 用查询接口与上下文包
* Reviewer 用同一证据链审计

## 局限

* 代码理解系统不能自动保证生成代码业务正确。
* 组织流程与责任机制仍是落地关键条件。
* 不同团队的规则与风险阈值需要本地化。

## 小结

1. AI 放大的是修改速度，也放大验证缺口。
2. 代码理解是 AI 工程的基础设施，不是附属展示。
3. 定位、约束、扩展、证明是最小能力集。
4. 人与 AI 应共享同一事实层。

## 组织政策草案（可改编）

1. AI PR 必须附变更实体列表
2. 必须附影响路径或说明为何不适用
3. 相关测试必须被识别并执行
4. 架构规则失败默认阻断
5. 查询轨迹保留不少于 14 天

政策不必一开始就很重，但必须可执行；只靠“请大家 Review 仔细一点”无法对抗生成速度。

## 工作示例：速度不对称的数字直觉

假设：

* Agent 每小时可提 10 个跨文件 PR
* 人工深度 Review 每个需 20 分钟
* 则每小时需要约 3.3 小时 Review 产能

若不引入自动证据层与测试选择，Review 必然崩溃或沦为形式签字。代码理解系统首先是在修复这种产能不对称。

## 常见问题：AI 时代动机

### AI 已经能读仓库，为何还要图谱？

能读不等于能稳定检索结构关系并审计。

### 这是不是反对 AI Coding？

相反，这是让 AI Coding 可进入主干的基础设施。

### 小团队也需要吗？

一旦 AI 批量改码，小团队更需要自动证据，因为 Review 产能更少。

## 本章检查清单

1. 是否承认速度不对称
2. 是否定义 AI PR 最低证据
3. 是否区分生成与验证
4. 是否规划事实层共享给人和 Agent

## 关键要点复盘

围绕「为什么 AI 时代更需要代码理解」，读者离开本章前应能做到：

1. 解释生成速度与 Review 产能不对称
2. 写出 AI PR 最低证据政策
3. 用 PR-42 对比有无理解层的差别
4. 自评团队 L0-L4 成熟度
5. 衔接到 Agent 上下文工程

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 能力成熟度（团队自评）

| 级别 | 特征                    |
| -- | --------------------- |
| L0 | AI 随意改，人工凭感觉 Review   |
| L1 | 有测试门禁，但无影响面           |
| L2 | 有静态影响面与相关测试推荐         |
| L3 | Agent 上下文与轨迹可审计       |
| L4 | 人/CI/Agent 共享事实层并度量返工 |

本书目标是帮助读者从 L0/L1 走向 L2/L3，并理解 L4 的方向。

## 从 PR-42 看“为什么需要理解层”

若无代码理解层，Agent 可能：

1. 用文本替换所有 `0.9`（误伤无关常量）
2. 不更新测试断言
3. 不说明支付金额依赖折后价
4. Reviewer 只能逐文件肉眼扫

有理解层后，最小证据是：

```
changed: method:DiscountPolicy#apply
path: apply -> calculateTotal -> createOrder -> create
tests: PricingServiceTest, OrderServiceTest (assert 180 -> 170)
rules: pricing-no-payment pass
```

同一改动，从“看起来只是一行”变成“可审计的金额语义变更”。

## 团队落地最小包

第一周不必上平台，先规定：

1. AI PR 描述必须贴变更实体
2. 必须贴相关测试命令与结果
3. 跨模块改动必须手写影响路径或自动报告
4. 禁止无轨迹的“全仓自动重构”

这四条就能把大量高风险生成挡在主干之外。

## 练习

1. 列出 Agent 修改 `mini-shop` 折扣时的 4 类失败，并映射到缺失能力。
2. 用 SWE-bench 的仓库级设定，解释为何“单文件生成成功”不等于工程完成。
3. 写一条团队政策：AI PR 合并前必须具备哪些证据。

## 本章导航

* 上一章：[架构理解与遗留系统改造](/di-si-pian-san-ge-he-xin-gong-cheng-chang-jing/architecture-and-legacy-modernization)
* 下一章：[Agent 上下文工程](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/agent-context-engineering)
* 相关章：[给 AI Agent 的查询接口](/di-liu-pian-shi-jian-xiang-mu/query-interface-for-ai-agent)；[AI 修改后的验证报告](/di-liu-pian-shi-jian-xiang-mu/ai-change-verification-report)

## 延伸阅读与参考资料

* [SWE-bench](https://github.com/swe-bench/SWE-bench)。资料卡：`../docs/research-cards/rc-swe-bench.md`
* [GitHub Copilot docs](https://docs.github.com/en/copilot)。
* [Model Context Protocol](https://modelcontextprotocol.io/)。资料卡：`../docs/research-cards/rc-mcp.md`
* [NIST AI Risk Management Framework](https://www.nist.gov/itl/ai-risk-management-framework)：AI 风险治理参考（通用）。
* [OpenAI / vendor tool-use docs 入口](https://platform.openai.com/docs)：工具调用成为 Agent 标配能力的工程背景。
* 本书案例：[`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)。


# Agent 上下文工程

## 本章要解决的问题

如何给 AI Agent 提供正确、充分、可验证的代码上下文，而不是单纯扩大窗口？

## 读者读完应获得什么

1. 能区分“上下文窗口”和“代码理解”。
2. 能设计包含符号、调用方、测试和规则的上下文包。
3. 能记录查询轨迹，使 Agent 行为可审计。

## 本章不讲什么

* 不讨论具体模型供应商的提示词技巧大全。
* 不把向量检索当成唯一上下文方案。

## 本章与邻章边界

* 本章聚焦**改前**：如何构造任务化、可审计的上下文包。
* 图谱工具清单与协议映射详见“代码图谱如何服务 AI Agent”；改后审计详见 Review 证据层。

***

Agent 上下文工程关注如何围绕任务选择、组织和约束信息。如果没有这层工程，Agent 容易变成“会写代码的搜索器”：能读文件、改文件，但不一定知道哪些边界不能跨、哪些测试必须跑。

```mermaid
flowchart TB
 Task[任务/Issue] --> Intent[意图和边界]
 Intent --> Retrieval[语义检索]
 Intent --> GraphQuery[代码图谱查询]
 GraphQuery --> Symbols[符号/调用/测试/规则]
 Retrieval --> Docs[相关文档片段]
 Symbols --> Pack[Agent 上下文包]
 Docs --> Pack
 Pack --> Agent[AI Agent 修改代码]
 Agent --> Evidence[查询轨迹与验证证据]
```

![Agent 上下文包结构（精确技术图）](/files/utO1E5qAtGMqSub1immH)

> 后续 AI 配图备注：可生成“Agent 先查询代码图谱再修改”的流程插画。

## 上下文窗口不等于代码理解

把更多文件塞进提示，并不等于更好理解。有效上下文应满足：

1. **相关**：与任务有明确关系
2. **结构化**：说明符号与依赖，而不只是文本
3. **可验证**：结论能追溯到查询与源码

因此上下文工程 = 任务理解 + 检索 + 图谱查询 + 裁剪 + 证据组织。

## 任务：调整 VIP 折扣

任务描述：

```
将 mini-shop 的 VIP 折扣从 0.9 调整为 0.85，并保证相关测试通过。
```

意图边界：

| 项              | 内容                               |
| -------------- | -------------------------------- |
| in\_scope      | `DiscountPolicy.apply`、相关定价/订单测试 |
| out\_of\_scope | 支付渠道集成、非 VIP 规则重做、无关注架重构         |

先写清边界，再取上下文，可减少 Agent 乱动。

## 相关文件选择

错误做法：全文搜索 `0.9` 或 `calculate`，把日志字符串也当候选。 正确做法：先定位符号，再扩展邻居。

最小相关集合：

1. `DiscountPolicy.java`（修改目标）
2. `PricingService.java`（直接调用方）
3. `PricingServiceTest.java` / `OrderServiceTest.java`（断言依赖）
4. 可选：`OrderService.java`（理解金额如何流向支付）

## 必须查询的图谱问题

1. `find_symbol("DiscountPolicy.apply")`
2. `find_callers(method:DiscountPolicy#apply)`
3. `related_tests(method:DiscountPolicy#apply)`
4. `architecture_rules(module=pricing)`

这些查询的结果应进入上下文包，而不是只留在系统日志里。

## 上下文包结构

完整样例：[`examples/mini-shop/artifacts/agent-context-pack.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/agent-context-pack.json)

```
task
intent.in_scope / out_of_scope
symbols[]
callers[]
related_tests[]
architecture_rules[]
snippets[]
query_trace[]
```

示例：

```json
{
 "task": "将 VIP 折扣从 0.9 调整为 0.85，并保证相关测试通过",
 "symbols": [{"id": "method:DiscountPolicy#apply", "role": "primary_edit_target"}],
 "callers": [
 "method:PricingService#calculateTotal",
 "method:OrderService#createOrder"
 ],
 "related_tests": [
 "test:PricingServiceTest#shouldApplyVipDiscount",
 "test:OrderServiceTest#shouldCreateVipOrderWithDiscount"
 ],
 "architecture_rules": ["pricing 模块不得直接依赖 payment 模块"]
}
```

## 查询轨迹和审计

每次工具调用都应记录：

```
tool name
arguments
result summary
timestamp
```

价值：

* Reviewer 可检查 Agent 是否查过测试
* 失败时可复盘上下文是否缺失
* 可对比“模型声称”和“系统检索到的事实”

对 AI Coding 工具建设者，查询轨迹是产品能力，不是调试边角。

## 与验证闭环衔接

上下文包负责“改前理解”，验证报告负责“改后证明”：

```
上下文包 -> Agent 修改 -> 影响面分析 -> 测试结果 -> 验证报告
```

`PR-42` 验证报告样例见 [`examples/mini-shop/artifacts/verification-report-pr-42.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/verification-report-pr-42.md)。

## 常见失败模式

1. 只给目标文件，不给调用方和测试
2. 用文本相似度替代符号关系
3. 无 out\_of\_scope，导致越改越大
4. 无查询轨迹，Review 只能盲信
5. 把低置信度调用边当确定事实

## 设计原则（可检查）

一个合格上下文包应能通过这些问题：

1. 是否包含**主编辑符号**及其源码位置？
2. 是否包含**直接/关键调用方**，而不只是相似文本？
3. 是否包含**相关测试**？
4. 是否包含**架构规则/范围边界**？
5. 是否包含**查询轨迹**以便审计？

任一题为“否”，Agent 就更像在猜，而不是在受约束地修改。

## 上下文不是“更多 token”

一个常见误区是：只要把仓库塞进更长上下文窗口，Agent 就会变靠谱。实践里恰恰相反——无关文件、生成物、测试夹具和历史注释会淹没真正的种子符号。上下文工程的核心是**裁剪**：用图谱查询决定带什么，用 out\_of\_scope 决定不带什么，用 query\_trace 证明你不是瞎贴。

对 `PR-42`，高质量上下文包几乎总是小的：一个主符号、少量 callers、两个测试、一条架构规则、若干短 snippet。它看起来“少”，却比粘贴整个 `order` 包更安全。

查看金标：`examples/mini-shop/artifacts/agent-context-pack.json`。

## 局限

* 图谱不完整时上下文会偏
* 过严裁剪可能漏掉隐式依赖
* 上下文工程不能替代测试与人工设计审查

## 小结

1. 上下文工程是任务化的信息选择，不是窗口堆料。
2. 符号、调用方、测试、规则是最小必备结构。
3. 上下文包应可序列化、可审计、可复用。
4. 查询轨迹让 Agent 从“会改”变成“可审查地改”。

## 关键要点复盘

围绕本章，读者离开前应能做到：

1. 设计上下文包字段
2. 说明切片规则（seed/include/exclude）
3. 把 query\_trace 写入包
4. 指出全仓粘贴源码的失败
5. 衔接到图谱查询工具

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 练习

1. 为 VIP 折扣任务写 in\_scope / out\_of\_scope。
2. 写出 4 次图谱查询及期望结果，并形成 query\_trace。
3. 比较“只给 DiscountPolicy.java”与完整上下文包的失败风险。
4. 将 `agent-context-pack.json` 改成更短但信息不丢的版本。

## 常见问题：上下文工程

### 上下文窗口更大是否就够？

不够。需要结构化符号、边界与轨迹。

### 要不要把全仓源码塞进 prompt？

不要。按 seed/include/exclude 切片。

## 本章检查清单

1. 上下文包字段是否完整
2. 是否包含 related\_tests 与 rules
3. 是否记录 query\_trace

## 本章导航

* 上一章：[为什么 AI 时代更需要代码理解](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/why-code-understanding-matters-in-ai-era)
* 下一章：[代码图谱如何服务 AI Agent](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/code-graph-for-ai-agent)
* 相关章：[给 AI Agent 的查询接口](/di-liu-pian-shi-jian-xiang-mu/query-interface-for-ai-agent)；[AI 修改后的验证报告](/di-liu-pian-shi-jian-xiang-mu/ai-change-verification-report)

## 延伸阅读与参考资料

* [GitHub Copilot: Explore a codebase](https://docs.github.com/en/copilot/tutorials/explore-a-codebase)。资料卡：`../docs/research-cards/rc-github-copilot-explore.md`
* [Model Context Protocol](https://modelcontextprotocol.io/)。资料卡：`../docs/research-cards/rc-mcp.md`
* [LSP](https://microsoft.github.io/language-server-protocol/)：符号级检索基础。资料卡：`../docs/research-cards/rc-lsp.md`
* [RAG survey / retrieval literature 入口](https://arxiv.org/)（检索 Retrieval-Augmented Generation）：语义检索与结构检索互补。
* [SWE-bench](https://github.com/swe-bench/SWE-bench)：仓库级任务对上下文的要求。资料卡：`../docs/research-cards/rc-swe-bench.md`
* 本书样例：[`examples/mini-shop/artifacts/agent-context-pack.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/agent-context-pack.json)。


# 代码图谱如何服务 AI Agent

## 本章要解决的问题

图谱如何成为 Agent 的上下文压缩、边界约束和审计基础？

## 读者读完应获得什么

1. 能说明图谱查询与纯 RAG 的互补关系。
2. 能设计最小工具集：find\_symbol / callers / impact / tests / rules。
3. 能描述失败模式与降级策略。

## 本章不讲什么

* 不绑定单一 Agent 框架。
* 不把 MCP 当唯一实现。

## 本章与邻章边界

* 本章聚焦**查询与约束**：Agent 通过哪些图谱工具获得结构事实。
* 不重讲上下文包组装细节（见 Agent 上下文工程），也不展开 PR 证据报告模板（见 Review 证据层）。

***

向量检索擅长找“语义相似文本”，代码图谱擅长表达“结构上相关”。Agent 两者都需要。

## 为什么需要图，而不只是 RAG

| 需求      | RAG | 代码图谱 |
| ------- | --- | ---- |
| 找描述相似代码 | 强   | 弱    |
| 找精确调用方  | 弱   | 强    |
| 架构规则    | 弱   | 强    |
| 影响路径    | 弱   | 强    |
| 可审计轨迹   | 中   | 强    |

改折扣时，“VIP 优惠文案”可能语义相似，但结构无关；`DiscountPolicy.apply` 的调用方才是关键。

## 最小工具面

```
find_symbol
find_callers
find_callees
impact_analysis
related_tests
architecture_rules
```

`PR-42` 上的成功路径：

```
find_symbol(apply)
 -> find_callers
 -> related_tests
 -> architecture_rules
 -> 生成补丁
 -> impact_analysis 复核
```

## 上下文压缩

图谱帮助把全库压缩为任务子图：

```
全仓库文件 N
 -> 相关符号与邻居 K (K << N)
 -> 提示中只放 K 的关键片段与结构化摘要
```

压缩的目标不是更短，而是更高密度的正确关系。

## 边界约束

在工具层强制：

* 默认不允许跨 `out_of_scope` 模块写文件
* 破坏 `architecture_rules` 时升级为需确认
* 修改后必须重新查询影响面

这比只在 prompt 里写“请遵守架构”更可靠。

## 失败模式

1. 图谱过期：索引未更新
2. 低置信调用边被当确定
3. 工具太多导致 Agent 乱点
4. 只查不验证，修改后不复核

降级策略：标注不确定、扩大测试范围、请求人工确认。

## Agent 查图调用链

```mermaid
sequenceDiagram
  participant A as Agent
  participant Q as Graph Query API
  participant G as Code Graph
  A->>Q: find_symbol(DiscountPolicy.apply)
  Q->>G: lookup
  G-->>Q: method:DiscountPolicy#apply
  A->>Q: find_callers(id)
  Q-->>A: calculateTotal / createOrder / create
  A->>Q: related_tests(id)
  Q-->>A: PricingServiceTest / OrderServiceTest
  Note over A: 写入 query_trace 与 context pack
```

没有轨迹的查图，等于不可审计的“感觉检索”。

Agent 需要的不是“会聊天的代码搜索”，而是一组稳定、可失败、可追踪的图查询工具。工具契约比模型口才重要：`find_symbol` 返回什么、未知 ID 如何报错、`impact_analysis` 是否附 `trace_id`，直接决定后续步骤能否被审计。

把图谱查询做成工具，还有一个组织收益：人和 Agent 共用同一查询层。Reviewer 看到的路径，应能从 Agent 的 `query_trace` 复现。做不到这一点，你就仍在运行两套互相猜疑的理解系统。

## 局限

* 图谱质量决定工具上限，过期索引会误导 Agent。
* 工具集不能消除提示注入与错误任务理解。
* 对动态行为仍需测试与运行时证据补充。

当工具层成为共享语言，团队讨论会发生变化：不再说“我觉得 payment 可能受影响”，而说“`impact_analysis` 返回了这条路径，置信度 high/medium”。这种语言切换，是 AI 编码从个人技巧变成工程制度的标志之一。

## 小结

1. 图谱补齐 RAG 在结构关系上的短板。
2. 小而稳的查询工具集优于万能聊天。
3. 图谱同时服务压缩、约束和审计。
4. 修改后复核与改前查询同样重要。

## 工具编排策略

不建议让 Agent 自由乱点工具。推荐策略：

1. **先 find\_symbol** 锁定主实体
2. **再 find\_callers / related\_tests** 扩展最小邻居
3. **architecture\_rules** 做边界检查
4. 修改后 **impact\_analysis** 复核
5. 全过程写入 query\_trace

可用状态机约束：

```
RESOLVE_SYMBOL -> EXPAND_CONTEXT -> EDIT -> VERIFY -> REPORT
```

任何一步失败（未知符号、规则失败、测试缺失）都应进入 `needs_confirmation`，而不是继续“自信修改”。

## 与 MCP 的关系

MCP 提供的是工具暴露与调用协议；它不负责：

* 图谱是否正确
* 检索策略是否合理
* 权限与多租户

因此协议层与事实层要分开建设：先有可信图谱查询，再包装成 MCP/工具接口。

## 工作示例：失败重试策略

若 `find_symbol("apply")` 返回多个重名：

1. 提高查询精度（限定模块 pricing）
2. 仍多候选则返回 needs\_confirmation
3. 禁止 Agent 随机挑一个修改

工具层要有“拒绝继续”的能力，这是安全默认，不是功能缺陷。

## 关键要点复盘

围绕「代码图谱如何服务 AI Agent」，读者离开本章前应能做到：

1. 列出最小工具集
2. 演示 find\_symbol→callers→tests
3. 要求失败响应结构化
4. 说明轨迹如何进入验证报告
5. 衔接到 Review 证据层

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 工具结果如何写进上下文包

```
tool: find_callers
result_summary: 1 high-confidence caller
injected_into_context:
 callers: [PricingService.calculateTotal]
 evidence: edge calls confidence=high
```

关键是“结果摘要 + 证据引用”一起注入，而不是把原始巨 JSON 全塞给模型。

## Agent 查图最小工具集

```
find_symbol(name|id) -> node
find_callers(id, depth=1..n)
find_callees(id)
impact_analysis(changed_ids)
related_tests(id)
architecture_rules(module|id)
```

每次工具调用写入 `query_trace`，最终进入验证报告。没有轨迹的 Agent 结论，Reviewer 无法复盘。

## 上下文包切片规则

给 Agent 的不是全图，而是任务切片：

```json
{
  "task": "change VIP discount factor",
  "seed": ["method:DiscountPolicy#apply"],
  "include": ["callers_depth_3", "related_tests", "rules"],
  "exclude": ["unrelated modules", "full repo dump"]
}
```

切片失败的典型症状：token 爆、改错文件、漏测试。

## 练习

1. 为 `mini-shop` 设计 6 个工具调用序列完成 PR-42。
2. 说明何时应降低 confidence 并要求人工确认。
3. 比较 RAG-only 与 Graph+RAG 在“找 apply 调用方”任务上的差异。

## 常见问题：Agent 查图

### 工具失败返回空数组可以吗？

应结构化报错，避免被当成“无影响”。

### 最小工具集有哪些？

find\_symbol / callers / callees / impact / tests / rules。

## 本章检查清单

1. 工具响应是否含 trace\_id
2. 是否写入 query\_trace
3. 是否与验证报告字段对齐

## 本章导航

* 上一章：[Agent 上下文工程](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/agent-context-engineering)
* 下一章：[AI 生成代码的 Review 证据层](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/ai-code-review-evidence)
* 相关章：[给 AI Agent 的查询接口](/di-liu-pian-shi-jian-xiang-mu/query-interface-for-ai-agent)；[AI 修改后的验证报告](/di-liu-pian-shi-jian-xiang-mu/ai-change-verification-report)

## 延伸阅读与参考资料

* [Model Context Protocol](https://modelcontextprotocol.io/)。资料卡：`../docs/research-cards/rc-mcp.md`
* [Joern CPG](https://docs.joern.io/code-property-graph/)：代码图查询思想。
* [CodeQL](https://codeql.github.com/docs/)：声明式代码查询参考。
* [GitHub Copilot docs](https://docs.github.com/en/copilot)。
* [JSON Schema](https://json-schema.org/)：工具输入输出契约。
* 本书样例：[`examples/mini-shop/artifacts/code-graph.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/code-graph.json)。


# AI 生成代码的 Review 证据层

## 本章要解决的问题

Reviewer 需要哪些证据才能判断 AI 改动是否可信？

## 读者读完应获得什么

1. 能列出 AI PR 的最小证据清单。
2. 能区分“模型解释”和“系统证据”。
3. 能把证据层接入 CI/PR 注释。

## 本章不讲什么

* 不设计完整人工管理流程。
* 不声称证据可替代所有人工判断。

## 本章与邻章边界

* 本章聚焦**改后**：Reviewer 需要哪些系统证据。
* 影响面算法细节见第四篇；Agent 改前上下文见上下文工程章。

***

![AI PR 证据层](/files/TZplWaJz84hwb4Vrzlc7)

AI 生成的 PR 往往包含流畅说明，但 Reviewer 需要的是可核验证据。证据层把代码理解系统接到评审现场。

## 最小证据清单

对任何 AI 修改，至少检查：

1. **改动范围**：实际变更实体列表
2. **影响路径**：入口与关键下游
3. **相关测试**：已跑/未跑/需更新
4. **规则检查**：架构/安全基线
5. **查询轨迹**：Agent 如何得到上下文
6. **残留风险**：已知不确定点

`PR-42` 样例报告：[`examples/mini-shop/artifacts/verification-report-pr-42.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/verification-report-pr-42.md)

## 模型说明 vs 系统证据

| 类型   | 例子                                  | 可信基础      |
| ---- | ----------------------------------- | --------- |
| 模型说明 | “只改了折扣，无风险”                         | 生成文本      |
| 系统证据 | callers=calculateTotal...；tests 需更新 | 图谱查询与命令结果 |

Review 政策应要求：关键断言必须有系统证据支撑。

## 证据在 PR 中的呈现

建议顺序：

```
1. 变更摘要（实体级）
2. 影响路径图/列表
3. 测试计划与结果
4. 规则与安全检查
5. 查询轨迹折叠区
6. 人工待确认项
```

不要把原始 JSON 一股脑贴出；先摘要，后下钻。

## 自动化与人工分工

* 自动：影响面、测试关联、规则、格式化报告
* 人工：业务语义、产品取舍、例外批准
* AI：草拟说明，但不可自证安全

## 反模式

1. 只看模型自信度
2. 绿测就过，不看是否测到变更路径
3. 证据不可回跳源码
4. 无查询轨迹，无法复盘

AI PR 的危险不在于模型会写错代码——人也会——而在于它能以很高的流畅度生成“看起来可合并”的说明。Reviewer 若只阅读自然语言总结，等于在和文笔比赛。证据层把比赛拉回事实：变更实体、影响路径、相关测试、规则结果、查询轨迹。

分级很重要。把所有信息平铺会制造新的疲劳；把提示级信息默认折叠，才能让阻断项和金额语义变化这类重要项被真正看见。`PR-42` 正好落在“重要”：业务值要人确认，但自动证据必须先把影响与测试说清。

## 局限

* 证据完整不等于业务正确，关键语义仍需人工判断。
* 自动化检查受索引新鲜度和规则覆盖限制。
* 证据过多会造成 Review 疲劳，需要分层呈现。

## 小结

1. AI PR 需要专门的证据层。
2. 证据必须来自可复现查询与检查。
3. 报告要服务 Reviewer 决策，而不是炫技。
4. 人工仍负责业务与例外判断。

## 进阶要点：证据分级

不是所有证据同等重要。可分级：

| 级别 | 例子             | 合并策略参考 |
| -- | -------------- | ------ |
| 阻断 | 架构规则失败、高危路径无测试 | block  |
| 重要 | 影响路径跨模块、金额语义变化 | 必审     |
| 提示 | 文案/日志变化、低置信调用边 | 可折叠展示  |

`PR-42` 属于“重要”：金额语义变化 + 测试需更新，但架构规则未破。

## 工作示例：PR 评论骨架

```markdown
### 自动证据
- Changed: DiscountPolicy.apply
- Paths: apply -> calculateTotal -> createOrder -> create
- Tests: 2 related (need assert update 180 -> 170)
- Rules: pricing-no-payment pass
- Trace: find_symbol, find_callers, related_tests, rules

### 人工待确认
- 业务是否确认 VIP 折扣新值 0.85
```

自动证据解决“改了什么/影响谁/测什么”；人工确认解决“该不该改成这个业务值”。

## 常见问题：AI Review 证据

### 模型很自信是否可合并？

不可以。自信不是证据。

### 测试全绿是否足够？

不够。还要确认测到了变更路径，且规则/影响面已被检查。

### 证据太多怎么办？

分级：阻断/重要/提示；默认展示前两级。

## 本章检查清单

1. 变更实体是否列出
2. 影响路径是否可回跳
3. 相关测试是否识别并执行
4. 规则结果是否展示
5. 查询轨迹是否保留

## 关键要点复盘

围绕「AI 生成代码的 Review 证据层」，读者离开本章前应能做到：

1. 区分阻断/重要/提示证据
2. 填写证据包字段契约
3. 用 PR-42 写自动证据+人工确认
4. 拒绝“模型自信/全绿即过”
5. 衔接到 AI 辅助重构

若任一做不到，请先复习本章例子与练习，再继续向后读。

## Reviewer 60 秒路径

1. 看变更实体是否与 PR 描述一致
2. 看影响路径是否到达入口/资金/权限点
3. 看测试是否覆盖这些路径
4. 看规则是否失败
5. 看轨迹是否显示 Agent 查过测试与规则

任何一步对不上，就从“快速合并”降级为“深入审”。

## 证据包字段契约

AI PR 证据层建议固定字段，便于 CI 与 UI 共用：

```json
{
  "pr": "PR-42",
  "changed_entities": [{"id": "method:DiscountPolicy#apply", "change_type": "modified"}],
  "impact_paths": [{"path": ["method:DiscountPolicy#apply", "method:PricingService#calculateTotal", "method:OrderService#createOrder", "method:OrderController#create"]}],
  "related_tests": ["test:PricingServiceTest#shouldApplyVipDiscount"],
  "rules": [{"id": "pricing-no-payment", "status": "pass"}],
  "risk": {"level": "medium", "reasons": ["pricing semantics change"]},
  "query_trace": ["find_symbol", "find_callers", "related_tests", "architecture_rules"],
  "human_checks": ["业务是否确认折扣 0.85"]
}
```

缺 `changed_entities` 或 `query_trace` 的报告，只能算摘要，不能算可审计证据。

## 练习

1. 用 PR-42 填完整证据清单 6 项。
2. 把模型说明“无风险”改写成必须附带的系统证据段落。
3. 设计 CI 门禁：哪些证据缺失应 block merge。

## 本章导航

* 上一章：[代码图谱如何服务 AI Agent](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/code-graph-for-ai-agent)
* 下一章：[AI 辅助重构与系统迁移](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/ai-assisted-refactoring-and-migration)
* 相关章：[给 AI Agent 的查询接口](/di-liu-pian-shi-jian-xiang-mu/query-interface-for-ai-agent)；[AI 修改后的验证报告](/di-liu-pian-shi-jian-xiang-mu/ai-change-verification-report)

## 延伸阅读与参考资料

* [GitHub status checks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/about-status-checks)
* [CodeQL code scanning](https://codeql.github.com/docs/codeql-overview/about-code-scanning-with-codeql/)
* [SARIF](https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html)。资料卡：`../docs/research-cards/rc-sarif.md`
* [Codecov PR reporting](https://docs.codecov.com/docs)
* [Test Impact Analysis](https://learn.microsoft.com/en-us/azure/devops/pipelines/test/test-impact-analysis)。资料卡：`../docs/research-cards/rc-test-impact.md`
* 本书样例：[`verification-report-pr-42.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/verification-report-pr-42.md)。


# AI 辅助重构与系统迁移

## 本章要解决的问题

AI 如何参与重构与迁移，同时避免破坏系统边界与行为？

## 读者读完应获得什么

1. 能设计“小步改动 + 行为保持 + 对比证据”的流程。
2. 能判断哪些重构适合 Agent 自动做。
3. 能定义迁移前后的验证报告。

## 本章不讲什么

* 不提供某框架版本升级的逐步操作手册。
* 不鼓励无测试大爆炸重写。

## 本章与邻章边界

* 本章聚焦受约束的重构/迁移协作方式。
* 不写成某框架升级操作手册；架构事实地图见第四篇遗留改造章。

***

重构与迁移的核心不是“把代码改新”，而是“在约束下改变结构，并证明行为可接受”。AI 适合加速机械步骤，不适合无地图推进。

## 推荐闭环

```mermaid
flowchart LR
 Map[现状地图] --> Guard[测试/规则护栏]
 Guard --> Step[小步修改]
 Step --> DiffGraph[结构/依赖对比]
 DiffGraph --> Verify[测试与影响面]
 Verify --> Next[下一步 / 回滚]
```

## 适合 AI 的任务

* 重命名与导入修复
* 重复样板转换
* 测试骨架生成
* 迁移脚本草稿
* 依赖差异总结

## 不适合无约束交给 AI 的任务

* 边界不清的模块拆分
* 无表征测试的核心交易路径改写
* 多服务协议同时变更且无可观测性

## mini-shop 小例子

目标：把折扣系数提取为可配置常量，行为先保持 `0.9`，再切换到 `0.85`。

1. 用测试锁住 VIP/非 VIP 价格
2. Agent 只改 `DiscountPolicy` 结构，不改外部 API
3. 对比调用图：对外调用关系应不变
4. 再改系数，跑影响面与测试
5. 输出迁移报告：行为差异、测试更新、规则检查

## 验证对比项

| 项      | 迁移前                 | 迁移后          |
| ------ | ------------------- | ------------ |
| 关键路径   | create->...->apply  | 应保持          |
| 架构规则   | pricing 不依赖 payment | 应保持          |
| VIP 总价 | 180.0               | 170.0（若业务切换） |
| 测试     | 旧断言                 | 更新后全绿        |

## 失败案例（应避免）

1. **无测试抽取接口**：Agent 把 `DiscountPolicy` 抽成接口并移动包名，但没有表征测试，Review 无法判断价格行为是否保持。
2. **越界清理**：任务只是改折扣，Agent 顺便“优化”`OrderService` 日志与支付重试，导致 diff 噪声与风险上升。
3. **依赖反向**：为了复用支付费率，Agent 让 `pricing` 依赖 `payment`，破坏架构规则。

这些失败都可通过“范围约束 + 规则检查 + 影响面报告”在合并前拦截。

## 迁移报告模板（可直接套用）

每次 AI 参与的结构改造，至少产出：

```markdown
# Migration Report: <title>
## Scope
- allowed files/modules:
- forbidden changes:
## Guardrails before edit
- characterization tests:
- architecture rules:
## Steps
1. behavior-preserving structural change
2. verify tests/graph/rules
3. intentional behavior change (if any)
4. update tests + impact report
## Evidence
- call graph before/after:
- tests before/after:
- rules before/after:
## Residual risks
- ...
## Rollback
- ...
```

对 `mini-shop` 折扣配置化，第 1 步应保持 VIP 总价 `180.0`；第 3 步才切到 `0.85` 并更新断言到 `170.0`。

## 范围约束如何写给 Agent

不要只说“帮我重构定价模块”，而要给可检查边界：

```
GOAL: extract discount factor constant without behavior change
ALLOW: DiscountPolicy.java only
DENY: OrderService, PaymentClient, public API signatures
MUST_KEEP: VIP total=180.0 for qty=2 unit=100
MUST_PASS: architecture rule pricing-no-payment
OUTPUT: diff + callgraph summary + test results
```

边界越可机器检查，AI 越不容易“顺便优化”。

## 与影响面/验证章的衔接

* 小步结构改：重点看调用图是否保持、测试是否仍绿
* 行为变更步：走完整影响面报告（见变更影响分析章）
* 合并前：验证报告必须同时包含规则与相关测试（见 AI Review 证据 / 验证报告章）

重构与迁移最容易被 AI 带偏的点，是把“结构变新”误当成“任务完成”。真正完成的定义是：在声明的约束下改变结构，并且行为可接受、边界仍成立。因此要把工作拆成两段——先行为保持的结构改造，再行为变更——并给 Agent 可机器检查的允许/禁止范围。

`mini-shop` 折扣配置化是最小示范：第一步仍锁 `180.0`，第二步才切到 `0.85` 并更新测试。跳过护栏的“顺手优化”会把 diff 变成不可审的大杂烩，这是迁移失败的常见前兆。

## 局限

* 小步策略依赖测试与规则护栏，缺少护栏时 AI 容易扩大 diff。
* 迁移中的业务语义取舍无法只由图谱决定。
* 跨仓库/跨服务迁移需要比单仓 `mini-shop` 更强的链路观测。

迁移计划里最值钱的字段常常不是“目标架构多先进”，而是“每一步如何回滚”。AI 加速前进时，回滚点与表征测试就是刹车。没有刹车的加速，只是把事故安排得更早到来。

## 小结

1. 重构/迁移先护栏后改动。
2. AI 负责加速，系统负责约束与证明。
3. 每次小步都要有可对比证据。
4. 无测试无地图的大改应拒绝自动化裸奔。

## 行为保持证明的层次

1. **编译/解析通过**（必要但不充分）
2. **表征测试通过**
3. **架构规则通过**
4. **关键路径对比（调用图/契约）**
5. **必要时的运行时对比**

AI 很容易完成第 1 层并宣称成功。出版级工程实践要求至少到第 2-4 层。

## 工作示例：可接受的 AI 小步

任务：折扣系数配置化，但行为暂保持 0.9

1. Agent 仅修改 `DiscountPolicy` 内部读取常量/配置
2. 表征测试保持 180.0
3. 调用图对外边不变
4. 再开第二个 PR 调整为 0.85 并更新测试

把“结构改造”和“行为变更”拆开，Review 复杂度会显著下降。

## 常见问题：AI 重构

### 能否让 Agent 一次完成大迁移？

通常不应。应拆成可验证小步，先行为保持，再行为变更。

### 没有测试能不能自动重构？

高风险。至少先补表征测试，再允许结构改动。

### 如何判断 AI 重构成功？

解析通过、测试通过、架构规则通过、关键路径对比通过，缺一不可轻易宣称成功。

## 本章检查清单

1. 是否拆成小步
2. 是否有表征测试
3. 是否对比调用图/规则
4. 是否保留回滚点
5. 是否避免无关清理 diff

## 关键要点复盘

围绕「AI 辅助重构与系统迁移」，读者离开本章前应能做到：

1. 拆分行为保持与行为变更两步
2. 写出给 Agent 的范围约束
3. 使用迁移报告模板
4. 用调用图/规则/测试证明小步成功
5. 衔接到理解基础设施

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 反模式对照表

| 反模式       | 后果       | 纠正           |
| --------- | -------- | ------------ |
| 大爆炸重写     | 无法定位回归   | Strangler 小步 |
| 无表征测试抽取接口 | 行为漂移     | 先锁测试         |
| 顺手清理无关代码  | diff 不可审 | 范围冻结         |
| 忽略架构规则    | 边界腐蚀     | 规则门禁         |
| 只看编译通过    | 假成功      | 多层证明         |

## 练习

1. 把折扣配置化拆成 3 步，并给每步验收标准。
2. 指出 2 类不应交给无约束 Agent 的改造。
3. 设计迁移前后对比表：路径、规则、测试、行为。

## 本章导航

* 上一章：[AI 生成代码的 Review 证据层](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/ai-code-review-evidence)
* 下一章：[从代码可视化到软件理解基础设施](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/software-understanding-infrastructure)
* 相关章：[给 AI Agent 的查询接口](/di-liu-pian-shi-jian-xiang-mu/query-interface-for-ai-agent)；[AI 修改后的验证报告](/di-liu-pian-shi-jian-xiang-mu/ai-change-verification-report)

## 延伸阅读与参考资料

* [Strangler Fig](https://martinfowler.com/bliki/StranglerFigApplication.html)。资料卡：`../docs/research-cards/rc-strangler-fig.md`
* [Refactoring.com catalog](https://refactoring.com/catalog/)
* [Characterization testing 概念](https://michaelfeathers.silvrback.com/characterization-testing)
* [ADR](https://adr.github.io/)。资料卡：`../docs/research-cards/rc-adr.md`
* [ArchUnit](https://www.archunit.org/)
* 本书案例：[`examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)。


# 从代码可视化到软件理解基础设施

## 本章要解决的问题

如何把一次性图表能力升级为持续更新的软件理解基础设施？

## 读者读完应获得什么

1. 能描述组织级最小基础设施形态。
2. 能列出数据、查询、集成、治理四条建设主线。
3. 能把本书能力映射到路线图，而不是工具堆砌。

## 本章不讲什么

* 不推销特定商业平台。
* 不要求一上来全量中台化。

## 本章与邻章边界

* 本章做组织级收束与建设路线，不重复前文机制细节。
* 最小可运行闭环实现见第六篇实践项目。

***

当代码可视化只用于演示，它是材料；当它持续服务于开发、Review、AI Agent 和治理，它是基础设施。

“基础设施”这个词容易让人联想到大平台、多租户和豪华门户。本书用它时更克制：只要一套软件事实能力被**持续更新**，并被 IDE、CI、Agent、Review 共同依赖，它就已经是基础设施。反过来，哪怕图画得很炫，只要每次演示都靠手工导出一次 JSON，它仍只是材料。

判断标准不是节点数量，而是：**离开某位熟悉系统的人，团队是否仍能在 PR 中得到同样质量的影响面与证据。**

## 最小基础设施形态

```mermaid
flowchart TB
 Collect[持续采集] --> Fact[软件事实库/代码图谱]
 Fact --> Query[查询与报告服务]
 Query --> IDE[IDE]
 Query --> CI[CI/PR]
 Query --> Agent[AI Agent]
 Query --> Portal[工程门户]
 CI --> Feedback[反馈回写]
 Agent --> Feedback
 Feedback --> Collect
```

## 四条主线

1. **数据主线**：源码、运行时、变更、组织信息持续入库
2. **查询主线**：符号、调用、影响面、规则、测试
3. **集成主线**：IDE、CI、PR、Agent、门户共用 API
4. **治理主线**：权限、审计轨迹、质量 SLO、索引新鲜度

## 与 mini-shop 实践的关系

第六篇最小系统是基础设施的“可讲解缩影”：

* collector / graph / analysis / ui / agent-api / report

组织级只是在可靠性、多仓、权限和规模上扩展，而不是换一套完全不同的概念。

## 为什么顺序比技术选型更重要

很多团队一上来就争论 Neo4j 还是 SQLite、自研还是买平台。更常见的失败是：选好了存储，却没有单仓可重复采集；做了聊天机器人，却没有 PR 影响面；上了门户，索引却每周过期。顺序错了，后面所有集成都会放大脏数据。

建议把前三步当成不可跳过的地基：

1. 单仓采集与稳定 ID
2. 可查询图谱 + 金标查询
3. PR 影响面报告进入工作流

Agent 接口应建立在这三步之上，而不是并行另起一套“AI 专用检索”。

## 建设顺序建议

1. 单仓可重复采集与调用图
2. PR 影响面报告
3. Agent 查询接口与上下文包
4. 多仓与组织元数据
5. 运行时证据融合
6. 平台化治理

每一步都要能回答：减少了多少理解成本或 Review 风险。

## 成功度量

* 影响面报告在 PR 中的使用率
* 相关测试推荐命中率
* Agent 修改后返工率
* 索引延迟与准确率
* Reviewer 平均理解时间

## 局限

* 平台化有组织成本，不能指望一次建设完成。
* 多仓、多语言会显著提升采集与一致性难度。
* 没有使用度量时，基础设施容易变成展示工程。

索引新鲜度、轨迹完整率、影响面使用率这些指标，听起来像运营后台，实际上是理解基础设施的生命体征。事实层一旦过期，人和 Agent 会一起被过期地图误导，而且因为输出很自信，错误更难被发现。

## 小结

1. 基础设施 = 持续事实 + 共享查询 + 工作流集成。
2. 从单仓闭环长出来，而不是先画大台。
3. 人、CI、Agent 共用同一证据层。
4. 用工程度量证明价值，而不是用图数量证明价值。

## 进阶要点：从项目到平台的最小增量

不要一开始就做“全公司统一中台”。更稳的增量是：

1. 单仓图谱 + PR 影响面（本周可用）
2. Agent 查询接口 + 轨迹（赋能 AI 工作流）
3. 多仓与 Owner 目录（组织层）
4. 运行时证据融合（降噪与热点）

每一步都要有使用率或返工率等度量，否则平台化容易空转。

## 角色与职责

| 角色     | 职责            |
| ------ | ------------- |
| 平台组    | 索引、查询 API、SLA |
| 应用团队   | 规则、Owner、表征测试 |
| 质量/安全  | 门禁策略与高危规则     |
| AI 工具组 | Agent 策略与轨迹消费 |

基础设施失败常常不是技术做不到，而是职责悬空：谁都不维护索引新鲜度，谁都抱怨“图不准”。

## 工作示例：索引新鲜度 SLO

| 指标        | 目标      |
| --------- | ------- |
| 主分支索引延迟   | < 15 分钟 |
| PR 增量索引延迟 | < 5 分钟  |
| 关键查询成功率   | > 99%   |
| 图谱契约测试    | 每次发布必过  |

没有 SLO 的“平台”最后会变成无人维护的静态导出任务。

## 常见问题：基础设施化

### 先做平台还是先做单仓闭环？

先单仓闭环，再平台化。

### 如何避免平台空转？

设使用率/返工率/索引延迟等度量。

### 谁维护规则与 Owner？

应用团队维护领域规则与 Owner；平台维护索引与 API。

## 本章检查清单

1. 是否有事实层
2. 是否有查询 API
3. 是否接入 PR/Agent
4. 是否有新鲜度 SLO
5. 是否有角色分工

## 关键要点复盘

围绕「从代码可视化到软件理解基础设施」，读者离开本章前应能做到：

1. 画出最小基础设施拓扑
2. 给出落地顺序 1→5
3. 选择早期运行指标
4. 说明人/CI/Agent 共享事实层
5. 衔接到实践项目总览

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 采购/自建决策提示

| 问题             | 倾向            |
| -------------- | ------------- |
| 是否只要展示图？       | 工具即可          |
| 是否要进 PR/Agent？ | 需要可查询事实层      |
| 是否多语言多仓？       | 平台化与标准 schema |
| 是否强合规审计？       | 轨迹与权限成为硬需求    |

不要用“买一个可视化工具”替代“建设理解基础设施”的决策，除非需求仅止于展示。

## 最小基础设施拓扑

```
Collectors (AST/graph/diff/test/trace)
    -> Fact Store (graph + evidence)
        -> Query API (human UI + Agent tools)
            -> Reports (impact/verification)
            -> Governance (rules, audit trail)
```

落地顺序建议：

1. 稳定 ID 与采集
2. 可查询图谱
3. 影响面报告
4. Agent 工具与轨迹
5. 组织策略与度量

跳过 1-3 直接做“AI 平台”，通常只会得到更快的不可审改动。

## 运行指标（早期就该看）

| 指标       | 含义                        |
| -------- | ------------------------- |
| 自动影响面覆盖率 | AI/人工 PR 中有报告的比例          |
| 相关测试命中率  | 推荐测试真正失败/需更新的比例           |
| 轨迹完整率    | 含 query\_trace 的 PR 比例    |
| 返工率      | 合并后因理解错误导致的 revert/hotfix |

## 练习

1. 画出你们组织从 L2 到 L4 的三步路线图。
2. 给出 4 个成功度量，并说明如何采集。
3. 解释为何 IDE/CI/Agent 应共享同一事实层。

## 本章导航

* 上一章：[AI 辅助重构与系统迁移](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/ai-assisted-refactoring-and-migration)
* 下一章：[构建一个最小代码理解系统](/di-liu-pian-shi-jian-xiang-mu/mini-code-understanding-system)
* 相关章：[给 AI Agent 的查询接口](/di-liu-pian-shi-jian-xiang-mu/query-interface-for-ai-agent)；[AI 修改后的验证报告](/di-liu-pian-shi-jian-xiang-mu/ai-change-verification-report)

## 延伸阅读与参考资料

* [Backstage](https://backstage.io/docs/overview/what-is-backstage/)。资料卡：`../docs/research-cards/rc-backstage-catalog.md`
* [OpenTelemetry](https://opentelemetry.io/)
* [Internal Developer Platform](https://internaldeveloperplatform.org/)
* [MCP](https://modelcontextprotocol.io/)。资料卡：`../docs/research-cards/rc-mcp.md`
* [GitHub platform docs](https://docs.github.com/)：PR/Checks 集成位
* 本书实践篇：[`part6/mini-code-understanding-system.md`](/di-liu-pian-shi-jian-xiang-mu/mini-code-understanding-system)


# 第六篇：实践项目


# 构建一个最小代码理解系统

## 本章要解决的问题

如何用最小实现跑通“采集 -> 建图 -> 分析 -> 可视化 -> Agent 查询 -> 验证报告”闭环？

## 读者读完应获得什么

1. 能说明系统目标、边界和模块划分。
2. 能以 `mini-shop` 作为标准示例仓库推进实现。
3. 能定义端到端验收标准。

## 本章不讲什么

* 不做成多租户商业平台。
* 不追求全语言全框架覆盖。

***

本篇把前面的原理与场景收束到实践项目。目标不是大而全，而是完整可讲解。

```mermaid
flowchart LR
 Repo[mini-shop 源码] --> Collector[采集]
 Collector --> Graph[代码图谱]
 Diff[PR-42 Diff] --> Impact[影响面分析]
 Graph --> Impact
 Graph --> UI[可视化]
 Graph --> API[Agent 查询接口]
 Impact --> Report[验证报告]
 API --> Agent[AI Agent]
 Agent --> Report
```

![最小系统模块图（精确技术图）](/files/5MwXYLjmSkWdquulNR5s)

## 本篇阅读路径

请按下面顺序阅读，后文默认复用总览中的模块划分，不再重复原理定义：

```
总览（本章）
 -> 采集源码结构
 -> 构建代码图谱
 -> 构建变更影响分析
 -> 构建可视化界面
 -> 给 AI Agent 的查询接口
 -> AI 修改后的验证报告
```

标准输入输出以 `examples/mini-shop/` 与 `examples/mini-shop/artifacts/` 为准。

## 项目目标

1. 解析 `examples/mini-shop`，提取文件/类/方法/调用/测试
2. 生成可查询图谱（JSON 即可）
3. 输入 `PR-42` Diff，输出影响面
4. 提供基础可视化与报告
5. 提供 Agent 工具查询接口
6. 输出验证报告

已提供参考产物：

* [`artifacts/code-graph.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/code-graph.json)
* [`artifacts/impact-report-pr-42.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/impact-report-pr-42.json)
* [`artifacts/agent-context-pack.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/agent-context-pack.json)
* [`artifacts/verification-report-pr-42.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/verification-report-pr-42.md)

## 系统边界

做：

* Java 子集解析
* 直接调用关系
* Diff 到方法映射
* 反向影响路径
* 测试关联
* JSON 查询 API

不做：

* 完整 IDE
* 完美别名分析
* 生产权限体系
* 大规模分布式图存储

## 模块划分

```
collector/ 扫描与 AST 抽取
graph/ 节点边存储与校验
analysis/ 影响面与测试推荐
api/ Agent 查询工具
report/ Markdown/JSON 报告
ui/ 最小页面或静态报告页
```

## 技术取舍

| 模块       | 默认选择                     | 原因        |
| -------- | ------------------------ | --------- |
| 解析       | JavaParser 或 Tree-sitter | 易讲清       |
| 存储       | JSON/SQLite              | 易复现       |
| 可视化      | Mermaid + 简单 HTML        | 先证据后炫技    |
| Agent 接口 | 本地工具/JSON API            | 可平滑映射 MCP |

## 端到端验收

1. 对 `mini-shop` 生成图谱，包含 `DiscountPolicy.apply` 调用方
2. 对 `pr-42.diff` 识别变更实体
3. 影响路径覆盖到 `OrderController.create`
4. 相关测试包含 pricing/order 两测
5. 能导出验证报告
6. 查询接口可返回 callers/tests

第六篇不是要你交付商业平台，而是要你亲手把主线焊成闭环。最小系统的意义在于暴露接口缝：采集的 ID 能否被建图消费，影响面是否只认图谱实体，UI 是否与报告同源，Agent API 是否写出轨迹。这些缝在 PPT 架构里看不见，一做就全暴露。

请把端到端验收剧本当宪法：任一步实体 ID 不一致，就停在那一步修，而不是先做视觉或模型微调。`mini-shop` 足够小，正是为了让你没有借口跳过一致性。

## 局限

* 最小系统只覆盖教学闭环，不替代生产级平台。
* 解析精度、多语言与规模化不在本项目范围。
* artifacts 是标准样例，实现时允许替换存储，但字段契约应保持。

最小系统还有一个教学上的诚实之处：它逼你承认取舍。你可能没有完美 UI，没有多仓，没有实时 trace，但你仍能完成从 diff 到验证报告的决策链。先拥有这条链，再谈扩展；否则扩展只是把缺口复制到更大范围。

## 小结

1. 最小系统的价值是闭环，不是功能数量。
2. `mini-shop` 与 artifacts 提供标准输入输出。
3. 先 JSON 跑通，再考虑扩展存储与语言。
4. 后续章节分别实现各模块。

## 里程碑验收表

| 里程碑    | 验收                                  |
| ------ | ----------------------------------- |
| M1 采集  | mini-shop 全量 parse，产出 methods/calls |
| M2 建图  | 金标调用链可查询                            |
| M3 影响面 | PR-42 报告字段齐全                        |
| M4 接口  | 5 工具可调用且有 trace                     |
| M5 报告  | Markdown+JSON 同源输出                  |
| M6 UI  | 三视图可完成一次 PR 阅读                      |

只有 M1-M5 全绿，才算实践闭环完成；M6 可并行。

## 工作示例：本地演示脚本顺序

```
1. collect examples/mini-shop -> out/graph.json
2. impact out/graph.json artifacts/pr-42.diff -> out/impact.json
3. context task="vip discount" -> out/context.json
4. report out/impact.json -> out/report.md
```

第六篇各章应按这个脚本顺序对齐输入输出文件名，避免读者在章节间迷路。

## 关键要点复盘

围绕「构建一个最小代码理解系统」，读者离开本章前应能做到：

1. 复述端到端验收剧本
2. 画出模块输入输出
3. 指出任一步 ID 不一致即失败
4. 说明最小系统不是商业平台
5. 衔接到采集实现

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 端到端验收剧本（mini-shop）

1. 采集源码结构 → 生成/更新 `code-graph.json`
2. 输入 `pr-42.diff` → 产出 `impact-report-pr-42.json`
3. 组装 Agent 上下文包 `agent-context-pack.json`
4. 生成 `verification-report-pr-42.md`
5. UI/报告页能在 60 秒讲清变更

任一步产物字段与正文 ID 不一致，即验收失败。

## 模块边界

| 模块        | 输入           | 输出          |
| --------- | ------------ | ----------- |
| collector | 源码           | 结构事实        |
| graph     | 结构事实         | nodes/edges |
| impact    | diff+graph   | 影响报告        |
| agent-api | graph+report | 工具响应        |
| report    | 全部           | 验证报告        |

## 练习

1. 对照 artifacts，列出端到端验收 6 项是否可观察。
2. 说明为何先 JSON 后图数据库。
3. 给 collector/graph/analysis/api/report 各写一句话职责。

## 常见问题：最小系统

### 和商业平台差距在哪？

商业平台强调规模、权限、多仓；本书优先可讲解闭环。

### 可以跳过 UI 吗？

可先报告后 UI，但查询与报告不能省。

## 本章导航

* 上一章：[从代码可视化到软件理解基础设施](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/software-understanding-infrastructure)
* 下一章：[采集源码结构](/di-liu-pian-shi-jian-xiang-mu/collect-source-structure)
* 相关章：[代码图谱：节点、边与属性](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/code-graph-model)；[Agent 上下文工程](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/agent-context-engineering)

## 延伸阅读与参考资料

* [JavaParser](https://javaparser.org/)。资料卡：`../docs/research-cards/rc-javaparser.md`
* [Tree-sitter](https://tree-sitter.github.io/tree-sitter/)。资料卡：`../docs/research-cards/rc-tree-sitter.md`
* [MCP](https://modelcontextprotocol.io/)。资料卡：`../docs/research-cards/rc-mcp.md`
* [SQLite](https://www.sqlite.org/docs.html)。资料卡：`../docs/research-cards/rc-sqlite.md`
* [Neo4j modeling](https://neo4j.com/docs/getting-started/data-modeling/)。资料卡：`../docs/research-cards/rc-neo4j-modeling.md`
* 标准产物：[`examples/mini-shop/artifacts/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/README.md)


# 采集源码结构

## 本章要解决的问题

如何从源码中抽取文件、类、方法、候选调用和测试，形成稳定 JSON？

## 读者读完应获得什么

1. 能设计采集输入输出契约。
2. 能定义实体稳定 ID。
3. 能处理解析失败而不中断全量任务。

## 本章不讲什么

* 不在本章完成精确语义消解。
* 不支持所有构建系统边角。

***

采集是流水线第一步。目标是可重复地从 `mini-shop` 抽出结构事实。

## 输入输出

输入：

```
repo_path = examples/mini-shop
source_roots = [src/main/java]
test_roots = [src/test/java]
```

输出节点：file / class / method / test 输出边：contains / calls(候选) / tests(候选)

## 扫描与解析

1. 递归扫描 `.java`
2. 区分 main/test
3. 解析 AST，保留行号
4. 单文件失败时记录错误并继续

## 稳定 ID

```
file:src/main/java/com/minishop/pricing/DiscountPolicy.java
class:com.minishop.pricing.DiscountPolicy
method:com.minishop.pricing.DiscountPolicy#apply
test:com.minishop.pricing.PricingServiceTest#shouldApplyVipDiscount
```

ID 必须在多次采集间稳定，否则影响面与历史分析会断。

## 方法节点样例

```json
{
 "id": "method:com.minishop.pricing.PricingService#calculateTotal",
 "type": "method",
 "name": "calculateTotal",
 "file_path": "src/main/java/com/minishop/pricing/PricingService.java",
 "start_line": 11,
 "end_line": 16,
 "calls": [
 {"method_name": "apply", "receiver_text": "discountPolicy", "line": 14}
 ]
}
```

注意：此时 `calls` 仍可能是候选，精确绑定可在图谱构建阶段增强。

## 测试识别

简单规则即可起步：

* 路径在 `src/test/java`
* 类名 `*Test`
* 方法带 `@Test`

并尝试从测试方法体提取被测调用，生成 `tests` 候选边。

## 输出目录建议

```
out/mini-shop/
 files.json
 types.json
 methods.json
 edges.json
 errors.json
```

也可直接合并为 [`artifacts/code-graph.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/code-graph.json) 形态。

## 验收

* 解析全部 mini-shop 源文件
* 包含 `DiscountPolicy.apply` 与 `OrderService.createOrder`
* 至少抽到 `calculateTotal -> apply` 候选调用
* 错误文件不影响其他文件结果

## 采集流程

```mermaid
flowchart TD
 Src[源码树] --> Parse[Parser/AST]
 Parse --> Extract[抽取 file/class/method]
 Extract --> Cand[候选调用/测试]
 Cand --> Out[structure JSON]
 Out --> Next[交给建图模块]
```

采集阶段保留候选，符号消解与置信度可在建图阶段提升。

采集是事实链的第一公里。这里的目标不是“解析得尽可能学术正确”，而是稳定产出后续模块能依赖的结构事实：文件、类型、方法、候选调用、测试与 ID。过早做完整语义消解，会让采集变重且难复现；过晚保留候选，又会在建图时丢信息。

工程折中是：采集阶段宁可不完美也要可重跑，并把不确定性留在候选集合里。`DiscountPolicy.apply` 与 `PricingService.calculateTotal` 里的调用，应能在输出 JSON 中被找到，即使此时还只是 candidate。

## 局限

* 候选调用不等于精确调用。
* 生成代码与非常规目录布局需要配置。
* 仅覆盖教学所需 Java 子集时，迁移到其他语言要替换 parser。

## 小结

1. 采集先保证覆盖率与稳定 ID。
2. 候选调用可以后置消解。
3. 失败隔离是工程必备。
4. 输出应能直接进入建图。

## 采集质量门禁

在进入建图前，采集器应输出质量报告：

```json
{
 "files_total": 10,
 "files_parsed": 10,
 "files_failed": 0,
 "methods_extracted": 12,
 "call_exprs": 8,
 "parse_errors": []
}
```

门禁示例：

1. 解析成功率 < 95%：警告
2. 关键模块（order/pricing）解析失败：阻断
3. 无任何 method 节点：阻断

`mini-shop` 教学数据应保持 100% 可解析，作为回归基线。

## 从候选调用到可解释抽取

对 `discountPolicy.apply(...)`，采集阶段至少保留：

* receiver\_text
* method\_name
* arg\_count
* line/column
* enclosing\_method\_id

这些字段决定后续消解与证据展示是否可用。缺少位置信息的调用边，几乎无法进入 Review 证据层。

## 关键要点复盘

围绕「采集源码结构」，读者离开本章前应能做到：

1. 给出采集输出最小 JSON
2. 区分候选调用与已消解调用
3. 保持稳定 ID
4. 为 mini-shop 列出应抽出的方法集合
5. 衔接到建图

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 采集输出最小 JSON

```json
{
  "files": [{"path": "src/main/java/com/minishop/pricing/DiscountPolicy.java"}],
  "types": [{"id": "class:DiscountPolicy", "file": "...", "lines": [1, 20]}],
  "methods": [{"id": "method:DiscountPolicy#apply", "owner": "class:DiscountPolicy", "lines": [3, 10]}],
  "candidate_calls": [{"from": "method:PricingService#calculateTotal", "name": "apply", "line": 13}],
  "tests": [{"id": "test:PricingServiceTest#shouldApplyVipDiscount"}]
}
```

后续建图阶段再把 `candidate_calls` 提升为带 `resolves_to` 的 `calls` 边。采集阶段保留候选，避免过早丢信息。

## 练习

1. 为 `DiscountPolicy.apply` 设计稳定 ID。
2. 写解析失败时的错误记录字段。
3. 说明候选调用与精确调用的差别，并指出下一章如何消解。

## 常见问题：采集

### 候选调用要不要直接当 calls？

不要。先保留候选，消解后再提升。

### ID 变了怎么办？

显式迁移映射，禁止静默换 ID。

## 本章导航

* 上一章：[构建一个最小代码理解系统](/di-liu-pian-shi-jian-xiang-mu/mini-code-understanding-system)
* 下一章：[构建代码图谱](/di-liu-pian-shi-jian-xiang-mu/build-code-graph)
* 相关章：[代码图谱：节点、边与属性](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/code-graph-model)；[Agent 上下文工程](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/agent-context-engineering)

## 延伸阅读与参考资料

* [JavaParser](https://javaparser.org/)。资料卡：`../docs/research-cards/rc-javaparser.md`
* [Tree-sitter using parsers](https://tree-sitter.github.io/tree-sitter/using-parsers)。资料卡：`../docs/research-cards/rc-tree-sitter.md`
* [JLS](https://docs.oracle.com/javase/specs/jls/se17/html/index.html)
* [ANTLR](https://www.antlr.org/)。资料卡：`../docs/research-cards/rc-antlr.md`
* [Source path / build layout conventions (Maven)](https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html)
* 输出对照：[`code-graph.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/code-graph.json)


# 构建代码图谱

## 本章要解决的问题

如何把采集结果变成可查询、可校验的图谱模型？

## 读者读完应获得什么

1. 能定义 nodes/edges 表结构。
2. 能完成候选调用到实体的解析策略。
3. 能对图谱做基本完整性校验。

## 本章不讲什么

* 不引入必须的 Neo4j 集群。
* 不做分布式图计算。

***

采集产出的是素材，图谱构建负责统一 ID、补边、写属性和提供查询。

## 最小存储

### JSON

```json
{
 "nodes": [{"id": "...", "type": "method"}],
 "edges": [{"type": "calls", "from": "...", "to": "..."}]
}
```

### SQLite 示意

```sql
CREATE TABLE nodes(
 id TEXT PRIMARY KEY,
 type TEXT,
 name TEXT,
 file_path TEXT,
 start_line INT,
 end_line INT,
 props_json TEXT
);
CREATE TABLE edges(
 id TEXT PRIMARY KEY,
 type TEXT,
 from_id TEXT,
 to_id TEXT,
 confidence TEXT,
 source TEXT
);
```

## 调用消解策略（最小）

1. 同文件/同类方法名精确匹配
2. 唯一类名 + 方法名匹配
3. 多候选时保留 candidates，并标 `confidence=medium`
4. 无候选则保留未解析调用记录

对 `mini-shop`，`discountPolicy.apply` 可消解到 `DiscountPolicy.apply`。

## 必需边集合

对验收，至少存在：

```
OrderController.create -> OrderService.createOrder
OrderService.createOrder -> PricingService.calculateTotal
PricingService.calculateTotal -> DiscountPolicy.apply
OrderService.createOrder -> PaymentClient.charge
tests 边连接两个测试到对应方法
```

参考：[`artifacts/code-graph.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/code-graph.json)

## 校验规则

1. 所有边端点都存在
2. method 节点有 file/line
3. 无自环 calls（除非真实递归）
4. 架构规则可独立存储并查询

## 增量更新

文件变更时：

1. 删除该文件旧节点与边
2. 重新采集该文件
3. 重建相关 calls/tests
4. 更新 `updated_at`

## 建图与校验

```mermaid
flowchart LR
 Struct[structure JSON] --> Nodes[nodes]
 Struct --> Edges[edges + attrs]
 Nodes --> Val[校验：无悬空边]
 Edges --> Val
 Val --> Graph[code-graph.json]
 Graph --> Query[金标查询契约]
```

`DiscountPolicy#apply` 的 callers / tests 查不到，则建图未验收通过。

建图是把采集结果升级为合同数据的阶段。你要做的核心工作不是挑选图数据库，而是保证边不悬空、ID 稳定、关键查询可回归。没有校验清单就进入影响面，等于把脏数据送进决策。

把五条金标查询写成自动化测试并不过分：它们是系统的单元测试。`apply` 的 callers 与 tests 一旦漂移，后面所有 PR-42 故事都会一起漂。

## 局限

* 最小消解策略在重载/多态场景会留下候选。
* JSON 方案不适合超大规模仓，需后续分层存储。
* 框架注入边需要专用增强，不会凭空出现。

把建图阶段建成质量门，而不是数据搬运工。校验失败就阻断下游，听起来严厉，却能避免影响面和 Agent 在错误图上“自圆其说”。脏图上的精美报告，比没有报告更危险。

## 小结

1. 先有干净模型，再谈高级图算法。
2. 消解允许候选，但必须标置信度。
3. 校验器比“看起来有数据”更重要。
4. JSON/SQLite 足够支撑全书实践。

## 进阶要点：增量更新事务

文件级重建时建议：

```
begin
 delete nodes/edges where file_path = F
 insert new nodes/edges for F
 re-link unresolved calls touching F
commit
```

并记录 `index_version` 与 `updated_at`。Agent 查询若发现索引过期，应明确报错，而不是静默返回陈旧图。

## 工作示例：未解析调用的诚实表达

```json
{
 "type": "calls_unresolved",
 "from": "method:X#y",
 "callee_text": "foo.bar",
 "confidence": "low"
}
```

宁可保留 unresolved，也不要为了“图好看”伪造精确边。Agent 与 Reviewer 都需要知道哪里不确定。

## 常见问题：构建图谱

### 候选调用要不要丢弃？

不要丢，标记 confidence。

### 如何做增量？

按文件删旧建新并重链。

### 如何防陈旧索引？

index\_version + 过期报错。

## 本章检查清单

1. schema 清晰
2. 消解策略
3. 校验器
4. 增量更新
5. 金标链可查

## 关键要点复盘

围绕「构建代码图谱」，读者离开本章前应能做到：

1. 完成建图校验清单
2. 保证无悬空边
3. 跑通金标查询
4. 写入 source/confidence
5. 衔接到影响面实现

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 建图校验清单

生成 `code-graph.json` 后必须跑：

1. 所有 edge 的 from/to 都存在于 nodes
2. 关键方法 ID 稳定（`method:Class#method`）
3. 至少 1 条 `tests` 边指向 `DiscountPolicy#apply`
4. 架构规则可计算
5. 与 `PR-42` 变更实体可连接

```
assert no dangling edges
assert find(method:DiscountPolicy#apply)
assert callers(apply) includes calculateTotal
```

校验失败时禁止进入影响面阶段。

## 练习

1. 写出 nodes/edges 的最小 SQL schema。
2. 对 `discountPolicy.apply` 给出消解策略与 confidence。
3. 列出 4 条图谱完整性校验。

## 本章导航

* 上一章：[采集源码结构](/di-liu-pian-shi-jian-xiang-mu/collect-source-structure)
* 下一章：[构建变更影响分析](/di-liu-pian-shi-jian-xiang-mu/build-change-impact-analysis)
* 相关章：[代码图谱：节点、边与属性](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/code-graph-model)；[Agent 上下文工程](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/agent-context-engineering)

## 延伸阅读与参考资料

* [SQLite docs](https://www.sqlite.org/docs.html)。资料卡：`../docs/research-cards/rc-sqlite.md`
* [Neo4j modeling](https://neo4j.com/docs/getting-started/data-modeling/)。资料卡：`../docs/research-cards/rc-neo4j-modeling.md`
* [Joern CPG](https://docs.joern.io/code-property-graph/)
* [LSP](https://microsoft.github.io/language-server-protocol/)。资料卡：`../docs/research-cards/rc-lsp.md`
* [JSON Graph / property graph 实践综述入口](https://neo4j.com/docs/)
* 样例：[`code-graph.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/code-graph.json)


# 构建变更影响分析

## 本章要解决的问题

如何基于 Diff 和图谱自动输出影响面报告？

## 读者读完应获得什么

1. 能实现 Diff -> 实体 -> 反向路径 -> 测试 -> 风险 的算法骨架。
2. 能对 `PR-42` 产出与样例一致的关键字段。
3. 能解释不确定结果如何表示。

## 本章不讲什么

* 不追求研究级指针分析精度。

***

## 算法骨架

```
1. parse_diff(diff) -> changed_lines_by_file
2. map_lines_to_entities(graph, changed_lines) -> changed_entities
3. for e in changed_entities:
 reverse_dfs(callers) within depth N
4. collect entry points / external resources
5. collect related tests
6. score risk
7. emit report json/md
```

## Diff 映射

对 `pr-42.diff`，变更行落入 `DiscountPolicy.apply` 方法区间，故：

```
changed_entities = [method:DiscountPolicy#apply]
```

## 反向路径

```
apply
 ^ calculateTotal
 ^ createOrder
 ^ create
```

伪代码：

```python
def find_callers(graph, method_id, depth=5):
 result = []
 stack = [(method_id, [])]
 while stack:
 cur, path = stack.pop()
 if len(path) > depth: continue
 for edge in inbound_calls(graph, cur):
 nxt = edge.from
 result.append(path + [nxt])
 stack.append((nxt, path + [nxt]))
 return result
```

## 测试关联

```
tests_edge.to in affected_methods
或 test 方法体候选调用命中 affected_methods
```

## 风险规则（可解释）

```
if touches_money_path: +2
if has_failing_or_stale_tests: +2
if crosses_modules: +1
if breaks_architecture_rule: +3
```

`PR-42` 应为 medium，并给出 reasons。

## 输出契约

与 [`impact-report-pr-42.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/impact-report-pr-42.json) 对齐：

```json
{
 "changed_entities": [],
 "impact_paths": [],
 "related_tests": [],
 "risk": {"level": "medium", "reasons": []},
 "recommended_actions": []
}
```

## 验收

* 输入 `artifacts/pr-42.diff`
* 识别 `DiscountPolicy.apply`
* 路径覆盖 `OrderController.create`
* 测试包含 pricing 与 order
* 生成 JSON + Markdown

## 影响面实现流程

```mermaid
flowchart TD
 Diff[pr-42.diff] --> Ent[变更实体]
 Graph[code-graph.json] --> Ent
 Ent --> Rev[反向调用路径]
 Rev --> Tests[相关测试]
 Tests --> Risk[风险分级]
 Risk --> Report[impact-report JSON/MD]
```

输出必须与 `examples/mini-shop/artifacts/impact-report-pr-42.json` 字段兼容。

影响面实现章的任务，是把 part4 的方法落成可运行算法：diff → 实体 → 反向路径 → 测试 → 风险 → 报告。重点不在炫技式路径枚举，而在输出字段与金标 artifacts 对齐，让 UI、Agent、验证报告都能消费同一 JSON。

当你的结果与 `impact-report-pr-42.json` 不一致时，优先怀疑映射粗细（文件级 vs 方法级）和边方向（caller/callee 反了），而不是先调风险分数权重。

## 局限

* 静态反向调用无法覆盖所有动态入口。
* 风险规则需要按团队校准。
* 深度过大时路径爆炸，需要裁剪与汇总。

## 小结

1. 影响面是可实现的确定性流水线。
2. 关键在实体映射与调用反向遍历。
3. 风险分数必须可解释。
4. 输出要直接服务 PR 与 Agent 验证。

## 端到端伪代码（可实现）

```python
def analyze(pr_diff, graph):
 changed = map_diff_to_entities(pr_diff, graph)
 impacted = set(changed)
 for e in changed:
 impacted |= reverse_callers(graph, e, depth=5)
 tests = related_tests(graph, impacted)
 risk = score_risk(changed, impacted, tests, graph.rules)
 return Report(changed, paths(impacted), tests, risk)
```

用 `mini-shop` 的 `pr-42.diff` 做金标测试： `changed={DiscountPolicy.apply}` 且路径包含 `OrderController.create`。

## 工作示例：深度裁剪

反向调用 depth=5 在小仓足够；大仓需要：

1. 按模块裁剪
2. 优先测试入口/API 入口
3. 汇总为“前 N 条关键路径 + 其余计数”

报告应写：`paths_shown=3, paths_total=42`，避免伪称“完整枚举”。

## 常见问题：实现影响面

### depth 设多少？

小仓 5 足够；大仓需裁剪与汇总。

### 如何测算法正确？

用 PR-42 金标：实体、路径、测试、风险字段。

### 风险分数如何避免黑盒？

每条 reason 必须可解释、可配置。

## 本章检查清单

1. diff 映射
2. 反向路径
3. 测试关联
4. 风险解释
5. 报告契约

## 影响面算法伪代码

```
entities = map_diff_to_entities(diff, graph)
seed = entities.ids
paths = reverse_call_paths(seed, graph, max_depth=5)
entries = paths.map(entry_point)
tests = related_tests(seed ∪ paths.nodes)
risk = score(entities, paths, tests, rules)
emit report(entities, paths, tests, risk, actions)
```

金标检查：`PR-42` 报告中的 `changed_entities`、路径与 `examples/mini-shop/artifacts/impact-report-pr-42.json` 一致。

## 关键要点复盘

围绕「构建变更影响分析」，读者离开本章前应能做到：

1. 实现 diff→实体→路径→测试→风险
2. 对照 artifacts 金标字段
3. 输出 recommended\_actions
4. 处理低置信边扩展
5. 衔接到可视化 UI

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 练习

1. 实现（伪代码）diff 行到方法实体的映射。
2. 对 PR-42 跑一遍反向路径，核对是否到达 `OrderController.create`。
3. 给风险规则打分并解释 reasons。

## 本章导航

* 上一章：[构建代码图谱](/di-liu-pian-shi-jian-xiang-mu/build-code-graph)
* 下一章：[构建可视化界面](/di-liu-pian-shi-jian-xiang-mu/build-visualization-ui)
* 相关章：[代码图谱：节点、边与属性](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/code-graph-model)；[Agent 上下文工程](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/agent-context-engineering)

## 延伸阅读与参考资料

* [git diff](https://git-scm.com/docs/git-diff)。资料卡：`../docs/research-cards/rc-git-diff.md`
* [Test Impact Analysis](https://learn.microsoft.com/en-us/azure/devops/pipelines/test/test-impact-analysis)。资料卡：`../docs/research-cards/rc-test-impact.md`
* [GitHub checks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/about-status-checks)
* [CodeQL](https://codeql.github.com/docs/)
* [SARIF](https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html)。资料卡：`../docs/research-cards/rc-sarif.md`
* 样例：[`impact-report-pr-42.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/impact-report-pr-42.json)


# 构建可视化界面

## 本章要解决的问题

如何用最小界面把图谱和影响面变成可操作证据？

## 读者读完应获得什么

1. 能设计三个核心视图：图谱、影响面、热点/详情。
2. 能定义节点下钻与源码回跳交互。
3. 能用静态 HTML/Mermaid 先交付可用版本。

## 本章不讲什么

* 不追求复杂力导向大屏。
* 不先做设计系统。

***

## 界面信息流

```mermaid
flowchart LR
 Data[graph + impact + report] --> Views[三视图]
 Views --> GraphV[图谱子图]
 Views --> ImpactV[影响路径/测试/风险]
 Views --> DetailV[节点详情/源码回跳]
 ImpactV --> Decision[Review 决策]
 DetailV --> Decision
```

数据同源：UI 不得各自重新“猜”影响面。

## 设计原则

1. 默认展示任务子图
2. 每个节点可回源码
3. 边显示来源/置信度
4. 先摘要后细节
5. 报告与图共用数据

## 三个视图

### 1. 图谱视图

* 模块过滤：order/pricing/payment
* 显示 contains 与 calls
* 搜索符号

### 2. 影响面视图

输入 PR/Diff 结果后展示：

* 变更实体高亮
* 影响路径列表
* 相关测试表
* 风险标签

### 3. 详情视图

点击 `DiscountPolicy.apply` 显示：

```
id / file / lines
callers
callees
tests
recent changes (如有)
```

## 最小实现路径

阶段 A：

* 读取 `code-graph.json`
* Mermaid 渲染调用链
* Markdown 渲染影响报告

阶段 B：

* 增加交互过滤与搜索
* 节点点击展示 JSON 详情

阶段 C（可选）：

* React Flow / Cytoscape 增强

## 页面信息架构

```
[仓库][PR选择][符号搜索]
-------------------------
| 子图 | 路径/测试/风险 |
| | 详情/源码片段 |
-------------------------
| 查询轨迹 / 报告导出 |
```

## 数据到视图的绑定契约

UI 不应各自拼装字符串，而应消费统一产物：

| 视图    | 数据来源                                   | 关键字段                                                        |
| ----- | -------------------------------------- | ----------------------------------------------------------- |
| 图谱视图  | `code-graph.json`                      | `nodes[]`, `edges[]`                                        |
| 影响面视图 | `impact-report-pr-42.json`             | `changed_entities`, `impact_paths`, `related_tests`, `risk` |
| 详情/报告 | `verification-report-pr-42.md` + graph | 路径、测试、规则、轨迹                                                 |

### 图谱视图伪代码

```
load graph
filter nodes by module in {order, pricing, payment}
keep edges type in {contains, calls}
render task subgraph
on node click -> open detail(node.id)
```

### 影响面视图伪代码

```
load impact report for PR-42
highlight changed_entities on graph
list impact_paths as ordered chains
table related_tests with status hint
badge risk.level + risk.reasons
```

### 详情面板最小 JSON

点击 `method:DiscountPolicy#apply` 时展示：

```json
{
  "id": "method:DiscountPolicy#apply",
  "file": "src/main/java/com/minishop/pricing/DiscountPolicy.java",
  "lines": [3, 10],
  "callers": ["method:PricingService#calculateTotal"],
  "callees": [],
  "tests": [
    "test:PricingServiceTest#shouldApplyVipDiscount",
    "test:OrderServiceTest#shouldCreateVipOrderWithDiscount"
  ],
  "edge_meta": {"source": "static", "confidence": "high"}
}
```

## 工作示例：用静态页交付 PR-42

最小可交付不必上框架：

1. `index.html` 左栏渲染 Mermaid 调用链
2. 右栏 `fetch`/`embed` `impact-report-pr-42.json` 生成路径列表
3. 底部链到 `verification-report-pr-42.md`
4. 节点 `id` 显示为可复制文本，便于 Agent/人对照

验收时只问一件事：Reviewer 能否在 60 秒内回答“改了谁、影响谁、测什么、风险为何是 medium”。

## 反模式

| 反模式         | 问题          | 纠正                   |
| ----------- | ----------- | -------------------- |
| 默认全仓力导向大图   | 认知过载，找不到变更  | 默认任务子图               |
| 图与报告各算各的    | 数字不一致，失去证据  | 同源 JSON              |
| 只有漂亮图无可回跳路径 | 不能进入 Review | 节点回源码/文件行            |
| 隐藏低置信边      | 假安全感        | 显示 source/confidence |

## 验收

* 能看到 `apply -> calculateTotal -> createOrder`
* 能打开 `PR-42` 报告
* 能从节点定位到文件路径
* 不出现无过滤全图爆炸

可视化界面成功的标准很苛刻也很快检验：Reviewer 能否在 60 秒内看懂 PR-42 改了谁、影响谁、测什么、风险为何是 medium。做不到，就说明默认视图仍在服务“展示图谱”，而不是服务决策。

数据同源是底线。若图上的路径与 Markdown 报告来自两套临时拼装，界面会成为新的不一致源。先让三视图读同一批 artifacts，再考虑布局美化和图交互库。

## 局限

* 最小 UI 不支持复杂协作与权限。
* 大图交互需要额外性能优化。
* 可视化不能补齐采集阶段缺失的事实。

界面上的一句“边来源：static / confidence: high”，往往比多两种布局主题更能提升信任。UI 工程在这里与信息设计重合：你不是在做产品增长，而是在做可审证据的呈现。

## 小结

1. UI 服务证据，不服务装饰。
2. 三视图足够支撑理解与验证。
3. Mermaid+报告可先交付价值。
4. 交互增强不应破坏数据同源。

## 可访问性与可解释性

技术图若无法解释，就不是证据。UI 文案建议强制出现：

* “为什么看到这些节点”（查询条件）
* “边的来源与置信度”
* “点击可回源码”
* “证据更新时间”

缺这四项，界面再漂亮也难以进入严肃 Review 流程。

## 工作示例：PR 阅读 60 秒路径

1. 打开影响面视图，看变更实体高亮
2. 展开第一条路径到入口
3. 看相关测试表是否红/需更新
4. 点开规则检查
5. 需要时再下钻图谱邻域

如果用户必须先拖拽全图 5 分钟才能找到变更点，UI 就算失败。

## 常见问题：可视化界面

### 为什么三视图就够？

覆盖理解、验证、详情，足够闭环。

### 必须用 WebGL 大图吗？

否。先证据后炫技。

### 如何验证 UI 成功？

用户能在 60 秒完成 PR 关键路径阅读。

## 本章检查清单

1. 默认子图
2. 节点回源码
3. 来源置信度
4. 报告同源数据

## 关键要点复盘

围绕「构建可视化界面」，读者离开本章前应能做到：

1. 实现三视图与数据绑定契约
2. 保证 60 秒 PR 阅读路径
3. 显示置信度与回源码
4. 避免默认全仓大图
5. 衔接到 Agent 查询接口

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 最小 HTML 骨架（示意）

```html
<section id="graph">
  <!-- Mermaid: apply -> calculateTotal -> createOrder -->
</section>
<section id="impact">
  <h2>PR-42 Impact</h2>
  <ul id="paths"></ul>
  <table id="tests"></table>
  <div id="risk"></div>
</section>
<section id="detail">
  <pre id="node-json"></pre>
  <a id="source-link" href="#">Open source path</a>
</section>
```

交互最低要求：

1. 点击路径高亮对应节点
2. 点击节点填充 `node-json`
3. 风险 `medium` 用非绿色标签（避免“全绿即安全”误导）

## 练习

1. 画一个三栏信息架构草图：子图 / 路径与测试 / 详情。
2. 说明为何默认不能渲染全仓大图。
3. 为节点详情列出必须字段。

## 本章导航

* 上一章：[构建变更影响分析](/di-liu-pian-shi-jian-xiang-mu/build-change-impact-analysis)
* 下一章：[给 AI Agent 的查询接口](/di-liu-pian-shi-jian-xiang-mu/query-interface-for-ai-agent)
* 相关章：[代码图谱：节点、边与属性](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/code-graph-model)；[Agent 上下文工程](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/agent-context-engineering)

## 延伸阅读与参考资料

* [Mermaid docs](https://mermaid.js.org/)：最小可交付图示渲染。
* [Cytoscape.js](https://js.cytoscape.org/)：交互图扩展选项。
* [React Flow](https://reactflow.dev/)：节点详情与工作流式界面。
* [NNG cognitive load](https://www.nngroup.com/articles/minimize-cognitive-load/)：默认子图与信息分层的依据。
* [OpenTelemetry Traces](https://opentelemetry.io/docs/concepts/signals/traces/)：路径可视化直觉；资料卡：`../docs/research-cards/rc-opentelemetry-traces.md`
* [SARIF](https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html)：结果/证据交换格式参考；资料卡：`../docs/research-cards/rc-sarif.md`
* 样例数据：[`code-graph.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/code-graph.json)、[`verification-report-pr-42.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/verification-report-pr-42.md)


# 给 AI Agent 的查询接口

## 本章要解决的问题

Agent 应该通过哪些结构化工具查询代码图谱？

## 读者读完应获得什么

1. 能给出最小工具 schema。
2. 能返回带来源与置信度的结果。
3. 能记录 query\_trace。

## 本章不讲什么

* 不实现完整权限系统。
* 不让 Agent 直接任意写图谱。

***

## 设计原则

1. 输入明确、输出结构化
2. 结果带来源证据
3. 标注不确定性
4. 查询可追踪
5. 写操作与查询分离

## 工具清单

### find\_symbol

```json
{
 "name": "find_symbol",
 "input": {"query": "DiscountPolicy.apply"},
 "output": {
 "matches": [
 {
 "id": "method:DiscountPolicy#apply",
 "file": "src/main/java/com/minishop/pricing/DiscountPolicy.java",
 "start_line": 4,
 "end_line": 10
 }
 ]
 }
}
```

### find\_callers / find\_callees

```json
{
 "name": "find_callers",
 "input": {"symbol": "method:DiscountPolicy#apply", "depth": 3},
 "output": {
 "callers": [
 {"id": "method:PricingService#calculateTotal", "confidence": "high"}
 ]
 }
}
```

### impact\_analysis

输入 Diff 或 changed files，输出与影响面章节一致的结构。

### related\_tests

```json
{
 "input": {"symbol": "method:DiscountPolicy#apply"},
 "output": {
 "tests": [
 "test:PricingServiceTest#shouldApplyVipDiscount",
 "test:OrderServiceTest#shouldCreateVipOrderWithDiscount"
 ]
 }
}
```

### architecture\_rules

```json
{
 "input": {"module": "pricing"},
 "output": {
 "rules": [
 {
 "id": "rule:pricing-no-payment",
 "status": "pass"
 }
 ]
 }
}
```

## 查询轨迹

每次调用追加：

```json
{
 "tool": "find_callers",
 "args": {"symbol": "method:DiscountPolicy#apply"},
 "summary": "1 caller found",
 "ts": "2026-07-22T12:00:00Z"
}
```

轨迹应进入上下文包与验证报告。

## MCP / 本地 API 映射

可先实现 CLI：

```
cv-query find_symbol --q DiscountPolicy.apply
cv-query find_callers --id method:DiscountPolicy#apply
```

再包装为 MCP tools 或 HTTP JSON。

## 错误处理

* 未知符号：返回 empty + suggestion
* 低置信结果：`confidence=low` 且 `needs_confirmation=true`
* 图未索引：明确错误，不可用幻觉补全

## 验收

* 对 mini-shop 图谱 5 类工具可用
* 结果可被 Agent 直接序列化进上下文包
* 轨迹完整

## 工具调用与轨迹

```mermaid
sequenceDiagram
  participant Agent
  participant API as Agent Query API
  participant Store as Graph/Reports
  Agent->>API: impact_analysis(changed_ids)
  API->>Store: reverse paths + tests + rules
  Store-->>API: result
  API-->>Agent: JSON + trace_id
  Note over Agent,API: 失败也要结构化，禁止空影响面伪装成功
```

查询接口章要把“Agent 会用工具”落成 API 合同：请求什么、返回什么、失败什么样、轨迹如何记录。最危险的实现是失败时返回空影响面——模型会把它解释成“无影响”，从而大胆合并。

请把错误视为一等公民：未知 ID、图过期、权限不足都应结构化返回。成功响应则至少能支撑上下文包与验证报告的字段填充。契约稳定后，换 MCP 还是 HTTP 都只是传输层选择。

## 局限

* 接口不负责保证 Agent 一定正确使用结果。
* 无权限模型时不适合直接暴露到公网。
* 图不完整时，工具会诚实返回空/低置信，而不是编造。

## 小结

1. 工具少而稳，胜过自由对话式乱读仓库。
2. schema 与证据字段是接口核心。
3. 查询轨迹是审计能力。
4. 实现可从 CLI 平滑升级到 MCP。

## 安全与权限最小集

即便是教学系统，也建议预留：

1. **只读查询默认开启**
2. **写操作（若有）与查询分离**
3. **返回体避免塞入密钥/本地绝对路径敏感信息**
4. **对超大结果强制 limit + pagination**

示例：

```json
{
 "ok": false,
 "error": "RESULT_TOO_LARGE",
 "hint": "reduce depth or add filter"
}
```

Agent 面对该错误应收缩查询，而不是改去全文读取仓库绕过图谱。

## 契约测试

为防止接口漂移，实践项目应为每个工具准备契约样例：

* 输入 fixture
* 期望输出关键字段
* 在 `mini-shop` 图谱上的金标结果

例如 `find_callers(DiscountPolicy.apply)` 的金标应包含 `PricingService.calculateTotal`。

## 工具响应示例

`impact_analysis` 响应应可直接渲染：

```json
{
  "tool": "impact_analysis",
  "input": {"changed": ["method:DiscountPolicy#apply"]},
  "result": {
    "paths": [["method:DiscountPolicy#apply", "method:PricingService#calculateTotal", "method:OrderService#createOrder", "method:OrderController#create"]],
    "related_tests": ["test:PricingServiceTest#shouldApplyVipDiscount"],
    "risk": "medium"
  },
  "trace_id": "q-17"
}
```

错误响应也要结构化（未知 ID、图过期、权限不足），避免 Agent 把失败当成空影响面。

## 关键要点复盘

围绕「给 AI Agent 的查询接口」，读者离开本章前应能做到：

1. 实现核心工具响应 JSON
2. 返回 trace\_id
3. 结构化错误（未知 ID/图过期）
4. 与上下文包字段对齐
5. 衔接到验证报告

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 练习

1. 为 `find_callers` 写 JSON schema（输入/输出）。
2. 设计未知符号与低置信结果的错误返回。
3. 记录 PR-42 的完整 query\_trace（至少 4 步）。

## 常见问题：查询接口

### REST 还是 MCP？

都能；关键是工具契约稳定与可审计轨迹。

### 图过期如何处理？

返回结构化错误并提示重建索引。

## 本章导航

* 上一章：[构建可视化界面](/di-liu-pian-shi-jian-xiang-mu/build-visualization-ui)
* 下一章：[AI 修改后的验证报告](/di-liu-pian-shi-jian-xiang-mu/ai-change-verification-report)
* 相关章：[代码图谱：节点、边与属性](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/code-graph-model)；[Agent 上下文工程](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/agent-context-engineering)

## 延伸阅读与参考资料

* [Model Context Protocol](https://modelcontextprotocol.io/)。资料卡：`../docs/research-cards/rc-mcp.md`
* [JSON Schema](https://json-schema.org/)
* [LSP](https://microsoft.github.io/language-server-protocol/)。资料卡：`../docs/research-cards/rc-lsp.md`
* [OpenAPI 参考](https://swagger.io/specification/)：若走 HTTP API 的契约思路
* [GitHub Copilot tool/platform docs](https://docs.github.com/en/copilot)
* 样例：[`agent-context-pack.json`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/agent-context-pack.json)


# AI 修改后的验证报告

## 本章要解决的问题

AI 修改后应交付什么验证证据，才能让人和 CI 做出合并判断？

## 读者读完应获得什么

1. 能定义验证报告模板。
2. 能把影响面、测试、规则、查询轨迹组装成交付物。
3. 能用 `PR-42` 完整跑通改后验证故事。

## 本章不讲什么

* 不宣称报告可自动替代负责人决策。

***

![验证报告信息结构](/files/msmmBzYpXHOva0qHbavK)

验证报告是最小系统闭环的最后一环，也是 AI Coding 工具与 Review 流程的交接点。

## 跟做：从 PR-42 产物生成一份可合并报告

本节按仓库内真实文件走一遍，不要求你先实现完整平台。

### 输入

1. 源码（改前）：`examples/mini-shop/src/.../DiscountPolicy.java` 中 VIP 分支为 `0.9`
2. 变更：`examples/mini-shop/artifacts/pr-42.diff`（`0.9` → `0.85`）
3. 图谱：`examples/mini-shop/artifacts/code-graph.json`
4. 影响面：`examples/mini-shop/artifacts/impact-report-pr-42.json`
5. 上下文：`examples/mini-shop/artifacts/agent-context-pack.json`

### 手工步骤（15 分钟）

1. 打开 diff，确认变更落在 `DiscountPolicy.apply` 的字面量，而不是日志字符串。
2. 在图谱中定位 `method:DiscountPolicy#apply`，列出 callers。
3. 对照影响面 JSON：路径应到达 `OrderController.create`，测试应包含两个 VIP 断言测试。
4. 计算示例：`qty=2, unitPrice=100` → 原总价 `180.0`，新总价 `170.0`。
5. 写报告时把“业务是否批准 0.85”留在人工确认区；自动证据只保证影响与测试识别正确。
6. 最终与 `verification-report-pr-42.md` 逐段对照：摘要、路径、测试、规则、轨迹、建议。

若你的实现输出与金标在实体 ID 或路径节点上不一致，先修采集/建图，不要先美化 Markdown。

## 报告模板

```markdown
# 验证报告：<PR/任务>

## 改动摘要
## 变更实体
## 影响路径
## 相关测试与结果
## 架构/安全规则
## 风险与残留不确定点
## 查询轨迹
## 建议动作
```

完整示例：[`artifacts/verification-report-pr-42.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/verification-report-pr-42.md)

## PR-42 故事线

1. Agent 领取“调整 VIP 折扣”任务
2. 通过查询接口构建上下文包
3. 修改 `DiscountPolicy.apply`
4. 运行影响面分析
5. 发现测试断言需从 180.0 更新到 170.0
6. 更新测试并重跑
7. 导出验证报告供 Review

## 字段来源

| 字段   | 来源模块                         |
| ---- | ---------------------------- |
| 变更实体 | analysis/diff mapper         |
| 影响路径 | graph callers search         |
| 测试   | related\_tests + test runner |
| 规则   | architecture\_rules          |
| 查询轨迹 | api query logger             |

## 机器可读 + 人可读

同时输出：

* `verification-report.json`（CI/工具消费）
* `verification-report.md`（人读/PR 注释）

二者字段同源，避免两套真相。

## 合并建议逻辑（示例）

```
if architecture_fail: block
elif high_risk and tests_missing: block
elif medium_risk and tests_green: approve_with_notes
else: manual_review
```

逻辑应可配置，并始终展示 reasons。

## 验收

* 对 PR-42 生成报告
* 含路径、测试、风险、轨迹
* 可被 UI 与 PR 注释复用
* 与 impact-report 数据一致

## 局限

* 报告质量受图谱与测试质量上限约束。
* 自动合并建议不能替代责任人决策。
* 跨系统副作用（配置中心、特性开关）可能不在报告内。

验证报告是合并谈判的公共文本。它让 Agent、作者、Reviewer 和未来的自己站在同一页上。若报告缺轨迹或实体 ID，谈判就会退回印象与职权；若报告完整，争论可以收敛到真正需要人决定的业务点——例如 0.85 是否被批准。

## 小结

1. 验证报告是 AI 修改的标准交付物。
2. 证据必须同源、可回跳、可机读。
3. 测试与规则结果要进入同一报告。
4. 到这里，最小代码理解闭环完整闭合。

## 报告分级模板

### Blocker

架构规则失败 / 高危路径无测试 / 解析失败

### Major

金额/权限语义变化、跨模块影响、测试需更新未更新

### Minor

日志文案、低置信候选边、文档同步

`PR-42` 至少是 Major：金额语义变化 + 测试断言过期。

## 工作示例：JSON 与 Markdown 同源

JSON：

```json
{"risk":{"level":"medium","reasons":["money_path","tests_stale"]}}
```

Markdown：

```markdown
风险：中
原因：金额路径；测试断言过期
```

禁止两套手写结果；必须由同一 `Report` 对象渲染，否则 CI 与人工评论会打架。

## 常见问题：验证报告

### 报告由谁生成？

系统生成；模型只能起草说明。

### 能否自动合并？

可建议，不可默认免责自动合并高风险变更。

### JSON 和 Markdown 哪个权威？

同一对象双渲染，禁止两套手写。

## 本章检查清单

1. 字段同源
2. 风险可解释
3. 测试结果纳入
4. 轨迹可回放
5. 门禁策略透明

## 关键要点复盘

围绕「AI 修改后的验证报告」，读者离开本章前应能做到：

1. 列出报告必填七段
2. 用稳定实体 ID 而非仅文件名
3. 附查询轨迹与人工待确认
4. 对照 verification-report 金标
5. 完成实践闭环回顾

若任一做不到，请先复习本章例子与练习，再继续向后读。

## 验证报告必填章节

1. 变更摘要（实体 ID，不是只写文件名）
2. 影响路径
3. 相关测试与结果
4. 架构规则
5. 风险与建议动作
6. 查询轨迹
7. 人工待确认项

`examples/mini-shop/artifacts/verification-report-pr-42.md` 是金标样例。缺轨迹或实体 ID 的报告不得标记为完成。

## 练习

1. 按模板重写 PR-42 报告的“建议动作”部分。
2. 设计 machine-readable JSON 与 Markdown 的字段映射表。
3. 给出 merge 门禁伪策略，并说明为何不能完全自动免责。

## 本章导航

* 上一章：[给 AI Agent 的查询接口](/di-liu-pian-shi-jian-xiang-mu/query-interface-for-ai-agent)
* 下一章：无（全书正文结束；请回到实践闭环复盘）
* 相关章：[代码图谱：节点、边与属性](/di-san-pian-cheng-xu-fen-xi-yu-dai-ma-tu-pu/code-graph-model)；[Agent 上下文工程](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/agent-context-engineering)

## 延伸阅读与参考资料

* [SARIF](https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html)。资料卡：`../docs/research-cards/rc-sarif.md`
* [GitHub PR comments API 概念](https://docs.github.com/en/rest/issues/comments)
* [JUnit XML 报告生态](https://github.com/testmoapp/junitxml)
* [CodeQL scanning](https://codeql.github.com/docs/codeql-overview/about-code-scanning-with-codeql/)
* [Test Impact Analysis](https://learn.microsoft.com/en-us/azure/devops/pipelines/test/test-impact-analysis)。资料卡：`../docs/research-cards/rc-test-impact.md`
* 样例：[`verification-report-pr-42.md`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/artifacts/verification-report-pr-42.md)


# 附录


# 术语表

本术语表服务《Code Visualization》出版级终稿。正文关键术语应与本表一致。

## 使用约定

1. 同一概念全书只用一个主术语；别名在“近义/勿混”中标注。
2. 中英文并存时，正文主用中文，必要时括注英文或缩写。
3. 缩写首次出现写全称，其后可用缩写。
4. 若章节使用近义说法，应能映射回本表主术语。

## 核心术语

| 术语        | 英文/缩写                           | 定义                                            | 近义/勿混                 | 主要章节                |
| --------- | ------------------------------- | --------------------------------------------- | --------------------- | ------------------- |
| 软件理解系统    | Software Understanding System   | 采集、分析、建模、查询代码及相关事实，并服务开发/Review/Agent 决策的系统能力 | 不等于单张架构图或一次性可视化       | part1, part5, part6 |
| 代码可视化     | Code Visualization              | 以图、路径、矩阵、报告、查询结果表达代码事实的方法与界面层                 | 不等于装饰性画图              | part1, part3        |
| 代码图谱      | Code Graph                      | 以节点、边、属性组织代码与相关事实的可查询模型                       | 不等于单一调用图视图            | part3, part6        |
| 结构事实      | Structural Fact                 | 从源码结构得到的实体与关系（文件/类/方法/候选调用等）                  | 不等于运行时事实              | part2, part3        |
| 行为事实      | Behavioral Fact                 | 从执行中得到的事实（Trace、Coverage、Profile 等）           | 不等于静态可能路径             | part3               |
| 演进事实      | Evolutionary Fact               | 从 Diff/Commit/PR/缺陷历史得到的变化事实                  | 不等于影响面报告本身            | part3, part4        |
| 组织事实      | Organizational Fact             | Owner、团队、服务目录、架构规则等协作与治理信息                    | 不等于代码结构               | part1, part4        |
| AST       | Abstract Syntax Tree            | 抽象语法树，表达语法结构而非文本外观                            | 不等于 CST 的全部细节，也不等于符号表 | part2               |
| Token     | Token                           | 词法分析得到的最小语法单元                                 | 不等于 AST 节点            | part2               |
| 词法分析      | Lexical Analysis / Lexer        | 将字符流切分为 Token 的过程                             | 不等于语法分析               | part2               |
| 语法分析      | Syntax Analysis / Parser        | 将 Token 组织成树结构的过程                             | 不等于语义分析               | part2               |
| 符号表       | Symbol Table                    | 名称定义、作用域与绑定信息的集合                              | 不等于 AST 本身            | part2               |
| 作用域       | Scope                           | 名称可见与绑定生效的程序区域                                | 不等于文件边界 alone         | part2               |
| 定义-引用     | Definition-Reference            | 符号定义与其使用点之间的解析关系                              | 不等于文本同名匹配             | part2               |
| IR        | Intermediate Representation     | 便于分析/优化的中间表示                                  | 不等于源码 AST             | part2               |
| SSA       | Static Single Assignment        | 每个变量赋值唯一命名的 IR 形式                             | 不等于业务语义正确性            | part2               |
| CFG       | Control Flow Graph              | 控制流图，描述可能执行路径                                 | 不等于调用图                | part2, part3        |
| DFG       | Data Flow Graph                 | 数据流图，描述值的产生与使用传播                              | 不等于 CFG               | part2, part3        |
| 调用图       | Call Graph                      | 方法/函数间调用关系图                                   | 需标注静态/动态与置信度          | part3, part4        |
| 静态分析      | Static Analysis                 | 不执行程序，从源码/字节码/IR 推导事实                         | 不等于测试或证明无缺陷           | part3               |
| 动态分析      | Dynamic Analysis                | 基于运行/测试时信号获得事实                                | 未见不等于不可能              | part3               |
| 变更分析      | Change Analysis                 | 将版本历史映射为可查询演进事实                               | 不等于影响面分析全过程           | part3               |
| 影响面分析     | Change Impact Analysis          | 从变更实体推导影响路径、相关测试与风险                           | 不等于只看 diff 行          | part4, part6        |
| 变更实体      | Changed Entity                  | Diff 映射到的类/方法等稳定代码实体                          | 不等于文件路径 alone         | part4, part6        |
| 证据层       | Evidence Layer                  | 可审计、可回跳源码/数据的验证信息集合                           | 不等于模型自然语言解释           | part3, part5        |
| 置信度       | Confidence                      | 对某条边/结论确定性的标注（如 high/medium/low）              | 不等于业务优先级              | part3, part6        |
| Agent 上下文 | Agent Context                   | 为完成任务提供给 AI Agent 的结构化相关信息与约束                 | 不等于更大上下文窗口            | part5               |
| 上下文包      | Context Pack                    | 可序列化任务上下文（符号、调用方、测试、规则、轨迹等）                   | 不等于 prompt 原文         | part5, part6        |
| 查询轨迹      | Query Trace                     | 工具调用与结果摘要的可审计记录                               | 不等于最终补丁               | part5, part6        |
| 验证报告      | Verification Report             | 修改后的影响面、测试、规则、风险与轨迹汇总                         | 不等于单独 CI 绿勾           | part5, part6        |
| 架构规则      | Architecture Rule               | 模块依赖/分层等可检查约束                                 | 不等于文档中的期望架构 alone     | part4, part5        |
| 事实架构      | As-is Architecture              | 由代码与关系数据反映的真实结构                               | 不等于宣称架构               | part4               |
| 宣称架构      | To-be / Documented Architecture | 文档或目标中的架构意图                                   | 不等于代码现状               | part4               |
| mini-shop | —                               | 全书贯穿的模拟订单计价示例仓库                               | 非真实业务系统               | 全书                  |
| PR-42     | —                               | mini-shop 中 VIP 折扣从 0.9 调整为 0.85 的模拟变更        | 教学案例，非真实 PR           | part4-part6         |

## 缩写速查

| 缩写   | 全称                           |
| ---- | ---------------------------- |
| AST  | Abstract Syntax Tree         |
| CST  | Concrete Syntax Tree         |
| IR   | Intermediate Representation  |
| SSA  | Static Single Assignment     |
| CFG  | Control Flow Graph           |
| DFG  | Data Flow Graph              |
| PDG  | Program Dependence Graph     |
| LSP  | Language Server Protocol     |
| MCP  | Model Context Protocol       |
| OTel | OpenTelemetry                |
| PR   | Pull Request                 |
| CI   | Continuous Integration       |
| ADR  | Architecture Decision Record |
| CPG  | Code Property Graph          |

## 模块与产物命名（实践一致）

| 名称        | 含义                                     |
| --------- | -------------------------------------- |
| collector | 源码扫描与 AST 抽取模块                         |
| graph     | 节点/边存储与查询模块                            |
| analysis  | 影响面与测试推荐模块                             |
| api       | Agent 查询接口                             |
| report    | 验证报告生成                                 |
| artifacts | `examples/mini-shop/artifacts/` 标准样例产物 |

## 维护规则

1. 新增术语先改本表，再进正文。
2. 审校时抽查正文是否漂回近义混用。
3. 与 `docs/research-cards/` 中的标准术语保持一致。


# 贯穿案例：mini-shop

本目录定义全书共用的模拟案例包。案例不对应真实业务或真实仓库，目标是让不同章节复用同一组代码、同一组变更和同一组 Agent 任务。

## 案例目标

`mini-shop` 模拟一个极小的订单计价系统，覆盖本书主线：

```
源码结构 -> AST/符号/调用 -> 代码图谱 -> 变更影响面 -> Agent 上下文 -> 验证报告
```

它故意保持很小，但足够体现：

1. 跨模块调用：`order` 依赖 `pricing` 和 `payment`
2. 同名方法歧义：多处出现 `save` / `calculate`
3. 测试关联：改计价逻辑会影响订单测试
4. Agent 风险：只看局部文件时容易漏改调用方和测试

## 仓库结构

```
examples/mini-shop/
  README.md
  src/main/java/com/minishop/
    order/
      OrderController.java
      OrderService.java
      OrderRepository.java
    pricing/
      PricingService.java
      DiscountPolicy.java
    payment/
      PaymentClient.java
  src/test/java/com/minishop/
    order/
      OrderServiceTest.java
    pricing/
      PricingServiceTest.java
```

## 核心业务故事

用户创建订单时：

1. `OrderController.create` 接收请求
2. `OrderService.createOrder` 组装订单
3. `PricingService.calculateTotal` 计算总价
4. `DiscountPolicy.apply` 应用折扣
5. `PaymentClient.charge` 发起支付
6. `OrderRepository.save` 持久化订单

## 贯穿任务

| 任务 ID | 场景                                         | 用于章节                                |
| ----- | ------------------------------------------ | ----------------------------------- |
| T1    | 从 `PricingService.calculateTotal` 源码提取 AST | part2/source-to-ast                 |
| T2    | 解析 `calculateTotal` 的符号、参数类型和方法引用          | part2/symbols-scopes-types          |
| T3    | 构建 order/pricing/payment 调用图               | part3/code-graph-model              |
| T4    | PR-42：修改折扣逻辑后的影响面分析                        | part4/change-impact-verification    |
| T5    | Agent 任务：调整 VIP 折扣，需要正确上下文包                | part5/agent-context-engineering     |
| T6    | 生成验证报告：相关测试、风险路径、查询轨迹                      | part6/ai-change-verification-report |

## PR-42 变更摘要

假设一次未完成修改：

* 文件：`pricing/DiscountPolicy.java`
* 目标：VIP 折扣从 `0.9` 改为 `0.85`
* 风险：
  * `PricingService.calculateTotal` 直接受影响
  * `OrderService.createOrder` 间接受影响
  * `OrderServiceTest` 和 `PricingServiceTest` 需要更新断言
  * 日志文本中的 `calculate` 字符串不应被误判为调用

## Agent 常见错误

如果 Agent 只读取 `DiscountPolicy.java`：

1. 可能只改常量，不更新测试
2. 可能不知道 `OrderService` 依赖该折扣结果
3. 可能用字符串搜索误匹配日志文本
4. 可能无法说明影响路径，导致 Review 无法审计

正确上下文至少应包含：

* 目标符号：`DiscountPolicy.apply`
* 直接调用方：`PricingService.calculateTotal`
* 上层调用方：`OrderService.createOrder`
* 相关测试：`PricingServiceTest`、`OrderServiceTest`
* 架构约束：pricing 不应直接依赖 payment

## 使用约定

1. 正文引用案例时统一写 `mini-shop`，不要另起一套虚构业务。
2. 例子优先使用 Java，因为类型和声明结构更适合讲解 AST/符号。
3. 如需对照其他语言，可补充 TypeScript/Python 片段，但不替换主案例。
4. 所有报告、JSON、查询接口示例都应基于本案例的实体命名。

## 相关文件

* 案例源码：[`../../examples/mini-shop/`](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/examples/mini-shop/README.md)
* AST 样章：[`../../part2/source-to-ast.md`](/di-er-pian-yuan-ma-jie-gou-hua-yuan-li/source-to-ast)
* 影响面样章：[`../../part4/change-impact-verification.md`](/di-si-pian-san-ge-he-xin-gong-cheng-chang-jing/change-impact-verification)
* Agent 上下文样章：[`../../part5/agent-context-engineering.md`](/di-wu-pian-ai-shi-dai-de-xin-ying-yong/agent-context-engineering)

## 标准产物（artifacts）

为便于各章引用同一输入输出，`examples/mini-shop/artifacts/` 提供：

| 文件                             | 用途         |
| ------------------------------ | ---------- |
| `code-graph.json`              | 最小代码图谱     |
| `pr-42.diff`                   | 模拟 PR Diff |
| `impact-report-pr-42.json`     | 影响面分析结果    |
| `agent-context-pack.json`      | Agent 上下文包 |
| `verification-report-pr-42.md` | 验证报告       |

后续写作与实践实现应以这些契约为准。

## 标准产物路径

| 产物         | 路径                                                          |
| ---------- | ----------------------------------------------------------- |
| 代码图谱       | `examples/mini-shop/artifacts/code-graph.json`              |
| PR diff    | `examples/mini-shop/artifacts/pr-42.diff`                   |
| 影响面报告      | `examples/mini-shop/artifacts/impact-report-pr-42.json`     |
| Agent 上下文包 | `examples/mini-shop/artifacts/agent-context-pack.json`      |
| 验证报告       | `examples/mini-shop/artifacts/verification-report-pr-42.md` |

正文与练习引用上述路径时，实体 ID 以图谱为准（例如 `method:DiscountPolicy#apply`）。

## 全书跟做主线（建议 90 分钟）

把下面顺序当作阅读/实践主线；各章细节都服务于这条链。

| 步 | 动作                | 打开的文件                                    | 对应章节                    |
| - | ----------------- | ---------------------------------------- | ----------------------- |
| 1 | 读关键路径与测试断言（180.0） | `src/**`、两个 Test                         | part2/part4             |
| 2 | 读 PR-42 diff      | `artifacts/pr-42.diff`                   | part3 变更分析、part4 影响面    |
| 3 | 对照图谱实体与调用边        | `artifacts/code-graph.json`              | part3 图谱、part6 建图       |
| 4 | 对照影响面报告           | `artifacts/impact-report-pr-42.json`     | part4 影响面、part6 影响面实现   |
| 5 | 读 Agent 上下文包      | `artifacts/agent-context-pack.json`      | part5 上下文/查图            |
| 6 | 对照验证报告并理解人工确认项    | `artifacts/verification-report-pr-42.md` | part5 Review、part6 验证报告 |

金标数字：

* 折扣：`0.9` → `0.85`
* 示例总价：`180.0` → `170.0`
* 变更实体：`method:DiscountPolicy#apply`
* 架构规则：`pricing` 不得依赖 `payment`

源码保持改前状态，便于你自己应用 diff 并复算。


# 版本与勘误

## 2026-07-22 — 其余偏清单章叙述加厚（未推送）

* 对 part1–part6 中仍偏清单的章节补充论述段落与工程判断
* 保持结构门槛与案例金标不变，目标是提升技术书读感

## 2026-07-22 — 叙述纵深与 PR-42 跟做主线（未推送）

* 加厚架构/AI 动机/基础设施/符号/影响面/验证报告等章的论述
* 影响面与验证报告增加可跟做剧本；sample-case 增加 90 分钟全书主线
* 目标：降低手册模板感，增强技术书可读性（仍不推送远端）

## 2026-07-22 — 本地 RC 加厚轮次（未推送）

* 终审：本地 DoD A/B/C(构建) 通过；标记本地 RC Ready；公开同步 E006 仍阻塞宣布
* 附录进入 SUMMARY（术语表/案例/勘误/资料卡）；部署说明改为本地优先；强化 mini-shop 跟做入口
* 28 章补交叉导航；关键章补 FAQ/检查清单，满足 DoD 交叉引用要求
* 无图章补 Mermaid；28 章关键要点复盘去模板化；UI 章补资料卡回指
* 资料卡字段补齐；证据章方法步骤；验证报告实体 ID 对齐；DoD §12 本地项勾选（E006 除外）
* part1 三章补失败模式/事实速查/五层产物映射；矩阵与 image-plan 状态与现网文件对齐
* part1 三章补失败模式/事实速查/五层产物映射；矩阵与 image-plan 状态与现网文件对齐
* 针对薄弱章补充 schema、工作示例、报告模板、失败模式与验收契约
* 重点加厚：符号表、CFG/DFG、图谱模型、静态/动态/变更分析、可视化 UI、AI 重构/Review、实践篇多章
* `npm run build` 通过；SUMMARY/内链检查通过；artifacts 与 PR-42 实体一致
* **未推送远端**；公开站点同步（E006）仍待你明确授权后再做

## 当前版本

* 版本名：RC 筹备稿（Beta 内容可读稿之上）
* 目录状态：已冻结
* 目标：出版级终稿（见 `definition-of-done.md`）

## 近期变更

### 2026-07-22（RC 推进）

* 确认公开站点 `code-visualization.shawnxie.top` 仍为旧版内容，RC 发布同步仍开放
* 语言机械审校与审校记录补充

### 2026-07-22（RC 推进 earlier）

* 建立并扩充术语表、图示清单、资料卡（18）、审校清单、changelog
* 28 章统一补齐练习，并增强权威参考资料与资料卡回指
* 样章与关键章继续加厚；大纲保持冻结

### 2026-07-22

* 完成定义升级为出版级终稿（RC）
* 增加内容丰富度与权威引用硬门槛
* 冻结大纲，补充 part5/part6 职责边界
* 建立术语表、图示清单骨架
* 建立贯穿案例 `mini-shop` 与 artifacts
* 28 章达到 Beta 可读结构

## 反馈与勘误

如发现事实错误、断链、术语不一致或案例数字冲突，请通过 README 中的联系方式反馈，并尽量提供：

1. 章节路径
2. 问题描述
3. 建议来源（官方文档/论文链接更佳）


# 资料卡索引

资料卡用于支撑出版级终稿的权威引用与事实校验。格式见 `docs/ai-writing-framework.md`。

## 已建立

| 资料卡                                                                                                                                               | 主题                       | 主要章节                |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | ------------------- |
| [rc-tree-sitter.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-tree-sitter.md)                       | Tree-sitter              | part2, part6        |
| [rc-antlr.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-antlr.md)                                   | ANTLR                    | part2               |
| [rc-javaparser.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-javaparser.md)                         | JavaParser               | part2, part6        |
| [rc-jls-names.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-jls-names.md)                           | JLS Names                | part2               |
| [rc-lsp.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-lsp.md)                                       | LSP                      | part2               |
| [rc-codeql-dataflow.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-codeql-dataflow.md)               | CodeQL Data Flow         | part2, part3, part5 |
| [rc-opentelemetry-traces.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-opentelemetry-traces.md)     | OpenTelemetry Traces     | part3               |
| [rc-git-diff.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-git-diff.md)                             | Git Diff                 | part3, part4, part6 |
| [rc-mcp.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-mcp.md)                                       | MCP                      | part5, part6        |
| [rc-swe-bench.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-swe-bench.md)                           | SWE-bench                | part1, part5        |
| [rc-github-copilot-explore.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-github-copilot-explore.md) | Copilot codebase explore | part4, part5        |
| [rc-backstage-catalog.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-backstage-catalog.md)           | Backstage Catalog        | part1, part5        |
| [rc-strangler-fig.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-strangler-fig.md)                   | Strangler Fig            | part4, part5        |
| [rc-adr.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-adr.md)                                       | ADR                      | part4               |
| [rc-sarif.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-sarif.md)                                   | SARIF                    | part5, part6        |
| [rc-neo4j-modeling.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-neo4j-modeling.md)                 | Graph modeling           | part3, part6        |
| [rc-sqlite.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-sqlite.md)                                 | SQLite                   | part6               |
| [rc-test-impact.md](https://github.com/Xiaoxie1994/code-visualization-book/tree/main/docs/research-cards/rc-test-impact.md)                       | Test Impact Analysis     | part4, part6        |

## 使用规则

1. 正文关键判断优先引用一级/官方来源。
2. 章末参考资料应能回指资料卡或同等权威链接。
3. 新增来源先补资料卡，再进正文。


