From 979c93bdbbd317649a67fb2bc52ca56c5824eff4 Mon Sep 17 00:00:00 2001 From: claude Date: Sat, 22 Aug 2026 00:58:51 +0000 Subject: [PATCH] feat(review): render walkthrough + risk_verdict + test_coverage --- pilot/ai_review.py | 36 ++++++++++++++++++++++++++++++++++ tests/pilot/test_ai_review.py | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/pilot/ai_review.py b/pilot/ai_review.py index d720a07..4112cc3 100644 --- a/pilot/ai_review.py +++ b/pilot/ai_review.py @@ -292,6 +292,9 @@ def format_review_body( findings_for_table: list[dict] | None = None, inline_count: int = 0, confidence: int = 5, + walkthrough: list[str] | None = None, + risk_verdict: str = "", + test_coverage: str = "", ) -> str: """Format the posted review summary body. @@ -301,6 +304,13 @@ def format_review_body( * **Summary of Changes** — 2–4 bullets of what the PR introduces (`summary_changes`); falls back to the opencode prose `summary` if the agent didn't emit the list. + * **Risk Verdict** — one-line " risk: " verdict + (`risk_verdict`); omitted when empty. + * **Walkthrough** — up to 6 file- or change-grouped bullets + (`walkthrough`); the file part is wrapped in backticks so paths + render as code in Gitea. Omitted when empty. + * **Test Coverage** — short `test_coverage` string ("Tests added" / + etc.); omitted when empty. * **Key Risks & Concerns** — bullets of potential bugs/edge cases found across the diff (`risks`). * **Findings Overview** — a Markdown table (severity / location / @@ -340,6 +350,32 @@ def format_review_body( else: parts.append("### Summary of Changes\n\n_No summary provided._") + # --- Risk Verdict --- + if risk_verdict: + parts.append(f"### Risk Verdict\n\n{risk_verdict}") + + # --- Walkthrough --- + wt = list(walkthrough or []) + if wt: + wt = wt[:6] + rendered = [] + for item in wt: + # Items typically look like "a.py — adds X" (em-dash separator). + # Wrap the file path in backticks so it renders as code in the + # Gitea markdown body; leave the description as plain prose. When + # no separator is present, render the whole line as plain prose + # (the agent's "plain prose" fallback for change-grouped bullets). + if " — " in item: + path, _, rest = item.partition(" — ") + rendered.append(f"- `{path}` — {rest}") + else: + rendered.append(f"- {item}") + parts.append(f"### Walkthrough\n\n" + "\n".join(rendered)) + + # --- Test Coverage --- + if test_coverage: + parts.append(f"### Test Coverage\n\n{test_coverage}") + # --- Key Risks & Concerns --- rs = list(risks or []) if rs: diff --git a/tests/pilot/test_ai_review.py b/tests/pilot/test_ai_review.py index 31c8f6a..eb3c131 100644 --- a/tests/pilot/test_ai_review.py +++ b/tests/pilot/test_ai_review.py @@ -859,6 +859,43 @@ def test_format_review_body_with_summary_changes_and_risks(): assert "`a.py:1`" in body +def test_format_review_body_renders_walkthrough(): + body = format_review_body( + "", "glm-5.2:cloud", "abc1234", + summary_changes=["adds X"], + risks=[], + walkthrough=["a.py — adds X", "b.py — refactors Y"], + risk_verdict="Low risk: clean.", + test_coverage="Tests added.", + findings_for_table=[], + ) + assert "### Walkthrough" in body + assert "`a.py` — adds X" in body + assert "### Risk Verdict" in body + assert "Low risk: clean." in body + assert "### Test Coverage" in body + assert "Tests added." in body + + +def test_format_review_body_omits_empty_sections(): + body = format_review_body( + "", "glm-5.2:cloud", "abc1234", + summary_changes=["adds X"], + walkthrough=[], risk_verdict="", test_coverage="", + ) + assert "### Walkthrough" not in body + assert "### Risk Verdict" not in body + assert "### Test Coverage" not in body + + +def test_format_review_body_placeholder_when_empty(): + body = format_review_body( + "", "glm-5.2:cloud", "abc1234", + walkthrough=[], risk_verdict="", test_coverage="", + ) + assert body # non-empty + + def test_render_collapsible_usage_contains_details(): usage = { "model": "glm-5.2:cloud", "input": 1000, "output": 200, "reasoning": 0,