[Swift / Contacts] “Remove from contacts” removes only the subscription; the chat and its history remain #14
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
[Swift / Contacts] “Remove from contacts” removes only the subscription; the chat and its history remain
Severity: Major
Issue ID: CONT-003-APP, CONT-003c · QA case: CONT-003 (Fail)
Date: November 3, 2026
Summary
The “Remove from contacts” action removes the contact subscription but leaves the existing chat and its message history on the device.
This conflicts with the product requirement that removing a contact should remove both the subscription and the chat.
The current behavior appears intentional. The confirmation dialog explicitly states:
“You stop seeing each other's status. The chat stays.”
The user is therefore not misled, but the implemented behavior differs from the documented requirement.
Affected component: iOS application, contact profile and removal flow:
AnotherIM/Live/ChatDetailsClient+Live.swift
removeContact
libtacky performs the requested roster remove operation; it does not remove the chat automatically.
Environment
Item Details
Application anotherim-swift
c5fdeae, branch feat/ui-redesign, build 93libtacky 2f42a2f2 / v1.2.0-beta2
Server ejabberd 26.09 from anotherim-server b9e675d
Test setup main running libtacky with the application profile; stranger using slixmpp
Verification libtacky test runs + source-code review of build 93
Note: The current UI behavior has not yet been manually verified on build 93. The application verdict is based on source-code review.
Preconditions
main and stranger are mutual contacts (both).
An existing message history is present between them.
Steps to Reproduce
Test environment
Run:
SWIFT_SRC= bash setup/run_all.sh contacts
This covers CONT-003, CONT-003c, and CONT-003-APP.
Application flow
Open a contact's profile.
Select “Remove from contacts” (ChatDetailsView.swift:519).
Confirm “Remove” in the confirmation dialog.
The contact list uses the same removal action via ContactsClient+Live.swift:43.
Expected Behavior
According to the product requirements, removing a contact should remove:
the contact subscription; and
the chat with that contact.
Relevant QA case: CONT-003, “Remove contact (subscription + chat)”.
Actual Behavior
libtacky
In run 02fddb03 (evidence/run_contacts_1.out):
CONT-003 PASS: after roster remove, the stranger's roster entry is removed from the server.
The stranger receives unavailable, unsubscribe, and unsubscribed.
CONT-003c: the chat remains present in chatlist get both before and after roster remove.
The same libtacky behavior was confirmed in 2/2 runs: 02fddb03 and 5c4087d2.
Application
ChatDetailsClient+Live.swift:106-108 implements contact removal as:
removeContact: { chat in
try await throwing {
try await online(chat).rosterRemove(chat.account, jid: chat.jid)
}
},
The flow calls only rosterRemove (TackyAPI.swift:633).
It does not:
clear the message history via messageClearHistory (available at TackyAPI.swift:550); or
close or remove the chat from the chat list.
For comparison, group removal explicitly clears history:
RoomService.remove(… clearHistory: true)
(ChatDetailsClient+Live.swift:135).
Reproduction Status
The application behavior is deterministic based on the reviewed source code.
CONT-003-APP is a static source-code verification. The 2/2 test runs apply to the libtacky behavior covered by CONT-003 and CONT-003c.
Root Cause
ChatDetailsClient+Live.swift:106-108 implements “Remove from contacts” by calling only roster remove.
libtacky does not remove an existing chat as a side effect of this operation, as confirmed by CONT-003c.
As a result, the contact subscription is removed while the chat and its history remain.
Suggested Fix
Consider extending removeContact to perform the required chat cleanup after rosterRemove, for example:
Clear the message history with messageClearHistory.
Remove or close the chat using the appropriate chatlist operation.
Group removal may provide a useful implementation reference.
Data-retention consideration: according to finding RT-20, clearing message history moves records to message_archive rather than physically deleting them. The intended data-retention behavior should therefore be clarified before implementing the fix.
The final implementation and expected behavior should be confirmed by the development and product teams, particularly because the current UI explicitly says “The chat stays.”
Verification After Fix
Create a chat with several messages between two mutual contacts.
Select “Remove from contacts” and confirm the action.
Verify whether the chat remains in the chat list.
If the chat remains accessible, verify whether its message history is still visible.
On the other account, verify the subscription/contact state.
Record screenshots before and after the action, UTC timestamps, and relevant diagnostics entries such as roster remove and chatlist.
Evidence and Status
Evidence:
evidence/run_contacts_.out
evidence/contacts_.json
evidence/ChatDetailsClient+Live.swift_100-112.txt
evidence/TackyAPI.swift_630-636.txt
Test report:
results/2026-11-03_calls_auth_contacts.md, section 4.
Verified: two test-environment runs and the relevant application source code in
c5fdeae.Not verified: the visible UI behavior in build 93.
Open question: Is the current behavior — explicitly stating “The chat stays” — intentional and should the product requirements be updated, or should the implementation be changed to remove the chat as required?
❯ - #14: Fixed in
4832765(product decision: the chat goes too). "Remove from contacts" now also clears the history on this device and closes the chat.