diff --git a/lib/actions/thread-actions.js b/lib/actions/thread-actions.js
--- a/lib/actions/thread-actions.js
+++ b/lib/actions/thread-actions.js
@@ -16,7 +16,7 @@
 import { permissionsAndAuthRelatedRequestTimeout } from '../shared/timeouts.js';
 import type {
   DMChangeThreadSettingsOperation,
-  DMThreadSettingsChangesBase,
+  DMThreadSettingsChanges,
 } from '../types/dm-ops.js';
 import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js';
 import {
@@ -132,7 +132,7 @@
 
       invariant(viewerID, 'viewerID should be set');
 
-      const changes: { ...DMThreadSettingsChangesBase } = {};
+      const changes: { ...DMThreadSettingsChanges } = {};
       if (input.changes.name) {
         changes.name = input.changes.name;
       }
diff --git a/lib/shared/dm-ops/add-members-spec.js b/lib/shared/dm-ops/add-members-spec.js
--- a/lib/shared/dm-ops/add-members-spec.js
+++ b/lib/shared/dm-ops/add-members-spec.js
@@ -43,66 +43,6 @@
   };
 }
 
-function createAddNewMembersResults(
-  dmOperation: DMAddMembersOperation,
-  viewerID: string,
-  utilities: ProcessDMOperationUtilities,
-): AddMembersResult {
-  const { editorID, time, messageID, addedUserIDs, threadID } = dmOperation;
-  const messageData =
-    createAddNewMembersMessageDataFromDMOperation(dmOperation);
-  const rawMessageInfos = [
-    rawMessageInfoFromMessageData(messageData, messageID),
-  ];
-  const currentThreadInfo = utilities.threadInfos[threadID];
-  if (!currentThreadInfo.thick) {
-    return {
-      rawMessageInfos: [],
-      updateInfos: [],
-      threadInfo: null,
-    };
-  }
-  const defaultRoleID = values(currentThreadInfo.roles).find(role =>
-    roleIsDefaultRole(role),
-  )?.id;
-  invariant(defaultRoleID, 'Default role ID must exist');
-  const { membershipPermissions } = createRoleAndPermissionForThickThreads(
-    currentThreadInfo.type,
-    currentThreadInfo.id,
-    defaultRoleID,
-  );
-  const newMembers = addedUserIDs
-    .filter(userID => !userIsMember(currentThreadInfo, userID))
-    .map(userID =>
-      minimallyEncodeMemberInfo<ThickMemberInfo>({
-        id: userID,
-        role: defaultRoleID,
-        permissions: membershipPermissions,
-        isSender: editorID === viewerID,
-        subscription: joinThreadSubscription,
-      }),
-    );
-
-  const resultThreadInfo = {
-    ...currentThreadInfo,
-    members: [...currentThreadInfo.members, ...newMembers],
-  };
-  const updateInfos = [
-    {
-      type: updateTypes.UPDATE_THREAD,
-      id: uuid.v4(),
-      time,
-      threadInfo: resultThreadInfo,
-    },
-  ];
-
-  return {
-    rawMessageInfos,
-    updateInfos,
-    threadInfo: resultThreadInfo,
-  };
-}
-
 const addMembersSpec: DMOperationSpec<DMAddMembersOperation> = Object.freeze({
   notificationsCreationData: async (dmOperation: DMAddMembersOperation) => {
     const messageData =
@@ -114,12 +54,57 @@
     viewerID: string,
     utilities: ProcessDMOperationUtilities,
   ) => {
-    const { rawMessageInfos, updateInfos } = createAddNewMembersResults(
-      dmOperation,
-      viewerID,
-      utilities,
+    const { editorID, time, messageID, addedUserIDs, threadID } = dmOperation;
+    const messageData =
+      createAddNewMembersMessageDataFromDMOperation(dmOperation);
+    const rawMessageInfos = [
+      rawMessageInfoFromMessageData(messageData, messageID),
+    ];
+    const currentThreadInfo = utilities.threadInfos[threadID];
+    if (!currentThreadInfo.thick) {
+      return {
+        rawMessageInfos: [],
+        updateInfos: [],
+      };
+    }
+    const defaultRoleID = values(currentThreadInfo.roles).find(role =>
+      roleIsDefaultRole(role),
+    )?.id;
+    invariant(defaultRoleID, 'Default role ID must exist');
+    const { membershipPermissions } = createRoleAndPermissionForThickThreads(
+      currentThreadInfo.type,
+      currentThreadInfo.id,
+      defaultRoleID,
     );
-    return { rawMessageInfos, updateInfos };
+    const newMembers = addedUserIDs
+      .filter(userID => !userIsMember(currentThreadInfo, userID))
+      .map(userID =>
+        minimallyEncodeMemberInfo<ThickMemberInfo>({
+          id: userID,
+          role: defaultRoleID,
+          permissions: membershipPermissions,
+          isSender: editorID === viewerID,
+          subscription: joinThreadSubscription,
+        }),
+      );
+
+    const resultThreadInfo = {
+      ...currentThreadInfo,
+      members: [...currentThreadInfo.members, ...newMembers],
+    };
+    const updateInfos = [
+      {
+        type: updateTypes.UPDATE_THREAD,
+        id: uuid.v4(),
+        time,
+        threadInfo: resultThreadInfo,
+      },
+    ];
+
+    return {
+      rawMessageInfos,
+      updateInfos,
+    };
   },
   canBeProcessed(
     dmOperation: DMAddMembersOperation,
@@ -140,8 +125,4 @@
   supportsAutoRetry: true,
 });
 
-export {
-  addMembersSpec,
-  createAddNewMembersResults,
-  createAddNewMembersMessageDataFromDMOperation,
-};
+export { addMembersSpec, createAddNewMembersMessageDataFromDMOperation };
diff --git a/lib/shared/dm-ops/change-thread-settings-and-add-viewer-spec.js b/lib/shared/dm-ops/change-thread-settings-and-add-viewer-spec.js
deleted file mode 100644
--- a/lib/shared/dm-ops/change-thread-settings-and-add-viewer-spec.js
+++ /dev/null
@@ -1,103 +0,0 @@
-// @flow
-
-import {
-  addViewerToThreadMembersSpec,
-  createAddViewerToThreadMembersResults,
-  createAddViewerToThreadMembersMessageDataFromDMOp,
-} from './add-viewer-to-thread-members-spec.js';
-import {
-  processChangeSettingsOperation,
-  createChangeSettingsMessageDatasAndUpdate,
-} from './change-thread-settings-spec.js';
-import type {
-  DMOperationSpec,
-  ProcessDMOperationUtilities,
-} from './dm-op-spec.js';
-import type { DMChangeThreadSettingsAndAddViewerOperation } from '../../types/dm-ops.js';
-import type { MessageData } from '../../types/message-types.js';
-import { values } from '../../utils/objects.js';
-
-function createAddViewerAndMembersOperation(
-  dmOperation: DMChangeThreadSettingsAndAddViewerOperation,
-) {
-  const { editorID, time, messageIDsPrefix, changes, existingThreadDetails } =
-    dmOperation;
-  const newMemberIDs =
-    changes.newMemberIDs && changes.newMemberIDs.length > 0
-      ? [...new Set(changes.newMemberIDs)]
-      : [];
-  return {
-    type: 'add_viewer_to_thread_members',
-    editorID,
-    time,
-    messageID: `${messageIDsPrefix}/add_members`,
-    addedUserIDs: newMemberIDs,
-    existingThreadDetails,
-  };
-}
-
-function processAddViewerToThreadMembersOperation(
-  dmOperation: DMChangeThreadSettingsAndAddViewerOperation,
-  viewerID: string,
-) {
-  const operation = createAddViewerAndMembersOperation(dmOperation);
-  if (operation.addedUserIDs.length === 0) {
-    return null;
-  }
-  return createAddViewerToThreadMembersResults(operation, viewerID);
-}
-
-const changeThreadSettingsAndAddViewerSpec: DMOperationSpec<DMChangeThreadSettingsAndAddViewerOperation> =
-  Object.freeze({
-    notificationsCreationData: async (
-      dmOperation: DMChangeThreadSettingsAndAddViewerOperation,
-    ) => {
-      const messageDatas: Array<MessageData> = [];
-      const addNewMembersOperation =
-        createAddViewerAndMembersOperation(dmOperation);
-      if (addNewMembersOperation) {
-        const addNewMembersMessageData =
-          createAddViewerToThreadMembersMessageDataFromDMOp(
-            addNewMembersOperation,
-          );
-        messageDatas.push(addNewMembersMessageData);
-      }
-
-      const { fieldNameToMessageData } =
-        createChangeSettingsMessageDatasAndUpdate(dmOperation);
-      messageDatas.push(...values(fieldNameToMessageData));
-      return { messageDatas };
-    },
-    processDMOperation: async (
-      dmOperation: DMChangeThreadSettingsAndAddViewerOperation,
-      viewerID: string,
-      utilities: ProcessDMOperationUtilities,
-    ) => {
-      const addMembersResult = processAddViewerToThreadMembersOperation(
-        dmOperation,
-        viewerID,
-      );
-
-      return processChangeSettingsOperation(
-        dmOperation,
-        viewerID,
-        utilities,
-        addMembersResult,
-      );
-    },
-    canBeProcessed(
-      dmOperation: DMChangeThreadSettingsAndAddViewerOperation,
-      viewerID: string,
-      utilities: ProcessDMOperationUtilities,
-    ) {
-      const operation = createAddViewerAndMembersOperation(dmOperation);
-      return addViewerToThreadMembersSpec.canBeProcessed(
-        operation,
-        viewerID,
-        utilities,
-      );
-    },
-    supportsAutoRetry: true,
-  });
-
-export { changeThreadSettingsAndAddViewerSpec };
diff --git a/lib/shared/dm-ops/change-thread-settings-spec.js b/lib/shared/dm-ops/change-thread-settings-spec.js
--- a/lib/shared/dm-ops/change-thread-settings-spec.js
+++ b/lib/shared/dm-ops/change-thread-settings-spec.js
@@ -3,20 +3,13 @@
 import invariant from 'invariant';
 import uuid from 'uuid';
 
-import {
-  type AddMembersResult,
-  createAddNewMembersResults,
-  createAddNewMembersMessageDataFromDMOperation,
-} from './add-members-spec.js';
 import type {
   DMOperationSpec,
   ProcessDMOperationUtilities,
 } from './dm-op-spec.js';
 import type {
-  DMChangeThreadSettingsAndAddViewerOperation,
   DMChangeThreadSettingsOperation,
-  DMOperationResult,
-  DMThreadSettingsChangesBase,
+  DMThreadSettingsChanges,
 } from '../../types/dm-ops.js';
 import type { MessageData, RawMessageInfo } from '../../types/message-types';
 import { messageTypes } from '../../types/message-types-enum.js';
@@ -27,43 +20,8 @@
 import { values } from '../../utils/objects.js';
 import { rawMessageInfoFromMessageData } from '../message-utils.js';
 
-function createAddMembersOperation(
-  dmOperation: DMChangeThreadSettingsOperation,
-) {
-  const { editorID, time, messageIDsPrefix, changes, threadID } = dmOperation;
-  const newMemberIDs =
-    changes.newMemberIDs && changes.newMemberIDs.length > 0
-      ? [...new Set(changes.newMemberIDs)]
-      : [];
-  if (!changes.newMemberIDs || changes.newMemberIDs.length === 0) {
-    return null;
-  }
-  return {
-    type: 'add_members',
-    editorID,
-    time,
-    messageID: `${messageIDsPrefix}/add_members`,
-    addedUserIDs: newMemberIDs,
-    threadID,
-  };
-}
-
-function processAddMembersOperation(
-  dmOperation: DMChangeThreadSettingsOperation,
-  viewerID: string,
-  utilities: ProcessDMOperationUtilities,
-) {
-  const operation = createAddMembersOperation(dmOperation);
-  if (!operation) {
-    return null;
-  }
-  return createAddNewMembersResults(operation, viewerID, utilities);
-}
-
 function getThreadIDFromChangeThreadSettingsDMOp(
-  dmOperation:
-    | DMChangeThreadSettingsOperation
-    | DMChangeThreadSettingsAndAddViewerOperation,
+  dmOperation: DMChangeThreadSettingsOperation,
 ): string {
   return dmOperation.type === 'change_thread_settings'
     ? dmOperation.threadID
@@ -71,18 +29,16 @@
 }
 
 function createChangeSettingsMessageDatasAndUpdate(
-  dmOperation:
-    | DMChangeThreadSettingsOperation
-    | DMChangeThreadSettingsAndAddViewerOperation,
+  dmOperation: DMChangeThreadSettingsOperation,
 ): {
   +fieldNameToMessageData: { +[fieldName: string]: ChangeSettingsMessageData },
-  +threadInfoUpdate: DMThreadSettingsChangesBase,
+  +threadInfoUpdate: DMThreadSettingsChanges,
 } {
   const { changes, editorID, time } = dmOperation;
   const { name, description, color, avatar } = changes;
   const threadID = getThreadIDFromChangeThreadSettingsDMOp(dmOperation);
 
-  const threadInfoUpdate: { ...DMThreadSettingsChangesBase } = {};
+  const threadInfoUpdate: { ...DMThreadSettingsChanges } = {};
 
   if (name !== undefined && name !== null) {
     threadInfoUpdate.name = name;
@@ -124,75 +80,12 @@
   return { fieldNameToMessageData, threadInfoUpdate };
 }
 
-function processChangeSettingsOperation(
-  dmOperation:
-    | DMChangeThreadSettingsOperation
-    | DMChangeThreadSettingsAndAddViewerOperation,
-  viewerID: string,
-  utilities: ProcessDMOperationUtilities,
-  addMembersResult: ?AddMembersResult,
-): DMOperationResult {
-  const { time, messageIDsPrefix } = dmOperation;
-  const threadID = getThreadIDFromChangeThreadSettingsDMOp(dmOperation);
-
-  let threadInfoToUpdate: ?RawThreadInfo = utilities.threadInfos[threadID];
-  const updateInfos: Array<ClientUpdateInfo> = [];
-  const rawMessageInfos: Array<RawMessageInfo> = [];
-
-  if (addMembersResult) {
-    if (addMembersResult.threadInfo) {
-      threadInfoToUpdate = addMembersResult.threadInfo;
-    }
-    updateInfos.push(...addMembersResult.updateInfos);
-    rawMessageInfos.push(...addMembersResult.rawMessageInfos);
-  }
-
-  invariant(threadInfoToUpdate?.thick, 'Thread should be thick');
-  const { fieldNameToMessageData, threadInfoUpdate } =
-    createChangeSettingsMessageDatasAndUpdate(dmOperation);
-
-  const fieldNameToMessageDataPairs = Object.entries(fieldNameToMessageData);
-  rawMessageInfos.push(
-    ...fieldNameToMessageDataPairs.map(([fieldName, messageData]) =>
-      rawMessageInfoFromMessageData(
-        messageData,
-        `${messageIDsPrefix}/${fieldName}`,
-      ),
-    ),
-  );
-
-  threadInfoToUpdate = {
-    ...threadInfoToUpdate,
-    ...threadInfoUpdate,
-  };
-
-  if (fieldNameToMessageDataPairs.length > 0) {
-    updateInfos.push({
-      type: updateTypes.UPDATE_THREAD,
-      id: uuid.v4(),
-      time,
-      threadInfo: threadInfoToUpdate,
-    });
-  }
-
-  return {
-    rawMessageInfos,
-    updateInfos,
-  };
-}
-
 const changeThreadSettingsSpec: DMOperationSpec<DMChangeThreadSettingsOperation> =
   Object.freeze({
     notificationsCreationData: async (
       dmOperation: DMChangeThreadSettingsOperation,
     ) => {
       const messageDatas: Array<MessageData> = [];
-      const addNewMembersOperation = createAddMembersOperation(dmOperation);
-      if (addNewMembersOperation) {
-        const addNewMembersMessageData =
-          createAddNewMembersMessageDataFromDMOperation(addNewMembersOperation);
-        messageDatas.push(addNewMembersMessageData);
-      }
 
       const { fieldNameToMessageData } =
         createChangeSettingsMessageDatasAndUpdate(dmOperation);
@@ -204,18 +97,47 @@
       viewerID: string,
       utilities: ProcessDMOperationUtilities,
     ) => {
-      const addMembersResult = processAddMembersOperation(
-        dmOperation,
-        viewerID,
-        utilities,
-      );
+      const { time, messageIDsPrefix } = dmOperation;
+      const threadID = getThreadIDFromChangeThreadSettingsDMOp(dmOperation);
+
+      let threadInfoToUpdate: ?RawThreadInfo = utilities.threadInfos[threadID];
+      const updateInfos: Array<ClientUpdateInfo> = [];
+      const rawMessageInfos: Array<RawMessageInfo> = [];
+
+      invariant(threadInfoToUpdate?.thick, 'Thread should be thick');
+      const { fieldNameToMessageData, threadInfoUpdate } =
+        createChangeSettingsMessageDatasAndUpdate(dmOperation);
 
-      return processChangeSettingsOperation(
-        dmOperation,
-        viewerID,
-        utilities,
-        addMembersResult,
+      const fieldNameToMessageDataPairs = Object.entries(
+        fieldNameToMessageData,
       );
+      rawMessageInfos.push(
+        ...fieldNameToMessageDataPairs.map(([fieldName, messageData]) =>
+          rawMessageInfoFromMessageData(
+            messageData,
+            `${messageIDsPrefix}/${fieldName}`,
+          ),
+        ),
+      );
+
+      threadInfoToUpdate = {
+        ...threadInfoToUpdate,
+        ...threadInfoUpdate,
+      };
+
+      if (fieldNameToMessageDataPairs.length > 0) {
+        updateInfos.push({
+          type: updateTypes.UPDATE_THREAD,
+          id: uuid.v4(),
+          time,
+          threadInfo: threadInfoToUpdate,
+        });
+      }
+
+      return {
+        rawMessageInfos,
+        updateInfos,
+      };
     },
     canBeProcessed(
       dmOperation: DMChangeThreadSettingsOperation,
@@ -236,8 +158,4 @@
     supportsAutoRetry: true,
   });
 
-export {
-  changeThreadSettingsSpec,
-  processChangeSettingsOperation,
-  createChangeSettingsMessageDatasAndUpdate,
-};
+export { changeThreadSettingsSpec, createChangeSettingsMessageDatasAndUpdate };
diff --git a/lib/shared/dm-ops/dm-op-specs.js b/lib/shared/dm-ops/dm-op-specs.js
--- a/lib/shared/dm-ops/dm-op-specs.js
+++ b/lib/shared/dm-ops/dm-op-specs.js
@@ -2,7 +2,6 @@
 
 import { addMembersSpec } from './add-members-spec.js';
 import { addViewerToThreadMembersSpec } from './add-viewer-to-thread-members-spec.js';
-import { changeThreadSettingsAndAddViewerSpec } from './change-thread-settings-and-add-viewer-spec.js';
 import { changeThreadSettingsSpec } from './change-thread-settings-spec.js';
 import { createSidebarSpec } from './create-sidebar-spec.js';
 import { createThreadSpec } from './create-thread-spec.js';
@@ -29,6 +28,4 @@
   [dmOperationTypes.LEAVE_THREAD]: leaveThreadSpec,
   [dmOperationTypes.REMOVE_MEMBERS]: removeMembersSpec,
   [dmOperationTypes.CHANGE_THREAD_SETTINGS]: changeThreadSettingsSpec,
-  [dmOperationTypes.CHANGE_THREAD_SETTINGS_AND_ADD_VIEWER]:
-    changeThreadSettingsAndAddViewerSpec,
 });
diff --git a/lib/types/dm-ops.js b/lib/types/dm-ops.js
--- a/lib/types/dm-ops.js
+++ b/lib/types/dm-ops.js
@@ -1,6 +1,6 @@
 // @flow
 
-import t, { type TInterface, type TUnion, type TStructProps } from 'tcomb';
+import t, { type TInterface, type TUnion } from 'tcomb';
 
 import { clientAvatarValidator, type ClientAvatar } from './avatar-types.js';
 import type { RawMessageInfo } from './message-types.js';
@@ -28,8 +28,6 @@
   LEAVE_THREAD: 'leave_thread',
   REMOVE_MEMBERS: 'remove_members',
   CHANGE_THREAD_SETTINGS: 'change_thread_settings',
-  CHANGE_THREAD_SETTINGS_AND_ADD_VIEWER:
-    'change_thread_settings_and_add_viewer',
 });
 export type DMOperationType = $Values<typeof dmOperationTypes>;
 
@@ -264,61 +262,34 @@
     removedUserIDs: t.list(tUserID),
   });
 
-export type DMThreadSettingsChangesBase = {
+export type DMThreadSettingsChanges = {
   +name?: string,
   +description?: string,
   +color?: string,
   +avatar?: ClientAvatar,
 };
 
-type DMThreadSettingsChanges = $ReadOnly<{
-  ...DMThreadSettingsChangesBase,
-  +newMemberIDs?: $ReadOnlyArray<string>,
-}>;
-
-type DMChangeThreadSettingsBase = {
+export type DMChangeThreadSettingsOperation = $ReadOnly<{
+  +type: 'change_thread_settings',
+  +threadID: string,
   +editorID: string,
   +time: number,
   +changes: DMThreadSettingsChanges,
   +messageIDsPrefix: string,
-};
-
-const dmChangeThreadSettingsBaseValidatorShape: TStructProps<DMChangeThreadSettingsBase> =
-  {
+}>;
+export const dmChangeThreadSettingsOperationValidator: TInterface<DMChangeThreadSettingsOperation> =
+  tShape<DMChangeThreadSettingsOperation>({
+    type: tString(dmOperationTypes.CHANGE_THREAD_SETTINGS),
+    threadID: t.String,
     editorID: tUserID,
     time: t.Number,
     changes: tShape({
       name: t.maybe(t.String),
       description: t.maybe(t.String),
       color: t.maybe(tColor),
-      newMemberIDs: t.maybe(t.list(tUserID)),
       avatar: t.maybe(clientAvatarValidator),
     }),
     messageIDsPrefix: t.String,
-  };
-
-export type DMChangeThreadSettingsOperation = $ReadOnly<{
-  +type: 'change_thread_settings',
-  +threadID: string,
-  ...DMChangeThreadSettingsBase,
-}>;
-export const dmChangeThreadSettingsOperationValidator: TInterface<DMChangeThreadSettingsOperation> =
-  tShape<DMChangeThreadSettingsOperation>({
-    type: tString(dmOperationTypes.CHANGE_THREAD_SETTINGS),
-    threadID: t.String,
-    ...dmChangeThreadSettingsBaseValidatorShape,
-  });
-
-export type DMChangeThreadSettingsAndAddViewerOperation = $ReadOnly<{
-  +type: 'change_thread_settings_and_add_viewer',
-  +existingThreadDetails: CreateThickRawThreadInfoInput,
-  ...DMChangeThreadSettingsBase,
-}>;
-export const dmChangeThreadSettingsAndAddViewerOperationValidator: TInterface<DMChangeThreadSettingsAndAddViewerOperation> =
-  tShape<DMChangeThreadSettingsAndAddViewerOperation>({
-    type: tString(dmOperationTypes.CHANGE_THREAD_SETTINGS_AND_ADD_VIEWER),
-    existingThreadDetails: createThickRawThreadInfoInputValidator,
-    ...dmChangeThreadSettingsBaseValidatorShape,
   });
 
 export type DMOperation =
@@ -332,8 +303,7 @@
   | DMJoinThreadOperation
   | DMLeaveThreadOperation
   | DMRemoveMembersOperation
-  | DMChangeThreadSettingsOperation
-  | DMChangeThreadSettingsAndAddViewerOperation;
+  | DMChangeThreadSettingsOperation;
 export const dmOperationValidator: TUnion<DMOperation> = t.union([
   dmCreateThreadOperationValidator,
   dmCreateSidebarOperationValidator,
@@ -346,7 +316,6 @@
   dmLeaveThreadOperationValidator,
   dmRemoveMembersOperationValidator,
   dmChangeThreadSettingsOperationValidator,
-  dmChangeThreadSettingsAndAddViewerOperationValidator,
 ]);
 
 export type DMOperationResult = {