feat: add unified-review workflow (scoring tools + skill)

Adds the unified-review integration that fuses CRG graph context with the
ai-code-review scoring methodology and gstack-review fix-first workflow:

- scoring.py: objective Layer-2 metrics (sql_risk, exception_coverage,
  redundancy_rate, high_risk_density, vulnerability_risk) with
  good/warn/fail grades, plus dedupe_findings (fingerprint merge,
  multi-source confidence boost, PR quality score) and report data builder
- tools/scoring_tools.py + main.py: three new MCP tools
  (score_review_tool, dedupe_findings_tool, generate_report_tool)
- assets/report-template.html: self-contained HTML report template
- skills.py + skills/unified-review/: new read-only unified-review skill
  with language/manual-review/specialist checklists
- docs and CHANGELOG updated; tests added (test_scoring, test_report,
  test_unified_review) and test_skills updated for 5 skills
This commit is contained in:
dev
2026-08-05 13:31:55 +08:00
parent 82b7c6dc9e
commit 84ae9b817e
32 changed files with 2229 additions and 19 deletions
+105
View File
@@ -33,9 +33,11 @@ from .tools import (
apply_refactor_func,
build_or_update_graph,
cross_repo_search_func,
dedupe_findings_func,
detect_changes_func,
embed_graph,
find_large_functions,
generate_report_func,
generate_wiki_func,
get_affected_flows_func,
get_architecture_overview_func,
@@ -58,6 +60,7 @@ from .tools import (
query_graph,
refactor_func,
run_postprocess,
score_review_func,
semantic_search_nodes,
traverse_graph_func,
with_provenance,
@@ -686,6 +689,108 @@ async def detect_changes_tool(
return await coro
@mcp.tool()
async def score_review_tool(
changed_files: Optional[list[str]] = None,
base: str = "HEAD~1",
include_churn: bool = True,
repo_root: Optional[str] = None,
detail_level: str = "standard",
) -> dict:
"""Compute objective Layer-2 review metrics for changed files.
Runs the git-history / graph risk factors plus the heuristic metrics
(SQL risk, exception coverage, redundancy, high-risk density,
vulnerability) that back the unified-review scoring. LLM-judged
metrics (requirement coverage, logic alignment, trust boundaries) are
reported in ``llm_judged`` for the calling agent to fill in.
Offloaded to a thread via ``asyncio.to_thread`` — runs `git log`
subprocesses and graph queries that can take several seconds.
Args:
changed_files: Files to score (auto-detected from git diff if
omitted).
base: Git ref to diff against. Default: HEAD~1.
include_churn: Include git-churn risk factors. Default: True.
repo_root: Repository root path. Auto-detected if omitted.
detail_level: "standard" for full output, "minimal" for
token-efficient summary. Default: standard.
"""
root = _resolve_repo_root(repo_root)
def _run() -> dict:
return with_provenance(score_review_func(
changed_files=changed_files, base=base,
include_churn=include_churn, repo_root=root,
detail_level=detail_level,
), root)
return await asyncio.to_thread(_run)
@mcp.tool()
def dedupe_findings_tool(
findings: list,
suppress_prior: Optional[list] = None,
repo_root: Optional[str] = None,
) -> dict:
"""Merge review findings by fingerprint and boost multi-source confidence.
Findings with the same ``path:line:category`` fingerprint are merged
(highest confidence wins); findings confirmed by more than one source
(main review + specialist subagents) get confidence +1 (cap 10).
Low-confidence findings are routed to the appendix or suppressed, and a
PR quality score is computed as ``max(0, 10 - (critical*2 +
informational*0.5))``.
Args:
findings: Raw finding dicts with ``path``, ``category``,
``severity``, ``confidence`` and optional ``source``/``line``.
suppress_prior: Previously user-skipped findings (from a prior
review-log) to suppress when their file has not changed.
repo_root: Repository root path. Auto-detected if omitted.
"""
return dedupe_findings_func(
findings=findings, suppress_prior=suppress_prior,
repo_root=repo_root,
)
@mcp.tool()
async def generate_report_tool(
review_data: dict,
output_path: Optional[str] = None,
repo_root: Optional[str] = None,
) -> dict:
"""Generate a self-contained HTML code review report.
Injects ``review_data`` (output of ``score_review_tool`` plus
``dedupe_findings_tool`` results and free-form verdict/tier/scope) into
the bundled ``report-template.html`` as ``{{REPORT_DATA}}`` and writes
the standalone file (default ``repo_root/code-review-report.html``).
Offloaded to a thread via ``asyncio.to_thread`` — rendering loads the
template asset and writes the output file.
Args:
review_data: Review data dict (metrics, findings, verdict, tier,
scope, files, baseline, timestamp, manual_review).
output_path: Output file path. Defaults to
``<repo_root>/code-review-report.html``.
repo_root: Repository root path. Auto-detected if omitted.
"""
root = _resolve_repo_root(repo_root)
def _run() -> dict:
return with_provenance(generate_report_func(
review_data=review_data, output_path=output_path,
repo_root=root,
), root)
return await asyncio.to_thread(_run)
@mcp.tool()
def refactor_tool(
mode: str = "rename",