Skip to content

optimize: subagent transcripts (isSidechain=true) are counted as sessions, inflating session counts and the low-worth / context-heavy detectors #974

Description

@adamkwhite

Problem

Claude Code writes each subagent's transcript to its own file under <project>/<session-uuid>/subagents/agent-*.jsonl. Every entry in those files carries isSidechain: true.

codeburn optimize counts each of these as a session. On my machine that is a 3.3x inflation of the session count, and it feeds two of the five High-severity findings, both of which subagents fail by construction rather than by waste.

Note up front: subagent token spend is real and should keep counting toward cost totals. The problem is treating a sidechain transcript as a session for the session-level detectors.

Evidence

codeburn 0.9.20 (npm), Claude Code 2.1.228, Linux (WSL2).

Transcript files modified in the last 30 days:

$ cd ~/.claude/projects
$ find . -name '*.jsonl' -mtime -30 | wc -l
266
$ find . -name 'agent-*.jsonl' -mtime -30 | wc -l
188
$ find . -name '*.jsonl' -mtime -30 ! -name 'agent-*' | wc -l
78

Reported session counts over that window:

Source Sessions
codeburn optimize (default --period 30days) 257
Claude Code /insights 66 analyzed (76 total)
real (non-agent-*) transcript files 78

257 tracks the 266 total files. 66/76 tracks the 78 real sessions.

Every entry in a sampled subagent file is flagged:

$ # ./-home-adam-Code-claude-memory-mcp/51d23210-.../subagents/agent-a104705e05a4bebdc.jsonl
entries: 291   isSidechain value counts: {True: 291}

Impact on findings

Finding "N context-heavy sessions". Its own examples are subagents:

-home-adam-Code-job-agent/agent-ad163f3e75953e7eb        7.1M input/cache vs 87.7K output (80.6:1)
-home-adam-Code-claude-memory-mcp/agent-a769c824627f199aa  3.4M input/cache vs 55.5K output (60.6:1)

A subagent is given a large context and returns a short answer. A high input:output ratio is its correct behavior, not context bloat. Flagging it inverts the signal.

Finding "N possibly low-worth expensive sessions". The delivery test in the shipped bundle is:

DELIVERY_COMMAND_PATTERNS = [
  /(?:^|[;&|]\s*)git\s+(?:commit|push)(?=\s|$|--)(?![^;&|]*--dry-run)/,
  /(?:^|[;&|]\s*)gh\s+pr\s+(?:create|merge)(?=\s|$|--)(?![^;&|]*--dry-run)/
]

Subagents do not commit or open PRs; the parent session does. So every subagent is an unsatisfiable candidate. 70 sessions were flagged for me against 78 real sessions.

This is the same detector class as #664 (founding/bootstrap sessions flagged as waste) misfiring on a different population.

The signal is already parsed

isSidechain is captured at session level. From the bundle's own comment:

// rich-session-capture-v1: parse-time capture of per-turn gitBranch, per-call
// LOC deltas / interruptions / userModified / toolErrors, and session-level
// title / prLinks / isSidechain.

The session-meta validator also carries isSidechain, agentType, and parentSessionId, and emptySessionMeta() initialises { prLinks: [], isSidechain: false, agentSpawnLinks: {}, ambiguousSpawnAgentIds: [] }.

There is also an entry-level skip in the parser:

if (entry.isSidechain === true) continue;

Given that every entry in these files is isSidechain: true, that filter would empty them out — so the path feeding optimize's session list evidently does not apply it. The flag is honoured in one parse path and ignored in the one that produces the session population for the detectors.

Suggested direction

Listing options rather than assuming a preference:

  1. Exclude sessions with session-level isSidechain === true from findLowWorthCandidates and the context-heavy detector, while leaving their cost in the totals.
  2. Attribute subagent cost and tokens to parentSessionId so a parent session is judged on the full work it dispatched — this would also make the low-worth delivery test meaningful, since the parent is what commits.
  3. If subagents stay in the session list, report them in a separate bucket with their own thresholds, since a 60:1 input:output ratio is normal for a sidechain.

Option 2 seems the most faithful, but 1 is a much smaller change and removes the false positives on its own.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions