"""Proof-backed reviewer handoff claim verifier (#395). Reviewer final reports must not claim proof-sensitive workflow steps unless each claim is backed by explicit command/tool evidence in the transcript or structured MCP result metadata. This verifier scans report text for the five proof-sensitive claim families from issue #395 (inventory completeness, earlier-PR skips, baseline validation, master integration, cleanup) and fails closed when a claim appears without its required evidence. """ from __future__ import annotations import re from typing import Any # Issue #395 criterion 6: reports must distinguish these proof provenances. PROOF_PROVENANCE_CLASSES = ( "command actually run", "MCP metadata", "inherited from previous blocker state", "not checked", ) _INVENTORY_CLAIM_RE = re.compile( r"inventory\s+(?:complete|completeness\s*:\s*complete)", re.IGNORECASE ) _PAGINATION_METADATA_RE = re.compile( r"(?:has_more\s*=?\s*false|is_final_page\s*=?\s*true|" r"inventory_complete\s*=?\s*true|total[_ ]count\s*[=:]\s*\d+|" r"no next page|final page|pagination complete)", re.IGNORECASE, ) _PAGE_SIZE_ASSUMPTION_RE = re.compile( r"(?:less|fewer)\s+than\s+(?:the\s+)?(?:default\s+)?page\s*size|" r"under\s+the\s+(?:default\s+)?page\s*size|" r"below\s+(?:the\s+)?(?:default\s+)?page\s*size", re.IGNORECASE, ) _SKIPPED_PR_RE = re.compile(r"skipped\s+PR\s*#?(\d+)", re.IGNORECASE) _SKIP_EVIDENCE_RE = re.compile( r"(?:mergeable\s*:\s*false|gitea_view_pr|gitea_get_pr_review_feedback|" r"gitea_check_pr_eligibility|git\s+merge-tree|merge simulation|" r"conflicting files?\s*:|REQUEST_CHANGES\s+at\s+(?:current\s+)?head|" r"prior blocker reused|blocker revalidated live)", re.IGNORECASE, ) _BASELINE_CLAIM_RE = re.compile(r"\bbaseline\b", re.IGNORECASE) _BASELINE_REQUIRED = ( ("baseline worktree path", re.compile(r"branches/baseline-[\w./-]+", re.IGNORECASE)), ("baseline target SHA", re.compile(r"target\s+SHA\s*:?\s*[0-9a-f]{7,40}", re.IGNORECASE)), ("baseline dirty-before status", re.compile(r"dirty\s+before\s*:?\s*\w+", re.IGNORECASE)), ("exact baseline validation command", re.compile(r"(?:command\s*:|pytest|python\s+-m)", re.IGNORECASE)), ("exact baseline result", re.compile(r"(?:result\s*:|passed|failed)", re.IGNORECASE)), ("baseline dirty-after status", re.compile(r"dirty\s+after\s*:?\s*\w+", re.IGNORECASE)), ) _INTEGRATION_CLAIM_RE = re.compile( r"(?:master\s+(?:was\s+)?(?:merged|rebased|integrated)|" r"merged?\s+master\s+into|master[- ]integration|rebased\s+onto\s+master)", re.IGNORECASE, ) _INTEGRATION_EVIDENCE_RE = re.compile( r"(?:git\s+merge(?:\s+--no-commit|\s+--no-ff)?|git\s+rebase|git\s+merge-tree)", re.IGNORECASE, ) _CLEANUP_CLAIM_RE = re.compile( r"worktrees?\s+(?:were\s+)?(?:removed|cleaned|deleted)|" r"cleanup\s*:\s*(?!none)\S", re.IGNORECASE, ) _CLEANUP_EVIDENCE_RE = re.compile(r"git\s+worktree\s+list", re.IGNORECASE) def assess_proof_backed_handoff_report(report_text: str) -> dict[str, Any]: """Fail closed on proof-sensitive claims that lack explicit evidence (#395).""" text = report_text or "" reasons: list[str] = [] if _INVENTORY_CLAIM_RE.search(text): if _PAGE_SIZE_ASSUMPTION_RE.search(text): reasons.append( "inventory completeness claimed from a page size assumption; " "explicit pagination metadata (has_more=false / is_final_page=true / " "inventory_complete=true / total count) is required" ) elif not _PAGINATION_METADATA_RE.search(text): reasons.append( "inventory completeness claimed without explicit pagination " "metadata proof (has_more=false, is_final_page=true, " "inventory_complete=true, or total count)" ) for match in _SKIPPED_PR_RE.finditer(text): pr_number = match.group(1) window = text[match.start():match.start() + 400] if not _SKIP_EVIDENCE_RE.search(window): reasons.append( f"skipped PR #{pr_number} claim has no explicit command/tool " "proof or structured mergeability/blocker evidence" ) if _BASELINE_CLAIM_RE.search(text): missing = [ name for name, pattern in _BASELINE_REQUIRED if not pattern.search(text) ] if missing: reasons.append( "baseline validation claim missing required proof fields: " + ", ".join(missing) ) if _INTEGRATION_CLAIM_RE.search(text) and not _INTEGRATION_EVIDENCE_RE.search(text): reasons.append( "master-integration claim lacks the exact merge/rebase/simulation " "command and result" ) if _CLEANUP_CLAIM_RE.search(text) and not _CLEANUP_EVIDENCE_RE.search(text): reasons.append( "cleanup claim lacks final `git worktree list` (or equivalent) proof " "that session-owned worktrees were removed" ) return { "proven": not reasons, "block": bool(reasons), "reasons": reasons, "provenance_classes": PROOF_PROVENANCE_CLASSES, }