summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorpepper <3782201+rohvani@users.noreply.github.com>2026-09-01 16:13:34 -0400
committerpepper <3782201+rohvani@users.noreply.github.com>2026-09-01 16:13:34 -0400
commitcfbbdcb6e874d73ef9429293d3afff58e1d6c216 (patch)
treef9ea9e683dc3951a49a0773084d84ffa0dd9383e /indra
parent38635da94eb5e7f2356305ffd38567199e65528f (diff)
Restore canonical ChatService tail ordering
Apply the durable archive boundary before reconciling dated legacy overlaps so post-boundary messages stay in canonical service order and survive consumer caps. Name the offset-less SLT conversion at the seam and cover capped archive summaries and UTC-7/UTC-8 boundary cases. Validated with the RelWithDebInfo secondlife-bin build, the LLChatServiceHistoryCore suite (14 tests), the LLConversationLog suite (3 tests), and all 19 newview CTest targets.
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/llchatservicehistory.cpp19
-rw-r--r--indra/newview/llchatservicehistorycore.cpp5
-rw-r--r--indra/newview/llchatservicehistorycore.h4
-rw-r--r--indra/newview/tests/llchatservicehistorycore_test.cpp21
4 files changed, 37 insertions, 12 deletions
diff --git a/indra/newview/llchatservicehistory.cpp b/indra/newview/llchatservicehistory.cpp
index b140259de1..b73937b546 100644
--- a/indra/newview/llchatservicehistory.cpp
+++ b/indra/newview/llchatservicehistory.cpp
@@ -2848,9 +2848,8 @@ LLChatServiceHistory::HistoryResult readStitched(
std::vector<std::pair<F64, LLSD>> dated;
std::list<LLSD> undated;
- // Exact canonical overlaps keep their legacy position. For unmatched rows, the
- // durable archive's oldest key controls the seam; retain undated rows and dated
- // rows whose earliest possible SLT interpretation predates that boundary.
+ // Admit only the legacy prefix that may predate the durable service boundary.
+ // Offset-less SLT timestamps use their earliest UTC interpretation (UTC-7).
for (const LLSD& message : legacy)
{
F64 wall = 0.0;
@@ -2858,14 +2857,13 @@ LLChatServiceHistory::HistoryResult readStitched(
{
undated.push_back(message);
}
- else
+ else if (!archive.has_oldest || legacyWallMayPrecedeService(wall, service_epoch))
{
LLSD stitched = message;
stitched[LEGACY_WALL_TIME] = wall;
- // Replace an exact legacy occurrence in place with its canonical row.
- // This keeps local ordering around same-minute system messages while
- // consuming only one occurrence from each source.
+ // Reconcile exact overlaps only inside the admitted legacy prefix,
+ // consuming one occurrence from each source.
size_t match = service.size();
for (const F64 offset : { 7.0 * 3600.0, 8.0 * 3600.0 })
{
@@ -2889,11 +2887,7 @@ LLChatServiceHistory::HistoryResult readStitched(
stitched = serviceMessage(service[match]);
service_placed[match] = true;
}
- if (match != service.size() || !archive.has_oldest ||
- wall + 7.0 * 3600.0 < service_epoch)
- {
- dated.emplace_back(wall, stitched);
- }
+ dated.emplace_back(wall, stitched);
}
}
std::stable_sort(dated.begin(), dated.end(),
@@ -2921,6 +2915,7 @@ LLChatServiceHistory::HistoryResult readStitched(
}
}
+ // Apply the consumer limit to the complete seam order, retaining the service tail.
while (limit && result.messages.size() > limit)
{
result.messages.pop_front();
diff --git a/indra/newview/llchatservicehistorycore.cpp b/indra/newview/llchatservicehistorycore.cpp
index 3478bb2f11..06fdd8ecf6 100644
--- a/indra/newview/llchatservicehistorycore.cpp
+++ b/indra/newview/llchatservicehistorycore.cpp
@@ -297,6 +297,11 @@ bool sameDirectSenderName(const std::string& left, const std::string& right)
return !left_resident.empty() && left_resident == right_resident;
}
+bool legacyWallMayPrecedeService(F64 wall_epoch, F64 service_epoch)
+{
+ return wall_epoch + 7.0 * 3600.0 < service_epoch;
+}
+
bool parseCreatedAt(const std::string& text, std::string& normalized)
{
// Validate the complete wire shape before LLDate performs calendar conversion.
diff --git a/indra/newview/llchatservicehistorycore.h b/indra/newview/llchatservicehistorycore.h
index 86c6b0131e..9b4254eca6 100644
--- a/indra/newview/llchatservicehistorycore.h
+++ b/indra/newview/llchatservicehistorycore.h
@@ -110,6 +110,10 @@ namespace LLChatServiceHistoryCore
bool parseCreatedAt(const std::string& text, std::string& normalized);
bool sameDirectSenderName(const std::string& left, const std::string& right);
+ // Legacy SLT wall times carry no UTC offset; UTC-7 is their earliest possible
+ // interpretation at the durable service boundary.
+ bool legacyWallMayPrecedeService(F64 wall_epoch, F64 service_epoch);
+
// Both wire validators are all-or-nothing and clear their output before parsing.
bool validateConversationList(const LLSD& value, const LLUUID& agent_id,
std::vector<ListEntry>& entries);
diff --git a/indra/newview/tests/llchatservicehistorycore_test.cpp b/indra/newview/tests/llchatservicehistorycore_test.cpp
index e5f542d3f7..52bc16edba 100644
--- a/indra/newview/tests/llchatservicehistorycore_test.cpp
+++ b/indra/newview/tests/llchatservicehistorycore_test.cpp
@@ -233,9 +233,12 @@ template<> template<> void object_t::test<9>()
{
NamedTempFile file("chatservice", validArchive());
ArchiveScan scan;
+ TimeUuidKey oldest;
+ parseTimeUuid(FIRST, oldest);
ensure("valid archive", scanArchive(file.getPath().string(), AGENT, RESIDENT, 0, 1, scan));
ensure_equals("two summarized", scan.row_count, U32(2));
+ ensure("display cap preserves durable oldest", scan.oldest == oldest);
ensure_equals("newest display cap", scan.display_rows.size(), size_t(1));
ensure_equals("newest retained", scan.display_rows.front().msg_id, std::string(SECOND));
}
@@ -288,4 +291,22 @@ template<> template<> void object_t::test<13>()
ensure("different residents stay distinct",
!sameDirectSenderName("bridie.linden", "beanie.tester"));
}
+
+template<> template<> void object_t::test<14>()
+{
+ const F64 wall = 1000.0;
+ const F64 daylight_utc = wall + 7.0 * 3600.0;
+
+ // The earlier UTC-7 interpretation controls conservative seam admission.
+ ensure("possible pre-boundary row retained",
+ legacyWallMayPrecedeService(wall, daylight_utc + 1.0));
+ ensure("row at boundary excluded",
+ !legacyWallMayPrecedeService(wall, daylight_utc));
+ ensure("post-boundary row excluded",
+ !legacyWallMayPrecedeService(wall, daylight_utc - 1.0));
+
+ // A boundary between the UTC-7 and UTC-8 interpretations remains ambiguous.
+ ensure("ambiguous DST row retained",
+ legacyWallMayPrecedeService(wall, daylight_utc + 30.0 * 60.0));
+}
}