ci: the hosted light rescue reads as cmux-bot, the workflow token only as fallback

Merged
TE
2d ago
+176-29

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_TOKEN is the cmux-bot token (|| github.token when the mint failed); HOSTED_LIGHT_FALLBACK_TOKEN is github.token.
  • The token is minted again before its hour is up (the sweep runs five), from the BOT_APP_ID/BOT_APP_KEY the step already passes only when the mint worked, with owned_pool_rescue.app_token_minter.
  • Each token's pool is tracked from its own X-RateLimit-* headers. Reads move to github.token only while cmux-bot's pool is at #35099's POOL_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

metricbeforeafterdeltaharness 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 pool0 while cmux-bot's pool is above 500−all of ittests/test_ci_hosted_light_rescue.py BotTokenFirst (6 cases)
hosted-light writes on the repository poolunchanged (a few per rescue)unchanged0same

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
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_KEY the job already passes; cancellations, re-runs, and the sweeper wake stay on github.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.