exec phase idles until run.timeout after the worker opened the PR, then reports 'Out of credits' from a stale rate-limit event

Aperta
#1,626 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
42/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
typescript
Ambito
devtools

Direzione di ricerca

Start by tracing the Claude Code driver’s phase-completion handling and the rate-limit path through isRateLimitFailureInfo, hasBillingMarkers, and billingHaltReason; the issue names no files or tests. Compare how a final worker result and a timeout are handled, and how rate-limit event status reaches errorMetadata. Done means completed work does not idle until timeout, and a timeout is not attributed to a non-rejected stale event.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

bug

Summary

Two exec phases in one sequant run finished their work (PR opened, final assistant message posted) 18 and 24 minutes before run.timeout, then sat idle until the timeout ended them. The run table reported both as ✘ failed · Out of credits, although the subscription window was open and a follow-up run executed normally minutes later. State was left at exec: failed with open, green PRs and no exec marker on the issue, so --resume would re-run exec.

Two separate problems:

  1. Phase-complete detection waits on process exit. A worker that has pushed, opened the PR and posted its final message is done, but the phase stays open until the Claude Code process exits or run.timeout fires.
  2. A timeout is labelled with a stale rate-limit event. The driver retains any rate_limit_event with billing markers (overageDisabledReason: out_of_credits, five-hour window, live resetsAt) regardless of status (isRateLimitFailureInfo → hasBillingMarkers), and billingHaltReason then names it as the cause of a later, unrelated failure. The run log's errorContext carried {category: billing, errorType: BillingError, errorMetadata: {rateLimitType: five_hour, overageDisabledReason: out_of_credits, resetsAt: …}} on a phase whose real end was durationSeconds ≈ 1803. The event's status is not retained, so the log cannot show whether it was allowed_warning or rejected.

Environment

  • sequant 2.20.0, Claude Code driver, --no-tui -v, --resume --concurrency 2, phases spec,exec,qa, run.timeout 1800
  • macOS, Claude Max subscription (overage disabled)
  • Next.js/TypeScript repo, three small issues, exec on Sonnet

Timeline (UTC, from the run log and the worker transcripts)

Issue exec start PR opened + final message phase end idle
A 01:32:21 01:37:53 02:02:25 (1803.9 s, "Out of credits") 24 min
B 01:51:14 02:03:36 02:21:17 (1802.8 s, "Out of credits") 18 min
  • The third issue in the same run passed exec → qa normally (exec 2 min, qa 16 min).
  • A one-word claude -p probe answered at 02:20, and sequant run A B --phases qa ran and passed at 02:25–02:27, an hour before the recorded resetsAt.
  • Worker B had a 120 s tsc command that Claude Code moved to the background; its output file ends in [killed] stamped at the phase end, so that background task was alive at the kill. Worker A's background command had finished three minutes before its final message, so a lingering background task does not explain both.
  • Earlier timeouts in the same repo (four judgment issues on Opus, Oct 13–15) were a different shape: the worker was still active 1–5 min before the timeout and had no PR. Those were genuine time-outs.

Expected

  • A phase whose worker has opened the PR and posted a final message completes when the stream yields the final result, or after a short grace period, not at run.timeout.
  • A phase that ends by timeout is reported as Timeout after 1800s (as the Oct 13–15 runs were) unless the captured rate-limit event has status: rejected. Retaining status in errorMetadata would make this checkable after the fact.
  • On a timeout where the branch has a commit and an open PR, state should not be left as exec: failed without an exec marker; at minimum the summary should say the PR exists.

Repro (best effort)

Run an exec phase on a subscription account that is near its five-hour cap with overage disabled (so a rate_limit_event with overageDisabledReason: out_of_credits is emitted during the session), with a worker that starts a long tsc/jest command that Claude Code moves to the background, and let the worker finish and open the PR. Observe whether the phase ends at the final message or at run.timeout, and what reason the run table prints.

Happy to attach the two run logs (with repo-specific paths redacted) on request.

Lingua principale
TypeScript
Stelle
1
Fork
1
Merge medio
11h 3m
PR unite (30g)
84

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di sequant-io/sequant

Tutte le issue di sequant-io/sequant

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.