ci: the hosted light rescue reads as cmux-bot, the workflow token only as fallback
The owned-pool sweeper's minute hosted-light pass read with github.token, the repository's one GITHUB_TOKEN pool (1,000 requests an hour on this plan) that every workflow shares, the NEXT nightly's tick and notarization preflight among them (run 41790985234 failed on "API rate limit exceeded for installation"). The sweeper job already mints a cmux-bot installation token, whose pool is the App installation's own, and #34787 already moved the rest of this job's reads onto it.
This moves the hosted-light pass's reads (run listings, job reads, PR head and run re-reads, the recovery journal) to that cmux-bot token:
HOSTED_LIGHT_TOKENis the cmux-bot token (|| github.tokenwhen the mint failed);HOSTED_LIGHT_FALLBACK_TOKENisgithub.token.- The token is minted again before its hour is up (the sweep runs five), from the
BOT_APP_ID/BOT_APP_KEYthe step already passes only when the mint worked, withowned_pool_rescue.app_token_minter. - Each token's pool is tracked from its own
X-RateLimit-*headers. Reads move togithub.tokenonly while cmux-bot's pool is at #35099'sPOOL_RESERVE(500) or its token is refused (401/403/429: a refused GET did nothing, so it is asked again once on the workflow token; cmux-bot is tried again after its reset or 5 minutes). With both pools at the reserve, the pass makes no new reads, as before. - Cancels, re-runs and the sweeper wake stay on
github.token, so who triggers a re-run is unchanged. The routing App is still never used.
Leo's coordinator asked to cut the repository token's calls per hour so the nightly stops failing on "API rate limit exceeded", moving the heavy automated callers (pickers, janitors, rescue) to a cmux-bot installation token. No new secret or permission: the token, its permissions and the App key are the ones this job already uses.
Performance
| metric | before | after | delta | harness or run link |
|---|---|---|---|---|
| hosted-light reads on the repository GITHUB_TOKEN pool, per hour | ~120-360 listings + up to ~2,400 job reads (after #35184; ~1,440 listings before it), capped by #35099 at half the pool | 0 while cmux-bot's pool is above 500 | −all of it | tests/test_ci_hosted_light_rescue.py BotTokenFirst (6 cases) |
| hosted-light writes on the repository pool | unchanged (a few per rescue) | unchanged | 0 | same |
The read count is from the code (2-6 listings and at most 40 conditional job reads a pass, one pass a minute); an unchanged run's 304 is free on either token. These reads now spend cmux-bot's installation pool instead.
Validation: python3 tests/test_ci_hosted_light_rescue.py (63 passed), tests/test_ci_runner_pools.py (45; its routing-App isolation contract now pins the cmux-bot-first token and the github.token fallback), tests/test_ci_owned_pool_rescue.py (480), tests/test_ci_workflow_run_api_budget.py (46), actionlint clean. No build caches apply.
Prior art: #35184 (repository-wide listing, merged), #35099 (pool reserve), #34787 (this job's other reads on cmux-bot), #34508 (put this pass on the workflow token to spare the routing App; this keeps the routing App out and moves the pass to cmux-bot instead).
🤖 Generated with Claude Code
Agent session: agent session
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Moves the hosted-light rescue pass's reads from the repository's shared GITHUB_TOKEN pool to a cmux-bot installation token, so the NEXT nightly's tick and notarization stop failing on "API rate limit exceeded". The workflow token is now only a fallback while cmux-bot's pool is at the 500 reserve or its token is refused.
- The token is re-minted before its hour is up from the
BOT_APP_ID/BOT_APP_KEYthe job already passes; cancellations, re-runs, and the sweeper wake stay ongithub.token. - No new secret or permission; the routing App is still never used.
Summary by CodeRabbit
- Bug Fixes
- CI recovery checks now use the available bot credential for reads and switch to the workflow credential when the bot credential is unavailable, refused, or near its rate limit.
- Write operations continue using the workflow credential, and bot credentials can be refreshed during longer-running checks.
- Rate-limit tracking now reflects the credential used for reads.