messaging: fix timestamps, UX, DM names, perf #56

Merged
zaelgohary merged 2 commits from development_fix_messaging_bugs into development 2026-04-19 09:35:12 +00:00
Member

Summary

Fourteen bug + perf fixes in the messaging archipelago, each tracked by its own issue.
lhumina_code/hero_os#53

Bugs

# Title
#44 Chat list shows Jan 1970 timestamps (secs vs ms conversion)
#45 Sent message only appears after reopening the chat
#46 NewChat "+" doesn't add participants; prop sync subscribes unnecessarily
#47 New messages don't auto-scroll into view
#48 Switching chats flashes old data + rapid switch can clobber the view
#49 Unread badge never clears (mark_as_read is never called)
#50 Chat list preview goes stale after sending
#51 Empty own_user_key makes every message render as "Me"
#54 DM name shows "DM with <public_key>" instead of the contact's name
#55 format_time / format_relative_time show misleading output for timestamp=0

Performance

# Title
#52 fetch_chats is sequential → parallelized with join_all
#53 fetch_messages fetched every message in the DB → switched to the new conversationservice.list_messages RPC

Key changes

  • New pure helper resolve_chat_display_name(raw_name, is_group, participant_keys, own_user_key, contacts) -> String — slices only, keeps the crate library-clean.
  • ChatPreviewData gains participant_keys: Vec<String> (carries through from Conversation so DM names can be resolved downstream).
  • Contacts now load on archipelago mount (was previously gated on Route::NewChat).
  • Race guard: every await in the chat-load spawn re-checks route.peek() before writing to active state.
  • Local state patching (unread badge, chat list preview) replaces full-list refetches after mark_as_read / send.

Test plan

  • cargo check -p hero_archipelagos_messaging against hero_osis development
  • End-to-end regression passes — see the companion test suite in hero_os
  • cargo clippy -p hero_archipelagos_messaging — no new warnings
  • rustfmt --edition 2021 --check on all six modified messaging files
  • In the deployed Hero OS: chat list shows real relative times (not Jan 1970)
  • Sending a message: bubble appears immediately and list preview updates
  • Opening a chat: badge clears, no stale-data flash on switch
  • Auto-scroll fires on every new message
  • DM chats display the contact's alias/name instead of the raw public key
## Summary Fourteen bug + perf fixes in the messaging archipelago, each tracked by its own issue. https://forge.ourworld.tf/lhumina_code/hero_os/issues/53 ### Bugs | # | Title | |---|---| | #44 | Chat list shows Jan 1970 timestamps (secs vs ms conversion) | | #45 | Sent message only appears after reopening the chat | | #46 | NewChat "+" doesn't add participants; prop sync subscribes unnecessarily | | #47 | New messages don't auto-scroll into view | | #48 | Switching chats flashes old data + rapid switch can clobber the view | | #49 | Unread badge never clears (`mark_as_read` is never called) | | #50 | Chat list preview goes stale after sending | | #51 | Empty `own_user_key` makes every message render as "Me" | | #54 | DM name shows `"DM with <public_key>"` instead of the contact's name | | #55 | `format_time` / `format_relative_time` show misleading output for `timestamp=0` | ### Performance | # | Title | |---|---| | #52 | `fetch_chats` is sequential → parallelized with `join_all` | | #53 | `fetch_messages` fetched every message in the DB → switched to the new `conversationservice.list_messages` RPC | ## Key changes - New pure helper `resolve_chat_display_name(raw_name, is_group, participant_keys, own_user_key, contacts) -> String` — slices only, keeps the crate library-clean. - `ChatPreviewData` gains `participant_keys: Vec<String>` (carries through from `Conversation` so DM names can be resolved downstream). - Contacts now load on archipelago mount (was previously gated on `Route::NewChat`). - Race guard: every `await` in the chat-load spawn re-checks `route.peek()` before writing to active state. - Local state patching (unread badge, chat list preview) replaces full-list refetches after `mark_as_read` / `send`. ## Test plan - [x] `cargo check -p hero_archipelagos_messaging` against hero_osis `development` - [x] End-to-end regression passes — see the companion test suite in hero_os - [ ] `cargo clippy -p hero_archipelagos_messaging` — no new warnings - [ ] `rustfmt --edition 2021 --check` on all six modified messaging files - [ ] In the deployed Hero OS: chat list shows real relative times (not Jan 1970) - [ ] Sending a message: bubble appears immediately and list preview updates - [ ] Opening a chat: badge clears, no stale-data flash on switch - [ ] Auto-scroll fires on every new message - [ ] DM chats display the contact's alias/name instead of the raw public key
messaging: fix timestamps, optimistic send, auto-scroll, DM names, and perf
Some checks failed
Build and Test / build (pull_request) Failing after 12s
cdba2323a2
Bundles fourteen fixes in the messaging archipelago. Each is tracked by
a dedicated ticket so history stays granular.

Bugs
- Chat list shows Jan 1970: convert last_activity secs -> ms (#44)
- Sent message only visible after reopen: push returned msg into
  active_messages (#45) + guard against duplicate insert on retry/race
- NewChat '+' doesn't add participants: sync signal from prop every
  render with .peek() (no subscription) (#46)
- New messages don't auto-scroll into view: bridge prop length into a
  Signal so use_effect actually reacts, then scroll after double-rAF
  (#47)
- Chat switch flashes stale data + rapid switch can clobber the view:
  clear active state in handle_chat_click and check still_on_chat(&sid)
  after every .await (#48)
- Unread badge never clears: call mark_as_read after fetch; patch
  unread_count=0 locally instead of refetching the whole list (#49)
- Chat list preview stale after sending: patch last_message /
  last_message_time on the matching ChatPreviewData locally (#50)
- Empty own_user_key marks every message as 'Me': short-circuit is_own
  when the key is empty (#51)
- DM name shows 'DM with <public_key>': add participant_keys to
  ChatPreviewData, load contacts on mount, resolve the non-self
  participant's contact name in chat list + chat detail header (#54)
- format_time / format_relative_time mislead on timestamp=0: return ""
  early (#55)

Perf
- fetch_chats sequential: parallelize with futures::future::join_all
  (#52)
- fetch_messages N+1 across the whole DB: switch to the new
  conversationservice.list_messages(conversation_sid) RPC -- single
  server-side call replaces list + N gets (#53, requires the companion
  hero_osis PR)

Cleanup
- Pure helper resolve_chat_display_name(raw, is_group, keys, own_key,
  contacts) is slices-only, keeps the crate library-clean.
- Temporarily pins hero_osis_sdk to the matching feature branch
  (development_add_list_messages_and_timestamp_trigger); will be
  rolled back to development once the hero_osis PR lands.

Closes #44, #45, #46, #47, #48, #49, #50, #51, #52, #53, #54, #55
zaelgohary changed title from messaging: fix timestamps, optimistic send, auto-scroll, DM names, and perf to messaging: fix timestamps, UX, DM names, perf 2026-04-19 08:32:20 +00:00
cargo: restore hero_osis_sdk pin to development
Some checks failed
Build and Test / build (pull_request) Failing after 12s
ade7cdb787
hero_osis PR (list_messages + timestamp trigger) has landed on
development; drop the temporary feature-branch pin introduced while
the dependency was in flight.
zaelgohary merged commit ecda5eab17 into development 2026-04-19 09:35:12 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_archipelagos!56
No description provided.