8.6 KiB
generate_report_tool 入参 Schema(权威参考)
依据
code-review-graph源码code_review_graph/scoring.py::build_report_data与render_markdown_report反推的精确约定。任何偏离都会导致报告静默丢内容。
1. 顶层键
工具从 review_data dict 中只读取以下键(scoring.py:620-633):
| 键 | 类型 | 默认值 | 作用 |
|---|---|---|---|
scope |
str | "change-level" |
审查范围 |
tier |
str | "standard" |
审查档位 |
timestamp |
str | "" |
生成时间 |
files |
str | "" |
审查文件(逗号分隔字符串,兼容字段) |
reviewed_files |
list[str] | [] |
本轮审查文件数组;报告顶部以可折叠列表(details/summary)展示,缺省回退 files |
baseline |
str | "generic" |
git 基线 SHA |
verdict |
str | "❌ FAIL" |
结论,"PASS" 或 "FAIL" |
quality_score |
int/float | None |
PR 质量分 |
counts |
dict | {} |
严重度统计 |
metrics |
dict | {} |
客观指标(值必须是 dict) |
findings |
list[dict] | [] |
问题清单 |
manual_review |
list[str] | [] |
人工复核项 |
llm_judged |
list[str] | [] |
保留兼容字段,一律置空;不再新增 LLM 判定指标 |
summary |
str | "" |
摘要(仅 HTML 渲染) |
2. findings 条目字段(scoring.py:645-658)
工具对每条 finding 做如下映射:
data["issues"].append({
"severity": f.get("severity", "minor"),
"category": f.get("category", ""),
"message": f.get("summary", f.get("message", "")), # summary 优先,其次 message
"location": f"{f.get('path','')}:{f.get('line','')}" # 仅当 line 非空
if f.get("line") else str(f.get("path","")),
"confidence": f.get("confidence"),
"fix": f.get("fix", ""),
})
| 字段 | 说明 | 若不传会怎样 |
|---|---|---|
path |
文件路径 | 与 line 合成 location;仅传 path 也可显示路径 |
line |
行号 | line 为空则 location 只有 path(无 :行号) |
message |
问题描述 | 缺失 → 报告只剩类别/位置 |
summary |
问题描述(优先级高于 message) | 同上 |
fix |
修复建议 | 缺失 → 无修复建议段 |
severity |
blocker/major/minor(也接受 critical/warn/informational) |
默认 minor |
category |
如 business/security/data 等 |
默认空 |
confidence |
int 1-10 | 缺失则不显示置信度 |
3. metrics 结构(scoring.py:636-643)
metrics 的值必须是 dict,每项支持 grade/value/note/evidence。note 必传(透传 score_review_tool 返回的 note/evidence),否则报告"说明"列为空。
"metrics": {
"sql_risk": {"value": 0, "grade": "good", "note": "全部参数化查询,无注入风险。"},
"exception_coverage": {"value": 0, "grade": "fail", "note": "Rust Result 误报。"}
}
MD 报告显示标签来自硬编码映射:sql_risk→SQL 注入风险、exception_coverage→异常分支覆盖、redundancy_rate→代码冗余率、high_risk_density→高风险场景密度、vulnerability_risk→漏洞风险。其他指标名直接显示原名。指标表应仅含上述五个客观指标(指标集约束见 SKILL.md Step 4),禁止手工注入 requirement_coverage/logic_alignment/llm_trust_boundary/shell_injection/enum_completeness 等 LLM 判定指标;也不要混入 blast_radius/objective_grade 等键——build_report_data 会按五指标白名单过滤,非五指标键一律丢弃。
4. counts 说明(scoring.py:727-732)
MD 报告的问题统计行只读 counts.critical 和 counts.informational:
f"- **问题统计**:{counts.get('critical', 0)} 严重 · {counts.get('informational', 0)} 次要"
因此若想统计正确,counts 需用 critical/informational 键(或将 major/minor 数量合入)。
4b. coverage 字段(Step 7.5 G3,引擎 v2.5.0)
review_data.coverage 直接透传 coverage_tool 返回值全部字段(不要手挑子集,否则计数字段渲染 0/0 或 N/A):
| 字段 | 说明 |
|---|---|
coverage_pct |
全库覆盖(已深读文件数 / 全部源文件数,文件数口径);gate="line+unit"(feature)时为 None |
high_risk_coverage_pct |
高风险覆盖(已深读高风险文件数 / 信号点名文件数,文件数口径);gate="line+unit"(feature)时为 None |
grade |
good/warn/fail |
deep_read_count / total_files |
已深读数 / 总源文件数 |
high_risk_total_files / high_risk_deep_count |
高风险文件数 / 已深读高风险数 |
deep_read_weight / total_weight |
已深读权重 / 总权重(兼容保留,仅用于排序参考) |
target_reached / target |
门禁结果 / 高风险目标值(gate="both" 时需全库 ≥85% 且 高风险 ≥95% 才 True;standard=85/95) |
overall_target / high_risk_target |
双目标值:全库 85% / 高风险 95%(报告据此分别显示) |
gate |
门禁口径(high_risk/overall/both/both+line/line+unit) |
remaining_files_to_target |
距全库目标还差多少文件数(驱动补轮的主字段) |
remaining_weight_to_target |
距目标还差多少权重(兼容保留) |
priority_deep_read_files |
按风险权重降序的待深读文件([{path, weight}]) |
uncovered_files |
未深读文件清单(G1) |
silent_files |
静默文件清单(G2 抽检源) |
note |
引擎口径说明 |
增量:
coverage_tool(include_prior=True)合并跨轮索引.code-review-graph/coverage-index.json中 SHA 未变的已深读文件。报告后必须save_coverage_index_tool写索引供下轮复用。
4b-1. feature(单功能)审查:gate="line+unit"
feature 覆盖度门禁只保留行级覆盖 + 单元覆盖,不做全库/高风险文件数覆盖检查:
"coverage": {
"gate": "line+unit",
"coverage_pct": null,
"high_risk_coverage_pct": null,
"line_coverage_pct": 100.0,
"unit_coverage_pct": 100.0,
"line_gap_files": [],
"unit_gap_files": [],
"target_reached": true
}
coverage_pct/high_risk_coverage_pct为null是预期行为(不做文件数覆盖检查),勿误判失败。target_reached只由行覆盖 ≥95% + 单元完整性无缺口决定。- 报告
## 覆盖度区块只渲染行/单元覆盖与状态行,不渲染全库/高风险行。 - 必须同时传
reviewed_files(本轮深读文件数组),报告顶部以可折叠列表展示。
5. 完整可复制模板
{
"verdict": "PASS",
"scope": "feature",
"target": "EVM",
"tier": "standard",
"timestamp": "2026-08-06T15:24:47",
"files": "server/src/api/evm_api.rs, server/src/services/evm_service.rs",
"baseline": "f4235d00008a0de651ad8988adc1bca27ede1fb2",
"quality_score": 7.5,
"counts": {"blocker": 0, "major": 3, "minor": 5},
"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": "progressive 模式下 EV 计算依赖 workflow_states.completion_percentage,更新后未失效 EVM 缓存,5 分钟 TTL 内显示过期数据。",
"fix": "在 update_state / create_state / delete_state 中调用 EvmService::invalidate_evm_cache(project_id, None)。"
}
],
"manual_review": [
"list_evm_cases 无 data_scope 是否为有意设计(需产品/权限负责人确认)"
],
"summary": "发现 3 个 major 与 5 个 minor。SQL 全部参数化无注入风险,无 blocker,结论 PASS。"
}
6. 错误用法 → 现象对照表
| 错误用法 | 代码示例 | 现象 |
|---|---|---|
用 issues 键 |
{"issues": [...]} |
问题清单(0),条目全丢 |
finding 用 title/detail |
{"title": "...", "detail": "..."} |
只剩类别+位置,描述/修复为空 |
传合并 location |
{"location": "a.rs:5"} |
位置为空(工具只认 path+line) |
| metrics 传扁平标量 | "sql_risk": 0 |
指标表空(要求 dict) |
counts 用 major/minor |
{"counts":{"major":3}} |
MD 统计行显示 0 严重·0 次要 |
7. 生成后自检清单(Step 8.5)
生成报告后必须打开 .md 验证:
## 问题清单(N),N == findings 条数,且 > 0- 每条 issue 同时含描述 + 位置(
`path:line`)+ 修复建议 - 若任一缺失 → 修正
review_data字段后重新调用generate_report_tool覆盖