Files
code-review-graph/CODE_REVIEW_GUIDE_ZH.md
T

56 KiB
Raw Blame History

代码审查功能文档

代码审查能力由两个独立工作流组成:unified-reviewdiff 审查)与 project-review(项目级审查)。本文聚焦审查工作流的操作细节(流程、覆盖度机制、客观指标、报告产物、实操踩坑)。

📖 文档分工

  • 本文CODE_REVIEW_GUIDE_ZH.md)— 审查流程 / 指标解读 / 覆盖度机制 / 报告产物 / 踩坑记录
  • 工具总览CODE_REVIEW_GRAPH_ZH.md)— 工具定位、MCP 工具清单、CLI 命令、配置与部署、opencode 集成现状

目录

  1. 两种审查工作流
  2. unified-reviewdiff 代码审查
  3. project-review:项目级代码审查
  4. 并行深读流水线
  5. 审查调用的 MCP 工具
  6. 5 项客观指标详解
  7. 审查 Skill 体系
  8. 审查报告成果物
  9. 快速上手

1. 两种审查工作流

维度 unified-review project-review
审查对象 git diff(默认 HEAD~1..HEAD 全部源文件 / 单个功能
范围来源 自动检测 git diff 由用户自然语言指令决定
opencode 命令 /code-review-graph-unified-review /code-review-graph-project-review
MCP prompt /code-review-graph:unified_review /code-review-graph:project_review

共同特性

  • 只读:不修改代码,所有修复由人工裁决
  • 客观评分:统一走 score_review_tool 的 5 项量化指标
  • 去重合并:统一走 dedupe_findings_tool
  • 双格式报告:默认产出中文 HTML + Markdown
  • 验收门禁:任一 🔴 blocker → 判定 ❌ FAIL

2. unified-reviewdiff 代码审查

2.1 执行流程

步骤 做了什么 起到什么功能
Step 0 范围 固定 standard 档位(全层审查);检测语言/框架;判定 change/file/service/chain 级范围 决定审查深度与范围粒度,避免对简单改动做全量审查,对高风险模块自动升级审查强度
Step 1 图谱上下文 build_or_update_graph 确保图谱最新;get_review_context 拿 blast radius + 源码片段;detect_changes 拿风险分、测试缺口、受影响流 让 AI 只读变更波及的最小文件集,建立"改了什么、影响了谁"的全貌,token 高效
Step 2 Layer 1 链路分解 八分类检查(接口/业务/数据/工具/错误处理/安全/性能/可观测性)+ gstack CRITICAL 五类(SQL 数据安全、竞态并发、LLM 信任边界、Shell 注入、枚举完整性) 逐类排查 AI 易漏的高风险缺陷(注入、竞态、信任边界、枚举遗漏),建立分类清单
Step 3 Layer 2 量化评分 score_review_tool 计算 5 项客观指标(SQL 风险/异常分支/冗余率/高风险密度/漏洞启发式);需求覆盖、逻辑对齐等由 LLM 判断(llm_judged 标注) 用数据支撑评分而非主观判断:指标带 good/warn/fail 分级与证据,明确哪些需 LLM 补判
Step 4 specialist 派发 diff ≥ 50 行时并行派发 testing/maintainability/security/performance/data-migration/api-contract 子代理,各自独立审查 用"多个专注专家并行独立审查"覆盖单一视角盲区,多专家确认的 finding 置信度更高
Step 5 合并去重 dedupe_findings_toolpath:line:category 指纹合并、多源确认置信 +1、低置信抑制、计算 PR 质量分 把主审查 + 各 specialist 的 findings 合并成唯一清单,去除重复噪音,量化整体质量
Step 6 人工裁决 只读。每条 finding 带 severity + 置信度 + file:line + 修复建议,按 severity 批量呈现,逐个决定修/不修 把关决策权交给人工,防止 AI 擅自改码;blocker 不可批量跳过,确保高风险项被确认
Step 7 验收门禁 任一 🔴 blocker → verdict ❌ FAIL;分类 Ready / Needs Fix / Unusable 给出明确的合并/上线结论,任何阻塞项都阻止通过,避免带病合并
Step 8 报告 generate_report_toolformat="both")产出中文 HTML + Markdown 报告 生成可分发、可存档的审查成果物,供 PR 描述、文档、评审留痕
Step 9 持久化 gstack-review-log 可用则记录审查结果,否则静默跳过 供跨次审查去重抑制与 /ship 识别,形成审查历史

2.2 档位

审查默认运行在 standard 档位(全层审查:Layer 1 链路分解 + Layer 2 客观评分 + 报告)。tier 参数支持 fast / standard / strict 三档,其中 fast / strict.code-review.yaml 配置或 MCP prompt 调用时指定;/code-review-graph-unified-review 命令固定 standard。覆盖度目标固定为双目标:全库 ≥85% 高风险 ≥95%project-review 三件套口径见 §3.5.4)。


3. project-review:项目级代码审查

3.1 范围解析(Step 0

用户指令 解析结果
"对项目代码进行全面审查" / "全面审查" / "整个项目" scope="whole-project"
"对支付功能的代码进行审查" / "审查 auth 模块" scope="feature", target=<关键词>

3.2 全项目流程(whole-project

步骤 做了什么 起到什么功能
Step 0 范围解析 从用户指令解析出 scope="whole-project" 明确本次审查是整个项目而非 diff/单功能
Step 1 图谱就绪 + 最小上下文 build_or_update_graph_tool() 确保图谱最新;get_minimal_context_tool(task="project review") 拿节点/边/社区/风险概览 保证后续查询基于最新代码结构;最小上下文把全库概览压缩为几百 token,避免主上下文被 500+ 文件淹没
Step 2 架构全景 get_architecture_overview + list_communities(模块地图) 先建立全局模块结构认知,为后续定位高风险区域提供上下文
Step 3 高风险定位 get_knowledge_gaps(未测试热点/孤立节点)+ get_hub_nodes(热点)+ get_bridge_nodes(瓶颈)+ find_large_functions(超大函数)+ get_surprising_connections(异常耦合) 图论分析(节点度、介数中心性、社区划分、测试覆盖边),不读代码内容——它能告诉你"这个函数被 20 处调用,改动影响大",但说不出代码写得如何。
Step 4 全量客观评分 score_review_tool(all_files=True) 评分全部源文件;community_health_tool() 前置检查图谱健康 对每个源文件跑 5 项客观指标,文本质量扫描(_iter_source_lines 读文件逐行匹配正则),不关心调用关系——它能告诉你"这个文件异常处理薄弱",但看不出它是架构瓶颈。社区归属率 <90% 需先 postprocess 重建,否则覆盖度失真。
Step 5 并行深读流水线 deep_read_plan_tool(target_coverage=85, include_prior=True) 生成风险加权分组 → 每次并行派发 4-6 个 explore 子代理分组深读(每组 ≤40 文件)→ 子代理返回 deep_read_files + findings(每条必须带 file:line 证据)→ coverage_tool(deep_read_files=<全清单>, gate="both", include_prior=True) 复算 主上下文不逐文件读 500+ 文件,改为子代理流水线分摊。这是 whole-project 覆盖达标的唯一可行路径。深读计划按风险权重贪心,85% 全库计划先选满全部高风险文件,天然逼近高风险 95%。详见 §3.6
Step 6 覆盖度门禁与补轮 双目标未达标(全库 <85% 或 高风险 <95%)→ 按 coverage_tool 返回的 priority_deep_read_files 补派 1-3 个子代理;silent_files 随机抽 15% 深读(G2),发现 ≥1 major 则升级全量 可量化兜底"该读的都读了",防止审查深度由感觉决定
Step 7 合并去重 dedupe_findings_tool 合并去重 + PR 质量分 统一 findings 清单,量化整体质量
Step 8 人工裁决 + 门禁 只读裁决;任一 🔴 blocker → ❌ FAIL 人工把关 + 明确的审查结论
Step 9 报告 + 自检 generate_report_tool(review_data=..., output_path="docs/reviews/...") 产出 HTML + MarkdownStep 9.5 打开生成的 md 自检(问题清单数、三要素、客观指标表);Step 9.6 跑 verify-report.ps1 命名自检 全项目体检报告,可分发存档;自检防"空报告/漏命名"回归
Step 10 持久化 save_coverage_index_tool(deep_read_files=<本轮全量深读清单>) 写跨轮覆盖索引(file + per-file SHA 下一轮 include_prior=True 自动复用未变更文件,多轮后增量归零即全覆盖

3.3 单功能流程(feature

步骤 做了什么 起到什么功能
Step 0 范围解析 从用户指令解析出 scope="feature", target=<关键词> 明确只审查目标功能,缩小范围
Step 1 图谱就绪 build_or_update_graph_tool() + get_minimal_context_tool 保证查询基于最新代码
Step 2 定位功能代码 semantic_search_nodes(query=target)(语义定位)+ query_graph(children_of, target=<模块>)(模块展开)→ 聚合功能涉及文件 files=[...] 把"功能关键词"转化为具体文件清单,确定审查对象
Step 3 影响面分析 get_impact_radius(changed_files=files) 找出该功能波及的调用方/依赖方,评估改动影响范围
Step 4 客观评分 score_review_tool(changed_files=files + 影响文件) 对功能代码跑 5 项客观指标
Step 5 链路分解 + 深读 Layer 1 八分类 + CRITICAL 检查(聚焦功能文件);文件多时也可用子代理分组深读 逐类排查功能内的高风险缺陷
Step 6 覆盖度计算 coverage_tool(deep_read_files=<功能文件>, gate="both") 复算 功能级覆盖兜底
Step 7 合并去重 dedupe_findings_tool 合并去重 + PR 质量分 统一 findings 清单
Step 8 人工裁决 + 门禁 只读裁决;任一 🔴 blocker → ❌ FAIL 人工把关 + 结论
Step 9 报告 + 自检 generate_report_tool(format="both")md 自检 + verify-report.ps1 功能审查报告,防回归
Step 10 持久化 save_coverage_index_tool 写覆盖索引 跨轮增量复用

3.4 all_files 参数

score_review_tool(all_files=True) 评分图谱内全部源文件,忽略 changed_files 与 git diff,用于全项目审查。默认 False

3.5 覆盖度保障机制

目标:保证"该深读的都读了,不该漏的没漏",用可量化的方式兜底非热点文件。本节是 project-review 的增强约定,unified-review 可复用(把"深读名单"理解为"变更文件 + 高风险文件")。

3.5.1 三层覆盖模型

对应步骤 覆盖范围 手段
L1 全量机械扫描 Step 4 all_files=True 100% 文件 × 5 项指标 正则启发式,查机械性风险
L2 并集信号 → 深读名单 Step 3 + 本节 任一信号点名的文件 多信号并集,无上限
L3 深度审查 Step 5.5 子代理深读 名单内全部文件 逐文件通读(大文件分段),产出带 file:line 证据的 finding

3.5.2 深读名单(并集信号,无上限)

进名单 = 任一命中:
  ① 拓扑热点:hub / bridge / large_functions / knowledge_gaps 标记
  ② Step 4 指标 fail 或 warn 的文件
  ③ churn 热点(≥3 次提交)
  ④ 测试缺口热点(untested_hotspots

任一命中 → 必须深读(无上限)
未被任何信号点名 → 记入"未深读文件清单",在报告中显式列出

关键原则:不覆盖不可怕,不知道没覆盖才可怕。报告必须附带"未深读文件清单",把覆盖边界显式化。

3.5.3 静默文件抽检

  • 从未被信号点名的文件("静默文件")随机抽 15% 深读
  • 升级规则:抽检中发现 ≥1 个 major → 该文件升级为全量深读,并触发同社区/同类文件追加抽检一轮

3.5.4 覆盖度度量(文件数口径 + 三件套质量口径,gate="both+line"

由引擎 coverage_tool 自动计算code-review-graph v2.5.0+,三件套口径 v2.5.1 起),审查代理只需传入 deep_read_files(本轮实际深读清单)、gate 与三件套数据(file_read_ranges / file_semantic_units)。

双重文件数口径:
  全库覆盖 coverage_pct          = 已深读文件数 / 全部源文件数
  高风险覆盖 high_risk_coverage_pct = 已深读高风险文件数 / 信号点名文件数

三件套质量口径(gate="both+line" 时生效):
  ① 单元完整性 unit_coverage_pct   = 语义单元无缺口的深读文件数 / 深读文件数
       语义单元 = 图谱 Function/Class/Test 节点;子代理上报 semantic_units 与其差集必须为空
       巨型文件豁免(最大单元行占比 >80%,如 migrations.rs run_migrations 98%)→ 仅按行覆盖校验
  ② 行覆盖 line_coverage_pct       = 行覆盖达标的深读文件数 / 深读文件数
       分子 = union(read_ranges);分母 = 真实文件行数(非图谱 line_end,±1 偏差已修正)
  ③ 防伪抽验(主代理执行,非引擎)  = 每组抽 2 文件 × 2-3 单元回读比对 note,每波 ≤40 次;
       结果落盘 spot_check_*.json 并注入 review_data.spot_check(顶层字段),
       由 verify-spot-check.ps1 强制校验"已执行"(引擎无法防假读,抽样是唯一手段)

gate 取值:
  "overall"     — 只看全库口径
  "high_risk"   — 只看高风险口径
  "both"        — 全库 + 高风险都要达标(保持原语义,向后兼容)
  "both+line"   — both + 行覆盖 ≥95% + 单元完整性无缺口(whole-project 新默认,见下)

目标值(固定 standard 档位)gate="both+line" 时要求全库 ≥85% 且 高风险 ≥95% 且 行覆盖 ≥95% 且 单元完整性无缺口line_target=95unit_target=100 差集为空)。target_reached=false → 报告顶部标 🔴 覆盖不足,并给出 remaining_files_to_target(还差几个文件)与 priority_deep_read_files(按风险权重降序的待深读清单)驱动补轮;both+line 额外返回 line_gap_files / unit_gap_files / unit_exempt_files 定位具体缺口文件。

增量语义(include_prior=Truesave_coverage_index_tool 在每轮报告后写 .code-review-graph/coverage-index.jsonv2:相对路径 → per-file SHA + ranges 行区间)。SHA 来源为图谱 nodes.file_hash(一次 SQL 查询,零 subprocess——已修复 v2.5.0 逐文件 git hash-object 超时问题)。下一轮 include_prior=True 时自动复用 SHA 未变文件的深读状态及行区间,只要求重读新增/变更文件,多轮后增量归零即全覆盖。

⚠️ 图谱同 range 多节点噪声豁免TS/TSX 图谱可能对同一行解析出多个箭头函数节点(如 const a = ..., x = ... 各占一行但 range 相同),导致单元完整性差集永远非空(one-to-one 匹配下无解)。处理原则:仅当该文件行覆盖已达 100%(或 ≥95%),判定为图谱解析噪声,将该文件从 unit_gap 中豁免并在报告显式标注"图谱同 range 多节点豁免",不要反复补读。unit_gap_files 的判定须结合具体 uncovered 单元名与行号人工确认是否噪声(对比源码该行是否有多个符号)。

⚠️ 0 字节空文件处理:深读计划可能选中空文件(如 web/src/components/evm/EvmConfigModal.tsx0 字节且无引用)。引擎对空文件报 unreadable/empty file 计入 line_gap_files。处理:验证文件字节数与引用情况,确认死文件后从深读清单移除,并作为一条 finding(死代码残留)记录在报告中。

3.5.5 三道闸门

  • G1 名单完整性:名单外文件须确认"被评估过"而非"被忽略",未被任何信号点名的文件记入未深读文件清单并在报告显式列出
  • G1.5 三件套质量门禁复核(v2.5.1+):报告前复核三件套聚合结果——line_gap_files unit_gap_files 必须为空(已补读至空);图谱同 range 多节点噪声豁免的文件须在报告中显式列出(每文件注明"行覆盖已 100%,图谱同 range 多节点豁免"),0 字节空文件须从清单移除并单列 finding;verified_filescoverage_tooldeep_read_files 一致;防伪抽验记录(抽了几组/几个单元/有无假读)附入报告,并由 verify-spot-check.ps1Step 8.8)强制校验
  • G2 抽检执行:用 coverage_tool 返回的 silent_files 随机抽 15% 深读;抽检中发现 ≥1 个 major → 该文件升级为全量深读,并触发同社区/同类文件追加抽检一轮;抽检记录附入报告(抽了几份、发现几个 major、有无升级)
  • G3 覆盖度收尾coverage_tool 自动计算,gate="both+line" 时全库 ≥85% 且 高风险 ≥95% 且 行覆盖 ≥95% 且 单元完整性无缺口才算达标,低于目标在报告顶部告警

3.5.6 执行前的前置检查

运行覆盖度流程前先确认图谱健康——调用 community_health_tool

  1. attribution_pct = nodes.community_id 非空 / 非 File 节点数 的百分比
  2. needs_postprocess=true(归属率 <90%)→ 先跑 code-review-graph postprocess 重建社区归属,再开始审查

已知问题:incremental_detect_communities 在 nodes 重建后可能因 community_id 全 NULL 而判定"无社区受影响"跳过写回,导致 communities.sizenodes.community_id 失同步。community_health_tool 可检出该状态,遇此情况用全量 postprocess 修复。

3.5.7 报告覆盖度透传(防 0/0 渲染)

coverage_tool 的返回值必须完整透传generate_report_toolreview_data.coverage(全部字段:coverage_pct/high_risk_coverage_pct/grade/deep_read_count/total_files/high_risk_total_files/high_risk_deep_count/deep_read_weight/total_weight/target_reached/target/gate/remaining_files_to_target/remaining_weight_to_target/priority_deep_read_files/uncovered_files/silent_files/note)。不要手挑子集——build_report_data 只读固定键名,缺字段会导致报告覆盖度区块渲染成 0/0N/A。报告会自动渲染 ## 覆盖度 区块。


3.6 并行深读流水线(whole-project 强制)

主上下文无法逐文件深读 500+ 文件;必须用并行 explore 子代理分组深读,否则全库覆盖永远卡在 2-5%。覆盖率为文件数口径,且每个深读文件需通过三件套质量门禁(单元完整性 / 行覆盖 / 防伪抽验,见 §3.5.4)。

3.6.1 流程

a. deep_read_plan_tool(target_coverage=85, include_prior=True)
   → 返回 groups[{name, weight, files[]}] + remaining_files
   (引擎按风险权重 + 目录贪心分组,每组 ≤40 文件;include_prior 排除上轮已深读未变更文件)
b. 按组并行派发 explore 子代理(每次 4-6 个,分多批),每组深读全部文件,返回(落盘到临时目录):
   - outputs[]:每文件含 path / total_lines / read_ranges[[s,e]..] /
     semantic_units[{range,kind,name,note}] / findings[]
   - findings[]:每条含 severity/category/confidence/file:line/message/fix
   【证据铁律】无 file:line 证据的条目视为未深读 → 该文件须重读
c. 每波子代理完成后跑三件套门禁(引擎原生支持):
   coverage_tool(deep_read_files=<verified_files>, gate="both+line",
                 file_read_ranges=<{rel:[[s,e]..]}>, file_semantic_units=<{rel:[...]}>)
   → line_gap_files  unit_gap_files → 补读队列;verified → 计入本轮 deep_read_files
   (引擎不可用时兜底:python skills/project-review/scripts/aggregate_deep_read.py <repo_root> <落盘目录>
d. 防伪抽验:每组抽 2 文件、该文件抽 2-3 个语义单元回读比对 note(每波 ≤40 次);
   结果落盘 spot_check_<batch>.json,抽到假读 → 该组重读并升级抽验率
e. 主代理合并全部 verified_files(去重)→
   coverage_tool(deep_read_files=<全清单>, gate="both+line", include_prior=True) 复算
   include_prior 自动复用跨轮索引中 SHA 未变文件及其 read_ranges
f. 未达标(文件数 <85%/<95% 或行覆盖 <95% 或单元有缺口)→ 对 priority_deep_read_files / line_gap_files / unit_gap_files 补派 1-3 个子代理 → 循环直至全达标
g. G2:对 silent_files 随机抽 15% 深读(见 §3.5.5)
h. 报告生成前:聚合全部 spot_check_*.json → 注入 review_data.spot_check(顶层字段)
i. 报告生成 + 命名自检后:verify-spot-check.ps1Step 8.8)→ save_coverage_index_tool(deep_read_files=<verified_files>, file_read_ranges=<ranges>) 写跨轮索引

3.6.2 子代理分组参考(AuraSpace 实测,约 508 文件)

# 约文件数
1-2 server/src/api1/2、2/2 60
3-4 server/src/services1/2、2/2 66
5 server/src/domain + deepwiki + infrastructure 88
6 server/tests + bin + models 17
7-8 web/src/views1/2、2/2 60
9-11 web/src/components1/3、2/3、3/3 110
12 web/src/store + utils + api 50
13 web/tests + scripts + SQL 57

实际分组以 deep_read_plan_tool 返回为准;每次并行 4-6 个子代理,其余排队,避免 MCP 并发压力与上下文风暴。

3.6.3 质量控制与防伪

风险 对策
子代理"声称读了"但没真读 强制三件套字段(total_lines/read_ranges/semantic_units+ findings 带行号证据;聚合脚本按①单元差集+②行并集双校验;主代理③抽样回读
子代理漏读文件 outputs 与分组清单 diff,漏读文件计入覆盖率缺口,触发补轮
子代理宽 range 冒充全读 单元完整性 one-to-one 匹配:一个上报 range 只能覆盖一个单元,无法用整文件 range 覆盖所有单元
各子代理口径不一 统一八分类 + CRITICAL 子轮 + severity/confidence 标准(子代理 prompt 模板)
增量掩盖新代码 include_prior=True 按 per-file SHA 判定;变更文件自动失效重读
并发压力 每批 4-6 个并行,其余排队;batch_size 40 控制单组体量
主上下文被大 JSON 撑爆 落盘机制:子代理写临时文件,主代理只读聚合摘要

3.6.4 "深读"的含义边界

  • 文件级保证(可量化)deep_read_files 是文件数口径,覆盖 85% 表示 85% 的文件被"读过"(高风险子集要求 95%)
  • 行级保证(v2.5.1 起可量化)read_ranges 的并集 / 真实文件行数 ≥95%;分母为真实文件行数(图谱 line_end 有 ±1 偏差,已弃用)。子代理对每个文件上报 total_lines + read_ranges + semantic_units,聚合脚本/引擎逐文件校验
  • 单元级保证(v2.5.1 起可量化)semantic_units 与图谱 Function/Class/Test 节点差集必须为空(one-to-one 匹配,宽 range 不能冒充);巨型文件(最大单元行占比 >80%)豁免,仅按行覆盖校验
  • 防伪机制findings 必须带 file:line 证据;主代理每轮 ≤15 次单元回读(引擎无法防假读,抽样是唯一手段);抽到假读 → 该组重读并升级抽验率

3.6.5 跨轮增量(多轮累积)

  • 每轮报告后 save_coverage_index_tool.code-review-graph/coverage-index.jsonv2:相对路径 → per-file SHA + ranges 行区间)
  • SHA 来源为图谱 nodes.file_hash(一次 SQL 查询,零 subprocess;已修复 v2.5.0 逐文件 git hash-object 超时)
  • 下一轮 deep_read_plan_tool / coverage_toolinclude_prior=True 自动复用 SHA 未变文件及其行区间 → 增量任务 = 新增文件 + 变更文件
  • 多轮后增量归零即实现全库全覆盖,避免每轮从 2-5% 起步

3.6.6 行级覆盖率执行步骤(新窗口 / 全新审查)

本节给出"行级覆盖率如何落地到一次实际审查"的分步操作。三件套门禁中,行覆盖是唯一有精确数值的维度(union(read_ranges) / 真实行数 ≥95%),本节聚焦它的完整执行链路;单元完整性(差集=空)与防伪抽验在 §3.6.1/§3.6.3 已述。

行级覆盖率的口径(引擎 scoring.py::compute_coverage

行覆盖率(每文件) = |union(read_ranges)| / len(Path(repo/f).read_text().splitlines())
行覆盖达标       = 行覆盖率 >= 95%   line_target,可参数覆盖)
line_coverage_pct = 行覆盖达标的深读文件数 / 深读文件数
line_gap_files   = 行覆盖率 <95% 的文件 [path, coverage_pct, total_lines, covered_lines]
  • 分母 = 真实文件行数(读取源文件,_real_line_count 带缓存)——不用图谱 line_end(实测 ±1 偏差)
  • 分子 = read_ranges 并集——子代理实际上报的读取区间(分段读即天然分段)
  • 无 ranges 上报的文件:行覆盖视为通过(不设硬卡),仅依赖单元完整性 + 抽验

执行步骤(主代理在全新会话中)

Step 0 前置(新窗口)
  - 确认无残留进程:Get-Process code-review-graph → 无输出
  - 首次调用 get_minimal_context_tool 会拉起 MCP serve(加载新引擎,含 both+line

Step 1 建图 + 概览
  - build_or_update_graph_tool() 图谱最新
  - get_minimal_context_tool(task="project review") 全库概览

Step 2 架构 + 高风险扫描(同旧流程,产出风险权重信号)

Step 3 客观评分
  - score_review_tool(all_files=True) + community_health_tool(前置健康检查)

Step 4 深读分组
  - deep_read_plan_tool(target_coverage=85, include_prior=True)
    → groups[{name, weight, files[]}](≤40/组)

Step 5 并行派发子代理(严格模式)
  - 每次 4-6 个 explore 子代理,prompt 见 references/deep-read-pipeline.md §二
  - 每文件必须返回 total_lines / read_ranges[[s,e]..] / semantic_units[{range,kind,name,note}]
  - semantic_units 必须逐一列出图谱全部单元(含 Props/interface/小函数,严格模式)
  - 结果落盘到临时目录(勿回传大 JSON)

Step 6 聚合脚本(每波后)
  - python skills/project-review/scripts/aggregate_deep_read.py <repo_root> <落盘目录>
  - 输出 verified_files / line_gap_files / unit_gap_files / unit_exempt_files
  - 行覆盖判定就在这里:line_gap_files 列出所有 <95% 的文件

Step 7 引擎门禁(行级覆盖率正式数值)
  - coverage_tool(deep_read_files=<verified_files>, gate="both+line",
                  file_read_ranges=<{rel:[[s,e]..]}>, file_semantic_units=<{rel:[...]}>)
  - 返回 line_coverage_pct / unit_coverage_pct / line_gap_files / unit_gap_files / unit_exempt_files
  - ⚠️ 必须传 file_read_ranges/file_semantic_units,否则行/单元覆盖不计算

Step 8 补轮(禁止降级)
  - line_gap_files  unit_gap_files 非空 → 对缺口文件重派子代理补报/重读
  - 禁止回退 gate="both" 静默跳过三件套;必须补至空,或报告显式标注 🔴

Step 9 报告
  - generate_report_tool(review_data.coverage = coverage_tool 全量透传)
  - "## 覆盖度" 区块须含行覆盖/单元覆盖(line_coverage_pct/unit_coverage_pct

Step 10 持久化
  - save_coverage_index_tool(deep_read_files=<verified_files>, file_read_ranges=<ranges>)
  - 写 v2 索引(sha + rangesSHA 来自 nodes.file_hash<1s

新窗口首轮验证(Step 0 后建议先跑一次冒烟)

coverage_tool(deep_read_files=["server/src/services/auth_service.rs"],
              gate="both+line",
              file_read_ranges={"server/src/services/auth_service.rs": [[1,66]]},
              file_semantic_units={"server/src/services/auth_service.rs": [全部 6 单元]})
→ 期望 line_coverage_pct=100, unit_coverage_pct=100, line_gap_files=[]
   (即 V2.1 E2E 验证通过,确认引擎加载了新代码)

常见坑

  • 子代理漏 read_ranges → 该文件行覆盖不计算(不算 gap 但也不验证),依赖单元完整性兜底;严格模式应要求 read_ranges 覆盖整文件
  • 大文件分段时 read_ranges 各段要有重叠边界或连续覆盖,避免 1 行缝隙拉低覆盖率
  • 全库 508 文件行覆盖聚合约 1-2s(分母读取带缓存);save_coverage_index 用 file_hash 后 <1s(不再有逐文件 git subprocess 超时)

3.6.7 实测踩坑与绕行方案(2026-08-18 全库审查实战记录)

本节是 508 文件全库审查(full-project-review-2026-08-18-144500)实测中暴露的、文档正文未覆盖的坑与对应解法。深读流水线各环节的坑按出现顺序记录。

# 环节 症状 解法
1 子代理输出落盘 子代理 JSON 是容器格式 {"group":..., "outputs":[{path, read_ranges, semantic_units, findings}]},而 aggregate_deep_read.py 期望单文件记录(每条记录的 path 在顶层) 聚合脚本 verified=0、全部文件被跳过,且无任何报错 解包:读容器 → 把 outputs 数组逐条拆成独立 JSON 文件(batchN_idx_<path>.json)→ 再跑聚合脚本。可用一段 Python 脚本完成,见下
2 聚合脚本 子代理用 write 写 JSON 可能带 UTF-8 BOM 报错 Unexpected UTF-8 BOM (decode using utf-8-sig) 聚合前批量剥 BOM:读字节,若前 3 字节为 EF BB BF 则写入 bytes[3:]
3 单元完整性补读 首轮聚合 unit_gap 可达 92 个文件(子代理漏报 serde visit_* 小方法、几行的 struct/Props interface unit_gap_files 非空 → 三件套门禁不通过 不要整文件重读。生成 gap_manifest.json(含每文件 uncovered 单元及精确 range),派 1-2 个"补读子代理"按 range 精准读取缺失单元、产出 supplement.json,主代理按 (path, range) 合并回原 payload 后再聚合
4 单元完整性 图谱对同一行解析出多个箭头函数节点(如 AgentConfigPanel.tsxa/x 同 range 420DataPermissionManagement.tsxd/childrenOf 同 range 76 该文件 total_units 高但永远 covered_units 差 1-3 个,one-to-one 匹配不可能满足(一个 range 只能匹配一个单元) 判断为图谱解析噪声:文件行覆盖已 100% 即视为已深读,在报告中显式标注"该文件存在图谱同 range 多节点,单元完整性豁免";不要反复重读
5 深读清单 深读计划可能选中 0 字节空文件(如 web/src/components/evm/EvmConfigModal.tsx line_gap_filesunreadable/empty file,且该文件无任何引用(死文件残留) 验证文件大小与引用:空文件 + 无引用 → 从深读清单移除,作为一条 finding(死代码)单独记录
6 补读子代理 补读子代理若只返回"补了 X 个单元"的一句话而不落盘补充 JSON 主代理拿不到补充的 semantic_units,无法合并 强制补读子代理也必须落盘 supplement*.json(结构化 range+note),主代理脚本合并后重跑聚合
7 MCP 大 JSON dedupe_findings_tool / generate_report_tool 直传 400+ 条 findings 时 MCP JSON 解析失败Invalid escape character / Expected '}' 工具调用直接报 invalid input,报告无法生成 绕行:直接在 Python 里调用引擎函数 code_review_graph.tools.generate_report_func(review_data, output_path=...) / coverage_func(...)sys.path.insert(0, <CRG 引擎路径>) 后 import),输出与 MCP 工具完全一致(见 §4.5)
8 报告统计 MD 报告的"问题统计"只读 countscritical / informational(不读 blocker/major/minor {"blocker":20,"major":141,"minor":315} 时统计显示 "20 严重 · 0 次要"major 数丢失 counts{"critical":<blocker数>, "major":<major数>, "informational":<minor数>} 才能正确渲染

解包 + 剥 BOM 参考脚本(主代理每轮可复用)

# 1) 剥 BOM
for f in glob.glob(dir + "/*.json"):
    b = Path(f).read_bytes()
    if b[:3] == b"\xef\xbb\xbf":
        Path(f).write_bytes(b[3:])
# 2) 解包 outputs → 单文件记录
data = json.load(open(batch, encoding="utf-8"))
for i, rec in enumerate(data["outputs"]):
    out = dir / f"{basename}_{i}_{rec['path'].replace('/','_')}.json"
    out.write_text(json.dumps(rec, ensure_ascii=False), encoding="utf-8")

合并 supplement 参考脚本

bypath = defaultdict(list)                      # path -> [semantic_units...]
for s in supp1 + supp2: bypath[s["path"]] += s["semantic_units"]
for rec in payloads:                            # 每个单文件记录
    if rec["path"] in bypath:
        have = {tuple(u["range"]): u for u in rec.get("semantic_units", [])}
        for u in bypath[rec["path"]]:
            have.setdefault(tuple(u["range"]), u)   # 按 range 幂等合并
        rec["semantic_units"] = list(have.values())

教训:深读流水线的"三件套门禁"把质量控制在引擎侧,但子代理与主代理之间的数据契约(容器格式、BOM、补读落盘)是纯人工编排,任何一处契约不一致都会让 verified 计数归零或三件套不达标。建议每波子代理完成后先跑一次聚合脚本看 verified 数,而非等到全部结束才校验。


4. 审查调用的 MCP 工具

4.1 核心审查工具

工具 功能
score_review_tool 客观 Layer-2 审查指标:SQL 风险、异常分支覆盖、代码冗余率、高风险场景密度、漏洞启发式 5 项,每项带 good/warn/fail 分级、阈值与证据。支持 all_files 全量评分、include_churnllm_judged 列出需 LLM 补判的指标
dedupe_findings_tool Finding 合并去重:按 path:line:category 指纹合并;多源确认置信 +1(上限 10);低置信移附录或抑制;计算 PR 质量分 max(0, 10 - (critical×2 + informational×0.5));支持抑制历史已跳过项
generate_report_tool 审查报告生成:中文 HTML + Markdown(默认 format="both");output_path 传归档目标文件名(含 docs/reviews/ 前缀,不含扩展名)
coverage_tool 覆盖度计算v2.5.0 / 三件套 v2.5.1):传入 deep_read_files + gate(默认 high_risk,可选 overall / both / both+line),引擎自动算双重文件数口径(全库 / 高风险)、未深读清单、静默文件清单、达标状态与待补深读优先级。gate="both+line" 时额外支持 file_read_ranges / file_semantic_units,返回行/单元覆盖三件套(line_coverage_pct / unit_coverage_pct / line_gap_files / unit_gap_files / unit_exempt_files
deep_read_plan_tool 深读分组规划v2.5.0):deep_read_plan_tool(target_coverage=85, include_prior=True, batch_size=40)gate 参数),按风险权重 + 目录贪心生成 groups[{name, weight, files[]}] + remaining_files,主代理据此并行派发子代理
save_coverage_index_tool 跨轮覆盖索引持久化v2.5.0 / v2 索引):把本轮深读清单(file + per-file SHA + 可选 ranges 行区间)写入 .code-review-graph/coverage-index.json,供下一轮 include_prior=True 增量复用。v2.5.1 起 SHA 来源为图谱 nodes.file_hash(零 subprocess,根治逐文件 git hash-object 超时)
community_health_tool 社区归属健康检查v2.4.0+):返回 nodes.community_id 归属率与 needs_postprocess,前置检查用

4.2 图谱上下文工具

工具 用途
build_or_update_graph_tool 确保图谱最新
get_minimal_context_tool 全库概览压缩(节点/边/社区/风险/受影响的流),project-review 主上下文第一步
get_review_context_tool 变更文件 + blast radius + 源码片段 + 审查指引
detect_changes_tool 风险评分 + 变更函数 + 测试缺口 + 受影响流
get_affected_flows_tool 受影响执行流
query_graph_tool 调用方/被调用方/测试/继承查询

4.3 图谱全景工具(project-review 用)

工具 用途
get_architecture_overview_tool 社区耦合总览
list_communities_tool 模块清单
get_knowledge_gaps_tool 结构弱点:孤立节点、未测试热点
get_hub_nodes_tool 最连接节点(架构热点)
get_bridge_nodes_tool 架构瓶颈
find_large_functions_tool 超大函数/类
get_surprising_connections_tool 意外跨社区耦合
semantic_search_nodes_tool 按关键词定位代码(单功能)
get_impact_radius_tool 单功能的 blast radius

4.4 工具调用链

unified-reviewdiff:
  build_or_update_graph → get_review_context → detect_changes
    → score_review_tool → [specialist 子代理] → dedupe_findings_tool → generate_report_tool

project-review(全项目):
  build_or_update_graph → get_minimal_context → 架构全景 + 高风险定位(6 个图谱工具)
    → score_review_tool(all_files=True) + community_health_tool(前置检查)
    → deep_read_plan_tool → [4-6 并行 explore 子代理 × N 批] → coverage_tool(gate="both+line")
    → [未达标]补轮 → [G2]silent 抽检 15%
    → dedupe_findings_tool → generate_report_tool(coverage 完整透传)
    → verify-report.ps1(命名自检) → save_coverage_index_tool(跨轮索引)

project-review(单功能):
  build_or_update_graph → get_minimal_context → semantic_search_nodes / query_graph 定位功能文件
    → get_impact_radius → score_review_tool(changed_files=<功能文件>)
    → coverage_tool(deep_read_files=<功能文件>) → dedupe_findings_tool → generate_report_tool

4.5 引擎函数直调绕行(MCP 大 JSON 失败时的兜底)

dedupe_findings_tool / generate_report_tool / coverage_tool 通过 MCP 传输 JSON 参数,当 findings 超过数百条(如全库审查 476 条)时可能因 MCP 参数解析失败Invalid escape character / Expected '}')而无法调用。此时可绕开 MCP 直调引擎 Python 函数,输出与 MCP 工具完全一致:

import sys, json
sys.path.insert(0, r"D:\code-review-graph\code-review-graph-main")   # CRG 引擎本地路径
import code_review_graph.tools as t

# 等价于 generate_report_tool
res = t.generate_report_func(
    review_data,                       # 与 MCP 版同构的 review_data dict
    output_path=r"D:\AuraSpace\docs\reviews\full-project-review-2026-08-18-144500",
    repo_root=r"D:\AuraSpace",
    format="both",
)
# 等价于 coverage_tool(gate="both+line")
res = t.coverage_func(
    deep_read_files=paths,
    gate="both+line",
    file_read_ranges=ranges_map,       # {rel: [[s,e]..]}
    file_semantic_units=units_map,     # {rel: [{range,kind,name,note}..]}
    repo_root=r"D:\AuraSpace",
)

触发条件:工具调用返回 invalid input / JSON Parse error,且 payload 确认超过 MCP 承载上限(实测 ≥400 条 findings 时出现)。直调入口统一为 code_review_graph.tools 下的同名函数;coverage_func 的签名见 §3.6.6 的 compute_coverage 说明。

4.6 深读子代理类型选择

深读子代理使用 explore 类型(与 project-review skill 及实际审查一致)。子代理需写 JSON 落盘回传三件套数据(容器格式 {group, outputs[]},每条含 path/read_ranges/semantic_units/findings),因此派发前须确认子代理工具集包含 write 落盘能力。若子代理无法落盘,主代理拿不到三件套数据,verified 计数会归零。


5. 5 项客观指标详解

score_review_toolunified-review Step 3 / project-review Step 4)计算 5 项客观 Layer-2 指标。这些指标由静态正则启发式实现(源码:code_review_graph/scoring.py),扫描变更文件的行级文本(_iter_source_lines),不执行代码、不理解语义,因此会产生误报和漏报,需人工核实后再行动。阈值定义在 scoring.pyTHRESHOLDS

5.1 指标总览

指标 值类型 评级方向 good warn fail
SQL 注入风险 命中行数 越低越好 = 0 1-2 ≥ 3
异常分支覆盖 异常行占比 % 越高越好 ≥ 50% 30%50% < 30%
代码冗余率 重复行占比 % 越低越好 ≤ 10% 10%20% > 20%
high_risk_density 覆盖行占比 % 越高越好 ≥ 90% ≥ 70% 其余;无高风险行则为 na
vulnerability_risk 命中行数 越低越好 = 0 1-2 ≥ 2

整体客观评级取 5 项中最差项worst,任一 fail → 整体 FAIL;否则任一 warn → WARN;全 good → GOOD)。

5.2 这些指标有什么用处

核心用途一句话:把"凭感觉"的审查,变成"有证据、有优先级"的审查清单。它们不是给代码打分的考试成绩,而是审查者的导航仪——告诉你这份代码里"哪些行值得停下来细看",并给这个判断一个可复现的数字证据。

指标 实际帮你做什么 没有它的代价
SQL 注入风险 直接给出行号,逐个确认"这些是不是注入点",其余 SQL 不用看 要么漏看注入,要么浪费时间通读所有 SQL
异常分支覆盖 一眼知道错误处理厚薄,决定是否要重点查边界 不知道这模块错误处理是优是劣,全靠碰运气
代码冗余率 告诉你有没有"复制粘贴三份"的代码,决定是否值得重构 靠肉眼扫重复,扫不全
high_risk_density 标出所有含并发/事务/权限/缓存的行,提醒"这些别跳过" 容易忽略数据一致性风险点
vulnerability_risk 机械扫硬编码密钥/XSS/shell 特征,做安全快筛 靠人工记忆检查常见漏洞模式

为什么这个设计关键:审查最贵的成本是注意力。一份 diff 或一个功能可能上千行,逐行细看不现实。这 5 项指标把注意力压缩到三件事:

  • 哪些行evidence 给出 file:line
  • 怀疑什么sql/vulnerability 给出关键词模式)
  • 薄弱在哪里exception_coverage 低 = 错误处理该补查)

注意"触发器而非结论":命中 ≠ 缺陷。每个指标都带 evidence 供逐一人工核实,score_review_tool 的 note 反复强调这一点(如 sql_risk=1 可能是 JSX 误报)。

与 git diff 无关:指标扫描的是传入 changed_files 清单的文件全文,不依赖 git diff。unified-review 的清单来自 git diffproject-review 的清单来自用户指令 → semantic_search/query_graph 聚合(feature)或 all_files=Truewhole-project),二者喂给指标的只是不同的文件来源,指标引擎同一套。project-review 的只读、不碰 git 约束天然成立。

分工边界:指标只覆盖"机械化风险",抓不住 IDOR、越权、竞态、LLM 信任边界等业务逻辑缺陷——那些由 Layer 1 人工链路分解 + specialist 子代理覆盖(见 §5.3 与 §5.2.5 注意)。

5.3 各指标收集方式与评分标准

5.3.1 sql_risk — SQL 注入风险

  • 收集方式:用 6 条正则扫描每行,匹配字符串插值/未参数化 SQL 特征:"SELECT ..." + 变量f"...{var}" 含 SQL、exec("SELECT...WHERE x = '" + var.format(...) 含 SQL、% "..." % (...) 含 SQL 等。
  • 评级:计数命中行数,0 → good1-2 → warn,≥3 → fail。
  • 注意:命中只是警告不是证据。前端 JSX/模板字符串含 SQL 字样易误报(如后端明明全部参数化绑定,报告仍可能报 1 处来自 .tsx 的"风险"),需逐一确认上下文,必要时跑 EXPLAIN 评估性能。

5.3.2 exception_coverage — 异常分支覆盖

  • 收集方式:用 10 条正则统计"异常/错误路径"行数(tryexceptcatch(raisethrowif err != nilif ... error.catch(else { return None 等)。
  • 计算异常行 / 总行 × 100%。经验基线来自"每 2 条正常路径约有 1 条异常路径"。
  • 评级:≥50% → good30%-50% → warn<30% → fail。
  • 注意:阈值命名易误解——warn_min=50 实际是 good 的及格线,good_min=30 是 warn 的下限。该指标对 ? 一元错误传播(Rust)、Result 链等"无显式异常关键字"的代码会低估,需人工补查。

5.3.3 redundancy_rate — 代码冗余率

  • 收集方式:将每行标准化为签名(去空白、数字→N、字符串→"s"),统计在 ≥3 处出现相同签名的行数。
  • 计算重复行 / 总行 × 100%
  • 评级:≤10% → good10%-20% → warn>20% → fail。
  • 注意:签名长度 <24 字符的短行被忽略。重复的函数参数签名(如 State(state)/Extension(claims))会高频命中,属结构性信号而非缺陷。

5.3.4 high_risk_density — 高风险场景密度

  • 收集方式:用 7 条正则标记"高关注行":并发(async/await/thread/mutex)、事务(transaction/commit/rollback)、原子性(atomic/race)、SQL 关键字、锁、缓存失效(cache/invalidate/evict)。
  • 计算覆盖行 / 相关行 × 100%——因所有相关行都被计入"覆盖",实际恒为 100%。无高风险行时返回 na(不适用),不计入整体评级。
  • 评级:≥90% → good,≥70% → warn,其余 fail。
  • 重要:这是审查关注信号,不是正确性评分——只提示"哪些行含并发/事务/安全模式需要人工验证",值高不表示代码好。

5.3.5 vulnerability_risk — 漏洞风险

  • 收集方式:用 6 条正则扫描 OWASP/密钥特征:硬编码 password/api_key/secret/tokeneval/exec(subprocess(shell=True)innerHTML/dangerouslySetInnerHTML/v-html<script>/onerror=/javascript: 等。
  • 评级:计数命中行数,0 → good1-2 → warn,≥2 → fail。
  • 注意:这只是文本级启发式,真实漏洞需依赖扫描器补充(npm auditpip-auditgovulncheck)。业务逻辑型安全缺陷(如 IDOR、越权、竞态)检不出,须由 Layer 1 人工审查 + specialist 子代理覆盖。

5.4 与 LLM 判断指标的边界

以下 5 项指标不进入 score_review_tool 的客观计算,而是列在返回的 llm_judged 字段,须由审查代理在 Layer 1 链路分解中人工/LLM 补判:

requirement_coverage(需求覆盖)、logic_alignment(逻辑对齐)、llm_trust_boundaryLLM 信任边界)、shell_injectionShell 注入)、enum_completeness(枚举完整性)。

5.5 实测示例

issues 功能 feature 审查(issues-feature-review-2026-08-10)实测结果:

指标 评级 人工核实结论
sql_risk 1 warn 误报:命中的是 IssuesView.tsx 的 JSX,后端全部参数化绑定,实际无注入
exception_coverage 0.39% fail 异常路径占比极低,错误多统一走 internal_error 返回 500 泛化信息,符合人工审查发现的错误处理不足
redundancy_rate 9.74% good 临界值;issue_api.rs 存在大量重复的 State/Extension 签名与权限校验模板
high_risk_density 100% good 仅提示含事务/并发/权限模式的行,需人工验证
vulnerability_risk 0 good 文本扫描无命中;真正的 IDOR 漏洞由人工 Layer 1 审查捕获

6. 审查 Skill 体系

6.1 核心 skill

Skill 对应工作流 位置
unified-review diff 三层统一审查 skills/unified-review/SKILL.md
project-review 项目级审查 skills/project-review/SKILL.md

6.2 references 检查清单

两个 skill 共享一套 references/

references/
├── review-checklist.md        # 通用审查清单(Layer 1 八分类 + CRITICAL 五类)
├── common-mistakes.md         # 常见审查错误
├── report-template.html       # 报告模板
├── manual-review/             # 高风险模块人工审查清单
│   ├── payment.md  order.md  inventory.md  permission.md
│   └── distributed-lock.md  data-migration.md
└── specialists/               # specialist 子代理检查清单
    ├── testing.md  maintainability.md  security.md  performance.md
    └── data-migration.md  api-contract.md  red-team.md

6.3 旧 skill

review-changes / review-delta / review-pr 保留供兼容,提供轻量审查;unified-review / project-review 为增强版。


7. 审查报告成果物

产物 文件 内容
HTML 报告 code-review-report.html 自包含单文件:结论、PR 质量分、覆盖度、客观指标表、问题清单(severity + 置信度 + 位置 + 修复建议)、人工审查清单、LLM 判断指标
Markdown 报告 code-review-report.md 同内容 Markdown 版,便于 git 提交 / PR 描述复用

参数:formathtml / markdown / both,默认 both)。报告均为只读产物

⚠️ review_data.counts 键名陷阱MD 报告的"问题统计"行只读 critical / informational 两个键(counts dict 里的 blocker/major/minor 会被忽略)。传 {"blocker":20,"major":141,"minor":315} 会渲染成 "20 严重 · 0 次要"major 数丢失。正确写法:{"critical":20, "major":141, "informational":315}。HTML 报告不受影响(读全量键)。

⚠️ MCP 大 JSON 兜底findings 超数百条时 MCP 传参可能解析失败,可直调引擎函数生成报告(见 §4.5),输出与 MCP 工具一致。

⚠️ review_data.metrics 格式陷阱generate_report_toolmetrics必须是 {grade, value, note} 字典(如 {"sql_risk": {"grade":"good","value":0,"note":"全部参数化"}})。若传扁平标量(如 "sql_risk": 3),build_report_data 会静默丢弃,报告的"客观指标"表格不渲染。生成后自检必须确认指标表存在。

⚠️ findings 字段名陷阱build_report_data 只读 findings 键(不读 issues);每条只读 path+line(合成 location)、message(或 summary)、fixseveritycategoryconfidence。用错键名(如 title/detail/issues)会导致问题清单缺失或只剩类别+位置。

HTML <script> 安全转义:引擎在注入 const data = {...} 前会把 < 全部转义为 \u003cv2.5.0 修复,scoring_tools.py)。因此 finding 文本里即使含字面 </script><!-- 等序列也不会截断报告脚本;JS 解析后还原为 <,渲染时再转成 &lt;,显示不受影响。人工无需转义 finding 文案

7.1 生成后自检(防空报告回归)

  1. 打开生成的 .md,确认 ## 问题清单(NN == findings 数量(不为 0
  2. 每条 issue 同时含问题描述位置修复建议 三要素(位置形如 `server/...:111`
  3. ## 客观指标 表格存在且非空(缺失多为 metrics 传成扁平标量)
  4. 若发现缺描述/缺修复建议/问题数=0 → 修正 review_data重新调用 generate_report_tool 覆盖

7.2 归档命名规范

审查报告归档到 docs/reviews/,文件名格式:{范围}-review-{YYYY-MM-DD-HHMMSS}.{md,html}(时间戳精确到时分秒,避免同日多次审查互相覆盖)。

审查类型 范围值示例 示例文件名
全项目审查 full-project full-project-review-2026-08-12-141343.html
功能审查 {功能}-feature evm-feature-review-2026-08-06-151522.md
变更级审查 pr-{branch} pr-dev-init-xwj-v0.1-review-2026-08-06-151522.md

generate_report_tooloutput_path 直接传 docs/reviews/{文件名}(不含扩展名)。不传 output_path 会默认写到仓库根目录 code-review-report.*,属违规命名,需在命名自检中检出并修复。

7.3 命名自检(verify-report.ps1

生成完成后对仓库运行命名自检(脚本独立于 code-review-graph CLI,任何版本可用):

powershell -File "C:\Users\Administrator\.config\opencode\skills\project-review\verify-report.ps1" -Repo D:\AuraSpace
  • 退出码 0 → 通过:所有报告都在 docs/reviews/ 且文件名带 -YYYY-MM-DD-HHMMSS 后缀
  • 退出码 1 → 存在根目录残留 code-review-report.*。用 -Fix 自动归档,或重新以正确 output_path 调用 generate_report_tool 覆盖,然后重跑脚本确认退出码 0
  • 脚本列出的 historic naming warnings 无需处理(仅提示),但本次生成的报告必须满足规范

7.4 行级覆盖自检(verify-line-coverage.ps1,防"无行覆盖还全绿"

v2.5.1 起,whole-project/feature 报告必须含行覆盖字段(引擎 fail-closed:缺三件套数据 → 计入 line/unit gap → target_reached=false)。生成完成后对仓库运行行覆盖自检:

powershell -File "C:\Users\Administrator\.config\opencode\skills\project-review\verify-line-coverage.ps1" -Repo D:\AuraSpace
  • 退出码 0 → 通过:报告 ## 覆盖度 区块含行覆盖字段且 ≥95%gate="both+line" 已跑、三件套数据完整)
  • 退出码 1 → 阻塞:报告无行覆盖字段(漏跑 both+line 或漏传三件套数据)或行覆盖 <95%。必须补数据重新生成报告后重跑,直到退出码 0

7.5 防伪抽验自检(verify-spot-check.ps1,防"漏抽验还全绿"

whole-project / feature 审查必须执行防伪抽验(三件套③)并注入 review_data.spot_check(顶层字段)。生成完成后对仓库运行:

powershell -File "C:\Users\Administrator\.config\opencode\skills\project-review\verify-spot-check.ps1" -Repo D:\AuraSpace
  • 退出码 0 → 通过:报告 ## 覆盖度 区块含防伪抽验字段且单元数 >0
  • 退出码 1 → 阻塞:报告无防伪抽验字段或渲染"未执行 🔴"。必须补抽验(每组 2 文件 × 2-3 单元,每波 ≤40 次)+ 注入 spot_check + 重新生成报告后重跑,直到退出码 0
  • 诚实声明:该脚本只能验证抽验声明完整性,无法验证主代理是否真读了文件(引擎防伪能力的已知边界)
  • 命名自检(Step 8.6)、行覆盖自检(Step 8.7)、防伪抽验自检(Step 8.8)三脚本必须全过才算审查完成

该脚本检测的是报告渲染后的 ## 覆盖度 区块:引擎渲染模板对缺失行覆盖会显示"行覆盖:未执行 🔴",脚本据此拦截。


8. 快速上手

前提:构建图谱

code-review-graph build     # 或 /code-review-graph-build-graph

三种审查用法

# 1. 审查本次 git diffunified-review
/code-review-graph-unified-review

# 2. 全项目代码体检(project-review
/code-review-graph-project-review 对项目代码进行全面审查

# 3. 审查单个功能(project-review
/code-review-graph-project-review 审查支付功能的代码

MCP prompt 直接调用

/code-review-graph:unified_review base="HEAD~1"
/code-review-graph:project_review scope="whole-project" target=""
/code-review-graph:project_review scope="feature" target="payment"

全项目审查的深读约定(v2.5.1

  • 全项目审查必须走并行深读流水线(§3.6):deep_read_plan_tool 分组 → 4-6 个并行 explore 子代理深读(三件套字段落盘)→ 每波 coverage_tool(gate="both+line", file_read_ranges=..., file_semantic_units=...) 三件套门禁 → 未达标补轮 → 防伪抽验每组 2 文件 × 2-3 单元,每波 ≤40 次(结果落盘 spot_check_*.json 并注入 review_data.spot_check
  • 覆盖度目标(三件套):全库 ≥85% 高风险 ≥95% 行覆盖 ≥95% 单元完整性无缺口(gate="both+line"gate="both" 保持旧双目标语义)
  • 报告生成后执行 三自检verify-report.ps1(命名)→ verify-line-coverage.ps1(行覆盖)→ verify-spot-check.ps1(防伪抽验)→ save_coverage_index_toolv2 索引含 rangesSHA 来自 nodes.file_hash)写跨轮索引

修复流程(人工裁决)

  1. 审查产出 findingsseverity + 置信度 + file:line + 修复建议)
  2. 按 severity 批量呈现,逐个决定:修 / 不修 / 自己改
  3. 🔴 blocker 不可批量跳过
  4. 确认后人工执行修复,重新审查验证