Skip to content

fix(core): Order breadcrumbs by their own timestamp (JAVA-579) - #6097

Draft
runningcode wants to merge 2 commits into
mainfrom
no/java-579-c7-breadcrumb-ordering
Draft

fix(core): Order breadcrumbs by their own timestamp (JAVA-579)#6097
runningcode wants to merge 2 commits into
mainfrom
no/java-579-c7-breadcrumb-ordering

Conversation

@runningcode

Copy link
Copy Markdown
Contributor

📜 Description

Breadcrumb.compareTo ordered breadcrumbs purely by a System.nanoTime() reading taken in the constructor. That reading is meaningful only for breadcrumbs created in the same process run, and two paths violate that:

  • Deserialized breadcrumbs. Breadcrumb.fromMap and Breadcrumb.Deserializer both went through the public Breadcrumb(Date) constructor, so a breadcrumb read back from disk — or handed over by a hybrid SDK — got a fresh tick at parse time. A breadcrumb recorded yesterday sorted as if it had just happened, and the order CombinedScopeView merges the three scopes into became parse order rather than recorded order.
  • Clones. The copy constructor also took a fresh tick, so Scope's breadcrumb cloning moved every copied breadcrumb to the end of the order.

This orders by the recorded timestamp instead, 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.

SentryClient already 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 the maxBreadcrumbs cap 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: breadcrumbs sharing a timestamp keep their recorded order, a deserialized breadcrumb is ordered by its own timestamp rather than by parse time, and a clone keeps its position. The existing CombinedScopeViewTest merge-order test still passes unchanged.

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec.

Note for hybrid SDKs: breadcrumbs passed in via Breadcrumb.fromMap now 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

The other §C4–C7 items are separate PRs. §C4 (TimeSpan back-projection) changes serialized app-start timestamps and is gated behind the v9 work.

🤖 Generated with Claude Code

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>
@linear-code

linear-code Bot commented Sep 11, 2026

Copy link
Copy Markdown

JAVA-579

@sentry

sentry Bot commented Sep 11, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.56.0 (1) release

⚙️ sentry-android Build Distribution Settings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant