Skip to content

Commit 4435473

Browse files
committed
fix: minimize TOCTOU window — reset_session before rename on failure path
Address 擺渡 F1: on ws failure, call reset_session immediately to kill the session before doing rename_thread I/O. This shrinks the race window where a concurrent message could hit the doomed session. Title is still applied on both success and failure paths (per 主人's requirement), but failure path now does reset first.
1 parent f779506 commit 4435473

1 file changed

Lines changed: 18 additions & 10 deletions

File tree

src/dispatch.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -697,20 +697,19 @@ async fn dispatch_batch(
697697
if created_now {
698698
if let Some(pr) = parse_result {
699699
if !pr.metadata.raw.is_empty() {
700-
// Apply [[title:...]] override before ws check — title is independent.
701-
if let Some(title) = &pr.metadata.title {
702-
if !title.is_empty() {
703-
if let Err(e) = adapter.rename_thread(&dispatch_channel, title).await {
704-
warn!(session_key, error = %e, "failed to apply title directive");
705-
}
706-
}
707-
}
700+
// Apply [[title:...]] independently — works regardless of ws outcome.
701+
let title_to_apply = pr.metadata.title.clone();
708702

709703
// If workspace resolution failed on a NEW session, rollback and abort.
710-
// The session was created with default cwd — we must not leave it alive
711-
// when the user explicitly requested a different workspace (ADR §3.1).
704+
// Reset FIRST to minimize TOCTOU window (擺渡 F1), then rename.
712705
if let Some(Err(e)) = ws_resolved {
713706
target.reset_session(&session_key).await;
707+
// Apply title after reset so the thread is identifiable.
708+
if let Some(ref title) = title_to_apply {
709+
if !title.is_empty() {
710+
let _ = adapter.rename_thread(&dispatch_channel, title).await;
711+
}
712+
}
714713
let _ = adapter
715714
.send_message(&dispatch_channel, &format!("⚠️ {e}"))
716715
.await;
@@ -722,6 +721,15 @@ async fn dispatch_batch(
722721
if let Some(first_msg) = batch.first_mut() {
723722
first_msg.prompt = pr.prompt;
724723
}
724+
725+
// Apply title on success path.
726+
if let Some(ref title) = title_to_apply {
727+
if !title.is_empty() {
728+
if let Err(e) = adapter.rename_thread(&dispatch_channel, title).await {
729+
warn!(session_key, error = %e, "failed to apply title directive");
730+
}
731+
}
732+
}
725733
}
726734
}
727735
}

0 commit comments

Comments
 (0)