The rare CI hang is a lock-order deadlock in Compose Multiplatform 1.8.2,
shown by the thread dump of run 40299943329:
- the test thread renders the scene and holds the FlushCoroutineDispatcher
runLock while LazyListState.scrollToItem measures and wants the
SnapshotStateObserver's observedScopeMapsLock;
- the AWT event thread sends the global snapshot notifications and holds
observedScopeMapsLock in drainChanges while a re-read derived state wakes
the scene's snapshotFlow collector, whose dispatch wants runLock.
The application renders on the event thread, where both monitors are simply
re-entered. The tests now do the same: onEventThread builds, renders and
closes each scene there and rethrows what the block throws.
Claude-Session: https://claude.ai/code/session_01FJBfPYm6rCH4zD6T7bcC7Y
The rare CI hang in SelectedStationMessageUiVisualRenderingTest blocks on a
monitor in SnapshotStateObserver.observeReads (line 643 is the monitorenter
of observedScopeMapsLock in Compose 1.8.2). The timed-out thread's stack
shows where it waits but not which thread holds the lock. With the thread
dump enabled, JUnit prints every thread to the test's standard output, which
ends up in the XML report of the test-results artifact.
Claude-Session: https://claude.ai/code/session_01FJBfPYm6rCH4zD6T7bcC7Y