Daemon: classify Claude session/usage-limit exhaustion — stop claiming until reset instead of insta-failing runs#1798
Open
interactor-pm-service[bot] wants to merge 2 commits into
Conversation
…with no pause Mirror the GitHub rate-limit handling (G#343/G#376) for a Claude account usage/session-limit exhaustion. Blocking reason (self-healing): - Add a new `claude_rate_limited` BlockingReasonKind + `claudeRateLimitedUntil` signal. It fires on a FUTURE reset time, carries no fix command, sets `resolvesAt`, and OUTRANKS `claude_auth_missing` so an exhausted usage limit never masquerades as a sign-in loss. - Thread `claudeRateLimitedUntil` through the sync layer, the register / heartbeat / detail ingestion routes, and Machine (+ migration). - Fold into the goal block-state as a `self_healing` resolution (goal → progressing with the reset as eta), the machine card + fleet-sidebar renderers, and the board label map. Generalize the fleet-sidebar self-heal branch to any reason carrying `resolvesAt` (not just github_rate_limited). No-penalty RELEASE outcome: - New wire outcome `claude_limited` (field `claudeRateLimitedUntil`) on the engine report route: requeue the task via a new `requeueForClaudeLimit` helper (same requeue-state logic as tryRequeueForRetry) WITHOUT bumping transientRetryCount and WITHOUT escalateFailedRun/recordPause; set retryNotBefore from the reset so it isn't instantly re-claimed; finalize the run to `retried`. Persist the reported reset onto the run's Machine as a redundancy. WIRE NAMES (for the daemon task): field `claudeRateLimitedUntil` (ISO-8601); report outcome string `claude_limited`. Tests: new-kind derivation (fires future / null past / never masquerades as claude_auth_missing), report-route release (task→queued, no pause, retry count unchanged, run→retried, machine stamped), goal-block-state fold to progressing/self-healing, and machine-card + fleet-sidebar render specs. Agent config: senior-pm updated to explain the new self-healing reason. No new user tool registered, so no config-sync TOOL_NAMES change is needed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… claims until reset Daemon half of G (mirror of the GitHub rate-limit pause, G#343) — pairs with the platform task's `claude_limited` report outcome + `claudeRateLimitedUntil` field (commit 5df526b). Detection (llm-errors.ts): a DISTINCT `classifyClaudeAccountLimit` sibling of the transient classifier — anchored to BOTH a 429 status AND a session/usage-limit phrase ("hit your session limit", "usage limit reached"), kept as tight as the envelope regexes so a coding run's output tail (a bare 429, "rate limit" prose) is not misclassified. Parses the reset ("resets 3am (UTC)" → next future 3am UTC; ISO; epoch) into a limit-until instant, defaulting to the top of the next hour when unparseable so the pause self-clears. Deliberately a sibling verdict — it never enters the bounded RetryReason set llm-retry.ts validates. Retry short-circuit (task.ts): runClaudeWithRetry classifies the account limit BEFORE the transient classifier and STOPS — re-spawning claude against an exhausted account only burns the in-place budget. Surfaces `accountLimit` to the caller. Release + pause + report (container-loop.ts): a session-limited run reports the no-penalty `claude_limited` outcome carrying the reset (via the extracted, unit-testable `assembleEngineReport`, before the retryable/failed fallbacks) so the task requeues to `queued` instead of a run_failure pause. A module-level `claudeRateLimitedUntil`, REMEMBERED across ticks (no free Claude probe like gh's), gates the claim loop head with one honest log line and clears automatically once past; it's serialized onto register/heartbeat's `AuthStatus.claudeRateLimitedUntil` so the machine card + fleet sidebar render the self-healing reason. Bump DAEMON_VERSION 0.41.0 → 0.42.0 with a changelog entry. No agent-visible tool/data change here (senior-pm config was updated in the paired platform commit), so no config-sync update is needed. Tests: llm-errors (real strings → parsed reset; unparseable → default window; negatives for bare-429 / limit-in-prose; precedence over transient), task (short-circuit, no retry; transient 429 still retries), container-loop (assembleEngineReport release precedence + the remembered-block pause/heartbeat seam), api (version bump). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Integration PR for this goal — its tasks commit onto this branch (one PR per goal). Opened automatically by the engine on first push; left as a draft until the goal completes.