When a Claude account is suspended, the API returns "Your organization does
not have access to Claude" on the success path or "Failed to authenticate.
API Error: 403 terminated" on the error path. Both are now classified as
'org-access-denied', suppressed from Discord output, and trigger automatic
token rotation. If all tokens are exhausted, enters cooldown without Kimi
fallback (same as usage-exhausted and auth-expired).
Changes:
- agent-error-detection: add isClaudeOrgAccessDeniedMessage(), expand
classifyClaudeAuthError() and shouldRotateClaudeToken()
- streamed-output-evaluator: detect org-access-denied in success-path chain
- provider-fallback: add NO_FALLBACK_COOLDOWN_REASONS set and
isPrimaryNoFallbackCooldownActive() helper
- provider-retry: handle org-access-denied in rotation loop
- message-agent-executor / task-scheduler: use generalized no-fallback
cooldown check
- Tests: +8 test cases across 5 test files (415 total passing)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix token rotation not taking effect: getCurrentToken() was shadowed
by static .env CLAUDE_CODE_OAUTH_TOKEN value in agent environment
- Don't fall back to Kimi on usage-exhausted (only on transient 429/network)
- Add disk cache for Claude usage API data (survives restarts, 429s)
- Rate-limit usage API calls to 1 per token per 5 minutes
- Add ignoreRateLimits option to rotateToken() for exhausted recovery
- Rotate to next token in getActiveProvider() when current is exhausted
- Add isUsageExhausted() helper to provider-fallback