fix(webhook): re-read PR labels at review start so a late AI-USAGE counts
Labelling a PR is two webhook events. AI-REVIEW arrives first, the review claims (repo, index, sha) and starts; the AI-USAGE event that follows a moment later hits the in-flight dedupe and is dropped. `report_usage` was snapshotted from the first payload, which had not seen AI-USAGE yet, so the review posted without its usage block even though the label was on the PR by the time it finished — observed on gitea_admin/pragent#9 (`usage=False` in the pod log, no <details> section in the posted review). Re-read the labels from the API at review start and upgrade the flag. The read is best-effort: any failure logs and returns [], leaving the payload's verdict intact, because a usage section is not worth failing a review over. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B11e8TZZxJyzHW7jj7KWUN
This commit is contained in:
@@ -134,3 +134,43 @@ def test_missing_label_is_ignored(monkeypatch):
|
||||
def test_review_slots_bound_matches_config():
|
||||
assert ws.MAX_CONCURRENT >= 1
|
||||
assert ws._review_slots._value <= ws.MAX_CONCURRENT
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# AI-USAGE opt-in applied after the triggering label event
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_run_review_rereads_labels_for_late_ai_usage(monkeypatch):
|
||||
# Labelling a PR AI-REVIEW then AI-USAGE fires two events; the review
|
||||
# claims on the first, so the second is deduped and the payload snapshot
|
||||
# never sees AI-USAGE. The re-read at review start must recover it.
|
||||
seen = {}
|
||||
monkeypatch.setattr(ws, "_fetch_current_labels",
|
||||
lambda repo, index: [{"name": "AI-REVIEW"}, {"name": "AI-USAGE"}])
|
||||
monkeypatch.setattr(ws, "review_pr", lambda **kw: seen.update(kw) or True)
|
||||
ws._run_review(("o/r", "9", "abc1234"), "t", "b", False, "main")
|
||||
assert seen["report_usage"] is True
|
||||
|
||||
|
||||
def test_run_review_keeps_usage_off_when_label_absent(monkeypatch):
|
||||
seen = {}
|
||||
monkeypatch.setattr(ws, "_fetch_current_labels",
|
||||
lambda repo, index: [{"name": "AI-REVIEW"}])
|
||||
monkeypatch.setattr(ws, "review_pr", lambda **kw: seen.update(kw) or True)
|
||||
ws._run_review(("o/r", "9", "abc1234"), "t", "b", False, "main")
|
||||
assert seen["report_usage"] is False
|
||||
|
||||
|
||||
def test_label_reread_failure_is_not_fatal(monkeypatch):
|
||||
# A dead API must not take the review down with it — the re-read is a
|
||||
# best-effort upgrade of an opt-in flag, nothing more.
|
||||
def _boom(*a, **k):
|
||||
raise OSError("api down")
|
||||
monkeypatch.setattr(ws.urllib.request, "urlopen", _boom)
|
||||
assert ws._fetch_current_labels("o/r", "9") == []
|
||||
|
||||
seen = {}
|
||||
monkeypatch.setattr(ws, "review_pr", lambda **kw: seen.update(kw) or True)
|
||||
ws._run_review(("o/r", "9", "abc1234"), "t", "b", False, "main")
|
||||
assert seen["report_usage"] is False
|
||||
|
||||
Reference in New Issue
Block a user