Stop PR queue advancement when infra_stop blocks capability and require CONTROL-CHECKOUT REPAIR MODE handoffs with infra diagnostics. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
162 lines
5.3 KiB
Python
162 lines
5.3 KiB
Python
"""Infra-stop repair handoff verifier for blocked reviewer workflows (#289)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from typing import Any
|
|
|
|
from capability_stop_terminal import (
|
|
TERMINAL_REPORT_HEADING,
|
|
assess_capability_stop_report,
|
|
)
|
|
|
|
_REPAIR_HANDOFF_RE = re.compile(
|
|
r"repair handoff|control-checkout repair mode",
|
|
re.IGNORECASE,
|
|
)
|
|
_CONTROL_REPAIR_RE = re.compile(r"control-checkout repair mode", re.IGNORECASE)
|
|
_PR_QUEUE_ADVANCE_RE = re.compile(
|
|
r"(?:selected pr|pr #\d+ (?:to review|selected)|eligible pr|"
|
|
r"next (?:eligible )?pr(?: to review)?|oldest eligible pr|pinned (?:review )?head)",
|
|
re.IGNORECASE,
|
|
)
|
|
_REVIEW_MUTATION_RE = re.compile(
|
|
r"(?:gitea_review_pr|gitea_merge_pr|request_changes|submitted\s+approve|"
|
|
r"merge result|review decision\s*:\s*approve)",
|
|
re.IGNORECASE,
|
|
)
|
|
_BACKGROUND_TOOL_RE = re.compile(r"\b(?:schedule|manage_task)\b", re.IGNORECASE)
|
|
_PR_REVIEW_REPORT_RE = re.compile(
|
|
r"(?:review summary|merge recommendation|validation result\s*:\s*pass|"
|
|
r"queue status report with selected pr)",
|
|
re.IGNORECASE,
|
|
)
|
|
|
|
_DIAGNOSTIC_FIELDS = {
|
|
"mcp process root": re.compile(r"mcp process root\s*:", re.IGNORECASE),
|
|
"inspected git root": re.compile(r"inspected git root\s*:", re.IGNORECASE),
|
|
"conflict marker path": re.compile(
|
|
r"(?:conflict marker path|exact conflict marker path)\s*:",
|
|
re.IGNORECASE,
|
|
),
|
|
"merge/rebase control path": re.compile(
|
|
r"(?:merge/rebase control path|exact merge/rebase control path)\s*:",
|
|
re.IGNORECASE,
|
|
),
|
|
"safe next repair action": re.compile(
|
|
r"safe next (?:repair )?action\s*:",
|
|
re.IGNORECASE,
|
|
),
|
|
}
|
|
|
|
|
|
def assess_infra_stop_handoff_report(
|
|
report_text: str,
|
|
*,
|
|
stop_session: dict | None = None,
|
|
) -> dict[str, Any]:
|
|
"""Validate repair handoff purity when infra_stop blocks reviewer capability (#289)."""
|
|
text = report_text or ""
|
|
session = dict(stop_session or {})
|
|
reasons: list[str] = []
|
|
|
|
infra_stop = bool(
|
|
session.get("infra_stop")
|
|
or session.get("infra_stop_blocked")
|
|
or session.get("route_result") == "infra_stop"
|
|
)
|
|
if not infra_stop:
|
|
return {
|
|
"proven": True,
|
|
"block": False,
|
|
"reasons": [],
|
|
"infra_stop": False,
|
|
"safe_next_action": "proceed",
|
|
}
|
|
|
|
lower = text.lower()
|
|
repair_handoff = bool(
|
|
_REPAIR_HANDOFF_RE.search(text)
|
|
or TERMINAL_REPORT_HEADING.lower() in lower
|
|
)
|
|
if not repair_handoff:
|
|
reasons.append(
|
|
"infra_stop requires a repair handoff, not a PR review report"
|
|
)
|
|
|
|
if _PR_REVIEW_REPORT_RE.search(text) and not _REPAIR_HANDOFF_RE.search(text):
|
|
reasons.append(
|
|
"final output must be a repair handoff instead of stale PR review state"
|
|
)
|
|
|
|
if _PR_QUEUE_ADVANCE_RE.search(text):
|
|
reasons.append(
|
|
"infra_stop blocks PR queue advancement; do not select or advance next PR"
|
|
)
|
|
|
|
if _REVIEW_MUTATION_RE.search(text):
|
|
reasons.append(
|
|
"review, approval, request-changes, merge, or comment mutations "
|
|
"forbidden while infra_stop is active"
|
|
)
|
|
|
|
if session.get("pinned_head_sha") or re.search(
|
|
r"pinned (?:review )?head sha\s*:", text, re.IGNORECASE
|
|
):
|
|
if session.get("capability_cleared") is not True:
|
|
reasons.append(
|
|
"cannot pin PR head SHA while review capability never cleared"
|
|
)
|
|
|
|
if session.get("main_checkout_diagnostics") and not _CONTROL_REPAIR_RE.search(text):
|
|
reasons.append(
|
|
"main-checkout diagnostics must be labeled CONTROL-CHECKOUT REPAIR MODE"
|
|
)
|
|
|
|
if _BACKGROUND_TOOL_RE.search(text):
|
|
reasons.append(
|
|
"background schedule/manage_task tools must not be used during "
|
|
"blocked infra_stop recovery"
|
|
)
|
|
|
|
assessment = session.get("infra_stop_assessment") or {}
|
|
if assessment.get("infra_stop") or infra_stop:
|
|
missing = [
|
|
label
|
|
for label, pattern in _DIAGNOSTIC_FIELDS.items()
|
|
if not pattern.search(text)
|
|
]
|
|
if missing and session.get("require_infra_diagnostics", True):
|
|
reasons.append(
|
|
"infra_stop repair handoff missing diagnostic fields: "
|
|
+ ", ".join(missing)
|
|
)
|
|
conflict_file = assessment.get("conflict_file")
|
|
if conflict_file and conflict_file.lower() not in lower:
|
|
reasons.append(
|
|
f"infra_stop assessment conflict file {conflict_file!r} "
|
|
"not reflected in repair handoff"
|
|
)
|
|
|
|
capability = assess_capability_stop_report(
|
|
text,
|
|
trust_gate_status=session.get("trust_gate_status"),
|
|
capability_denied=True,
|
|
)
|
|
if not capability.get("pure"):
|
|
reasons.extend(capability.get("reasons") or [])
|
|
|
|
proven = not reasons
|
|
return {
|
|
"proven": proven,
|
|
"block": not proven,
|
|
"reasons": list(dict.fromkeys(reasons)),
|
|
"infra_stop": True,
|
|
"repair_handoff": repair_handoff,
|
|
"safe_next_action": (
|
|
"stop PR queue work; emit CONTROL-CHECKOUT REPAIR MODE handoff "
|
|
"with infra diagnostics and safe next repair action"
|
|
if reasons
|
|
else "proceed"
|
|
),
|
|
} |