Skip to content

Stop Requesting Copilot Into a Reached Rate Limit - #2277

Merged
ptr727 merged 8 commits into
developfrom
feature/error-refusal-2261
Oct 2, 2026
Merged

ptr727 merged 8 commits into
developfrom
feature/error-refusal-2261

Conversation

@ptr727

@ptr727 ptr727 commented Oct 2, 2026

Copy link
Copy Markdown
Owner

Summary

The quota-safety half of #2261, per the maintainer's answers recorded on that issue: a generic error round is a possible quota hit after one occurrence, and the tooling never requests into it.

  • Error rounds. "Copilot encountered an error and was unable to review this pull request" is what the weekly rate limit posts. The maintainer pointed out that the real cause shows in the round's details. pr_review.py now finds the reviewer's own failed Actions run on that commit (dynamic/agents/copilot-pull-request-reviewer) and reads its job log. A logged errorType: 'rate_limit' reports as refusal=QUOTA with the reset time the log states. Anything else, an unreadable log included, reports as refusal=ERROR, a possible quota hit.
  • wait stops requesting. No request goes out while the pull request's newest Copilot review is a quota or error refusal, on this head or an earlier one, and wait exits 46. A request already pending is still polled for. Where nothing covers the head, the digest's refusal= field reads that refusal from the earlier head.
  • Defect fixed. wait used to send its auto-request before it consulted the repository-wide quota signal, so an exhausted account still spent a request. It now holds the request back under that signal too.
  • --ignore-quota-signal overrides both stops.

The defined-moments half of #2261 (the ruleset triggers, the local-pass attestation, and the Merge Gate change) follows in a separate pull request, since it rewrites this same wait region.

Verification

  • python3 -m unittest tests.test_pr_review: 507 tests pass. The liveness payload in the stop tests is body-less, as the real Q_LIVE is. Each new behavior was shown to fail with the change reverted or mutated.
  • Live check: run_cause against the real error round on Promote develop to main: Fork Handoff Chains, Qodo Login, JSON Report #2254 returns rate_limit with "reset on October 5, 2026 at 12:00 AM".
  • Two local strict-review passes. Round 1 found 12 findings, including a critical one: the stop was read from the body-less liveness payload, so it never fired. Round 2 found 6. All are fixed except two deliberate declines, the time bound from the parsed reset date and the unchanged # comment at the request site.

Refs #2261

🤖 Generated with Claude Code

ptr727 and others added 3 commits October 1, 2026 19:19
A Copilot round reading only "encountered an error" is what the weekly rate limit posts,
its cause written to the reviewer's own Actions run. pr_review.py now reads that run's job
log: a logged rate limit reports as refusal=QUOTA with the reset time, and anything else as
refusal=ERROR, a possible quota hit.

wait sends no request while the pull request's newest Copilot review is a quota or error
refusal, on this head or an earlier one, and exits 46. It also no longer requests while the
repository-wide quota signal is set, where it used to request first and stop after.
--ignore-quota-signal overrides both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The liveness query carries no review bodies, so the stop never fired there. wait now reads
it from a full read, still polls a request already pending, and the digest reports a quota
or error refusal on an earlier head. Any rate_limit errorType in the log counts, a log that
is not UTF-8 no longer crashes the read, and the 46 lines name the override.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The signal branch skipped the poll even with a request already pending, which also cut the
46 path short. Both quota branches now hold back only the request. The stale-refusal test
reads its own pull request's reviews and expects 46, and the docs are reflowed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings October 2, 2026 02:37
@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Repository: ptr727/ProjectTemplate/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 04cdf07f-a667-4922-a70e-3760c20da309

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.44444% with 4 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (develop@d2529f1). Learn more about missing BASE report.

Files with missing lines Patch % Lines
scripts/pr_review.py 94.44% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             develop    #2277   +/-   ##
==========================================
  Coverage           ?   57.76%           
==========================================
  Files              ?       16           
  Lines              ?     7705           
  Branches           ?        0           
==========================================
  Hits               ?     4451           
  Misses             ?     3254           
  Partials           ?        0           
Flag Coverage Δ
python-3.13 57.76% <94.44%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Three unresolved findings affect pending polling, truncated history handling, and supported GitHub CLI compatibility.

Review effort: Lite
Findings: 2 High severity · 1 Medium severity

Open (3)
What changed in this PR

This PR adds quota-aware Copilot review handling, preventing unsafe re-requests and reporting rate-limit details from failed Actions runs.

Changes:

  • Detects quota and generic error refusals.
  • Suppresses requests while refusals remain active.
  • Adds tests and updates review guidance and generated copies.

Review findings:

  • [P1] Critical, 2 votes: Pending requests can be skipped on current-head refusals.
  • [P1] Critical, 1 vote: Truncated review history can hide refusals and permit unsafe requests.
  • Moderate, 2 votes: --allow-escape-sequences exceeds the supported GitHub CLI floor.
File Description
tests/​test_pr_review.py Tests quota detection, refusal handling, log parsing, and overrides.
scripts/​README.md Documents the new refusal behavior.
scripts/​pr_review.py Implements quota detection and request suppression.
.github/​skills/​pr-review-conduct/​SKILL.md Updates generated GitHub skill guidance.
.claude-plugin/​fleet-skills/​skills/​pr-review-conduct/​SKILL.md Updates generated Claude skill guidance.
.claude-plugin/​fleet-skills/​.source-digests/​pr-review-conduct Refreshes the generated-content digest.
.agents/​skills/​pr-review-conduct/​SKILL.md Updates canonical review guidance.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread scripts/pr_review.py
Comment thread scripts/pr_review.py
Comment thread scripts/pr_review.py Outdated
ptr727 and others added 2 commits October 1, 2026 19:45
The escape-sequence flag arrived in gh 2.97 and the supported floor is 2.47, so a raw read
refused on an unknown flag is retried without it. The pending-poll claim is narrowed to the
earlier-head case the stop covers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings October 2, 2026 02:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Unresolved findings affect refusal precedence, override behavior, pending-request detection, and exit-code documentation.

Review effort: Lite
Findings: None

Resolved since last review (3)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Do not resurrect spent refusals after newer answers

scripts/​pr_review.py:3084

[P1] Do not resurrect a spent refusal after a newer answer. When a newer Copilot comment follows an earlier-head refusal, answered_outside_review(pr) treats that refusal as spent, but this new stopping_refusal(pr) ignores the comment and makes the digest print the old refusal=ERROR/QUOTA block anyway. That misreports an already-answered pull request and conflicts with the existing quota_signal and answered_outside_review semantics. Exclude the stopping refusal when answer is present.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Oct 2, 2026

Copy link
Copy Markdown
Owner Author

Answering the previously missed finding "Do not resurrect spent refusals after newer answers" (scripts/pr_review.py:3084): fixed in 7edefc1. stopping_refusal now returns nothing where answered_outside_review finds a newer Copilot comment, so neither the digest nor wait revives a refusal that comment spent. A test covers it and fails with the check removed.

Copilot AI lite review requested due to automatic review settings October 2, 2026 02:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Address pending-request detection, override handling, repository-wide error signals, and the documented pending-request exception.

Review effort: Lite
Findings: None

Previously missed (1)

In code that hasn't changed since last review

Medium severity Allow override to reevaluate current-head refusals

scripts/​pr_review.py:4105

[P1] Let the override re-evaluate a current-head refusal

Q_LIVE intentionally omits review bodies, so a current-head quota/error refusal makes head_review_done return True. Because this branch skips stopping_refusal when done is true, and the request condition also requires not done, --ignore-quota-signal can neither request nor poll past that refusal, despite the CLI help and docs promising it overrides both stops. Re-read the full review state when the override is set, while preserving the bodyless fast path, so a genuine review remains done but a refusal can be re-requested.

The body-less liveness read counts a head refusal as done, so with --ignore-quota-signal the
full read is consulted and the round baseline moves past that refusal, the same way
--min-rounds holds out for a new round.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Oct 2, 2026

Copy link
Copy Markdown
Owner Author

Answering the previously missed finding "Allow override to reevaluate current-head refusals" (scripts/pr_review.py:4105): fixed in 3bc4a84. With --ignore-quota-signal, a head the body-less liveness read reports as done gets a full read, and where its only round is a refusal, the round baseline moves past that refusal the way --min-rounds does. A request then goes out, and the wait holds for a genuinely new round. A test covers it and fails with the re-read removed.

Copilot AI lite review requested due to automatic review settings October 2, 2026 02:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Three unresolved moderate findings remain in scripts/pr_review.py.

Review effort: Lite
Findings: None

…sal-2261

# Conflicts:
#	.claude-plugin/fleet-skills/.source-digests/pr-review-conduct
#	tests/test_pr_review.py
Copilot AI lite review requested due to automatic review settings October 2, 2026 03:46
@ptr727
ptr727 merged commit 5a814c1 into develop Oct 2, 2026
8 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved refusal-precedence and override-verdict issues in scripts/pr_review.py block safe approval.

Review effort: Lite
Findings: 1 High severity

Open (1)

Comment thread scripts/pr_review.py
ptr727 added a commit that referenced this pull request Oct 2, 2026
…ted Local Pass (#2278)

## Summary

This is the defined-moments half of #2261, per the maintainer's answers
recorded on that issue. A Copilot round is requested when a pull request
opens and on the head of a pull request into the default branch, a
promotion among them, rather than on every push. On a pull request into
any other branch, a fix push after the first round is covered by the
recorded local strict-review pass the push already owes. The PR
publishes that pass so the review gate can read it.

- **Ruleset.** `repo-config/develop.json` and `main.json` set
`review_on_push` and `review_draft_pull_requests` to false and keep
review on open. Applying the change to live repositories is a separate
config run, which needs its own go-ahead. Narrowing the account-level
setting is a UI step for the maintainer.
- **`pr_review.py attest`.** It publishes the local pass as a comment
carrying `<!-- fleet-local-review: head=<sha> findings=<n> -->`, after
confirming four things:
  - the checkout is at the pushed head
  - the checkout holds no other change
  - its merge base is the pull request's own
  - `local_review.py check` passes against the base

The comment carries the findings count the pass recorded. Per the
maintainer's answer, the count is shown and not gated, since local
findings are advisory. `local_review.py status` now reports the
per-reviewer `findings` map that this reads.
- **`status`.** An attested head on a pull request into a non-default
branch, after Copilot's first round, reads as `review_on_head=local` and
`coverage=local`. That holds only for an owner, member, or collaborator
comment whose marker stands as a line of its own outside a fence, and
only where the whole review history is in view and no round on record
states or appears to state partial coverage.
- **`wait`.** On such a head `wait` requests nothing. An attested head
ends as covered, and one with no attestation exits `49`
(`AWAITING_LOCAL_PASS`). `--request` asks for a round anyway. A
promotion, a first round, a partial on record, and a history past the
window are all requested as before.
- **A post-merge finding on #2277, fixed here.** A newer quota or error
refusal now outranks older genuine coverage of the same head, in the
digest's `refusal=` field and in `wait`'s verdict, since it is the
newest word on the pull request.
- **CodeRabbit.** A drive prompts it at most once per pull request, on
the head it judges final, and never after a rate-limit notice.
- **Docs.** The rule is stated in `GOVERNANCE.md` "PR Review Etiquette",
`pr-review-conduct` (loop step 3, step 8, Merge Gate item 2, and the
reviewer bullets), the Copilot runbook, `scripts/README.md`,
`repo-config/README.md`, `docs/pr-reviewer-reference.md`, and the
one-liners in `README.md`, `RESYNC.md`, and `AUDIT.md`.

## Verification

- `tests.test_pr_review` and `tests.test_local_review` pass (658 tests).
Each new behavior was shown to fail with it reverted or mutated,
including the stale-refusal, partial, old-answer, and marker-shape
cases.
- A live GraphQL read confirmed that `baseRepository.defaultBranchRef`
and `IssueComment.authorAssociation` exist.
- Two local strict-review passes ran. Round 1 raised 16 findings: 15 are
fixed, and #5 went to the maintainer, who chose to show the count
without gating on it. Round 2 raised 3 low findings, all fixed.

Closes #2261

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
ptr727 added a commit that referenced this pull request Oct 2, 2026
…eview (#2284)

## Summary

Promotes develop to main with the pull requests below. Each was already
reviewed and merged into develop.

- [#2271](#2271): Correct
the false no-vocabulary claims about environment secrets.
- [#2276](#2276): A full
Copilot file table on an earlier round carries forward to a later head
when the pull request changes the same set of files at both commits, the
same bound a coverage statement uses.
- [#2275](#2275):
`install-tools.sh` no longer exits 1 silently when the tools named leave
out the last managed tool, and its report notes show a home path as `~`.
- [#2277](#2277): A
Copilot round that says only "encountered an error" is read as a
possible quota hit. `pr_review.py` reads the reviewer's own Actions run
log, which states the rate limit and the time it resets, and `wait` no
longer requests a review into either case.
- [#2278](#2278): A
Copilot round is requested when a pull request opens and on the head of
a pull request into the default branch, rather than on every push.
Covering a fix push into develop:
- A recorded local strict-review pass covers the push, published with
`pr_review.py attest` and read by `status` as `review_on_head=local`.
- The Copilot rule in `repo-config/develop.json` and `main.json` now
reviews on open only, not on push or for drafts.

Applying that ruleset change to the live fleet repositories is a
separate config run after this merges, and it needs the maintainer's
go-ahead. Until it runs, GitHub still reviews every push, including
pushes to this pull request.

Closes #2256
Closes #2260
Closes #2261
Closes #2268
Closes #2272

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants