Core
Events and failure detection
The typed event stream every sink receives, and how release-health reaches a crash-loop verdict without a crash SDK.
Every sink receives the same typed ReleaseHealthEvents. Each event carries a sessionId and a
timestamp; the table below lists what else it means and when it fires.
The event stream
| Event | Fired when |
|---|---|
session_start | Every launch, with update id, native version, build number, platform, and cohort |
update_downloaded | The adapter reports a new update ready to apply |
update_apply_success | A probation update was marked healthy |
update_apply_failed | Probation failed (crash loop or timeout chain), with a reason |
crash | A fatal JS error was caught in this session |
healthy | markHealthy() was accepted, with time-to-healthy |
rollback_recommended | An update was judged failed, with reason crash-loop or apply-failed |
rollback_executed | autoRollback ran the adapter's rollback(), with a success flag |
These events are what a sink consumes. The HTTP sink posts them as JSON; the Sentry sink turns them into tags and breadcrumbs.
How failure detection works
Crash detection needs no crash SDK. The native module (a TurboModule in Swift/Objective-C and Kotlin, persisting to UserDefaults and SharedPreferences) records a clean-exit flag on graceful background or terminate. A launch that follows neither is treated as an abnormal exit. Fatal JS errors are additionally caught in-session through the global error handler.
The engine counts consecutive failed probation launches and judges at launch start, so the
crash-loop verdict lands even when the crash itself killed the process before anything could be
sent. Dev reloads never count (__DEV__ short-circuits probation), and an intentional
reloadAsync-style apply mid-probation restarts the probation timer instead of counting as a
failure, provided you called notifyReload()
first.
What the heuristic is, honestly
This detects "the app did not exit cleanly", not "the app crashed at this stack trace". It correlates; it does not symbolicate. Force-quits, OS memory kills, and device reboots read as abnormal exits too, and during probation one such exit counts against the update like a crash.
Pair it with a crash reporter for ground truth. The Sentry sink exists exactly for that: it tags every Sentry issue with the update id and health status so the two systems tell one story. Read Limitations before you rely on the verdict.