Skip to content

Commit bd49c6f

Browse files
authored
test: expose pr264 projection evidence (#573)
1 parent 0926d73 commit bd49c6f

2 files changed

Lines changed: 197 additions & 0 deletions

File tree

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
from __future__ import annotations
2+
3+
from copy import deepcopy
4+
5+
import pytest
6+
7+
from scripts.reviewer_bot_lib import maintenance_schedule, repair_records, reviews
8+
from scripts.reviewer_bot_lib import overdue as overdue_lib
9+
from tests.fixtures.fake_runtime import FakeReviewerBotRuntime
10+
from tests.fixtures.reviewer_bot import (
11+
make_state,
12+
make_tracked_review_state,
13+
pull_request_payload,
14+
review_payload,
15+
)
16+
from tests.fixtures.reviewer_bot_builders import accept_reviewer_review
17+
from tests.fixtures.reviewer_bot_fakes import RouteGitHubApi
18+
19+
pytestmark = pytest.mark.integration
20+
21+
22+
def test_scheduled_pr264_legacy_duplicate_no_ping_path_preserves_state(monkeypatch):
23+
state = make_state()
24+
review = make_tracked_review_state(
25+
state,
26+
264,
27+
reviewer="iglesias",
28+
assigned_at="2026-02-10T17:20:07Z",
29+
active_cycle_started_at="2026-02-10T17:20:07Z",
30+
)
31+
review["active_head_sha"] = "head-live"
32+
accept_reviewer_review(
33+
review,
34+
semantic_key="pull_request_review:77",
35+
timestamp="2026-03-18T01:09:05Z",
36+
actor="iglesias",
37+
reviewed_head_sha="head-old",
38+
)
39+
sidecars = review.setdefault("sidecars", {})
40+
sidecars["reminder_delivery_receipts"] = {
41+
"legacy:264:9002": {
42+
"issue_number": 264,
43+
"reviewer": "iglesias",
44+
"head_sha": "head-live",
45+
"cycle_key": "2026-02-10T17:20:07Z",
46+
"scope_key": "reviewer=iglesias|head=head-live|cycle=2026-02-10T17:20:07Z|anchor=2026-02-10T17:20:07Z",
47+
"receipt_kind": "legacy_warning_or_reminder",
48+
"comment_id": 9002,
49+
"comment_created_at": "2026-04-14T00:44:23Z",
50+
"state_save_attempted": False,
51+
"state_save_succeeded": False,
52+
"result": "not_posted_existing_receipt",
53+
}
54+
}
55+
sidecars["deferred_gaps"] = {
56+
"pull_request_review:77": {
57+
"source_event_key": "pull_request_review:77",
58+
"workflow_name": "Reviewer Bot PR Review Submitted Observer",
59+
"failure_kind": "diagnostic_only",
60+
"diagnostic_summary": "retained diagnostic gap",
61+
}
62+
}
63+
sidecars["observer_discovery_watermarks"] = {
64+
"review_submitted": {
65+
"workflow_name": "Reviewer Bot PR Review Submitted Observer",
66+
"last_scan_completed_at": "2026-04-14T01:00:00Z",
67+
"diagnostics_retained": True,
68+
}
69+
}
70+
sidecars["reconciled_source_events"] = {
71+
"issue_comment:210": {
72+
"source_event_key": "issue_comment:210",
73+
"issue_number": 264,
74+
"source_event_action": "created",
75+
"replay_decision": "pass_diagnostic_only",
76+
"mark_reconciled": False,
77+
"clear_gap": False,
78+
"reconciled_at": None,
79+
"diagnostic_reason": "plain_lgtm_comment_is_diagnostic_only",
80+
}
81+
}
82+
repair_records.store_repair_marker(
83+
review,
84+
"status_label_projection",
85+
{
86+
"kind": "projection_failure",
87+
"issue_number": 264,
88+
"repair_action": "repair-review-status-labels",
89+
"target_collection_mode": "issue_scoped",
90+
"status_projection_epoch": "status_projection_v2",
91+
"before_status_labels": ["status: awaiting reviewer response"],
92+
"desired_status_labels": ["status: reviewer reassignment needed"],
93+
"labels_added": ["status: reviewer reassignment needed"],
94+
"labels_removed": ["status: awaiting reviewer response"],
95+
"repaired_at": None,
96+
"result": "blocked",
97+
},
98+
)
99+
repair_records.repair_markers(review)
100+
before_state = deepcopy(state)
101+
102+
comments = [
103+
{
104+
"id": 210,
105+
"user": {"login": "iglesias"},
106+
"created_at": "2026-04-13T23:23:25Z",
107+
"body": "LGTM",
108+
},
109+
{
110+
"id": 9001,
111+
"user": {"login": "github-actions[bot]"},
112+
"created_at": "2026-04-13T00:44:23Z",
113+
"body": "**Review Reminder**\n\ntransition period",
114+
},
115+
{
116+
"id": 9002,
117+
"user": {"login": "github-actions[bot]"},
118+
"created_at": "2026-04-14T00:44:23Z",
119+
"body": "**Review Reminder**\n\ntransition period",
120+
},
121+
]
122+
pr_payload = {
123+
**pull_request_payload(264, head_sha="head-live", author="manhatsu"),
124+
"requested_reviewers": [],
125+
"assignees": [],
126+
"labels": [{"name": "status: awaiting reviewer response"}],
127+
}
128+
routes = (
129+
RouteGitHubApi()
130+
.add_request(
131+
"GET",
132+
"issues/264",
133+
status_code=200,
134+
payload={
135+
"number": 264,
136+
"state": "open",
137+
"pull_request": {},
138+
"labels": [{"name": "status: awaiting reviewer response"}],
139+
},
140+
)
141+
.add_request("GET", "pulls/264", status_code=200, payload=pr_payload)
142+
.add_pull_request_reviews(
143+
264,
144+
[
145+
review_payload(
146+
501,
147+
state="APPROVED",
148+
submitted_at="2026-03-18T12:10:42Z",
149+
commit_id="head-live",
150+
author="plaindocs",
151+
)
152+
],
153+
)
154+
.add_request("GET", "issues/264/comments?per_page=100&page=1", status_code=200, payload=comments)
155+
)
156+
bot = FakeReviewerBotRuntime(monkeypatch)
157+
bot.ACTIVE_LEASE_CONTEXT = object()
158+
bot.github.stub(routes)
159+
bot.github.get_user_permission_status = lambda username, required_permission="push": "granted"
160+
bot.github.post_comment_result = lambda issue_number, body: (_ for _ in ()).throw(
161+
AssertionError("scheduled PR264 no-ping path must not post reviewer-facing comments")
162+
)
163+
monkeypatch.setattr(maintenance_schedule, "sweep_deferred_gaps", lambda bot, current: False)
164+
monkeypatch.setattr(
165+
maintenance_schedule,
166+
"collect_status_projection_repair_items",
167+
lambda bot, current: (_ for _ in ()).throw(AssertionError("scheduled PR264 no-ping path broadened repair collection")),
168+
)
169+
monkeypatch.setattr(
170+
reviews,
171+
"list_open_items_with_status_labels",
172+
lambda bot: (_ for _ in ()).throw(AssertionError("scheduled PR264 no-ping path reached broad status-label collection")),
173+
)
174+
reminder_decisions = []
175+
original_decide = overdue_lib.decide_overdue_reminder
176+
177+
def record_reminder_decision(*args, **kwargs):
178+
decision = original_decide(*args, **kwargs)
179+
reminder_decisions.append(decision)
180+
return decision
181+
182+
monkeypatch.setattr(overdue_lib, "decide_overdue_reminder", record_reminder_decision)
183+
184+
result = maintenance_schedule.handle_scheduled_check_result(bot, state)
185+
186+
assert result.state_changed is False
187+
assert result.touched_items == []
188+
assert result.closed_cleanup_removed_items == ()
189+
assert state == before_state
190+
assert reminder_decisions
191+
assert reminder_decisions[-1].action == "none"
192+
assert reminder_decisions[-1].reason == "legacy_duplicate_reminders_exhausted"
193+
assert all(call.method == "GET" for call in routes.request_calls)
194+
assert not any("labels" in call.endpoint for call in routes.request_calls)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Packet verification owner for review-state-machine guardrails."""
2+
3+
from tests.unit.reviewer_bot.test_review_state_equivalence import * # noqa: F401,F403

0 commit comments

Comments
 (0)