unarchive moves a conversation between partitions without a lock
- Status: Todo
- Kind: Bug
- Authors: jp
- Date: 2026-08-15
Workspace::unarchive_conversation moves a conversation directory out of the archive partition into the live one without holding its conversation lock. All three call sites go in bare: unarchive.rs:41, use_.rs:163, use_.rs:248.
Anything that reads the two partitions concurrently can therefore observe the conversation in neither. Workspace::cleanup_stale_files is the case that prompted this: it treats "absent from both partitions" as grounds for pruning a session's history entry, and falls back to lock_info to spot a conversation that is mid-write. That fallback finds nothing during an unarchive, because no lock is taken.
Scope
Cleanup's own exposure is already narrowed in f6a3c957: it re-reads the live partition after the archive scan, so a single move in either direction is caught by one of the scans. That does not cover multiple concurrent transitions, and it does nothing for any other reader of the two partitions.
The underlying issue is that unarchive is the one partition-moving operation that does not participate in the conversation-locking protocol. archive takes a ConversationMut and therefore holds the lock; unarchive takes a bare &ConversationId.
Notes
Fixing this means changing the signature of unarchive_conversation to require proof of the lock, in the shape archive_conversation already uses, and updating the three call sites to acquire it. Worth checking whether the picker paths in use_.rs can acquire a lock at the point they currently call through, or whether they need restructuring first.