Symptom

Kraken’s nightly architectural scan flagged NodeItem.kt and GraphScreen.kt for “unstructured coroutine launches”: pointerInput’s awaitPointerEventScope { while (true) { ... } } loop and GraphScreen’s polling launches were claimed to run outside any composable-scoped CoroutineScope (implying GlobalScope/manual CoroutineScope(Dispatchers.Default) usage), risking orphaned work that outlives screen dismissal. The lead also claimed rememberCoroutineScope() in NodeItem.kt was declared but never used.

Root cause

False positive. Both patterns are the standard, correct Compose idioms for their purpose:

Fix

No code change was needed. The existing coroutine usage in NodeItem.kt and GraphScreen.kt is already correctly lifecycle-scoped.

Prevention

If Kraken files a coroutine-structured-concurrency lead against a pointerInput { awaitPointerEventScope { while (true) { ... } } } block, check whether it’s a raw gesture-detection loop (the framework-recommended pattern) before treating the while (true) as an unbounded loop. Similarly, launch calls nested inside coroutineScope { } inside a suspend function called from LaunchedEffect are already structured — only flag launch/async that resolve to GlobalScope or a manually constructed CoroutineScope(...) not tied to composition.