diff --git a/scripts/reviewer_bot_core/reviewer_response_policy.py b/scripts/reviewer_bot_core/reviewer_response_policy.py index a9f68eddd..3e843756b 100644 --- a/scripts/reviewer_bot_core/reviewer_response_policy.py +++ b/scripts/reviewer_bot_core/reviewer_response_policy.py @@ -742,6 +742,9 @@ def derive_reviewer_response_state( reason="pull_request_head_unavailable", scope_fields={"current_scope_key": None, "current_scope_basis": None}, ) + # Plain PR issue/review comments are diagnostic-only in v65. Explicit + # command handoff is represented separately by current_cycle_reviewer_handoff. + reviewer_comment = None reviewer_handoff = _current_cycle_reviewer_handoff_record( review_data, @@ -824,7 +827,7 @@ def derive_reviewer_response_state( if reviewer_handoff is not None and latest_reviewer_response is reviewer_handoff: return _decorate_response( state="awaiting_contributor_response", - reason="accepted_same_scope_reviewer_activity", + reason="reviewer_feedback_handoff", scope_fields=_current_scope_fields(review_data, current_reviewer, current_head, contributor_handoff), anchor_timestamp=reviewer_handoff.get("timestamp"), current_head_sha=current_head, @@ -860,7 +863,7 @@ def derive_reviewer_response_state( response_anchor = reviewer_comment if isinstance(reviewer_comment, dict) else reviewer_handoff return _decorate_response( state="awaiting_contributor_response", - reason="accepted_same_scope_reviewer_activity", + reason="reviewer_feedback_handoff", scope_fields=_current_scope_fields(review_data, current_reviewer, current_head, contributor_handoff), anchor_timestamp=response_anchor.get("timestamp") if isinstance(response_anchor.get("timestamp"), str) else None, current_head_sha=current_head, @@ -989,6 +992,10 @@ def compute_reviewer_response_state( stored_reviewer_review = reviewer_review contributor_comment = review_data.get("contributor_comment", {}).get("accepted") had_reviewer_review = isinstance(reviewer_review, dict) + if is_pr: + # Plain PR issue/review comments are diagnostic-only in v65. Explicit + # command handoff is represented separately by current_cycle_reviewer_handoff. + reviewer_comment = None if not is_pr: return derive_reviewer_response_state( diff --git a/scripts/reviewer_bot_lib/issue314_state_health.py b/scripts/reviewer_bot_lib/issue314_state_health.py index e0c4c2d41..6ceb704d8 100644 --- a/scripts/reviewer_bot_lib/issue314_state_health.py +++ b/scripts/reviewer_bot_lib/issue314_state_health.py @@ -486,10 +486,17 @@ def _row_from_input(input: Issue314StateHealthClassificationInput, row: dict[str reason = "row_can_still_trigger_reviewer_reminder" blockers.append(reason) elif has_drift and issue_number == 264: - health = "operator_action_required" - repair = "not_attempted" - status_risk = "operator_visible_stale" - reason = "pr264_status_label_repair_deferred_to_issue_scoped_live_repair" + if projection.response_state != "reviewer_reassignment_needed": + health = "blocked" + repair = "blocked" + status_risk = "blocked_unknown" + reason = "pr264_projection_handoff_response_state_mismatch" + blockers.append(reason) + else: + health = "operator_action_required" + repair = "not_attempted" + status_risk = "operator_visible_stale" + reason = "pr264_status_label_repair_deferred_to_issue_scoped_live_repair" elif has_drift: health = "repairable" repair = "not_attempted" diff --git a/scripts/reviewer_bot_lib/reminder_comments.py b/scripts/reviewer_bot_lib/reminder_comments.py index a90e4373e..ef5c2baa9 100644 --- a/scripts/reviewer_bot_lib/reminder_comments.py +++ b/scripts/reviewer_bot_lib/reminder_comments.py @@ -77,7 +77,11 @@ def _matched_shape(first_line: str, body: str) -> str | None: if first_line.startswith(f"