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
7 changes: 7 additions & 0 deletions code_review_graph/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,8 @@ def get_affected_flows_tool(
changed_files: Optional[list[str]] = None,
base: str = "HEAD~1",
repo_root: Optional[str] = None,
detail_level: str = "standard",
max_flows: int = 50,
) -> dict:
"""Find execution flows affected by changed files.

Expand All @@ -541,10 +543,15 @@ def get_affected_flows_tool(
changed_files: List of changed file paths (relative to repo root). Auto-detected if omitted.
base: Git ref for auto-detecting changes. Default: HEAD~1.
repo_root: Repository root path. Auto-detected if omitted.
detail_level: "standard" for full step details, "minimal" for per-flow
metadata only. Default: standard.
max_flows: Maximum flows to return; total reports the full count.
Default: 50. Pass 0 to disable the limit.
"""
root = _resolve_repo_root(repo_root)
return with_provenance(get_affected_flows_func(
changed_files=changed_files, base=base, repo_root=root,
detail_level=detail_level, max_flows=max_flows,
), root)


Expand Down
31 changes: 29 additions & 2 deletions code_review_graph/tools/review.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ def get_affected_flows_func(
changed_files: list[str] | None = None,
base: str = "HEAD~1",
repo_root: str | None = None,
detail_level: str = "standard",
max_flows: int = 50,
) -> dict[str, Any]:
"""Find execution flows affected by changed files.

Expand All @@ -305,9 +307,16 @@ def get_affected_flows_func(
Auto-detected from git diff if omitted.
base: Git ref for auto-detecting changes (default: HEAD~1).
repo_root: Repository root path. Auto-detected if omitted.
detail_level: "standard" for full step details, "minimal" for
per-flow metadata only (name, criticality, depth, counts).
Every flow carries a full ``steps`` list in standard mode, so
large change sets can exceed 200k tokens without a bound (#849).
max_flows: Maximum flows to return (default: 50). ``total`` always
reports the untruncated count; 0 disables the limit.

Returns:
Affected flows sorted by criticality, with step details.
Affected flows sorted by criticality; ``truncated`` is set when
``max_flows`` cut the list.
"""
store, root = _get_store(repo_root)
try:
Expand All @@ -330,15 +339,33 @@ def get_affected_flows_func(
result = _get_affected_flows(store, abs_files)

total = result["total"]
flows = result["affected_flows"]
truncated = bool(max_flows) and max_flows > 0 and total > max_flows
if truncated:
flows = flows[:max_flows]
if detail_level == "minimal":
flows = [
{
"id": f.get("id"),
"name": f.get("name"),
"criticality": f.get("criticality"),
"depth": f.get("depth"),
"node_count": f.get("node_count"),
"file_count": f.get("file_count"),
}
for f in flows
]
out = {
"status": "ok",
"summary": (
f"{total} flow(s) affected by changes "
f"in {len(changed_files)} file(s)"
+ (f", showing {len(flows)}" if truncated else "")
),
"changed_files": changed_files,
"affected_flows": result["affected_flows"],
"affected_flows": flows,
"total": total,
"truncated": truncated,
}
out["_hints"] = generate_hints(
"get_affected_flows", out, get_session()
Expand Down
38 changes: 38 additions & 0 deletions tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -1266,6 +1266,44 @@ def test_get_affected_flows_summary(self):
assert "flow(s) affected" in result["summary"]
assert "changed_files" in result

def test_get_affected_flows_minimal_drops_steps(self):
"""detail_level="minimal" strips per-flow step details (#849)."""
result = get_affected_flows_func(
changed_files=["auth.py"],
repo_root=str(self.root),
detail_level="minimal",
)
assert result["status"] == "ok"
assert result["total"] >= 1
for flow in result["affected_flows"]:
assert "steps" not in flow
assert "path" not in flow
assert "name" in flow
assert "criticality" in flow

def test_get_affected_flows_max_flows_truncates(self):
"""max_flows bounds the list while total keeps the full count (#849)."""
result = get_affected_flows_func(
changed_files=["auth.py"],
repo_root=str(self.root),
max_flows=1,
)
assert result["status"] == "ok"
assert len(result["affected_flows"]) <= 1
if result["total"] > 1:
assert result["truncated"] is True
assert "showing 1" in result["summary"]

def test_get_affected_flows_max_flows_zero_disables_limit(self):
result = get_affected_flows_func(
changed_files=["auth.py"],
repo_root=str(self.root),
max_flows=0,
)
assert result["status"] == "ok"
assert result["truncated"] is False
assert len(result["affected_flows"]) == result["total"]


class TestCommunityTools:
"""Tests for community-related MCP tool functions."""
Expand Down