core: remove SimpleX Status preset contact (#7231)

* core: remove SimpleX Status preset contact

Preset contact cards are only created at user record creation
(createPresetContactCards), so this affects new profiles only;
existing profiles keep their stored SimpleX Status contact.

Removing the card shifts contact ids allocated after /create user
down by one, hence the test id updates.

* plans: justify SimpleX Status preset contact removal
This commit is contained in:
Narasimha-sc
2026-07-24 09:05:12 +01:00
committed by GitHub
parent fc28914455
commit dc3c106bda
5 changed files with 79 additions and 54 deletions
@@ -0,0 +1,41 @@
# Remove the SimpleX Status preset contact
Branch: `nd/remove-status-preset-contact` · PR #7231 (supersedes #7200)
## 1. Problem statement
Every new profile gets a "SimpleX Status" preset contact card. It is too confusing for non-technical users: it looks like a person or a chat, but it is an automated broadcast bot, and tapping it opens a connect dialog rather than content. On top of that, its stored contact link is the old `simplex:/contact/#/...` invitation address; the intended replacement is a channel, which a preset *contact* card cannot deliver (see §3).
## 2. Solution summary
Delete the preset entirely:
- `simplexStatusContactProfile` removed from `Library/Internal.hs` (14 lines incl. inline logo).
- Its `createContact` call removed from `createPresetContactCards` in `Library/Commands.hs` (one line; the "Ask SimpleX Team" preset stays).
- Test expectations updated mechanically (see §5).
No migration for existing profiles: preset cards are only ever created inside user record creation (`APICreateActiveUser``createPresetContactCards`), so existing profiles keep their stored card, matching how presets have always behaved. Users can still reach the bot via https://status.simplex.chat and the blog.
## 3. Why not fix the link instead (the #7200 dead end)
#7200 swapped the preset's link to a channel link (`https://smp5.simplex.im/c#...`). That cannot work: preset cards are contacts, and tapping one runs `APIConnectContactViaAddress` → `prepareContact`/`joinContact` — the direct-contact handshake. Channel short links (`/c#` decodes to `CCTChannel`) must be joined via `APIConnectPreparedGroup`; `APIConnect` explicitly rejects them ("channel links must be connected via APIConnectPreparedGroup"), but the contact-card path has no such guard and silently performs the wrong handshake. Making the status channel a preset would require a preset *prepared channel* — `APIPrepareGroup` needs a full connReq plus `GroupShortLinkData`, run after the user is active — a substantially larger change than wanted, for a card that confuses the users it is shown to.
## 4. Scope of effect
- **New profiles**: get only the "Ask SimpleX Team" card.
- **Existing profiles**: unchanged; their stored SimpleX Status contact remains until the user deletes it.
- **Discovery**: this removes the status bot's only in-app discovery path for new users — deliberate, since the card was doing more harm (confusion) than good (discovery).
## 5. Test impact
Removing the card shifts contact ids allocated after `/create user` down by one:
- 10 chat-list / `hasContactProfiles` expectations lose the status entry (`Direct.hs`, `Profiles.hs`).
- 24 numeric contact refs shift: `@6``@5` in `Direct.hs`; `@5``@4` and `@6``@5` in `Profiles.hs`, plus the id-arithmetic comments.
- `configureTimedMessages alice bob "6" "3"``"5"` — the contact id travels as a bare string argument, invisible to `@N`-pattern search; caught only by running the tests.
Verified unaffected: group ids (`#N`), pending-connection ids (`:N` — preset cards create no connection rows), user ids, unread/`/users` counts (cards create no chat items), `MobileTests`/`RemoteTests`/`Local.hs` (harness users bypass presets), display-name allocation (per-user).
## 6. Verification
All 8 non-timing-sensitive affected tests pass locally. The 3 TTL/timed-message tests (`testUsersDifferentCIExpirationTTL`, `testUsersRestartCIExpiration`, `testUsersTimedMessages`) fail identically on the base commit `6bb1da9e8` in the same environment — pre-existing cleanup-manager timing flakes (cf. `d7010d527`), not regressions. The packaged desktop build was verified to contain no "SimpleX Status" strings in `libsimplex.so` while retaining "Ask SimpleX Team".
-1
View File
@@ -441,7 +441,6 @@ processChatCommand cxt nm = \case
where
createPresetContactCards :: DB.Connection -> User -> ExceptT StoreError IO ()
createPresetContactCards db user = do
createContact db cxt user simplexStatusContactProfile
createContact db cxt user simplexTeamContactProfile
chooseServers :: Maybe User -> CM ([UpdatedUserOperatorServers], (NonEmpty (ServerCfg 'PSMP), NonEmpty (ServerCfg 'PXFTP)))
chooseServers user_ = do
File diff suppressed because one or more lines are too long
+24 -24
View File
@@ -1920,14 +1920,14 @@ testMultipleUserAddresses =
cLinkAlisa <- getContactLink alice True
bob ##> ("/c " <> cLinkAlisa)
alice <#? bob
alice #$> ("/_get chats 2 pcc=on", chats, [("@bob", "Audio/video calls: enabled"), ("@Ask SimpleX Team", ""), ("@SimpleX Status", ""), ("*", "")])
alice #$> ("/_get chats 2 pcc=on", chats, [("@bob", "Audio/video calls: enabled"), ("@Ask SimpleX Team", ""), ("*", "")])
alice ##> "/ac bob"
alice <## "bob (Bob): accepting contact request, you can send messages to contact"
concurrently_
(bob <## "alisa: contact is connected")
(alice <## "bob (Bob): contact is connected")
threadDelay 100000
alice #$> ("/_get chats 2 pcc=on", chats, [("@bob", lastChatFeature), ("@Ask SimpleX Team", ""), ("@SimpleX Status", ""), ("*", "")])
alice #$> ("/_get chats 2 pcc=on", chats, [("@bob", lastChatFeature), ("@Ask SimpleX Team", ""), ("*", "")])
alice <##> bob
bob #> "@alice hey alice"
@@ -1958,7 +1958,7 @@ testMultipleUserAddresses =
(cath <## "alisa: contact is connected")
(alice <## "cath (Catherine): contact is connected")
threadDelay 100000
alice #$> ("/_get chats 2 pcc=on", chats, [("@cath", lastChatFeature), ("@bob", "hey"), ("@Ask SimpleX Team", ""), ("@SimpleX Status", ""), ("*", "")])
alice #$> ("/_get chats 2 pcc=on", chats, [("@cath", lastChatFeature), ("@bob", "hey"), ("@Ask SimpleX Team", ""), ("*", "")])
alice <##> cath
-- first user doesn't have cath as contact
@@ -2171,7 +2171,7 @@ testUsersDifferentCIExpirationTTL ps = do
bob #> "@alisa alisa 4"
alice <# "bob> alisa 4"
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
threadDelay 3000000
@@ -2184,11 +2184,11 @@ testUsersDifferentCIExpirationTTL ps = do
-- second user messages
alice ##> "/user alisa"
showActiveUser alice "alisa"
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
threadDelay 2100000
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner")])
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner")])
where
cfg = testCfg {initialCleanupManagerDelay = 0, cleanupManagerStepDelay = 0, ciExpirationInterval = 500000}
@@ -2254,7 +2254,7 @@ testUsersRestartCIExpiration ps = do
bob #> "@alisa alisa 4"
alice <# "bob> alisa 4"
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
threadDelay 3000000
@@ -2267,11 +2267,11 @@ testUsersRestartCIExpiration ps = do
-- second user messages
alice ##> "/user alisa"
showActiveUser alice "alisa"
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
threadDelay 4000000
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner")])
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner")])
where
cfg = testCfg {initialCleanupManagerDelay = 0, cleanupManagerStepDelay = 0, ciExpirationInterval = 500000}
@@ -2313,7 +2313,7 @@ testEnableCIExpirationOnlyForOneUser ps = do
bob #> "@alisa alisa 4"
alice <# "bob> alisa 4"
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
threadDelay 2000000
@@ -2325,14 +2325,14 @@ testEnableCIExpirationOnlyForOneUser ps = do
-- messages are not deleted for second user
alice ##> "/user alisa"
showActiveUser alice "alisa"
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
withTestChatCfg ps cfg "alice" $ \alice -> do
alice <## "subscribed 1 connections on server localhost"
alice <## "subscribed 1 connections on server localhost"
-- messages are not deleted for second user after restart
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
alice #> "@bob alisa 5"
bob <# "alisa> alisa 5"
@@ -2342,7 +2342,7 @@ testEnableCIExpirationOnlyForOneUser ps = do
threadDelay 2000000
-- new messages are not deleted for second user
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4"), (1, "alisa 5"), (0, "alisa 6")])
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4"), (1, "alisa 5"), (0, "alisa 6")])
where
cfg = testCfg {initialCleanupManagerDelay = 0, cleanupManagerStepDelay = 0, ciExpirationInterval = 500000}
@@ -2376,12 +2376,12 @@ testDisableCIExpirationOnlyForOneUser ps = do
bob #> "@alisa alisa 2"
alice <# "bob> alisa 2"
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2")])
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2")])
threadDelay 2000000
-- second user messages are deleted
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner")])
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner")])
withTestChatCfg ps cfg "alice" $ \alice -> do
alice <## "subscribed 1 connections on server localhost"
@@ -2395,12 +2395,12 @@ testDisableCIExpirationOnlyForOneUser ps = do
bob #> "@alisa alisa 4"
alice <# "bob> alisa 4"
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner"), (1, "alisa 3"), (0, "alisa 4")])
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner"), (1, "alisa 3"), (0, "alisa 4")])
threadDelay 3000000
-- second user messages are deleted
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner")])
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner")])
where
cfg = testCfg {initialCleanupManagerDelay = 0, cleanupManagerStepDelay = 0, ciExpirationInterval = 500000}
@@ -2415,7 +2415,7 @@ testUsersTimedMessages ps' = do
alice ##> "/create user alisa"
showActiveUser alice "alisa"
connectUsers alice bob
configureTimedMessages alice bob "6" "3"
configureTimedMessages alice bob "5" "3"
-- first user messages
alice ##> "/user alice"
@@ -2444,7 +2444,7 @@ testUsersTimedMessages ps' = do
alice ##> "/user alisa"
showActiveUser alice "alisa"
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner"), (1, "alisa 1"), (0, "alisa 2")])
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner"), (1, "alisa 1"), (0, "alisa 2")])
threadDelay 1000000
@@ -2457,7 +2457,7 @@ testUsersTimedMessages ps' = do
alice ##> "/user alisa"
showActiveUser alice "alisa"
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner"), (1, "alisa 1"), (0, "alisa 2")])
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner"), (1, "alisa 1"), (0, "alisa 2")])
threadDelay 1000000
@@ -2466,7 +2466,7 @@ testUsersTimedMessages ps' = do
alice ##> "/user"
showActiveUser alice "alisa"
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner")])
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner")])
-- first user messages
alice ##> "/user alice"
@@ -2496,7 +2496,7 @@ testUsersTimedMessages ps' = do
alice ##> "/user alisa"
showActiveUser alice "alisa"
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner"), (1, "alisa 3"), (0, "alisa 4")])
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner"), (1, "alisa 3"), (0, "alisa 4")])
-- messages are deleted after restart
threadDelay 1000000
@@ -2510,7 +2510,7 @@ testUsersTimedMessages ps' = do
alice ##> "/user alisa"
showActiveUser alice "alisa"
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner"), (1, "alisa 3"), (0, "alisa 4")])
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner"), (1, "alisa 3"), (0, "alisa 4")])
threadDelay 1000000
@@ -2519,7 +2519,7 @@ testUsersTimedMessages ps' = do
alice ##> "/user"
showActiveUser alice "alisa"
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner")])
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner")])
where
ps = ps' {printOutput = True} :: TestParams
configureTimedMessages :: HasCallStack => TestCC -> TestCC -> String -> String -> IO ()
+14 -14
View File
@@ -3934,14 +3934,14 @@ testShortLinkChangePreparedContactUser = testChat2 aliceProfile bobProfile test
bob ##> ("/_prepare contact 1 " <> fullLink <> " " <> shortLink <> " " <> contactSLinkData)
bob <## "alice: contact is prepared"
-- 2 ids are for "user contacts", 2 ids are for second user contact cards, so alice is id 5
bob ##> "/_set contact user @5 2"
-- 2 ids are for "user contacts", 1 id is for second user contact card, so alice is id 4
bob ##> "/_set contact user @4 2"
bob <## "contact alice changed from user bob to user robert"
bob ##> "/user robert"
showActiveUser bob "robert"
bob ##> "/_connect contact @5 text hello"
bob ##> "/_connect contact @4 text hello"
bob
<### [ "alice: connection started",
WithTime "@alice hello"
@@ -3955,8 +3955,8 @@ testShortLinkChangePreparedContactUser = testChat2 aliceProfile bobProfile test
alice @@@ [("@robert", "hey")]
alice `hasContactProfiles` ["alice", "robert"]
bob #$> ("/_get chats 2 pcc=on", chats, [("@alice", "hey"), ("@Ask SimpleX Team", ""), ("@SimpleX Status", ""), ("*", "")])
bob `hasContactProfiles` ["robert", "alice", "Ask SimpleX Team", "SimpleX Status"]
bob #$> ("/_get chats 2 pcc=on", chats, [("@alice", "hey"), ("@Ask SimpleX Team", ""), ("*", "")])
bob `hasContactProfiles` ["robert", "alice", "Ask SimpleX Team"]
bob ##> "/user bob"
showActiveUser bob "bob (Bob)"
bob @@@ []
@@ -3984,16 +3984,16 @@ testShortLinkChangePreparedContactUserDuplicate = testChat2 aliceProfile bobProf
bob <## "alice: contact is prepared"
-- 2 ids are for "user contacts"
-- 2 ids are for second user contact cards
-- 1 id is for second user contact card
-- 1 for second user's alice
-- so this alice is id 6
bob ##> "/_set contact user @6 2"
-- so this alice is id 5
bob ##> "/_set contact user @5 2"
bob <## "contact alice changed from user bob to user robert, new local name: alice_1"
bob ##> "/user robert"
showActiveUser bob "robert"
bob ##> "/_connect contact @6 text hello"
bob ##> "/_connect contact @5 text hello"
bob
<### [ "alice_1: connection started",
WithTime "@alice_1 hello"
@@ -4012,8 +4012,8 @@ testShortLinkChangePreparedContactUserDuplicate = testChat2 aliceProfile bobProf
alice @@@ [("@robert", "hey"), ("@robert_1", "hey")]
alice `hasContactProfiles` ["alice", "robert", "robert"]
bob #$> ("/_get chats 2 pcc=on", chats, [("@alice", "hey"), ("@alice_1", "hey"), ("@Ask SimpleX Team", ""), ("@SimpleX Status", ""), ("*", "")])
bob `hasContactProfiles` ["robert", "alice", "alice", "Ask SimpleX Team", "SimpleX Status"]
bob #$> ("/_get chats 2 pcc=on", chats, [("@alice", "hey"), ("@alice_1", "hey"), ("@Ask SimpleX Team", ""), ("*", "")])
bob `hasContactProfiles` ["robert", "alice", "alice", "Ask SimpleX Team"]
bob ##> "/user bob"
showActiveUser bob "bob (Bob)"
bob @@@ []
@@ -4106,8 +4106,8 @@ testShortLinkChangePreparedGroupUser = testChat3 aliceProfile bobProfile cathPro
alice @@@ [("#team", "3"), ("@cath","sent invitation to join group team as admin")]
alice `hasContactProfiles` ["alice", "cath", "robert"]
bob #$> ("/_get chats 2 pcc=on", chats, [("#team", "3"), ("@Ask SimpleX Team", ""), ("@SimpleX Status", ""), ("*", "")])
bob `hasContactProfiles` ["robert", "alice", "cath", "Ask SimpleX Team", "SimpleX Status"]
bob #$> ("/_get chats 2 pcc=on", chats, [("#team", "3"), ("@Ask SimpleX Team", ""), ("*", "")])
bob `hasContactProfiles` ["robert", "alice", "cath", "Ask SimpleX Team"]
cath @@@ [("#team", "3"), ("@alice","received invitation to join group team as admin")]
cath `hasContactProfiles` ["cath", "alice", "robert"]
bob ##> "/user bob"
@@ -4220,7 +4220,7 @@ testShortLinkChangePreparedGroupUserDuplicate = testChat3 aliceProfile bobProfil
alice @@@ [("#team", "7"), ("@cath","sent invitation to join group team as admin")]
alice `hasContactProfiles` ["alice", "cath", "robert", "robert"]
bob `hasContactProfiles` ["robert", "robert", "robert", "alice", "alice", "cath", "cath", "Ask SimpleX Team", "SimpleX Status"]
bob `hasContactProfiles` ["robert", "robert", "robert", "alice", "alice", "cath", "cath", "Ask SimpleX Team"]
cath @@@ [("#team", "7"), ("@alice","received invitation to join group team as admin")]
cath `hasContactProfiles` ["cath", "alice", "robert", "robert"]
bob ##> "/user bob"