fix(llc, persistence): truncated channels sinking to the bottom of a last_updated sort - #2892
Conversation
…last_updated sort Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## v9 #2892 +/- ##
=====================================
Coverage ? 67.32%
=====================================
Files ? 431
Lines ? 27401
Branches ? 0
=====================================
Hits ? 18448
Misses ? 8953
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Submit a pull request
Linear: FLU-689
Github Issue: #
CLA
Description of the pull request
Backport of #2880 to
v9(merge commit02ba6a239d8e0292729d9b6bd8e9d277e240fa57).last_updatedis not a wire field — every SDK derives it locally fromlast_message_atandcreated_at. Flutter derived it with a plain null-fallback:When a channel is truncated the server does not clear
last_message_at— it sets it to a value older thancreated_at. Since the getter only falls back onnull, it returned that stale date, so a truncated channel dropped to the bottom of a channel list sorted{ last_updated: -1 }— below channels that had never been used at all. The default channel list sort islast_updateddescending (StreamChannelListController, and thePredefinedFilterfallback), so this hits the default configuration onv9exactly as it did onmaster.Flutter was the only SDK without a guard here: Android's
Channel.lastUpdatedtakes the max of the two dates, and iOS'sChannelDTO.defaultSortingAthas an explicitdistantPastfallback naming the truncation case. This adopts Android'smax()semantics, which covers anylastMessageAt < createdAtrather than just a sentinel value.Changes
packages/stream_chat—ChannelModel.lastUpdatedAtnow returns the later of the two dates. This is the valueChannelState.getComparableField(ChannelSortKey.lastUpdated)returns, so it fixes both the in-memory controller sort and the persistence comparator sort in one place. No behaviour change whenlast_message_atis newer ornull.packages/stream_chat_persistence—ChannelDao.cidsranked channels withORDER BY last_message_at DESC LIMIT 250. That result feedsStreamChatClient.sync(), which requests events missed while offline, so a truncated channel was the first to fall out of the 250-channel cap and silently stopped receiving missed events (only reproducible with more than 250 cached channels). It now orders by aCASE WHENexpression mirroring the Dart getter.Worth noting for review: this is a selection cutoff, not a presentation order. The offline
queryChannelsread path (ChannelQueryDao.getChannels) has noORDER BY/LIMITand applies the caller'sSortOrdercomparator in Dart, so the sort passed toqueryChannelswas always respected.created_atis non-nullable in the Drift schema, so theCASE WHENalways resolves. No schema change and no migration.Port notes
Manual port rather than a clean cherry-pick, for two reasons — neither changes behaviour relative to
master:v9formats at the default 80 columns (masteruses 120), so the DAO helper and theif-caseguard wrap across more lines. Theif (x case final x? when ...)construct is idiomatic onv9(156 uses in the LLC) and valid on its^3.6.2SDK floor.^2.22.1—v9pins an older drift thanmaster's^2.33.0. Verified against drift 2.22.1 directly:CaseWhenExpression({required cases, orElse})andisBiggerThanhave identical signatures there, so the DAO change is safe atv9's declared floor, not just at the resolved version.CHANGELOG entries were added under a new
## Upcomingsection in both packages, sincev9's topmost section (## 9.27.0) is already released.Tests
ChannelModel.lastUpdatedAt— newerlastMessageAtwins,nullfalls back tocreatedAt, older (truncated) falls back tocreatedAtChannelSortKey.lastUpdatedviagetComparableField— this key previously had no coverage at allChannelDao.cidsordering — the existingcidstest now saves three channels and asserts one ordering. It discriminates the fix: the oldORDER BY last_message_at DESCyieldsactive, stale, truncated, the new expression yieldsactive, truncated, staleVerified on this branch:
melos run formatclean,dart analyze --fatal-infosclean on all touched files, fullstream_chatsuite passes (1307 tests, 2 skipped), fullstream_chat_persistencesuite passes (260 tests).Also ran as a negative control: with only the two
lib/changes reverted, the newlastUpdatedAttest and thecidstest both fail — confirming the ported tests are not passing vacuously.Screenshots / Videos
No UI changes.