fix(review): cross-PR decision-lock isolation and recovery diagnosis (Closes #693)

Prevent foreign open-PR terminals on the durable review-decision lock from
blocking fresh formal reviews. Scope correction authorization to the named
prior review's PR/head, add read-only diagnosis with exact next_action and
durable handoff payloads, require thread-visible correction audits, and
cover the PR #688#692 recovery sequence in regression tests.
This commit is contained in:
2026-07-13 02:29:46 -04:00
parent 237656702f
commit 1844e29880
8 changed files with 1352 additions and 75 deletions
+24 -6
View File
@@ -2540,15 +2540,18 @@ class TestSubmitPrReview(unittest.TestCase):
lock = _load_review_decision_lock() or {}
lock["live_mutations"] = [{"pr_number": 8, "action": "approve", "review_id": 42, "review_state": "approve"}]
_save_review_decision_lock(lock)
r = gitea_authorize_review_correction(
prior_review_id=42,
prior_review_state="approve",
reason="typo",
operator_authorized=True,
)
with patch("mcp_server.api_request", return_value={"id": 9001}):
r = gitea_authorize_review_correction(
prior_review_id=42,
prior_review_state="approve",
reason="typo",
operator_authorized=True,
target_pr_number=8,
)
self.assertTrue(r["authorized"])
lock = _load_review_decision_lock()
self.assertTrue(lock["correction_authorized"])
self.assertEqual(lock["correction_pr_number"], 8)
def test_authorize_review_correction_mismatch(self):
from mcp_server import _load_review_decision_lock, _save_review_decision_lock
@@ -2562,6 +2565,7 @@ class TestSubmitPrReview(unittest.TestCase):
prior_review_state="approve",
reason="typo",
operator_authorized=True,
target_pr_number=8,
)
self.assertFalse(r["authorized"])
self.assertTrue(any("prior review ID" in x for x in r["reasons"]))
@@ -2572,10 +2576,22 @@ class TestSubmitPrReview(unittest.TestCase):
prior_review_state="request_changes",
reason="typo",
operator_authorized=True,
target_pr_number=8,
)
self.assertFalse(r["authorized"])
self.assertTrue(any("prior review state" in x for x in r["reasons"]))
# Cross-PR unlock refused (#693)
r = gitea_authorize_review_correction(
prior_review_id=42,
prior_review_state="approve",
reason="unlock other pr",
operator_authorized=True,
target_pr_number=692,
)
self.assertFalse(r["authorized"])
self.assertTrue(any("different PR" in x for x in r["reasons"]))
def test_authorize_review_correction_requires_operator_auth(self):
from mcp_server import _load_review_decision_lock, _save_review_decision_lock
lock = _load_review_decision_lock() or {}
@@ -2588,6 +2604,7 @@ class TestSubmitPrReview(unittest.TestCase):
prior_review_state="approve",
reason="typo",
operator_authorized=False,
target_pr_number=8,
)
self.assertFalse(r["authorized"])
self.assertTrue(any("operator authorization" in x for x in r["reasons"]))
@@ -2645,6 +2662,7 @@ class TestSubmitPrReview(unittest.TestCase):
prior_review_state="approve",
reason="operator approved correcting mistaken approve",
operator_authorized=True,
target_pr_number=8,
)
_mark_request_changes_ready(remote="prgs")
second = gitea_submit_pr_review(