fix(core): Order breadcrumbs by their own timestamp (JAVA-579) - #6097
Open
runningcode wants to merge 2 commits into
Open
fix(core): Order breadcrumbs by their own timestamp (JAVA-579)#6097runningcode wants to merge 2 commits into
runningcode wants to merge 2 commits into
Conversation
📲 Install BuildsAndroid
|
Breadcrumb.compareTo ordered purely by a System.nanoTime() reading taken in the constructor. A breadcrumb rebuilt from a serialized one — read back from disk, or handed over by a hybrid SDK — got that reading at parse time, so a breadcrumb recorded yesterday sorted as if it had just happened, and the merged order in CombinedScopeView became parse order. The clone constructor had the same problem: copying a breadcrumb moved it to the end of the order. Order by the recorded timestamp instead, and keep the creation tick only as the tie-breaker it was added for in #3355, since timestamps are millisecond-granular. A deserialized breadcrumb carries no tick, and a clone carries the original's, so neither jumps position. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
runningcode
force-pushed
the
no/java-579-c7-breadcrumb-ordering
branch
from
September 14, 2026 09:55
7f48517 to
95aa7c0
Compare
runningcode
marked this pull request as ready for review
September 14, 2026 09:59
runningcode
requested review from
0xadam-brown,
adinauer,
markushi and
romtsn
as code owners
September 14, 2026 09:59
adinauer
reviewed
Sep 14, 2026
adinauer
left a comment
Member
There was a problem hiding this comment.
We should always fill in creationTick as otherwise we risk a different bug.
| * SDK. It carries the timestamp it was serialized with and no creation tick. | ||
| */ | ||
| static @NotNull Breadcrumb deserialized(final @NotNull Date timestamp) { | ||
| return new Breadcrumb(timestamp, null); |
Member
There was a problem hiding this comment.
h I think we should fill in the creationTick here too. I'm worried about losing order on deserialization. The bug should still be fixed by preferring timestamp for the comparison and just using creationTick as tie breaker.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📜 Description
Breadcrumb.compareToordered breadcrumbs purely by aSystem.nanoTime()reading taken in the constructor. That reading is meaningful only for breadcrumbs created in the same process run, and two paths violate that:Breadcrumb.fromMapandBreadcrumb.Deserializerboth went through the publicBreadcrumb(Date)constructor, so a breadcrumb read back from disk or handed over by a hybrid SDK gets a fresh tick at parse time. A breadcrumb recorded yesterday sorted as if it had just happened, and the orderCombinedScopeViewmerges the three scopes into became parse order rather than recorded order.Scope's breadcrumb cloning moved every copied breadcrumb to the end of the order.This orders by the recorded
timestampinstead, keeping the creation tick as the tie-breaker it was added for in #3355. Timestamps are millisecond-granular, so breadcrumbs recorded within the same millisecond still resolve in the order they were actually recorded. A deserialized breadcrumb carries no tick (a tick from an earlier process run is a number from an unrelated origin, not a position in this run's order) and sorts purely by timestamp; a clone carries the original's tick and keeps its position.SentryClientalready re-sorts the final breadcrumb list by timestamp before sending, so this makes the scope-merge order agree with the order that actually ships — which matters for which breadcrumbs survive themaxBreadcrumbscap during the merge.💡 Motivation and Context
Audit finding §C7 from the clock-usage audit: a
System.nanoTime()value was driving an ordering decision across a process boundary, where it carries no meaning.💚 How did you test it?
Three unit tests in
BreadcrumbTest.📝 Checklist
sendDefaultPIIis enabled.Note for hybrid SDKs: breadcrumbs passed in via
Breadcrumb.fromMapnow sort by the timestamp they carry rather than by the moment they were handed over. That is the intended fix, but it does change the order hybrid breadcrumbs land in relative to native ones.🔮 Next steps