feat(crashlog): preserve the claude stream when a tick dies mid-call (observe #279) #280
No reviewers
Labels
No labels
Agent
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No assignees
2 participants
Notifications
Total time spent: 1 minute 49 seconds
Due date
igor
1 minute 49 seconds
No due date set.
Dependencies
No dependencies set
Reference
joshtronic/igor!280
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/preserve-claude-stream-on-crash"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Observability for #279, not a fix — so the next occurrence tells us the actual cause instead of us guessing.
Why: #279 (and #272) die with
status=1and no "claude exited" line, right after the security-review Skill's[tool_result]. The model invocation doesn't return, and the worktree is then removed (issue work) or overwritten next tick (PR rework) — so claude's actual death reason (its merged stderr lives in the raw stream) is lost. I exhausted static analysis: the post-pipe bookkeeping is provably abort-proof (cost/health are|| true'd,classifyandrecord_failurereturn 0), so the death is in the claude/Skill process, which can't be diagnosed without seeing what it printed.What this does:
claude_run_with_costdrops a.agent/claude-in-flightmarker for the duration of every call and clears it on a clean return.cleanup(), on an abnormal exit, copies any still-marked worktree's raw stream + display log + call-site into~/.local/state/agent/crash-logs/<stamp>-rc<N>-<wt>/before the worktree is gone.New
lib/crashlog.sh+bin/test-crashlog.sh(8 checks: preserve-with-marker, skip-without-marker, empty-arg no-op, rc in dir name, 20-cap, safe-on-missing-dir).bash -n+ check-sync green.So: next time a tick dies mid-Skill, we get claude's actual stderr/exit in
crash-logs/and can finally close out #279. Refs #279 (left open — this captures the cause, doesn't fix it). No reviewer.🤖 Review —
COMMENT(automated)CI for
c1b09c1b: successAdds best-effort post-mortem capture (
lib/crashlog.sh+ tests, wired intocleanup()/claude_run_with_cost) that copies a worktree's raw claude stream when a tick dies mid-model-call. Scope-tight (~110 lines), CI green, tests included, no CI-config changes, no security concerns. The one thing I can't verify from the diff is the integration assumption that makes the feature actually fire — hence COMMENT, not APPROVE.Checklist vs. diff — all honest:
claude_run_with_cost, clear on clean return,cleanup()capture, 20-dir cap, new lib + test file — all present.eqassertions intest-crashlog.sh. Matches.The unverifiable bit (please confirm before merge): The whole feature hinges on
$scratchinlib/claude.shresolving to$WORKTREE/.agent(or$PR_WORKTREE/.agent), becausecrashlog_preservelooks for the marker at$wt/.agent/claude-in-flightwhile the marker is dropped at$scratch/claude-in-flight. The diff doesn't show where$scratchis defined.local stream_log="$scratch/claude-stream.jsonl"), and the PR's own premise (stream lost when the worktree is removed) only holds if$scratchis inside the worktree — so this is very likely correct. But if$scratchlives outside the worktree, the marker is never found and the capture silently no-ops (no breakage, just no diagnosis of #279).crashlog_preservecopies$scratch/claude-output.log, but I can't see what$display_logis actually named inclaude.sh. If it isn'tclaude-output.log, that copy silently fails (|| true) and you lose the display log — the stream still survives, so it's a partial miss, not a break. The test fabricates its own files so it doesn't catch a filename mismatch against the real code.Correctness notes (no blockers):
[ -n "$wt" ] && [ -f ... ] || continueprecedence is fine — both false-A and true-A/false-B correctlycontinue.crashlog_prunekeep-20 logic (ls -1dt | tail -n +21 | rm -rf) is sound; empty/missing dirs return 0; glob-no-match is harmless.returnpath inclaude_run_with_costskips therm -f, a later unrelated abnormal exit would preserve a stale stream and log "claude call did not return"). Harmless for observability, worth a mental note.|| true-guarded, so a capture failure genuinely cannot change the tick's exit, as claimed.Ask: confirm
$scratch == $WORKTREE/.agentand that the display log isclaude-output.loginlib/claude.sh. If both hold, this is good to merge; if not, the feature won't capture what #279 needs.Independent review by the harness on
claude-opus-4-8. The human reviewer is requested once Igor has reviewed; a human still merges.