- Session gains mu sync.RWMutex + SnapshotMessages/AppendMessage/
TouchLastAccessed/SetProjectID/Project accessors
- sendMessageInternal, hydrateVisibleHistory, getOrCreateSession,
cleanStaleSessionsLocked, handleChat, handleChatStream,
enrichSessionWorkflowStage, bindSessionDocumentSummaryReader all use
locked accessors instead of raw field access
- ProjectID mutation now goes through SetProjectID (only when changed),
closing the cross-project pollution window in handleChat/handleChatStream
Co-authored-by: Cursor <cursoragent@cursor.com>