--- 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=)` and `query_graph_tool(pattern="children_of", target=)`, then `score_review_tool(changed_files=)` and `get_impact_radius_tool(changed_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=, 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 <落盘目录> - 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_.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=, 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=, 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=, file_semantic_units=)`——**只做行覆盖 ≥95% + 单元完整性无缺口**,**不做全库/高风险文件数覆盖检查**(引擎返回 `coverage_pct`/`high_risk_coverage_pct` 为 `null`,报告只渲染行/单元覆盖区块,不渲染全库/高风险行)。`target_reached=false`(行/单元未达标)→ **禁止生成报告**,执行补读闭环(见下)直至达标。 - ⚠️ **三件套数据必传(行覆盖非 0 的前提)**:feature 主上下文深读每个文件时,必须**边读边累积** `file_read_ranges={:[[s,e],...]}`(已读行区间)与 `file_semantic_units={:[{"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 /T /F`。 3. **引擎自检**:`community_health_tool()` 应返回 `needs_postprocess=false`、`attribution_pct>=90`;`coverage_tool(deep_read_files=[...], gate="both+line", file_read_ranges=, file_semantic_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=)` 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": "", "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 ``` - 退出码 **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 ``` - 退出码 **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 ``` - 退出码 **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=/{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"),并通过跨轮索引增量累积。