fix(review): read the AI-USAGE opt-in at render time, not at review start

The previous two commits put the label re-read in the webhook, at review
start. That is too early to help: the review claims on the AI-REVIEW event
and the re-read runs milliseconds later, while the reviewer's second click
(AI-USAGE) is still a second or two away. It would have kept 404ing quietly
if the path fix hadn't landed, and even fixed it caught nothing.

Move the check to where the decision is actually used — just before the
usage block is rendered, after the model has run. That is a minute or more
after the trigger, by which time the label is there. Attribution is computed
in the same branch, so a late opt-in still gets its per-comment token lines.

`pr_has_label` goes through the existing gitea_get helper, which owns the
/api/v1 prefix, so the path can't drift again. Any failure returns False and
the payload's verdict stands: a review is never lost over a usage section.

Reverts the webhook-side re-read from 4ef62f2 and aedea97.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B11e8TZZxJyzHW7jj7KWUN
This commit is contained in:
Marcos
2026-08-20 23:35:04 +00:00
parent aedea973ab
commit c58c00181e
4 changed files with 72 additions and 100 deletions
+29
View File
@@ -616,6 +616,35 @@ def test_reference_non_url_renders_as_plain_text():
assert "](CVE-" not in body
def test_pr_has_label_reads_the_live_labels(monkeypatch):
# The AI-USAGE opt-in is read at render time, not from the trigger
# payload: labelling AI-REVIEW then AI-USAGE is two events, the review
# claims on the first, and the second is dropped by the in-flight dedupe.
seen = {}
def _get(api, repo, path, token, accept="application/json"):
seen["path"] = path
return 200, b'[{"name": "AI-REVIEW"}, {"name": "AI-USAGE"}]'
monkeypatch.setattr(ai_review, "gitea_get", _get)
assert ai_review.pr_has_label("http://api", "o/r", "9", "t", "AI-USAGE") is True
assert seen["path"] == "issues/9/labels"
assert ai_review.pr_has_label("http://api", "o/r", "9", "t", "NOPE") is False
def test_pr_has_label_survives_a_broken_api(monkeypatch):
def _boom(*a, **k):
raise RuntimeError("gitea down")
monkeypatch.setattr(ai_review, "gitea_get", _boom)
assert ai_review.pr_has_label("http://api", "o/r", "9", "t", "AI-USAGE") is False
monkeypatch.setattr(ai_review, "gitea_get", lambda *a, **k: (404, b"nope"))
assert ai_review.pr_has_label("http://api", "o/r", "9", "t", "AI-USAGE") is False
monkeypatch.setattr(ai_review, "gitea_get", lambda *a, **k: (200, b'{"not": "a list"}'))
assert ai_review.pr_has_label("http://api", "o/r", "9", "t", "AI-USAGE") is False
def test_int_env_falls_back_on_garbage(monkeypatch, capsys):
monkeypatch.setenv("PRAGENT_DIFF_CONTEXT", "two")
assert ai_review._int_env("PRAGENT_DIFF_CONTEXT", 1) == 1