Repository navigation
perf(ci): cut GITHUB_TOKEN calls in pr-verify and pace timer lanes on burn rate - #11046
Conversation
check-intent spent 472 GITHUB_TOKEN calls over the 2026-10-29 17:58-18:58Z window. The job annotations and post-verify-notes' verdict-or-none counts split them into 20 judgments (334 calls, 16.7 each) and about 24 runs that judged nothing (138 calls, 5.75 each). The skips sat in two clusters, 4-6 and 11-12 calls: the trigger gate's own reads, about 3 or 4, plus the resolver's 2 (no-single-pr, draft, author) or its pinned 8 (already-judged). The resolver only reads and already skips every run the brief names: a red run that only an approval does not lift, a PR whose head moved on, and a head already judged. So it now runs first, the gate runs only when the resolver proceeds, and the agree step only after the gate proceeds. A judged run makes the same reads as before. This keeps one run per head, not one per attempt, rather than skipping red runs, because PR authors and lanes rely on verify-on-red: - pr-verify.yml:3-6 and resolve-pr.mjs:5-9,588 (heldOnly) judge a red run held only by an approval-liftable hold or do-not-merge, so a person approves a judged head. - pr-feedback-dispatch.yml:18-35 turns a FAIL into threads that address-feedback works, or the pr-verify-failed label that ci-status holds. No state is carried. A per-head record in the Actions cache was rejected, because a restore extracts anywhere in the workspace (#9455, pr-require-checks.yml:5210-5213). A lookup-first precheck was rejected too, because it would add reads to all 20 judgments an hour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r-review-main record About 32% of the 2026-10-29 17:58-18:58Z window's GITHUB_TOKEN spend had no per-job api-calls notice. Two of the listed jobs are local and spend the job token without counting it: - intake-triage apply-verdict reads through resolve-config with the job token; that step now records under github-token and the job logs both lanes-app and github-token, as work-unblock's label-unblocked does. - pr-review-main record POSTs one check run per verdict file with no checkout of log-api-budget; it counts its POSTs and ends with the notice in api_budget_emit_calls' shape, pinned against the emitter by a test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A budget trip (the breaker share of the header's limit left) turns the kill switch on and stops every lane. In the 2026-10-29 17:58-18:58Z window the pool reached used=4289 remaining=711 about 4 minutes before reset. The scheduled lanes were still spending at full rate then: reconcile at 68.5 calls per run, pr-unblock-dispatch at 20.6. On a schedule tick, pace.mjs reads the pool once and projects the remaining at the reset from the window's burn rate so far. When that falls under limits.api github-token `pace`, an even-numbered tick writes paced=true. `pace` is a new config value, default 0.2 in rate-limits.json, validated like the breaker and allowed in the schema. The lost-run reconciler and pr-unblock-dispatch skip their work on a paced tick and end green. Odd ticks still run, so a paced lane runs at half its cadence rather than stopping, and the reconciler keeps re-running the runs a trip stops. Any other event, or a failed read, runs as before. The breaker stays the backstop. 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. |
|
claude-review reviewed Review of the pr-verify reorder, the pacer and the api-calls notices. I found one problem, in the pacer's tick selection. Run-number parity does not give half cadence for pr-unblock-dispatch (inline comment on Checked and found fine
I read the diff and the surrounding workflows and ran no tests. The PR's verification claims are the author's and I did not confirm them. Cost: the pacer's one critical-findings: 1 Findings not posted inline (their lines are not in the diff):
The reconciler is schedule-plus-dispatch only, so its parity does alternate. The failure is specific to pr-unblock-dispatch. One fix: derive the tick parity from the clock, e.g. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0adc993318
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
claude-security-review reviewed No security issues found. I read the full diff and the PR context. I also read pr-verify: the resolver now runs before the trust gate (all three jobs). This is the one change that touches a trust control, so I checked what the resolver does before the gate and what still depends on the gate.
Burn-rate pacer (
Rate-limit config (
Manifests and instruction surfaces. No Spend. The pacer and the reordered pr-verify steps make fewer GITHUB_TOKEN calls. The change adds no billed resource and no paid-plan setting. |
… verdicts download Neither paced workflow set RESOLVED_CONFIG, so pace.mjs read only rate-limits.json and limits.api github-token pace in pr-pipeline.yaml, 0 included, never reached it. Each now writes the base config's limits.api with yq, in resolve-config's output shape, and hands that file to the pacer; a failed read leaves the defaults. pr-review-main's record job: when the verdict download failed, the record step was skipped, no counter file was left, and the notice step's cat ended it red under bash -e. It now reads the file only when it exists, else 0. The test runs that step with -eo pipefail, as Actions does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Unattended merge: risk MED at head |
Reorder the limits.api pace sentence so "the timer lanes slow down before the breaker stops every lane" describes pace itself and "`0` turns pacing off" is its own clause, per the review thread. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No related issue: these cuts come from the 2026-10-29 17:58-18:58Z GITHUB_TOKEN spend ranking (gh-monitor trend report). That report names no issue; the one number it cites, #10488, is the earlier pr-merge change it compares against.
Summary
The window spent about 4,289 GITHUB_TOKEN calls, and every budget trip stops all automation. This PR covers three of the four planned items.
What check-intent spent, measured from the window's run data. The data is per-job api-calls notices, annotation counts, and post-verify-notes' verdict-or-none spend:
pace(0.2), even-numbered schedule ticks skip their workFix
Resolve the pull requestnow runs on the kill switch.Check the triggerruns only when the resolver proceeds, and the agree step only when the gate proceeds. A gate refusal therefore stays a refusal; it doesn't become a mismatch error. A judged run makes the same reads as before.pr-verify.yml:3-6andresolve-pr.mjs:5-9,588(heldOnly) judge a red run that only an approval-liftable hold ordo-not-mergeholds, so a person approves a judged head.pr-feedback-dispatch.yml:18-35turns a FAIL into threads that address-feedback works, or into thepr-verify-failedlabel that ci-status holds..base(Harden pr-merge's run-cache restore in the token-holding jobs #9455,pr-require-checks.yml:5210-5213). A lookup-first precheck was rejected too, because it would add reads to all 20 judgments an hour.github-token, and the job logslanes-app github-token.api_budget_emit_calls' shape, pinned against the emitter. This adds no checkout and no permission.log-api-budget/pace.mjs).limits.apigithub-tokenpaceis new, default 0.2, inrate-limits.json. It is validated likebreakerand allowed inpr-pipeline.schema.json.No token scope or workflow permission is added. No hold is changed, and ci-status is untouched.
For review:
rate-limits.jsonanddocs/conventions/pr-pipeline/sit on the merge hold lists, so this PR waits for a person.pace: 0inlimits.apiturns the pacer off.Verification
pr-verify:
node --test .github/scripts/pr-verify/*.test.mjs: 147 pass.test_verify_rules_sync: OK.node --test .github/actions/log-api-budget/*.test.mjs: all pass. This includes:pace.test.mjs, with hand-worked projections, the evidence window's reading and the odd-tick floor.api_budget_emit_calls.Both new tests failed before their workflow changes.
Node suites for pr-verify, pr-unblock, pr-merge, resolve-config, check-trusted-trigger, report-check-run, check-wip-cap, reconcile, intake-triage, intake-reenter, pr-review-main and triage-sweep: 3,958 pass.
Shell suites:
ci-lanes-pr-hold243,check-convention-yaml45,check-loop-lane-floor-drift28,read-runner-dispatcher-gate9,plan-test-lanes55.babysit-prs Python (unittest):
test_babysit_gh_rate_guard(45),test_merge_holds_sync,test_babysit_risk,test_babysit_postmergeandtest_verify_rules_syncall pass.actionlint and
zizmor --offlineare clean on every changed workflow. markdownlint is clean.scripts/check-changelog-fragments.sh --checkand--check-requiredpass.Related
permissions: {}and make no API calls.🤖 Generated with Claude Code