"""Early duplicate-work detection for author work-issue sessions (#400).""" from __future__ import annotations from typing import Any import issue_claim_heartbeat as claim_hb PHASE_LOCK = "lock_issue" PHASE_COMMIT = "commit" PHASE_PUSH = "push" PHASE_CREATE_PR = "create_pr" OUTCOME_DUPLICATE_PR_PREVENTED = "duplicate_pr_prevented" OUTCOME_DUPLICATE_BRANCH_PREVENTED = "duplicate_branch_prevented" OUTCOME_DUPLICATE_COMMIT_PREVENTED = "duplicate_commit_prevented" OUTCOME_DUPLICATE_WORK_NOT_PREVENTED = "duplicate_work_not_prevented" _ACTIVE_CLAIM_STATUSES = frozenset({"active", "awaiting_review"}) def _issue_pattern(issue_number: int) -> str: return f"issue-{int(issue_number)}" def _linked_open_pr(issue_number: int, open_prs: list[dict]) -> dict | None: return claim_hb._linked_open_pr(issue_number, open_prs) def _matching_branches( issue_number: int, branch_names: list[str], *, locked_branch: str | None = None, ) -> list[str]: pattern = _issue_pattern(issue_number) matches = [ name for name in (branch_names or []) if pattern in (name or "").lower() ] if locked_branch: locked = locked_branch.strip() matches = [name for name in matches if name != locked] return matches def assess_work_issue_duplicate_gate( issue_number: int, *, open_prs: list[dict] | None = None, branch_names: list[str] | None = None, claim_entry: dict | None = None, locked_branch: str | None = None, phase: str = PHASE_LOCK, ) -> dict[str, Any]: """Fail closed when duplicate work is already in flight for an issue.""" reasons: list[str] = [] outcome = OUTCOME_DUPLICATE_WORK_NOT_PREVENTED prs = list(open_prs or []) branches = list(branch_names or []) pattern = _issue_pattern(issue_number) linked = _linked_open_pr(issue_number, prs) if linked: reasons.append( f"open PR #{linked.get('number')} already covers issue " f"#{issue_number} (fail closed)" ) outcome = OUTCOME_DUPLICATE_PR_PREVENTED conflicting_branches = _matching_branches( issue_number, branches, locked_branch=locked_branch ) if conflicting_branches: names = ", ".join(conflicting_branches[:5]) reasons.append( f"remote branch(es) already match issue pattern '{pattern}': " f"{names} (fail closed)" ) if outcome == OUTCOME_DUPLICATE_WORK_NOT_PREVENTED: outcome = OUTCOME_DUPLICATE_BRANCH_PREVENTED entry = claim_entry or {} if entry.get("linked_open_pr") and not linked: reasons.append( f"claim inventory reports open PR #{entry['linked_open_pr']} " f"for issue #{issue_number} (fail closed)" ) outcome = OUTCOME_DUPLICATE_PR_PREVENTED status = (entry.get("status") or "").strip().lower() if status in _ACTIVE_CLAIM_STATUSES and not linked: heartbeat = entry.get("latest_heartbeat") or {} claim_branch = (heartbeat.get("branch") or "").strip() if locked_branch and claim_branch and claim_branch != locked_branch: reasons.append( f"active claim lease on branch '{claim_branch}' blocks " f"work on '{locked_branch}' for issue #{issue_number} " "(fail closed)" ) if outcome == OUTCOME_DUPLICATE_WORK_NOT_PREVENTED: outcome = OUTCOME_DUPLICATE_BRANCH_PREVENTED elif not locked_branch and status == "active": reasons.append( f"issue #{issue_number} has an active claim lease " "(fail closed)" ) if outcome == OUTCOME_DUPLICATE_WORK_NOT_PREVENTED: outcome = OUTCOME_DUPLICATE_BRANCH_PREVENTED if phase in {PHASE_COMMIT, PHASE_PUSH} and reasons: if outcome == OUTCOME_DUPLICATE_PR_PREVENTED: outcome = OUTCOME_DUPLICATE_COMMIT_PREVENTED elif outcome == OUTCOME_DUPLICATE_BRANCH_PREVENTED: outcome = OUTCOME_DUPLICATE_COMMIT_PREVENTED block = bool(reasons) return { "block": block, "performed": not block, "issue_number": issue_number, "phase": phase, "outcome": outcome, "linked_open_pr": linked.get("number") if linked else entry.get("linked_open_pr"), "conflicting_branches": conflicting_branches, "claim_status": status or None, "reasons": reasons, "safe_next_action": ( "stop before mutating; preserve local work and produce a " "reconciliation handoff if a concurrent PR appeared after push" if block and phase == PHASE_CREATE_PR else "stop before mutating; do not commit or push duplicate work" if block else "proceed" ), } def assess_work_issue_duplicate_report(report_text: str) -> dict[str, Any]: """Require explicit duplicate-work outcome wording in work-issue reports.""" text = (report_text or "").lower() markers = { OUTCOME_DUPLICATE_PR_PREVENTED: ( "duplicate pr prevented", "duplicate_pr_prevented", ), OUTCOME_DUPLICATE_BRANCH_PREVENTED: ( "duplicate branch prevented", "duplicate_branch_prevented", ), OUTCOME_DUPLICATE_COMMIT_PREVENTED: ( "duplicate commit prevented", "duplicate_commit_prevented", ), OUTCOME_DUPLICATE_WORK_NOT_PREVENTED: ( "duplicate work not prevented", "duplicate_work_not_prevented", "no duplicate work", ), } matched = [ key for key, phrases in markers.items() if any(phrase in text for phrase in phrases) ] if len(matched) != 1: return { "complete": False, "downgraded": True, "reasons": [ "work-issue report must state exactly one duplicate-work " "outcome (duplicate PR/branch/commit prevented, or " "duplicate work not prevented)" ], } return { "complete": True, "downgraded": False, "outcome": matched[0], "reasons": [], }