Skip to content

Commit 3a53e59

Browse files
committed
refactor(reviewer-bot): localize workflow and review support seams
Move payload, read, bookkeeping, and live-review helpers to explicit owners so routine reviewer-bot changes stay local and the proof matches runtime truth. This also narrows schedule and sweeper hotspots around pass- and surface-level seams without widening runtime contracts.
1 parent 9ddc917 commit 3a53e59

38 files changed

+1721
-771
lines changed

scripts/reviewer_bot_core/approval_policy.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
from __future__ import annotations
1818

19+
from scripts.reviewer_bot_lib import review_read_support
20+
1921

2022
def compute_pr_approval_state_result(
2123
bot,
@@ -26,7 +28,6 @@ def compute_pr_approval_state_result(
2628
reviews: list[dict] | None = None,
2729
) -> dict[str, object]:
2830
from scripts.reviewer_bot_core import review_state_machine
29-
from scripts.reviewer_bot_lib import reviews as legacy_reviews
3031
from scripts.reviewer_bot_lib.reviews_projection import (
3132
collect_permission_statuses,
3233
compute_pr_approval_state_from_reviews,
@@ -36,23 +37,23 @@ def compute_pr_approval_state_result(
3637

3738
boundary = review_state_machine.get_current_cycle_boundary(bot, review_data)
3839
if boundary is None:
39-
return legacy_reviews._projection_failure("pull_request_unavailable")
40-
pull_request_result = legacy_reviews._pull_request_read_result(bot, issue_number, pull_request)
40+
return review_read_support._projection_failure("pull_request_unavailable")
41+
pull_request_result = review_read_support._pull_request_read_result(bot, issue_number, pull_request)
4142
if not pull_request_result.get("ok"):
4243
return pull_request_result
4344
pull_request = pull_request_result["pull_request"]
4445
head = pull_request.get("head")
4546
current_head = head.get("sha") if isinstance(head, dict) else None
4647
if not isinstance(current_head, str) or not current_head.strip():
47-
return legacy_reviews._projection_failure("pull_request_head_unavailable", "invalid_payload")
48-
reviews_result = legacy_reviews.get_pull_request_reviews_result(bot, issue_number, reviews)
48+
return review_read_support._projection_failure("pull_request_head_unavailable", "invalid_payload")
49+
reviews_result = review_read_support.get_pull_request_reviews_result(bot, issue_number, reviews)
4950
if not reviews_result.get("ok"):
5051
return reviews_result
5152
reviews = reviews_result["reviews"]
5253

5354
normalized_reviews = normalize_reviews_with_parsed_timestamps(
5455
reviews,
55-
parse_timestamp=legacy_reviews.parse_github_timestamp,
56+
parse_timestamp=review_read_support.parse_github_timestamp,
5657
)
5758
survivors = filter_current_head_reviews_for_cycle(
5859
normalized_reviews,
@@ -61,15 +62,15 @@ def compute_pr_approval_state_result(
6162
)
6263
permission_cache = collect_permission_statuses(
6364
survivors,
64-
permission_status=lambda author: legacy_reviews._permission_status(bot, author, "push"),
65+
permission_status=lambda author: review_read_support._permission_status(bot, author, "push"),
6566
)
6667
result = compute_pr_approval_state_from_reviews(
6768
survivors,
6869
current_head=current_head,
6970
permission_statuses=permission_cache,
7071
)
7172
if not result.get("ok"):
72-
return legacy_reviews._projection_failure(str(result.get("reason")))
73+
return review_read_support._projection_failure(str(result.get("reason")))
7374
return result
7475

7576

scripts/reviewer_bot_core/review_state_live_repair.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
from __future__ import annotations
1616

17-
from scripts.reviewer_bot_lib import reviews as legacy_reviews
17+
from scripts.reviewer_bot_lib import review_read_support
1818

1919
from . import review_state_machine, reviewer_review_helpers
2020

@@ -45,7 +45,7 @@ def refresh_reviewer_review_from_live_preferred_review(
4545
actor: str | None = None,
4646
) -> tuple[bool, dict | None]:
4747
if pull_request is None:
48-
pull_request_result = legacy_reviews._pull_request_read_result(bot, issue_number)
48+
pull_request_result = review_read_support._pull_request_read_result(bot, issue_number)
4949
if not pull_request_result.get("ok"):
5050
return False, None
5151
pull_request = pull_request_result["pull_request"]

scripts/reviewer_bot_core/review_state_machine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from datetime import datetime, timezone
1919
from typing import Any
2020

21-
from scripts.reviewer_bot_lib.reviews import parse_github_timestamp
21+
from scripts.reviewer_bot_lib.review_read_support import parse_github_timestamp
2222

2323
from . import state_adapters
2424

scripts/reviewer_bot_core/reviewer_response_policy.py

Lines changed: 134 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616

1717
from datetime import datetime, timezone
1818

19+
from scripts.reviewer_bot_lib import review_read_support
20+
1921
from . import reviewer_review_helpers
2022

23+
_UNSET = object()
24+
2125

2226
def _record_timestamp(record: dict | None, *, parse_timestamp) -> datetime | None:
2327
if not isinstance(record, dict):
@@ -68,31 +72,29 @@ def _contributor_revision_handoff_record(review_data: dict, current_head: str |
6872
return contributor_revision
6973

7074

71-
def compute_reviewer_response_state(
72-
bot,
73-
issue_number: int,
75+
def derive_reviewer_response_state(
7476
review_data: dict,
7577
*,
76-
issue_snapshot: dict | None = None,
77-
pull_request: dict | None = None,
78-
reviews: list[dict] | None = None,
78+
issue_is_pull_request: bool,
79+
current_head: str | None = None,
80+
reviewer_comment: dict | None | object = _UNSET,
81+
reviewer_review: dict | None | object = _UNSET,
82+
contributor_comment: dict | None | object = _UNSET,
83+
had_reviewer_review: bool = False,
84+
approval_result: dict[str, object] | None = None,
7985
) -> dict[str, object]:
80-
from scripts.reviewer_bot_lib import reviews as legacy_reviews
81-
82-
if issue_snapshot is None:
83-
issue_snapshot = bot.github.get_issue_or_pr_snapshot(issue_number)
84-
if not isinstance(issue_snapshot, dict):
85-
return {"state": "projection_failed", "reason": "issue_snapshot_unavailable"}
86-
is_pr = isinstance(issue_snapshot.get("pull_request"), dict)
8786
current_reviewer = review_data.get("current_reviewer")
8887
if not isinstance(current_reviewer, str) or not current_reviewer.strip():
8988
return {"state": "untracked", "reason": "no_current_reviewer"}
9089

91-
reviewer_comment = review_data.get("reviewer_comment", {}).get("accepted")
92-
reviewer_review = review_data.get("reviewer_review", {}).get("accepted")
93-
contributor_comment = review_data.get("contributor_comment", {}).get("accepted")
90+
if reviewer_comment is _UNSET:
91+
reviewer_comment = review_data.get("reviewer_comment", {}).get("accepted")
92+
if reviewer_review is _UNSET:
93+
reviewer_review = review_data.get("reviewer_review", {}).get("accepted")
94+
if contributor_comment is _UNSET:
95+
contributor_comment = review_data.get("contributor_comment", {}).get("accepted")
9496

95-
if not is_pr:
97+
if not issue_is_pull_request:
9698
if not reviewer_comment and not reviewer_review:
9799
return {
98100
"state": "awaiting_reviewer_response",
@@ -107,7 +109,7 @@ def compute_reviewer_response_state(
107109
if reviewer_review_helpers.compare_records(
108110
reviewer_review,
109111
latest_reviewer_response,
110-
parse_timestamp=legacy_reviews.parse_github_timestamp,
112+
parse_timestamp=review_read_support.parse_github_timestamp,
111113
) > 0:
112114
latest_reviewer_response = reviewer_review
113115
completion = review_data.get("current_cycle_completion")
@@ -121,33 +123,11 @@ def compute_reviewer_response_state(
121123
}
122124
return {"state": "done", "reason": None}
123125

124-
pull_request_result = legacy_reviews._pull_request_read_result(bot, issue_number, pull_request)
125-
if not pull_request_result.get("ok"):
126-
return {"state": "projection_failed", "reason": str(pull_request_result.get("reason"))}
127-
pull_request = pull_request_result["pull_request"]
128-
head = pull_request.get("head")
129-
current_head = head.get("sha") if isinstance(head, dict) else None
130126
if not isinstance(current_head, str) or not current_head.strip():
131127
return {"state": "projection_failed", "reason": "pull_request_head_unavailable"}
132128

133129
if not reviewer_comment and not reviewer_review:
134-
reviews_result = legacy_reviews.get_pull_request_reviews_result(bot, issue_number, reviews)
135-
if not reviews_result.get("ok"):
136-
return {"state": "projection_failed", "reason": str(reviews_result.get("reason"))}
137-
reviews = reviews_result["reviews"]
138-
preferred_live_review = reviewer_review_helpers.get_preferred_current_reviewer_review_for_cycle(
139-
bot,
140-
issue_number,
141-
review_data,
142-
pull_request=pull_request,
143-
reviews=reviews,
144-
)
145-
if preferred_live_review is not None:
146-
reviewer_review = reviewer_review_helpers.build_reviewer_review_record_from_live_review(
147-
preferred_live_review,
148-
actor=current_reviewer,
149-
)
150-
else:
130+
if not had_reviewer_review:
151131
return {
152132
"state": "awaiting_reviewer_response",
153133
"reason": "no_reviewer_activity",
@@ -158,37 +138,11 @@ def compute_reviewer_response_state(
158138
"contributor_handoff": None,
159139
}
160140

161-
stored_review_head = reviewer_review.get("reviewed_head_sha") if isinstance(reviewer_review, dict) else None
162-
refresh_live_review = reviews is not None or reviewer_review is None
163-
if not refresh_live_review:
164-
refresh_live_review = not isinstance(stored_review_head, str) or stored_review_head != current_head
165-
166-
preferred_live_review = None
167-
if refresh_live_review:
168-
reviews_result = legacy_reviews.get_pull_request_reviews_result(bot, issue_number, reviews)
169-
if not reviews_result.get("ok"):
170-
return {"state": "projection_failed", "reason": str(reviews_result.get("reason"))}
171-
reviews = reviews_result["reviews"]
172-
preferred_live_review = reviewer_review_helpers.get_preferred_current_reviewer_review_for_cycle(
173-
bot,
174-
issue_number,
175-
review_data,
176-
pull_request=pull_request,
177-
reviews=reviews,
178-
)
179-
if preferred_live_review is not None:
180-
reviewer_review = reviewer_review_helpers.build_reviewer_review_record_from_live_review(
181-
preferred_live_review,
182-
actor=current_reviewer,
183-
)
184-
elif refresh_live_review:
185-
reviewer_review = None
186-
187141
latest_reviewer_response = reviewer_comment
188142
if reviewer_review_helpers.compare_records(
189143
reviewer_review,
190144
latest_reviewer_response,
191-
parse_timestamp=legacy_reviews.parse_github_timestamp,
145+
parse_timestamp=review_read_support.parse_github_timestamp,
192146
) > 0:
193147
latest_reviewer_response = reviewer_review
194148

@@ -201,14 +155,14 @@ def compute_reviewer_response_state(
201155
if reviewer_review_helpers.compare_records(
202156
contributor_revision,
203157
contributor_handoff,
204-
parse_timestamp=legacy_reviews.parse_github_timestamp,
158+
parse_timestamp=review_read_support.parse_github_timestamp,
205159
) > 0:
206160
contributor_handoff = contributor_revision
207161

208162
if _compare_cross_channel_conversation(
209163
contributor_handoff,
210164
latest_reviewer_response,
211-
parse_timestamp=legacy_reviews.parse_github_timestamp,
165+
parse_timestamp=review_read_support.parse_github_timestamp,
212166
) > 0:
213167
reason = "contributor_comment_newer"
214168
if isinstance(contributor_handoff, dict) and str(contributor_handoff.get("semantic_key", "")).startswith(
@@ -239,17 +193,9 @@ def compute_reviewer_response_state(
239193
"contributor_handoff": contributor_handoff,
240194
}
241195

242-
from scripts.reviewer_bot_core import approval_policy
243-
244-
approval_result = approval_policy.compute_pr_approval_state_result(
245-
bot,
246-
issue_number,
247-
review_data,
248-
pull_request=pull_request,
249-
reviews=reviews,
250-
)
251-
if not approval_result.get("ok"):
196+
if not isinstance(approval_result, dict) or not approval_result.get("ok"):
252197
return {"state": "projection_failed", "reason": "live_review_state_unknown"}
198+
253199
completion = approval_result["completion"]
254200
write_approval = approval_result["write_approval"]
255201
if not completion.get("completed"):
@@ -284,3 +230,111 @@ def compute_reviewer_response_state(
284230
"contributor_comment": contributor_comment,
285231
"contributor_handoff": contributor_handoff,
286232
}
233+
234+
235+
def compute_reviewer_response_state(
236+
bot,
237+
issue_number: int,
238+
review_data: dict,
239+
*,
240+
issue_snapshot: dict | None = None,
241+
pull_request: dict | None = None,
242+
reviews: list[dict] | None = None,
243+
) -> dict[str, object]:
244+
if issue_snapshot is None:
245+
issue_snapshot = bot.github.get_issue_or_pr_snapshot(issue_number)
246+
if not isinstance(issue_snapshot, dict):
247+
return {"state": "projection_failed", "reason": "issue_snapshot_unavailable"}
248+
is_pr = isinstance(issue_snapshot.get("pull_request"), dict)
249+
250+
reviewer_comment = review_data.get("reviewer_comment", {}).get("accepted")
251+
reviewer_review = review_data.get("reviewer_review", {}).get("accepted")
252+
contributor_comment = review_data.get("contributor_comment", {}).get("accepted")
253+
had_reviewer_review = isinstance(reviewer_review, dict)
254+
255+
if not is_pr:
256+
return derive_reviewer_response_state(
257+
review_data,
258+
issue_is_pull_request=False,
259+
reviewer_comment=reviewer_comment,
260+
reviewer_review=reviewer_review,
261+
contributor_comment=contributor_comment,
262+
had_reviewer_review=had_reviewer_review,
263+
)
264+
265+
pull_request_result = review_read_support._pull_request_read_result(bot, issue_number, pull_request)
266+
if not pull_request_result.get("ok"):
267+
return {"state": "projection_failed", "reason": str(pull_request_result.get("reason"))}
268+
pull_request = pull_request_result["pull_request"]
269+
head = pull_request.get("head")
270+
current_head = head.get("sha") if isinstance(head, dict) else None
271+
if not isinstance(current_head, str) or not current_head.strip():
272+
return {"state": "projection_failed", "reason": "pull_request_head_unavailable"}
273+
274+
if not reviewer_comment and not reviewer_review:
275+
reviews_result = review_read_support.get_pull_request_reviews_result(bot, issue_number, reviews)
276+
if not reviews_result.get("ok"):
277+
return {"state": "projection_failed", "reason": str(reviews_result.get("reason"))}
278+
reviews = reviews_result["reviews"]
279+
preferred_live_review = reviewer_review_helpers.get_preferred_current_reviewer_review_for_cycle(
280+
bot,
281+
issue_number,
282+
review_data,
283+
pull_request=pull_request,
284+
reviews=reviews,
285+
)
286+
if preferred_live_review is not None:
287+
reviewer_review = reviewer_review_helpers.build_reviewer_review_record_from_live_review(
288+
preferred_live_review,
289+
actor=review_data.get("current_reviewer"),
290+
)
291+
292+
stored_review_head = reviewer_review.get("reviewed_head_sha") if isinstance(reviewer_review, dict) else None
293+
refresh_live_review = reviews is not None or reviewer_review is None
294+
if not refresh_live_review:
295+
refresh_live_review = not isinstance(stored_review_head, str) or stored_review_head != current_head
296+
297+
preferred_live_review = None
298+
if refresh_live_review:
299+
reviews_result = review_read_support.get_pull_request_reviews_result(bot, issue_number, reviews)
300+
if not reviews_result.get("ok"):
301+
return {"state": "projection_failed", "reason": str(reviews_result.get("reason"))}
302+
reviews = reviews_result["reviews"]
303+
preferred_live_review = reviewer_review_helpers.get_preferred_current_reviewer_review_for_cycle(
304+
bot,
305+
issue_number,
306+
review_data,
307+
pull_request=pull_request,
308+
reviews=reviews,
309+
)
310+
if preferred_live_review is not None:
311+
reviewer_review = reviewer_review_helpers.build_reviewer_review_record_from_live_review(
312+
preferred_live_review,
313+
actor=review_data.get("current_reviewer"),
314+
)
315+
elif refresh_live_review:
316+
reviewer_review = None
317+
318+
approval_result = None
319+
reviewed_head_sha = reviewer_review.get("reviewed_head_sha") if isinstance(reviewer_review, dict) else None
320+
if isinstance(reviewed_head_sha, str) and reviewed_head_sha == current_head:
321+
from scripts.reviewer_bot_core import approval_policy
322+
323+
approval_result = approval_policy.compute_pr_approval_state_result(
324+
bot,
325+
issue_number,
326+
review_data,
327+
pull_request=pull_request,
328+
reviews=reviews,
329+
)
330+
331+
return derive_reviewer_response_state(
332+
review_data,
333+
issue_is_pull_request=True,
334+
current_head=current_head,
335+
reviewer_comment=reviewer_comment,
336+
reviewer_review=reviewer_review,
337+
contributor_comment=contributor_comment,
338+
had_reviewer_review=had_reviewer_review,
339+
approval_result=approval_result,
340+
)

0 commit comments

Comments
 (0)