debug: add PTY spawn diagnostics for Session: None investigation

When an agent CLI exits without creating a session, we now log:
- Number of prior sessions and total session log bytes
- Child process exit status (exit code or signal)
- Explicit SESSION NONE warning with context

This will help diagnose whether the fatal runtime error
(output.write assertion) correlates with accumulated sessions,
budget exhaustion, or something else.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
dave
2026-04-11 11:21:06 +00:00
parent 44ef477a01
commit 5696d77922
+40 -2
View File
@@ -209,7 +209,22 @@ fn run_agent_pty_blocking(
cmd.env_remove("CLAUDECODE"); cmd.env_remove("CLAUDECODE");
cmd.env_remove("CLAUDE_CODE_ENTRYPOINT"); cmd.env_remove("CLAUDE_CODE_ENTRYPOINT");
slog!("[agent:{story_id}:{agent_name}] Spawning {command} in {cwd} with args: {args:?}"); // Count existing session files for this worktree to detect budget exhaustion.
let session_dir = format!(
"/home/huskies/.claude/projects/-workspace--huskies-worktrees-{}/",
story_id.replace('_', "-").replace('.', "-")
);
let session_count = std::fs::read_dir(&session_dir)
.map(|d| d.filter(|e| e.as_ref().map(|e| e.path().extension().is_some_and(|ext| ext == "jsonl")).unwrap_or(false)).count())
.unwrap_or(0);
let session_bytes: u64 = std::fs::read_dir(&session_dir)
.map(|d| d.filter_map(|e| e.ok()).filter(|e| e.path().extension().is_some_and(|ext| ext == "jsonl")).filter_map(|e| e.metadata().ok()).map(|m| m.len()).sum())
.unwrap_or(0);
slog!(
"[agent:{story_id}:{agent_name}] Spawning {command} in {cwd} with args: {args:?} \
(prior_sessions={session_count}, session_log_bytes={session_bytes})"
);
let mut child = pair let mut child = pair
.slave .slave
@@ -429,7 +444,19 @@ fn run_agent_pty_blocking(
} }
let _ = child.kill(); let _ = child.kill();
let _ = child.wait(); let wait_result = child.wait();
match &wait_result {
Ok(status) => {
slog!(
"[agent:{story_id}:{agent_name}] Child exited: {status:?}"
);
}
Err(e) => {
slog!(
"[agent:{story_id}:{agent_name}] Child wait error: {e}"
);
}
}
// Wait for the reader thread to finish so it releases the cloned PTY // Wait for the reader thread to finish so it releases the cloned PTY
// master fd before we return. Without this, the next PTY spawn for the // master fd before we return. Without this, the next PTY spawn for the
@@ -438,6 +465,17 @@ fn run_agent_pty_blocking(
slog!("[agent:{story_id}:{agent_name}] Reader thread panicked: {e:?}"); slog!("[agent:{story_id}:{agent_name}] Reader thread panicked: {e:?}");
} }
// Log whether session was created — Session: None indicates CLI died
// before emitting any events (possible causes: rate limit, budget
// exhaustion, PTY write failure, CLI crash).
if session_id.is_none() {
slog_warn!(
"[agent:{story_id}:{agent_name}] SESSION NONE: CLI exited without creating a session. \
Check for 'fatal runtime error' in agent logs. \
prior_sessions={session_count}, session_log_bytes={session_bytes}"
);
}
slog!( slog!(
"[agent:{story_id}:{agent_name}] Done. Session: {:?}", "[agent:{story_id}:{agent_name}] Done. Session: {:?}",
session_id session_id