Summary
A session that ends by timeout is journalled with tokens: 0 and tokens_weighted: 0, so the run total, per-story cost, max_tokens_per_story and any digest built on the journal omit the most expensive sessions of the night.
Observed (0.11.1)
Setup: an unattended nightly sweep run with [limits] session_timeout_min = 180, max_dev_attempts = 2 and [scm] isolation = "worktree"; the dev adapter is Claude Code.
session-end <story>-dev-1 status: timeout tokens: 0 tokens_weighted: 0
session-end <story>-dev-2 status: timeout tokens: 0 tokens_weighted: 0
The Claude transcripts of those two 3-hour sessions and their subagents sum to 114,498,346 raw tokens, 14.7M weighted at cache_read_weight = 0.1 (deduplicated per message id; a transcript repeats a response's usage once per content block). bmad-loop status reports the run at 41,460,533 raw, all from the one story that completed: the timed-out story was about 73 percent of the night's spend and shows as zero.
Consequences: max_tokens_per_story cannot fire for the sessions most likely to exceed it; status, metrics and the digest undercount by the full cost of every timeout; and #611's zero-token heuristic would classify a fully productive 3-hour session as an environment fault.
Proposal
On a timeout / stalled / over_budget verdict, read usage from the adapter's transcript for the session and its children, as a completed session's usage is read after usage_grace_s. The transcript is on disk before the kill (straggler-reap follows timeout-fired by ~200 ms). If the read fails, journal tokens: null rather than 0, so an absent measurement is distinguishable from a free session.
Summary
A session that ends by
timeoutis journalled withtokens: 0andtokens_weighted: 0, so the run total, per-story cost,max_tokens_per_storyand any digest built on the journal omit the most expensive sessions of the night.Observed (0.11.1)
Setup: an unattended nightly sweep run with
[limits] session_timeout_min = 180,max_dev_attempts = 2and[scm] isolation = "worktree"; the dev adapter is Claude Code.The Claude transcripts of those two 3-hour sessions and their subagents sum to 114,498,346 raw tokens, 14.7M weighted at
cache_read_weight = 0.1(deduplicated per message id; a transcript repeats a response's usage once per content block).bmad-loop statusreports the run at 41,460,533 raw, all from the one story that completed: the timed-out story was about 73 percent of the night's spend and shows as zero.Consequences:
max_tokens_per_storycannot fire for the sessions most likely to exceed it;status,metricsand the digest undercount by the full cost of every timeout; and #611's zero-token heuristic would classify a fully productive 3-hour session as an environment fault.Proposal
On a
timeout/stalled/over_budgetverdict, read usage from the adapter's transcript for the session and its children, as a completed session's usage is read afterusage_grace_s. The transcript is on disk before the kill (straggler-reapfollowstimeout-firedby ~200 ms). If the read fails, journaltokens: nullrather than0, so an absent measurement is distinguishable from a free session.