Skip to content

Commit 8c89b4c

Browse files
authored
Merge pull request #184 from netresearch/fix/copilot-quota-messaging
fix(pr-status): say the Copilot quota wall once, clearly, without retries
2 parents 2cacb2b + 9beff54 commit 8c89b4c

2 files changed

Lines changed: 50 additions & 3 deletions

File tree

skills/git-workflow/scripts/pr-status.sh

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
# base head headOid
3939
# checks checks_settled threads unresolved_threads
4040
# reviewDecision reviews_on_head has_review_on_head
41-
# has_copilot_review_on_head copilot_review_errored copilot_error_count
41+
# has_copilot_review_on_head copilot_review_errored copilot_error_count copilot_quota_hit
4242
# requested_reviewers
4343
# merge_methods auto_merge_allowed queue_active queue_entry
4444
# rulesets rules_fetched required_contexts undispatched unsigned
@@ -308,6 +308,10 @@ evaluate() {
308308
# $copilot_errored for why the check-run is not consulted.
309309
copilot_review_errored: $copilot_review_errored,
310310
copilot_error_count: ($copilot_errored|length),
311+
# True when an errored Copilot review body names the quota limit.
312+
# Quota is MONTHLY: once this is true, no re-request on any PR will
313+
# succeed until the monthly reset — distinct from a transient outage.
314+
copilot_quota_hit: (([$copilot_errored[] | select((.body // "") | test("quota"; "i"))] | length) > 0),
311315
author: $author,
312316
requested_reviewers: [$p.reviewRequests.nodes[]?.requestedReviewer|(.login // .slug)],
313317
unresolved_threads: ($unresolved|length),
@@ -422,7 +426,20 @@ evaluate() {
422426
elif ($needs_copilot and $s.copilot_review_errored
423427
and ($s.has_copilot_review_on_head | not)
424428
and (($s.requested_reviewers|map(test("copilot";"i"))|any) | not)) then
425-
(if $copilot_exhausted then
429+
(if $s.copilot_quota_hit then
430+
# Quota, not outage: the error body names the quota limit. Said
431+
# once, with the fact that makes retrying pointless — the quota
432+
# is monthly and will NOT recover this month, on this or any
433+
# other PR. No cmd on purpose: there is nothing to run.
434+
{action:"request-review",
435+
why:($unreviewed
436+
+ "Copilot is OUT OF REVIEW QUOTA — the error body says the requesting"
437+
+ " user reached the quota limit. The quota is MONTHLY: it will not"
438+
+ " recover this month, on this or any other PR, and re-requesting"
439+
+ " cannot change that. Review the diff yourself, note in the PR that"
440+
+ " the bot review was unavailable, and decide on that. Treat this"
441+
+ " notice as covering every PR until the monthly reset\($stale_approval)")}
442+
elif $copilot_exhausted then
426443
{action:"request-review",
427444
why:($unreviewed
428445
+ "Copilot failed \($s.copilot_error_count)x on \($s.headOid[0:8]), so the COMMENTED rows"
@@ -631,7 +648,13 @@ while :; do
631648
# re-arm of --watch returns instantly with the same line. Saying so is
632649
# what stops an operator re-arming it three times before switching to
633650
# `gh pr checks --watch`, which watches something that does move.
634-
if [ "$(jq -r '.copilot_error_count // 0' <<<"$s")" -ge 2 ]; then
651+
if [ "$(jq -r '.copilot_quota_hit // false' <<<"$s")" = "true" ]; then
652+
echo "ACTIONABLE: request-review (UNSATISFIABLE — Copilot is OUT OF REVIEW QUOTA" \
653+
"for the month; this will NOT change until the monthly reset, on this or any" \
654+
"other PR. Do not re-arm this watch and do not re-request — review the diff" \
655+
"yourself and decide. To watch something that moves:" \
656+
"gh pr checks $(jq -r '.number' <<<"$s") --repo $(jq -r '.repo' <<<"$s") --watch)"
657+
elif [ "$(jq -r '.copilot_error_count // 0' <<<"$s")" -ge 2 ]; then
635658
echo "ACTIONABLE: request-review (UNSATISFIABLE — the review bot has failed" \
636659
"$(jq -r '.copilot_error_count' <<<"$s")x on this head; re-arming this watch" \
637660
"returns immediately. Review the diff yourself, or watch the checks instead:" \

tests/test_pr_status_errored_review.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,30 @@ case "$(run_flag 'next.cmd')" in
223223
fail=1 ;;
224224
esac
225225

226+
# Quota is not an outage: the error body names the quota limit, the quota is
227+
# monthly, and no re-request on any PR will succeed until the reset. The retry
228+
# command must be withheld even on the FIRST failure, and the advice must say
229+
# the state will not change this month — this is the message an operator sees
230+
# exactly once instead of rediscovering the wall per PR.
231+
echo "case 7c: quota error — no retry cmd even on the FIRST failure, monthly advice"
232+
make_stub "$ERR_QUOTA"
233+
check "copilot_quota_hit" "true" "$(run_flag copilot_quota_hit)"
234+
check "copilot_error_count" "1" "$(run_flag copilot_error_count)"
235+
check "next.action" "request-review" "$(run_next)"
236+
check "next.cmd absent" "null" "$(run_flag 'next.cmd')"
237+
if status | jq -e '.next.why | test("MONTHLY")' >/dev/null; then
238+
echo " ok why states the quota is monthly and will not recover"
239+
else
240+
echo " FAIL why lacks the monthly-quota advice"
241+
fail=1
242+
fi
243+
244+
# The quota detector must be able to stay quiet: a generic outage row must not
245+
# trip it, or every outage would be misreported as a month-long dead end.
246+
echo "case 7d: generic outage only — quota flag stays false"
247+
make_stub "$ERR_GENERIC"
248+
check "copilot_quota_hit" "false" "$(run_flag copilot_quota_hit)"
249+
226250
# Regression for a dead end that shipped once: an earlier version escalated to a
227251
# distinct "review-yourself" action guarded on has_review_on_head. A review by
228252
# the PR author is excluded from that gate by design, and the operator driving

0 commit comments

Comments
 (0)