Skip to content

A timed-out session records cost_usd=0, so spend caps under-count the priciest runs #18

Description

@lorenzoliuzzo

Measured on a real run (2026-07-30T12:46:22Z, issue #1 of an out-of-fleet target). The session ran the full 1500s wall clock and was killed. The ledger entry:

{"outcome":"failure","detail":"session failed for #1 with no commit: session exceeded 1500s wall-clock timeout","cost_usd":0.0,"turns":0}

The persisted transcript for that same run contains 61 assistant lines and 35 tool calls over 25 minutes. The real spend was material; the recorded spend is zero.

Cause: _parse_result (session.py) only learns cost and turn count from the single type=result line that claude emits when it finishes. ClaudeSessionRunner.run catches subprocess.TimeoutExpired and returns SessionResult(ok=False, transcript=..., error=...) with the cost_usd/turns defaults of 0.0/0 — a timed-out stream never carries that final line.

Why this matters beyond bookkeeping: cost_usd is what the retry loop accumulates into max_total_budget_usd, and what my-fleet's $20/day ceiling and per-session caps meter. A timeout is the most expensive way a session can end, and it is the one shape that meters as free. A repeatedly-timing-out candidate can therefore run well past a ceiling that believes nothing has been spent — and _RETRYABLE includes failure, so --max-attempts > 1 will retry it, each attempt also metering zero.

Acceptance criteria

  • A timed-out session reports a non-zero, best-effort cost and turn count, recovered from the partial stream rather than defaulted (the incremental lines carry usage, and the partial stdout is already captured in exc.stdout).
  • Where cost genuinely cannot be recovered, it is recorded as unknown rather than as 0.0, and the retry/budget logic treats unknown as "assume the cap was consumed", not as free.
  • A test pinning that a timeout does not meter as zero.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions