"""Precise mutation category verifier for reviewer controller handoffs (#319).""" from __future__ import annotations import re from typing import Any _CONTROLLER_HANDOFF_RE = re.compile(r"controller handoff", re.IGNORECASE) _WORKSPACE_MUTATIONS_RE = re.compile( r"^\s*[-*]?\s*workspace\s+mutations\s*:", re.IGNORECASE | re.MULTILINE, ) _VAGUE_MUTATIONS_NONE_RE = re.compile( r"^\s*[-*]?\s*mutations\s*:\s*none\s*$", re.IGNORECASE | re.MULTILINE, ) _REQUIRED_CATEGORIES = ( "file edits by reviewer", "worktree/index mutations", "git ref mutations", ) _WORKTREE_FIELD_ALIASES = ( "worktree/index mutations", "worktree mutations", ) def _has_category(text: str, category: str) -> bool: pattern = re.compile( rf"^\s*[-*]?\s*{re.escape(category)}\s*:", re.IGNORECASE | re.MULTILINE, ) return bool(pattern.search(text)) def _has_worktree_category(text: str) -> bool: return any(_has_category(text, alias) for alias in _WORKTREE_FIELD_ALIASES) def _normalize_for_consistency_check(text: str) -> str: """Map #319 precise labels to #313 field names for consistency delegation.""" normalized = text if _has_category(text, "worktree/index mutations") and not _has_category( text, "worktree mutations" ): normalized = re.sub( r"(worktree/index mutations\s*:)", "Worktree mutations:", normalized, flags=re.IGNORECASE, ) return normalized def assess_mutation_categories_report( report_text: str, *, handoff_session: dict | None = None, observed_commands: list | None = None, ) -> dict[str, Any]: """Require precise mutation categories in reviewer controller handoffs (#319).""" text = report_text or "" session = dict(handoff_session or {}) reasons: list[str] = [] lower = text.lower() is_controller = bool( session.get("controller_handoff") or _CONTROLLER_HANDOFF_RE.search(text) ) if not is_controller and not session.get("require_categories"): return { "proven": True, "block": False, "reasons": [], "controller_handoff": False, "safe_next_action": "proceed", } if _WORKSPACE_MUTATIONS_RE.search(text): reasons.append( "controller handoffs must not use legacy 'Workspace mutations'; " "use precise mutation category fields" ) if _VAGUE_MUTATIONS_NONE_RE.search(text): reasons.append( "controller handoffs must not use vague 'Mutations: none'; " "report each precise category separately" ) missing = [ category for category in _REQUIRED_CATEGORIES if category != "worktree/index mutations" and not _has_category(text, category) ] if not _has_worktree_category(text): missing.append("worktree/index mutations") if missing: reasons.append( "controller handoff missing precise mutation categories: " + ", ".join(missing) ) commands = observed_commands or session.get("observed_commands") if commands: from review_proofs import assess_workspace_mutation_consistency consistency = assess_workspace_mutation_consistency( _normalize_for_consistency_check(text), commands, ) if not consistency.get("complete"): reasons.extend(consistency.get("reasons") or []) proven = not reasons return { "proven": proven, "block": not proven, "reasons": reasons, "controller_handoff": True, "safe_next_action": ( "replace Workspace mutations with file edits, worktree/index, git ref, " "and other precise mutation category fields" if reasons else "proceed" ), }