274 lines
27 KiB
Markdown
274 lines
27 KiB
Markdown
---
|
||
name: project-review
|
||
description: Whole-project or single-feature code review (not diff-based) using graph-wide analysis and objective scoring
|
||
---
|
||
|
||
# Project Review
|
||
|
||
Review the entire codebase or a single feature/module, independent of the git diff. Two scopes, driven by the user's instruction:
|
||
|
||
- **whole-project**: "对项目代码进行全面审查", "全面审查", "整个项目" → review every source file in the graph.
|
||
- **feature**: "审查 <功能/模块> 的代码" (e.g. payment, auth) → review only the code related to the target.
|
||
|
||
**This skill is READ-ONLY.** Every finding is presented to the user for a manual fix decision. Never apply code changes, commit, or push.
|
||
|
||
## Token Efficiency Rules
|
||
- ALWAYS start with `get_minimal_context(task="project review")`. Use `detail_level="minimal"` on all calls; escalate to `"standard"` only when a metric or finding needs evidence.
|
||
- **Whole-project deep-read is a sub-agent pipeline, not a main-context loop.** 主上下文不逐文件深读 500+ 文件;改为 Step 5.5 并行子代理分组深读。主上下文预算 ≤14 calls + N 子代理(见 Step 5.5)。
|
||
|
||
## Step 0 - Parse the scope
|
||
|
||
Read the user's instruction and set scope: whole-project (contains 全面/整个项目/所有/all) or feature + target (extract the feature/module keyword). Declare both in the report header.
|
||
|
||
> **快速参考**:审查 agent 的精简流程指引来自 `get_docs_section(section="project-review")`(引擎 `docs/LLM-OPTIMIZED-REFERENCE.md`),该文档已同步 review_data schema(`reviewed_files` 数组、coverage 全字段透传含三件套字段、metrics 带 note、仅五客观指标)。完整 schema 以本 SKILL.md 与 `references/report-schema.md` 为准。
|
||
|
||
## Step 1 - Graph ready
|
||
|
||
1. Call `build_or_update_graph_tool()` to ensure the graph is current.
|
||
2. Call `get_minimal_context_tool(task="project review")` for stats and community overview.
|
||
|
||
## Step 2 - Architecture map
|
||
|
||
Call `get_architecture_overview_tool(detail_level="minimal")` and `list_communities_tool(detail_level="minimal")` to map the module structure.
|
||
|
||
## Step 3 - High-risk scan (whole-project)
|
||
|
||
Call `get_knowledge_gaps_tool()`, `get_hub_nodes_tool()`, `get_bridge_nodes_tool()`, `find_large_functions_tool()` and `get_surprising_connections_tool()` to locate hotspots, chokepoints, untested areas and odd coupling.
|
||
|
||
## Step 4 - Objective scoring
|
||
|
||
- whole-project: `score_review_tool(all_files=True)` scores every source file in the graph.
|
||
- feature: locate the target files with `semantic_search_nodes_tool(query=<target>)` and `query_graph_tool(pattern="children_of", target=<target>)`, then `score_review_tool(changed_files=<files>)` and `get_impact_radius_tool(changed_files=<files>)` for the blast radius.
|
||
- **指标集约束**:报告的 `metrics` 只透传 `score_review_tool` 返回的五个客观指标(`sql_risk` / `exception_coverage` / `redundancy_rate` / `high_risk_density` / `vulnerability_risk`)。**禁止**手工追加 `requirement_coverage` / `logic_alignment` / `llm_trust_boundary` / `shell_injection` / `enum_completeness` 等 LLM 判定指标;`review_data.llm_judged` 一律传空 `[]`。
|
||
|
||
## Step 5 - Chain decomposition
|
||
|
||
Inspect the scored code across eight categories (interface, business, data, utility, error handling, security, performance, observability) and apply the gstack CRITICAL sub-pass (SQL & Data Safety, Race Conditions, LLM Output Trust Boundary, Shell Injection, Enum Completeness). Mark each ✅ / ⚠️ / —.
|
||
|
||
## Step 5.5 - 并行深读流水线(whole-project 强制,覆盖率达标的唯一可行路径)
|
||
|
||
> 引擎 v2.5.0 新增 `deep_read_plan_tool` / `save_coverage_index_tool`,`coverage_tool` 增加 `gate` / `include_prior`。主上下文无法逐文件深读 500+ 文件,必须用并行子代理分组深读,否则全库覆盖永远卡在 2-5%。覆盖率为**文件数口径**:已深读文件数 / 总文件数。
|
||
|
||
**目标**:全库覆盖 ≥85% **且** 高风险覆盖 ≥95%(双目标 `gate="both"`,standard 档位)**且**每个深读文件通过三件套质量门禁(①单元完整性=100% ②行覆盖≥95% ③防伪抽验≤15次/轮,见 references/deep-read-pipeline.md §〇)。深读计划按风险权重贪心,85% 的全库计划会先选满全部高风险文件,天然同时逼近高风险 95%。
|
||
|
||
**流程**:
|
||
```
|
||
a. 调 deep_read_plan_tool(gate="overall", target_coverage=85, include_prior=True)
|
||
→ 返回分组清单 groups[{name, weight, files[]}] + remaining_files
|
||
(include_prior=True 自动排除上一轮已深读且未变更的文件,实现增量)
|
||
b. 按组并行派发 explore 子代理(每次 4-6 个并行,分多批)。
|
||
每个子代理深读该组**全部**文件,返回(**落盘到临时目录,勿回传大 JSON**):
|
||
- 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 证据的条目视为未深读**(该文件须重读)
|
||
prompt 模板见 references/deep-read-pipeline.md
|
||
⚠️ **禁止用 `DEEPREAD_CONFIRM: <路径|总行数|已读范围|单元数>` 单行摘要替代结构化 JSON**:
|
||
主代理必须拿到每文件的 `read_ranges`(分段数组)与 `semantic_units`(逐单元
|
||
{range,kind,name})并落盘,否则 coverage_tool 无法做行/单元门禁,报告会
|
||
"无行覆盖" 且引擎 fail-closed 会全部判缺口。子代理 prompt 必须直接复制
|
||
deep-read-pipeline.md §二 的模板,不得自创简化格式。
|
||
c. 每波子代理完成后跑三件套门禁(**B 阶段已落地,引擎原生支持**):
|
||
- 主代理首选:coverage_tool(deep_read_files=<verified_files>, gate="both+line",
|
||
file_read_ranges=<{rel:[[s,e]..]}>, file_semantic_units=<{rel:[{range,kind,name}]}>)
|
||
→ 引擎返回 line_coverage_pct / unit_coverage_pct / line_gap_files / unit_gap_files / unit_exempt_files
|
||
- 引擎不可用时的兜底:python skills/project-review/scripts/aggregate_deep_read.py <repo_root> <落盘目录>
|
||
- line_gap ∪ unit_gap → 补读队列;verified → 计入本轮 deep_read_files
|
||
d. 防伪抽验(**强制,每波必做,三件套③**):
|
||
- 每波子代理完成后立即执行,与 c 门禁同步;**每组抽 2 个文件、每文件抽 2-3 个语义单元**回读比对 note(每波 ≤40 次 read,全审查约 50-72 次分摊到各波)
|
||
- 回读:用 read 打开源文件对应 range,比对子代理上报的 semantic_units.note 是否与实际内容相符
|
||
- 结果落盘 `spot_check_<batch>.json`(schema:groups_sampled / files_sampled / units_sampled / fake_read_found / groups_rereread / samples[{group,file,unit,range,note_match,in_read_ranges}])
|
||
- 抽到假读 → 该组重读并升级抽验率(同组改抽 2 文件×3 单元)
|
||
- ⚠️ 各波 spot_check 必须聚合后在 Step 8 注入 `review_data.spot_check`(顶层字段),否则报告渲染"未执行 🔴"且 verify-spot-check.ps1 exit 1
|
||
e. 主代理汇总全部 verified_files(去重)→
|
||
coverage_tool(deep_read_files=<verified_files>, gate="both+line", include_prior=True) 复算
|
||
(include_prior 自动复用跨轮索引中 SHA 未变的文件及其 read_ranges)
|
||
f. 未达标(文件数 <85%/<95% 或 行覆盖 <95% 或 单元有缺口)→
|
||
对 coverage 返回的 priority_deep_read_files / line_gap_files / unit_gap_files 补一轮 → 循环直至全达标
|
||
⚠️ **禁止降级**:unit_gap_files 或 line_gap_files 非空时,**不得**改回 `gate="both"` 静默跳过三件套;
|
||
必须补轮重读至空,或显式在报告中标注"三件套未达标 🔴"并列出缺口文件。
|
||
g. G2:对 silent_files 抽 15% 深读(见 Step 7.5)
|
||
h. 报告生成后:save_coverage_index_tool(deep_read_files=<verified_files>, file_read_ranges=<{rel:[[s,e]..]}>)
|
||
→ 写 .code-review-graph/coverage-index.json(v2:file + per-file SHA + ranges,SHA 来自 nodes.file_hash)
|
||
```
|
||
|
||
**约束**:
|
||
- 子代理数量:whole-project 508 文件 ≈ 14-16 组(后端 6 组 / 前端 8 组,见 references/deep-read-pipeline.md 分组表)。
|
||
- 质量控制(三件套,必须全部通过才算深读):
|
||
- ① 单元完整性:`semantic_units` 与图谱单元差集 = 空(one-to-one 匹配,宽 range 不能冒充;**严格模式**:Props interface / Type / 小函数也必须逐一列出)。巨型文件(**仅当**最大单元行占比>80%)豁免,按行覆盖校验。
|
||
- ② 行覆盖:`union(read_ranges)` / 真实行数 ≥95%(分母为真实文件行数,非图节点 line_end——后者有 ±1 偏差)。
|
||
- ③ 防伪抽验:主代理**每波必做**,每组抽 2 文件 × 2-3 单元,每波 ≤40 次 read;结果落盘 spot_check 并注入报告。引擎无法防假读,抽样是唯一手段。
|
||
- 每条 finding 必须带 `file:line` 证据。
|
||
- 若引擎工具 `deep_read_plan_tool` 不可用(旧版本),退化为:先 `coverage_tool` 取 `priority_deep_read_files` 手动分组派发。
|
||
- 增量语义:`include_prior=True` 时,变更文件(SHA 不同)自动失效需重读,防止"上轮读过"掩盖新代码。
|
||
|
||
> 🔒 **诚实声明(三件套③的防伪边界)**:防伪抽验的**真实性**(主代理是否真读了文件)引擎与脚本**均无法验证**——`verify-spot-check.ps1` 只能验证**声明完整性**(抽了、单元数>0、range 落在 read_ranges 内)。真实回读依赖主代理行为准则。此为引擎防伪能力的已知边界(deep-read-pipeline.md §〇)。
|
||
|
||
## Step 6 - Manual adjudication (READ-ONLY)
|
||
|
||
Present every finding with severity (🔴 blocker / 🟡 major / 🔵 minor), confidence (1-10), file:line and a proposed fix. Group by severity and ask the user per batch: fix / skip / self-fix. 🔴 blockers cannot be batch-skipped. **Do not modify code.**
|
||
|
||
## Step 7 - Acceptance gate
|
||
|
||
Any 🔴 blocker → verdict `❌ FAIL`. Classify each finding as Ready / Needs Fix / Unusable.
|
||
|
||
## Step 7.5 - 覆盖度自检(必须执行,防"审完了"由感觉决定)
|
||
|
||
按 `CODE_REVIEW_GUIDE_ZH.md` §3.5 的覆盖度保障机制,报告前完成三件事:
|
||
|
||
1. **深读名单完整性(G1)**:确认名单外文件是"被评估过"而非"被忽略";未被任何信号点名的文件记入 **"未深读文件清单"**,在报告中显式列出。
|
||
2. **静默抽检(G2)**:调用 `coverage_tool` 取返回的 `silent_files`(未被任何信号点名的文件),随机抽 **15%** 深读;发现 ≥1 major → 该文件升级全量深读,并同社区/同类追加抽检一轮。抽检记录附入报告(抽了几份 / 几个 major / 有无升级)。
|
||
3. **三件套质量门禁复核(G1.5)**:报告前复核 Step 5.5 的三件套聚合结果——`line_gap_files ∪ unit_gap_files` 必须为空(已补读至空);`verified_files` 与 `coverage_tool` 的 `deep_read_files` 一致;防伪抽验记录(抽了几组/几个单元/有无假读)附入报告。
|
||
4. **覆盖度计算(G3)**:
|
||
- **whole-project**:调用 `coverage_tool(deep_read_files=<本轮实际深读文件>, gate="both+line")`,引擎自动计算**三重口径**(文件数口径 + 三件套质量口径):
|
||
- **全库覆盖** = `coverage_pct`(已深读文件数 / 全部源文件数)
|
||
- **高风险覆盖** = `high_risk_coverage_pct`(已深读高风险文件数 / 信号点名文件数)
|
||
- **双口径门禁(G3)**:`gate="both+line"` 时 `target_reached` 要求**全库 ≥85% 且 高风险 ≥95% 且 行覆盖 ≥95% 且 单元完整性无缺口**(标准档位,三件套 AND)。`gate="both"` 保持原语义(仅前两项)。`target_reached=false` → 报告顶部标 🔴 覆盖不足。
|
||
- **缺口信息**:返回值含 `remaining_files_to_target`(还差多少文件数)与 `priority_deep_read_files`(按风险权重降序的待深读文件)——据此驱动 Step 5.5 的补轮深读。
|
||
- **增量**:`include_prior=True` 合并跨轮覆盖索引(.code-review-graph/coverage-index.json)中 SHA 未变的已深读文件。
|
||
- **feature(单功能)**:调用 `coverage_tool(deep_read_files=<本轮实际深读文件>, gate="line+unit", file_read_ranges=<ranges>, file_semantic_units=<units>)`——**只做行覆盖 ≥95% + 单元完整性无缺口**,**不做全库/高风险文件数覆盖检查**(引擎返回 `coverage_pct`/`high_risk_coverage_pct` 为 `null`,报告只渲染行/单元覆盖区块,不渲染全库/高风险行)。`target_reached=false`(行/单元未达标)→ **禁止生成报告**,执行补读闭环(见下)直至达标。
|
||
- ⚠️ **三件套数据必传(行覆盖非 0 的前提)**:feature 主上下文深读每个文件时,必须**边读边累积** `file_read_ranges={<rel>:[[s,e],...]}`(已读行区间)与 `file_semantic_units={<rel>:[{"range":[s,e],"kind","name"},...]}`(文件内语义单元),再传给 `coverage_tool`。**不传则 fail-closed 行覆盖=0%**,报告标"行覆盖 0%"且 `verify-line-coverage.ps1` exit 1 拦截。
|
||
- 🔁 **补读闭环(硬性,未达标禁止出报告)**:若 `target_reached=false`,**不得生成报告**。必须对 `line_gap_files`/`unit_gap_files`/`missing_data_files` 列出的文件补读缺失行区间/语义单元,重跑 `coverage_tool`,直至 `target_reached=true`。无法读全的文件**移出** `deep_read_files`(line+unit 不看文件数,只保留真正读满 ≥95% 的文件)。报告生成后跑 `verify-line-coverage.ps1`,exit 1 → 补读重新生成。
|
||
|
||
将覆盖度结果**完整透传**到 `review_data.coverage`(直接把 `coverage_tool` 返回值全部字段传入: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/overall_target/high_risk_target/gate/**line_coverage_pct/unit_coverage_pct/line_gap_files/unit_gap_files/unit_exempt_files/missing_data_files**/remaining_files_to_target/remaining_weight_to_target/priority_deep_read_files/uncovered_files/silent_files/note),不要手挑子集,否则计数字段渲染为 0/0 或 N/A。报告会自动渲染 `## 覆盖度` 区块(含行/单元覆盖)。**若 `line_coverage_pct` 为 null(未跑 both+line 或未传三件套),报告会显式标"行覆盖:未执行 🔴",且 verify-line-coverage.ps1 会 exit 1 拦截。** **feature 走 `gate="line+unit"` 时 `coverage_pct`/`high_risk_coverage_pct` 为 `null` 属正常,勿因 null 误判为失败;`reviewed_files` 必须传本轮深读文件数组,报告顶部以可折叠列表(details/summary)展示审查文件。**
|
||
|
||
**前置健康检查**:调用 `community_health_tool`,若 `needs_postprocess=true`(nodes.community_id 归属率 <90%),先 `code-review-graph postprocess` 重建社区归属再计算,否则覆盖度失真。
|
||
|
||
## Step 7.6 - 覆盖度自检验证(必须执行,防"优化没生效")
|
||
|
||
> 当 `coverage_tool` / `community_health_tool` / `score_review_tool` / `dedupe_findings_tool` / `generate_report_tool` / `deep_read_plan_tool` / `save_coverage_index_tool` **任一工具不可用**,或报告缺 `## 覆盖度` 区块时,按本步骤自检。机制未生效时禁止用 CLI 兜底继续审查,先修复环境。详见 `docs/plans/review-coverage-guarantee-plan.md` 第八章。
|
||
|
||
1. **环境自检(阻断)**:确认可用工具含上述 7 件套;缺失 → 检查本地源码 `D:\code-review-graph\code-review-graph-main` 版本为 2.5.0,`opencode.json` 与 `.mcp.json` 均指向 `.venv\Scripts\code-review-graph.exe`(非 `uv run`/`uvx`)。
|
||
2. **进程自检**:`Get-Process code-review-graph, uv` 应无残留 serve/uv 进程;残留进程会锁 `.venv\Scripts\code-review-graph.exe`,导致 `uv run` 报 `os error 32` → MCP 起不来。清理:`taskkill /PID <pid> /T /F`。
|
||
3. **引擎自检**:`community_health_tool()` 应返回 `needs_postprocess=false`、`attribution_pct>=90`;`coverage_tool(deep_read_files=[...], gate="both+line", file_read_ranges=<ranges>, file_semantic_units=<units>)` 应返回 `coverage_pct`/`high_risk_coverage_pct`/`line_coverage_pct`/`unit_coverage_pct`/`line_gap_files`/`unit_gap_files`/`unit_exempt_files`/`target_reached`/`remaining_weight_to_target`/`priority_deep_read_files`/`uncovered_files`/`silent_files` 全字段;`deep_read_plan_tool` 应返回 `groups`/`planned_files`。
|
||
4. **恢复路径**:杀残留进程 → `uv sync`(`D:\code-review-graph\code-review-graph-main`)修复 venv → 重启 opencode 新会话 → 重新执行本步骤 1-3 直到 PASS。
|
||
|
||
## Step 8 - Report
|
||
|
||
Call `generate_report_tool(review_data=<REQUIRED SCHEMA>)` to write `code-review-report.html` and `code-review-report.md` (default `format="both"`).
|
||
|
||
> **报告生成后(Step 8.6 命名自检通过后)必须执行**:
|
||
> `save_coverage_index_tool(deep_read_files=<本轮全量深读清单>, file_read_ranges=<{rel:[[s,e]..]}>)` —— 写跨轮覆盖索引 `.code-review-graph/coverage-index.json`(v2:file + per-file SHA + ranges,SHA 来自 nodes.file_hash)。下一轮审查 `include_prior=True` 时自动复用未变更文件及其行区间,实现增量覆盖,多轮后增量归零即全覆盖。
|
||
|
||
### ⚠️ review_data 精确 Schema(必须严格遵循,否则报告只剩类别/位置)
|
||
|
||
工具在 `scoring.py::build_report_data` 中**只读取以下键**。用错键名/字段名会静默丢内容。
|
||
|
||
顶层键(均为可选项,但 `findings` 缺了就没有问题清单):
|
||
|
||
| 顶层键 | 值类型 | 说明 |
|
||
|---|---|---|
|
||
| `verdict` | `"PASS"` / `"FAIL"` | 结论 |
|
||
| `scope` | str | **只允许** `"whole-project"` / `"feature"` / `"change-level"`。❌ 禁止传功能名(如 `"evm"`)——verify 脚本按此判定是否检查行覆盖/抽验,传错会绕过门禁 |
|
||
| `tier` | str | 如 `"standard"` |
|
||
| `timestamp` | str | 如 `"2026-08-06T15:24:47"` |
|
||
| `files` | str | 审查文件列表(逗号分隔,兼容字段) |
|
||
| **`reviewed_files`** | **list[str]** | **本轮审查的文件数组**(如 `["server/src/api/evm_api.rs", ...]`;**也可传逗号分隔字符串,引擎会自动拆分**)。whole-project/feature 必传;报告顶部以可折叠列表(details/summary)展示,缺省时回退 `files` 逗号拆分 |
|
||
| `baseline` | str | git SHA |
|
||
| `quality_score` | int/float | 0-10 |
|
||
| `counts` | dict | 如 `{"blocker":0,"major":3,"minor":5}`(MD 只读 `critical`/`informational` 键) |
|
||
| `metrics` | dict | `{指标名: {grade, value, note}}`,**值必须是 dict**;**`note` 必传**(透传 `score_review_tool` 返回的 note/evidence,否则指标"说明"列为空)。❌ 传扁平标量(如 `"sql_risk": 3`)会被静默丢弃。**仅含五个客观指标**(sql_risk/exception_coverage/redundancy_rate/high_risk_density/vulnerability_risk,见 Step 4 指标集约束);引擎会过滤 `blast_radius`/`objective_grade` 等非五指标键 |
|
||
| **`findings`** | **list[dict]** | **问题清单(必须用 `findings`,不能用 `issues`)** |
|
||
| `manual_review` | list[str] | 人工复核项 |
|
||
| `llm_judged` | list[str] | 保留兼容字段,**一律置空 `[]`**,不再新增 LLM 判定指标 |
|
||
| `spot_check` | dict | **防伪抽验记录(顶层字段,非嵌 coverage)**。whole-project/feature 必传,否则报告渲染"防伪抽验:未执行 🔴"且 verify-spot-check.ps1 exit 1。schema:`{groups_sampled, files_sampled, units_sampled, fake_read_found, groups_rereread, samples:[{group,file,unit,range,note_match,in_read_ranges}]}` |
|
||
| `summary` | str | 审查摘要 |
|
||
|
||
`findings` 每条**必须**的字段:
|
||
|
||
| 字段 | 说明 | 反例(会导致丢失) |
|
||
|---|---|---|
|
||
| `path` | 文件路径(与 `line` 合成 `location`) | ❌ 传合并字符串 `location` |
|
||
| `line` | 行号(int,与 `path` 合成 `location`) | ❌ 省略 `line` 导致无位置 |
|
||
| `message` | 问题描述(工具读 `summary` 或 `message`) | ❌ 用 `title`/`detail` |
|
||
| `fix` | 修复建议 | ❌ 用 `title`/`detail` |
|
||
| `severity` | `"blocker"`/`"major"`/`"minor"` | |
|
||
| `category` | 如 `"business"`/`"security"` | |
|
||
| `confidence` | int 1-10 | |
|
||
|
||
### 完整示例(可直接替换占位复制)
|
||
|
||
```json
|
||
{"verdict": "PASS", "scope": "feature", "tier": "standard", "timestamp": "2026-08-06T15:24:47",
|
||
"files": "server/src/api/evm_api.rs, server/src/domain/evm.rs",
|
||
"reviewed_files": ["server/src/api/evm_api.rs", "server/src/domain/evm.rs"],
|
||
"baseline": "<sha>", "quality_score": 7.5,
|
||
"counts": {"blocker": 0, "major": 1, "minor": 0},
|
||
"metrics": {"sql_risk": {"value": 0, "grade": "good", "note": "全部参数化,无注入风险。"}},
|
||
"findings": [
|
||
{"path": "server/src/services/workflow_service.rs", "line": 111,
|
||
"severity": "major", "category": "business", "confidence": 8,
|
||
"message": "workflow 更新 completion_percentage 后未失效 EVM 缓存,5 分钟 TTL 内显示过期数据。",
|
||
"fix": "在 update_state 中调用 EvmService::invalidate_evm_cache(project_id, None)。"}
|
||
],
|
||
"manual_review": ["确认 list_evm_cases 无 data_scope 是否为有意设计"],
|
||
"summary": "发现 1 个 major。SQL 全部参数化无注入风险,无 blocker,结论 PASS。"}
|
||
```
|
||
|
||
**常见错误(自查清单):**
|
||
- ❌ 用 `issues` 键 → 工具只读 `findings`,结果 `问题清单(0)`
|
||
- ❌ finding 用 `title`/`detail` → 工具读 `message`/`fix`,结果只剩类别+位置
|
||
- ❌ finding 直接传 `location` 字符串 → 工具由 `path`+`line` 合成,结果位置为空
|
||
- ❌ metrics 传扁平标量(`"sql_risk": 0`)→ 工具要求 `{grade, value, note}` dict
|
||
|
||
### Step 8.5 - 生成后自检(必须执行,防止空报告回归)
|
||
|
||
生成报告后**必须**打开生成的 `.md` 文件验证,全部通过才算完成:
|
||
|
||
1. `## 问题清单(N)` 中 N == findings 数量(不是 0)
|
||
2. 每条 issue 同时含**问题描述**、**位置**、**修复建议** 三要素(位置形如 `` `server/...:111` ``)
|
||
3. **`## 客观指标` 表格存在且非空**(若传了 metrics)——若缺失,多为 `metrics` 值不是 `{grade, value, note}` dict(扁平标量被静默丢弃),需修正后重新生成
|
||
4. **`## 客观指标` 表恰好 5 行**(`sql_risk` / `exception_coverage` / `redundancy_rate` / `high_risk_density` / `vulnerability_risk`)——出现其他指标名说明手工注入了 LLM 判定指标,违反 Step 4 指标集约束,需移除后重新生成
|
||
5. 若发现缺描述/缺修复建议/问题数=0 → 用上述 schema 修正 `review_data` 后**重新调用** `generate_report_tool` 覆盖,直到通过
|
||
|
||
### Step 8.6 - 报告命名自检(必须执行,防止报告落错位置/缺时间戳)
|
||
|
||
生成完成后,对仓库运行命名自检脚本(脚本独立于 code-review-graph CLI,任何版本可用):
|
||
|
||
```powershell
|
||
powershell -File "C:\Users\Administrator\.config\opencode\skills\project-review\verify-report.ps1" -Repo <repo_root>
|
||
```
|
||
|
||
- 退出码 **0** → 通过:所有报告都在 `docs/reviews/` 且文件名带 `-YYYY-MM-DD-HHMMSS` 后缀。
|
||
- 退出码 **1** → 存在根目录残留 `code-review-report.*`(漏传 `output_path` 的强信号)。用 `-Fix` 自动归档,或直接以正确 `output_path="docs/reviews/{name}-review-{YYYY-MM-DD-HHMMSS}"` **重新调用** `generate_report_tool` 覆盖,然后重跑脚本确认退出码 0。
|
||
- 脚本列出的 historic naming warnings 无需处理(仅提示),但**本次生成的报告**必须满足规范。
|
||
|
||
### Step 8.7 - 行级覆盖自检(必须执行,防止"无行覆盖还全绿")
|
||
|
||
生成完成后,对最新报告运行行覆盖自检脚本(独立于 code-review-graph CLI,任何版本可用):
|
||
|
||
```powershell
|
||
powershell -File "C:\Users\Administrator\.config\opencode\skills\project-review\verify-line-coverage.ps1" -Repo <repo_root>
|
||
```
|
||
|
||
- 退出码 **0** → 通过:whole-project/feature 报告含**行覆盖**字段且 ≥95%(三件套数据完整)。
|
||
- 退出码 **1** → 阻塞:报告覆盖度区块**没有行覆盖**(漏跑 `gate="both+line"`/`line+unit` 或漏传三件套)或行覆盖 <95%。必须补读(Step 7.5 补读闭环)后重新生成报告,再重跑,直到退出码 0。
|
||
- ⚠️ **scope 判定**:脚本只对 `change-level` 跳过;自定义 scope 值(如 `"evm"`、`"issues"`)只要报告含 `## 覆盖度` 区块,同样按行覆盖 ≥95% 检查——`scope` 传功能名不会绕过门禁。
|
||
|
||
### Step 8.8 - 防伪抽验自检(必须执行,防止"漏抽验还全绿")
|
||
|
||
whole-project / feature 审查**必须**执行防伪抽验(三件套③),并校验报告含抽验记录。生成完成后对最新报告运行:
|
||
|
||
```powershell
|
||
powershell -File "C:\Users\Administrator\.config\opencode\skills\project-review\verify-spot-check.ps1" -Repo <repo_root>
|
||
```
|
||
|
||
- 退出码 **0** → 通过:报告覆盖度区块含**防伪抽验**字段且单元数 >0(Step 5.5 抽验已执行并注入 `review_data.spot_check`)。
|
||
- 退出码 **1** → 阻塞:报告无防伪抽验字段,或渲染"未执行 🔴"。必须补抽验(Step 5.5 d)+ 注入 `spot_check` + 重新生成报告后重跑,直到退出码 0。
|
||
- ⚠️ **scope 判定**:同 Step 8.7——只对 `change-level` 跳过;自定义 scope 值(如 `"evm"`)含 `## 覆盖度` 区块时同样检查抽验。
|
||
- **诚实声明**:该脚本只能验证抽验**声明完整性**(抽了、单元数>0),无法验证主代理是否真读了文件——真实回读依赖行为准则,此为引擎防伪能力的已知边界。
|
||
- **Step 8.6(命名)、Step 8.7(行覆盖)、Step 8.8(防伪抽验)三脚本必须全过**才算审查完成。
|
||
|
||
**Archive naming:** output the report to `docs/reviews/` with `output_path=<base>/{scope}-review-{YYYY-MM-DD-HHMMSS}` (e.g. `docs/reviews/evm-feature-review-2026-08-06-151522`) so the filename carries an exact timestamp and avoids overwriting same-day reviews. Scope value examples: `full-project` (whole project), `{feature}-feature` (feature), `pr-{branch}` (change-level). **不传 `output_path` 时工具默认写到仓库根目录 `code-review-report.*`——这是违规命名,必须在 Step 8.6 用 `verify-report.ps1` 检出并修复。**
|
||
|
||
更详细的字段对照和完整模板见 `references/report-schema.md`。
|
||
|
||
## Output Format
|
||
|
||
`Project Review: N issues (X blocker, Y major, Z minor) — verdict: ✅ PASS / ❌ FAIL`. List each issue with severity, confidence, file:line, problem, and proposed fix.
|
||
|
||
## Token Efficiency Rules
|
||
- ALWAYS start with `get_minimal_context(task="project review")` before any other graph tool.
|
||
- Use `detail_level="minimal"` on all calls. Only escalate to `"standard"` when minimal is insufficient.
|
||
- **whole-project 深读是子代理流水线(Step 5.5),不是主上下文循环。** 主上下文预算 ≤14 tool calls;深读通过并行 explore 子代理(每次 4-6 个)完成,每个子代理返回 `deep_read 确认清单 + findings[]`(带 file:line 证据)。目标:每轮全库覆盖 ≥80% 且高风险 ≥80%(gate="both"),并通过跨轮索引增量累积。
|