mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-09 09:59:45 -10:00
fix(resume): keep the interrupted turn when --resume follows a killed TUI
CW-7453. After the TUI is killed mid-turn, `codewhale --resume <id>` opened the session with no error but without the interrupted turn: the next request carried only the system prompt and the new message. Cause. prepare_mounted_session captured the stale saved document and committed a canonical Resume whose updated_at is the operation time. The TUI's attach then ran promote_interrupted_checkpoint, which saw the saved document as newer than the crash checkpoint, skipped promotion and deleted the checkpoint, the only copy of the turn. `--continue` was unaffected because its recovery path promotes the checkpoint before the mount. Fix. prepare_mounted_session promotes the session's crash checkpoint under the external-write lease it already holds, before reading the document, so the mount captures the recovered turn. promote_interrupted_checkpoint becomes pub(crate). Fail-closed behavior is unchanged: that lease refuses a session live in this or another process. A fork of a crashed session now promotes the source's checkpoint first, which any later attach of the source would have done. Known limit, recorded on CW-7453: promote_interrupted_checkpoint still judges staleness by updated_at alone, so a metadata-only write that bumps a crashed session's document would still make the next attach drop its checkpoint. Verified with a real crash repro (CW/artifacts/cw7446-20261018, crashcont.sh): isolated CODEWHALE_HOME, a local mock provider with a 15 s stream, tmux kill-server mid-stream, 8 s wait with no codewhale process left, relaunch, then a follow-up message. The same script ran against a pre-fix and a fixed build of this tree: pre-fix --resume: follow-up request messages=2, turn gone fixed --resume: follow-up request messages=3, turn on screen pre-fix --continue: messages=3 (unchanged) fixed --continue: messages=3 (unchanged) scripts/dev-test.sh tui mounted interrupted_checkpoint attach_session: 24 run, 24 passed (14 mounted_history tests). scripts/dev-test.sh tui session_manager:: : 137 run, 137 passed. cargo fmt --check clean; sync-changelog --check up to date. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
This commit is contained in:
1 parent
88edb22461
commit
3111e961c0
4 files changed
+14
-3
No files matched your search
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- `codewhale --resume <id>` after the TUI was killed mid-turn keeps the
|
||||
interrupted turn. Before, the resume stamped the older saved document as
|
||||
newer than the crash checkpoint, and the checkpoint, the only copy of
|
||||
that turn, was then discarded as stale. `--continue` was not affected.
|
||||
- Three session data-loss paths are closed:
|
||||
- `/load` of an older exported copy of a session no longer replaces the
|
||||
newer saved conversation with the same id. It refuses and points to
|
||||
|
||||
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- `codewhale --resume <id>` after the TUI was killed mid-turn keeps the
|
||||
interrupted turn. Before, the resume stamped the older saved document as
|
||||
newer than the crash checkpoint, and the checkpoint, the only copy of
|
||||
that turn, was then discarded as stale. `--continue` was not affected.
|
||||
- Three session data-loss paths are closed:
|
||||
- `/load` of an older exported copy of a session no longer replaces the
|
||||
newer saved conversation with the same id. It refuses and points to
|
||||
|
||||
@@ -9967,9 +9967,12 @@ async fn prepare_mounted_session(
|
||||
} else {
|
||||
manager.resolve_session_id_prefix(&selector)?
|
||||
};
|
||||
// Capture the complete document and separate local goal under the
|
||||
// same existing inactive-session guard; neither read repairs history.
|
||||
// Under the existing inactive-session guard, promote any crash
|
||||
// checkpoint first: the mount below stamps a newer document, and the
|
||||
// later attach would then discard the checkpoint as stale. Then
|
||||
// capture the complete document and separate local goal.
|
||||
let _source_lease = manager.reserve_session_for_external_write(&id)?;
|
||||
manager.promote_interrupted_checkpoint(&id);
|
||||
let saved = manager.load_session_snapshot_bounded(&id, MAX_CANONICAL_HISTORY_BYTES)?;
|
||||
// Project grants were captured for this launch before awaiting. The
|
||||
// existing restore changes App workspace, so it cannot silently apply
|
||||
|
||||
@@ -3577,7 +3577,7 @@ impl SessionManager {
|
||||
/// consume it. Callers hold the session's attach lease. A stale checkpoint
|
||||
/// never replaces a newer document; an unreadable document and a failed
|
||||
/// save leave both files as they were.
|
||||
fn promote_interrupted_checkpoint(&self, id: &str) {
|
||||
pub(crate) fn promote_interrupted_checkpoint(&self, id: &str) {
|
||||
let Ok(Some(checkpoint)) = self.load_session_checkpoint(id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user