Repository navigation
fix(ci): hold rate-limit default changes for a person - #10304
Conversation
The limits.api defaults that stop a lane before GitHub rate-limits the account lived in pr-pipeline.schema.json, which is not on the merge hold floor, so a pull request raising or removing them could merge on the AI review lanes alone. Flooring the whole schema would hold most of its frequent changes for a person. Move the defaults, unchanged, into .github/actions/log-api-budget/rate-limits.json, their only copy: rate-guard.mjs and babysit_gh.py read it (babysit_gh.py's GITHUB_TOKEN_LIMIT_CAP constant now comes from it too), the schema drops its defaults, and every hold list floors the file (HOLD_PATH_FLOOR, babysit_risk.HIGH_FLOOR, ci-status's hold_patterns, both review lanes' hold-paths). A missing or invalid file still leaves rate-guard warning that the read floor is unchecked while stops hold, and still refuses every babysit_gh call; both now also reject a malformed value. 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 I found nothing to flag in this pull request. I read the whole diff and the PR context. I ran no tests, so the verification results in the PR description are author-claimed and unconfirmed by me. What the change does. It moves the
What I checked.
Spend. This change spends nothing, and no hold applies. |
|
claude-security-review reviewed No security findings. What I reviewed: the full 24-file diff and the PR context. Trusted-path files read in full: Trust-control analysis (judged from code, not PR text):
Manifests: no Cost: nothing here can cause a real charge. No hold. |
…defaults # Conflicts: # .github/actions/log-api-budget/rate-guard.test.mjs
No related issue: rate-limit defaults could change without a person; owner treats rate-limit stops as safety
Summary
The
limits.apidefaults that stop a lane before GitHub rate-limits the account (each pool'splan,writer-pause,breaker,read-floor, github-token'slimit-cap, content-creation'sper-minuteandper-hour) lived indocs/conventions/pr-pipeline/pr-pipeline.schema.json. That schema is not on the merge hold floor, so a pull request raising or removing those limits could merge on the two AI review lanes alone. Flooring the whole schema would hold every schema change for a person, and the schema changes often.Fix
.github/actions/log-api-budget/rate-limits.jsonholds the defaults, with the same values. It is their only copy.rate-guard.mjsapiLimitsreads it, and checks it: every pool present, no unknown pool or field, shares within 0 to 1, counts as positive integers.babysit_gh.pyreads it forwriter-pause,read-floorand github-token'slimit-cap. The last replaces theGITHUB_TOKEN_LIMIT_CAP = 1000constant, which held a second copy of the value.defaultvalues forlimits.apiand its descriptions point at the file.HOLD_PATH_FLOOR(merge-holds.mjs),babysit_risk.HIGH_FLOOR, ci-status'shold_patterns(pr-require-checks.yml), and thehold-pathsofpr-review-hosted.ymlandpr-review-security-hosted.yml. This follows the shape #10252 uses forescalation-routes.json.test_merge_holds_sync.pytakes #10252'sIMPORTpattern word for word. The pattern also follows a module-relative file a floored module reads (new URL("./…", import.meta.url)), so the floor test now reachesrate-limits.jsonthroughrate-guard.mjs.intake-label-needs-triage.ymlno longer checks out the schema. Onlyrate-guard.mjsneeded it there, and the new file comes with thelog-api-budget/checkout.Behaviour is unchanged:
apiLimits({resolvedPath: ""})andbabysit_gh.pool_limitsgive the same values for all five pools as before. Both were captured before the change and diffed after.apiLimitsthrow. The latch then warns that the read floor is unchecked, and stops still hold, as with a missing schema before.babysit_ghstill refuses every call when the file is missing.pr-pipeline.yamloverride still wins field by field.Verification
Tests that failed before the change and pass after:
test_merge_holds_sync.py: floor size 38,rate-limits.jsonand a case variant held on both sides, and the floor holds what its actions load.test_babysit_risk.py: the floor lists.scripts/ci-lanes-pr-hold.test.sh: the floor holdsrate-limits.json.rate-guard.test.mjs:rate-limits.json;limits.apidefault, and the file's pools and fields match the schema's.test_babysit_gh_rate_guard.py:Suite results:
node --test .github/actions/log-api-budget/*.test.mjs .github/scripts/pr-merge/*.test.mjs .github/actions/check-born-triaged/*.test.mjs: 606 pass, 0 fail.node --test .github/actions/resolve-config/*.test.mjs: 698 pass, 0 fail.node --testover the check-trusted-trigger, pr-unblock, work-unblock, reconcile-lost-runs, check-wip-cap and report-check-run suites: 1587 pass, 0 fail.python3 -m unittest discover -s tests -t .inbabysit-prs/scripts: 3075 tests OK.scripts/ci-lanes-pr-hold.test.sh: 155 pass.ci-review-lanes: 98 pass.ci-hold-cost-decision: 141 pass.ci-hold-merge-group: 66 pass.post-merge-demotion-alert: 154 pass.check-loop-lane-floor-drift: 28 pass.plan-test-lanes: 45 pass.check-lane-coverage.test.sh: 41 pass.scripts/check-lane-coverage.sh --checkpasses.actionlintis clean.scripts/run-ruff.sh checkandformat --checkpass.check-changelog-fragments.sh --checkand--check-required origin/mainpass.check-convention-yaml.sh --checkpasses.Related
#10252 floors
escalation-routes.jsonin the same shape. Whichever of the two merges second needs a rebase. After this change, #10252'sOFF_FLOORassertion intest_merge_holds_sync.py(set(OFF_FLOOR) <= set(reached)) fails, becauserate-guard.mjsno longer reaches the schema. That entry and its comment should go when #10252 rebases. The floor count also moves (37 to 38 here, 39 there, 40 together).pr-pipeline.yamloverrides can still raise a limit above its default:limit-cap,per-minuteandper-hourhave no schema maximum.read-floor: 0turns the read-floor warning off.writer-pauseandbreakeraccept 0.docs/conventions/pr-pipeline.yamlis already on the floor, so such an override already waits for a person. Not changed here.melodic-software/pr-pipeline-sandboxkeeps its own copy ofrate-guard.mjsand the schema (gh search code --owner melodic-software "api-content-pool"). When it is next staged from this repository, it needsrate-limits.jsonalong withrate-guard.mjs. Without it, its guard warns that the read floor is unchecked while its stops still hold. Org searches for"writer-pause","rate-guard.mjs"and"api-pool" read-floorfound no other reader.pr-require-checks.ymlstill setsAPI_BUDGET_READ_FLOOR: "0.1"andAPI_BUDGET_LIMIT_CAP: "1000"for ci-status, which has no checkout of the file.log-api-budget.test.mjspins both toapiLimits, so they followrate-limits.json, and the workflow is on the floor.🤖 Generated with Claude Code