Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions python/cube/commands/peer_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,7 @@ def _archive_decisions(
# resumed judge will see prompt-level instructions to ignore
# any prior decision content anyway.
pass
print_info(
f"📦 Archived {len(matches)} prior decision file(s) → " f".prompts/decisions/archive/{archive_root.name}/"
)
print_info(f"📦 Archived {len(matches)} prior decision file(s) → .prompts/decisions/archive/{archive_root.name}/")


def _format_thread_context(threads: list) -> str:
Expand Down Expand Up @@ -333,7 +331,7 @@ def _ensure_pr_review_worktree(
timeout=60,
)
if result.returncode != 0:
raise RuntimeError(f"PR review worktree sync failed ({' '.join(cmd)}): " f"{result.stderr.strip()}")
raise RuntimeError(f"PR review worktree sync failed ({' '.join(cmd)}): {result.stderr.strip()}")
else:
worktree.parent.mkdir(parents=True, exist_ok=True)
add = subprocess.run(
Expand Down Expand Up @@ -456,7 +454,7 @@ def _reconcile_panel_results(
),
log_path=None,
recovery_command=(
f"cube prv {task_id[len('pr-'):]}"
f"cube prv {task_id[len('pr-') :]}"
if disk_status == "missing" and task_id.startswith("pr-")
else None
),
Expand Down Expand Up @@ -500,7 +498,7 @@ def _reconcile_panel_results(
attempts=existing.attempts,
error_message="Decision file disappeared after panel completion",
log_path=existing.log_path,
recovery_command=(f"cube prv {task_id[len('pr-'):]}" if task_id.startswith("pr-") else None),
recovery_command=(f"cube prv {task_id[len('pr-') :]}" if task_id.startswith("pr-") else None),
forcing_follow_up_used=False,
)
)
Expand Down Expand Up @@ -564,7 +562,10 @@ def _run_pr_review(
except Exception as e:
print_warning(f"Could not fetch from origin: {e}")

if not pr.diff.strip():
# Use the cheap boolean check (git diff --quiet, exit-status only)
# instead of fetching diff content. Judges go through the worktree
# via Read; we don't need the diff string here.
if not pr.has_changes():
print_warning("PR has no diff - nothing to review")
raise typer.Exit(0)

Expand Down Expand Up @@ -774,7 +775,7 @@ def _run_pr_review(
if missing_judges:
names = ", ".join(j.label for j in missing_judges)
print_warning(
f"Partial panel failure: {len(missing_judges)} expected judge(s) " f"failed to produce a decision: {names}"
f"Partial panel failure: {len(missing_judges)} expected judge(s) failed to produce a decision: {names}"
)
print_info("Continuing with available judge decisions...")

Expand Down Expand Up @@ -854,11 +855,15 @@ def _run_pr_review(

# Use AI deduper to intelligently combine/dedupe all feedback AND merge
# human_calls across lenses asking the same question.
# Lazily compute the diff right before dedupe — capped at 8000
# lines, fetched via local git (no API cap). The dedupe prompt
# already truncates to ~8000 chars, so this is the right place
# to enforce a hard ceiling.
dedupe_result = run_async(
run_dedupe_agent(
feedback=all_feedback,
existing_comments=existing_comments,
pr_diff=pr.diff,
pr_diff=pr.get_diff(),
pr_number=pr_number,
human_calls=raw_human_calls,
)
Expand Down Expand Up @@ -937,7 +942,7 @@ def _run_pr_review(
+ (f" (+{len(gate.reasons) - 3} more)" if len(gate.reasons) > 3 else "")
)
elif post_action == "APPROVE":
print_success(f"Auto-approve gate passed — posting APPROVE " f"({approvals}/{expected_total} judges APPROVED)")
print_success(f"Auto-approve gate passed — posting APPROVE ({approvals}/{expected_total} judges APPROVED)")
# Append the gate body to the summary so the GitHub review body explains
# what the gate saw (judges + reasons, or the clean approval message).
summary = summary + "\n\n" + gate.body
Expand Down Expand Up @@ -1165,7 +1170,7 @@ def _run_branch_review(
names = ", ".join(j.label for j in missing_judges)
missing_suffix = f" ⚠️ {len(missing_judges)} judge(s) failed to produce a decision: {names}."
print_warning(
f"Partial panel failure: {len(missing_judges)} expected judge(s) " f"failed to produce a decision: {names}"
f"Partial panel failure: {len(missing_judges)} expected judge(s) failed to produce a decision: {names}"
)
print_info("Continuing with available judge decisions...")

Expand Down Expand Up @@ -1238,7 +1243,7 @@ def _run_branch_review(
for inline in dedupe_result.inline_comments:
comment = inline.comment
console.print(
f"[yellow]{comment.severity.upper():8}[/yellow] " f"{_rich_escape(str(comment.path))}:{comment.line}"
f"[yellow]{comment.severity.upper():8}[/yellow] {_rich_escape(str(comment.path))}:{comment.line}"
)
console.print(f"[dim]{_rich_escape(', '.join(inline.judges))}[/dim] {_rich_escape(comment.body)}")
console.print()
Expand Down
15 changes: 13 additions & 2 deletions python/cube/commands/ui_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,18 @@ def _fetch_pr_ui_diff(pr_number: int, repo: Optional[str] = None) -> tuple[str,
raise RuntimeError("gh CLI not installed or not authenticated. Run: gh auth login")

pr = fetch_pr(pr_number, cwd=str(PROJECT_ROOT), repo=repo)
ui_diff = _filter_ui_diff(pr.diff)
# UI review filters the diff by extension. Fetch with a generous
# ceiling so a huge mixed PR (lots of non-UI changes before the
# first UI file) doesn't get its UI hunks dropped to the
# truncation marker. The filter shrinks the result to UI-only;
# we cap AFTER filtering so the budget applies to relevant content.
raw_diff = pr.get_diff(max_lines=1_000_000)
ui_diff = _filter_ui_diff(raw_diff)
# Now apply a sane cap to the filtered result so prompt size is
# bounded even when the UI portion is genuinely huge.
ui_lines = ui_diff.splitlines()
if len(ui_lines) > 20_000:
ui_diff = "\n".join(ui_lines[:20_000]) + f"\n[... {len(ui_lines) - 20_000} more UI-diff lines truncated ...]"

if not ui_diff.strip():
raise RuntimeError(
Expand Down Expand Up @@ -458,7 +469,7 @@ def ui_review_command(
total = len(findings["P0"]) + len(findings["P1"]) + len(findings["P2"])
if total > 0:
print_success(
f"UI review complete: {len(findings['P0'])} P0, " f"{len(findings['P1'])} P1, {len(findings['P2'])} P2"
f"UI review complete: {len(findings['P0'])} P0, {len(findings['P1'])} P1, {len(findings['P2'])} P2"
)
else:
print_warning("No findings collected from judges")
Expand Down
Loading
Loading