feat(workflow-guard): verify MCP runtime clean/not mid-merge before starting reviewer work
This commit is contained in:
+53
-1
@@ -5,12 +5,14 @@ returns a route result before any downstream mutation tools run.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
import os
|
||||||
|
|
||||||
ROUTE_ALLOWED = "allowed_current_session"
|
ROUTE_ALLOWED = "allowed_current_session"
|
||||||
ROUTE_WRONG_ROLE = "wrong_role_stop"
|
ROUTE_WRONG_ROLE = "wrong_role_stop"
|
||||||
ROUTE_TO_AUTHOR = "route_to_author_session"
|
ROUTE_TO_AUTHOR = "route_to_author_session"
|
||||||
ROUTE_TO_REVIEWER = "route_to_reviewer_session"
|
ROUTE_TO_REVIEWER = "route_to_reviewer_session"
|
||||||
ROUTE_AMBIGUOUS = "ambiguous_task_stop"
|
ROUTE_AMBIGUOUS = "ambiguous_task_stop"
|
||||||
|
ROUTE_INFRA_STOP = "infra_stop"
|
||||||
|
|
||||||
REVIEWER_TASKS = frozenset({
|
REVIEWER_TASKS = frozenset({
|
||||||
"review_pr",
|
"review_pr",
|
||||||
@@ -93,6 +95,23 @@ def route_task_session(
|
|||||||
_record_route(result)
|
_record_route(result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
if required_role == "reviewer" and check_mid_merge():
|
||||||
|
result = {
|
||||||
|
"task_type": task_type,
|
||||||
|
"required_role": required_role,
|
||||||
|
"active_role": active_role_kind,
|
||||||
|
"active_profile": active_profile,
|
||||||
|
"route_result": ROUTE_INFRA_STOP,
|
||||||
|
"downstream_allowed": False,
|
||||||
|
"reasons": [
|
||||||
|
"infra_stop: Unresolved merge conflict or mid-merge state detected in MCP runtime source.",
|
||||||
|
"Please resolve all conflicts manually, finish/abort the merge, restart the MCP server, and retry."
|
||||||
|
],
|
||||||
|
"message": "infra_stop: Unresolved merge conflict or mid-merge state detected in MCP runtime source.",
|
||||||
|
}
|
||||||
|
_record_route(result)
|
||||||
|
return result
|
||||||
|
|
||||||
if allowed_in_current_session:
|
if allowed_in_current_session:
|
||||||
result = {
|
result = {
|
||||||
"task_type": task_type,
|
"task_type": task_type,
|
||||||
@@ -192,4 +211,37 @@ def check_author_mutation_after_reviewer_stop(mutation_task: str) -> tuple[bool,
|
|||||||
"task and relaunches an author MCP session.",
|
"task and relaunches an author MCP session.",
|
||||||
f"Attempted fallback mutation: {mutation_task}",
|
f"Attempted fallback mutation: {mutation_task}",
|
||||||
]
|
]
|
||||||
return True, []
|
return True, []
|
||||||
|
|
||||||
|
|
||||||
|
def check_mid_merge() -> bool:
|
||||||
|
"""Return True if the repository is mid-merge, mid-rebase, or has conflict markers."""
|
||||||
|
project_root = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
git_dir = os.path.join(project_root, ".git")
|
||||||
|
if os.path.exists(git_dir):
|
||||||
|
if (os.path.exists(os.path.join(git_dir, "MERGE_HEAD"))
|
||||||
|
or os.path.exists(os.path.join(git_dir, "rebase-merge"))
|
||||||
|
or os.path.exists(os.path.join(git_dir, "rebase-apply"))):
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Scan python files for conflict markers
|
||||||
|
conflict_patterns = [
|
||||||
|
b"<" * 7 + b" ",
|
||||||
|
b"=" * 7 + b"\n",
|
||||||
|
b"=" * 7 + b"\r\n",
|
||||||
|
b">" * 7 + b" "
|
||||||
|
]
|
||||||
|
for root, dirs, files in os.walk(project_root):
|
||||||
|
if any(p in root for p in ("venv", ".git", ".pytest_cache", "branches")):
|
||||||
|
continue
|
||||||
|
for file in files:
|
||||||
|
if file.endswith(".py"):
|
||||||
|
file_path = os.path.join(root, file)
|
||||||
|
try:
|
||||||
|
with open(file_path, "rb") as f:
|
||||||
|
content = f.read()
|
||||||
|
if any(pattern in content for pattern in conflict_patterns):
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
Reference in New Issue
Block a user