Repository navigation
perf(pr-pipeline): wait for the rate-limit reset in ci-status instead of failing - #9430
Conversation
… of failing ci-status failed closed whenever a GitHub API read hit the repository GITHUB_TOKEN rate limit and asked for a re-run that landed in the same empty window. The aggregate-results composite needed 399 to 523 s waits against a 60 s ceiling in the 05:26Z and 09:24Z runs. - Set RATE_LIMIT_WAIT_SECONDS: 600 on the job and pass it to the check-contract and aggregate-results composites, whose gh-api.sh already waits for the reset. - Add a first step that writes gh_read, the same wait for the inline steps: on a rate limit it reads the reset from GET /rate_limit, waits until five seconds past it (60 s for a secondary limit) and reads again, under a job-wide ceiling; past it the read fails closed naming the reset. Every fail-closed read in the six hold and review steps goes through it. - Raise timeout-minutes from 9 to 20 to hold one reset wait. - Test the helper in scripts/ci-gh-read.test.sh and the recover, past the ceiling and non-rate-limit cases in ci-hold-human-gated.test.sh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of the first commit found two gaps and a fail-open: - gh_read's job-wide budget did not include the composites' waits, and core and graphql reset on separate windows, so two reset waits plus the other waits could pass the 20-minute timeout. gh_read now waits only until a deadline RATE_LIMIT_WAIT_SECONDS after the job starts, which check-contract's wait also spends; the timeout is 25 minutes for that window, aggregate-results' own and five minutes of other waits. - A block past the deadline was stored for every resource, so a graphql block stopped later core reads. Blocks are now kept per resource. - The cost-hold step reads plain gh api again: its failure keeps the hold, and a wait there would remove the label on reads made before a newer hold landed. - gh_read waits once per call, like the composites' gh-api.sh, and reads again after one second when the window has already reset. - pr-feedback-dispatch polls an in-progress ci-status for 26 minutes, past its new timeout, so the re-run after a review is not skipped. - A test fails any new plain gh api read in ci-status that is neither a write nor marked gh-read-exempt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
The first live run of this branch hit the GITHUB_TOKEN installation limit: every read failed "API rate limit exceeded for installation" with x-ratelimit-remaining 0 and a reset five minutes out, while GET /rate_limit reported core remaining above 0, so gh_read waited one second and the review-lane step failed closed. gh_read now reads the wait from the x-ratelimit-* and retry-after headers of one `gh api -i` probe to the same resource, the headers the composites' gh-api.sh already uses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The pr-unblock lane stopped on this pull request and needs a person: a conflicted path is a workflow, submodule config or a settings file, which the lane does not resolve.
To resume, deal with the reason above, remove the gh workflow run pr-unblock.yml -R melodic-software/claude-code-plugins -f pr-number=9430 -f activity=resolve-conflicts |
Resolves the ci-status timeout comment against the new lanes-hold step: its eight retried reads go through gh_read, and its retry sleeps raise the other-waits allowance, so timeout-minutes is 28 and pr-feedback-dispatch polls an in-progress ci-status for 29 minutes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
claude-security-review reviewed I found no security issues in the incremental change (
critical-findings: 0 |
|
claude-review reviewed Incremental review of 9a1c034..89f0c70 (ci-status timeout kept at 11 min, I found no correctness bugs in the changed lines:
One advisory finding, anchored inline: the 360 s wait budget is smaller than the 399 to 523 s resets the PR cites as its motivation, so those cases will still fail red rather than wait (see the comment on the env lines). There is no cost or trust-gate hold. The change lowers the composites' rate-limit waits and adds no model call, schedule or runner. The PR has no closing issue, so I checked no acceptance criteria. No plugin manifests changed. |
|
The pr-unblock lane escalated this pull request as |
Takes main's base-config checkout in place of the contents-API reads and their retry loops in the human-gated, hold-lifted, merge-group and broker steps, so gh_read leaves those call sites. It stays on the surviving reads: the PR file list (the broker step's pages read and the review-lane step's fallback), the label, comment and event reads, and the review-lane and lanes-hold read_api helpers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The pr-unblock lane stopped on this pull request and needs a person: a conflicted path is a workflow, submodule config or a settings file, which the lane does not resolve.
To resume, deal with the reason above, remove the gh workflow run pr-unblock.yml -R melodic-software/claude-code-plugins -f pr-number=9430 -f activity=resolve-conflicts |
|
The pr-unblock lane escalated this pull request as |
The owner chose the most time-efficient wait that adds no re-run loop and no timeout raise. ci-status's timeout-minutes, and rerun-ci-status's poll and job timeout, go back to main's values, and check-contract and aggregate-results keep their 60 s rate-limit-wait-seconds default. gh_read still waits for the reset, but only when the wait ends by the job's timeout less a 300 s margin for the setup and the steps after it, counted from the helper step's start (GH_READ_JOB_SECONDS 660, pinned to timeout-minutes by the test). A reset past that fails the read red at once, naming the reset and saying a re-run after it is needed. The next review lane's rerun-ci-status, or a person, re-runs it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No related issue: efficiency register E5 (owner directive 2026-10-23)
Summary
ci-status failed closed as soon as a GitHub API read hit the repository's GITHUB_TOKEN rate limit, then told people to re-run. The re-run landed in the same exhausted window. In the 05:26Z and 09:24Z runs (39905801496, 39931677333, 39931558895) the reset was 399 to 523 s away.
With this change, ci-status's inline reads wait for the reset when it falls inside the job's existing timeout. Otherwise they fail red at once, naming the reset time and saying a re-run after it is needed. The owner's decision (Q10) was the most time-efficient option that adds no spam: no timeout raise, and no new re-run loop.
Fix
gh_read. A new first step writesgh_readto$RUNNER_TEMP, and later steps source it. On a rate limit it waits once and reads again.retry-after.x-ratelimit-*andretry-afterheaders of onegh api -iprobe to the same resource (core, or graphql for a graphql call).retry-afterseconds when that header is present.x-ratelimit-resetwhile remaining is 0.GET /rate_limitdoes not report the installation limit. It read coreremaining > 0while every read failed, and the failing responses' own headers saidremaining=0, reset 15:35:06.GH_READ_JOB_SECONDS: 660minusGH_READ_MARGIN_SECONDS: 300, so 360 s. The margin covers aggregate-results' 202 s of waits (60 s rate limit, 45 s own-gate, 7 s status writes, 90 s rerun wait) plus retry sleeps.::error::, which turns the check red, never neutral. The error names the reset and says a re-run after it is needed. Later reads of that resource before the reset fail without a call. Any other error returns at once, so each step's existing retries and fail-closed messages are unchanged.rate-limit-wait-secondsmatches main; this PR does not change it.rerun-ci-status, or the rate-limit wait from E10 in perf(pr-pipeline): re-run ci-status once per head after the review lanes finish #9429, picks the PR up after the reset.Which reads use it. The API reads that remain after #9433:
read_apihelpers in the review-lane and lanes-hold stepsTwo reads keep plain
gh api. The cost-hold step keeps it because a wait there would act on reads taken before a newer hold. The best-effort hold-reason read keeps it too. Both are markedgh-read-exempt, and a test fails on any new unmarked read.What does not change. ci-status keeps its
timeout-minutes: 11. The composites keep their 60 srate-limit-wait-secondsdefault.rerun-ci-statusand the pr-pipeline README are unchanged from main.Verification
scripts/ci-gh-read.test.sh(new, 33 checks).timeout-minutesin seconds, and the margin leaves room for the steps after a wait.rate-limit-wait-secondsoverride.retry-after, a secondary limit, and a cleared limit.gh apiread is a write or marked exempt.scripts/ci-hold-human-gated.test.sh, end to end.2026-10-24T00:50:00Z.scripts/ci-*.test.shpasses, as doactionlint,shellcheck,shfmt, andcheck-affected.sh --testson the merged head.Related
gh_readfollows:melodic-software/ci-workflows.github/actions/pr-require-checks/gh-api.shat v0.58.0.🤖 Generated with Claude Code