Symptom

Nightly architectural bug hunt flagged a severity:high lead asserting that ClientNodeManager and ServerNodeManager use incompatible concurrency primitives (Mutex+StateFlow vs. ThreadLocal+direct DB writes) and lack a shared protocol for “CREATED → READY” node lifecycle transitions, risking divergent state during concurrent requests.

Root cause

The hypothesis was a false positive. Three specific claims were made; all were incorrect:

  1. “CREATED → READY” transitionNodeState contains no READY value. The local model hallucinated a state machine that does not exist in the codebase.

  2. ThreadLocal is “fragile across dispatcher hops”PropagationContextElement correctly implements ThreadContextElement<PropagationContext?>, the KotlinX-coroutines mechanism designed specifically to propagate thread-local values across coroutine dispatchers. updateThreadContext / restoreThreadContext install and restore the value on the worker thread for the full duration of a coroutine, including after any suspension. The scanned code at ServerNodeManager.kt:72-92 is the correct and idiomatic implementation.

  3. Architectural mismatchClientNodeManager (in-memory StateFlows for Compose UI) and ServerNodeManager (H2 database + SharedFlow for SSE) are intentionally different because they serve different roles. The client receives updates from the server via SSE/REST; they are not competing concurrent writers to shared state. The difference between the two managers is the design, not a gap.

Fix

No production code change. Added PropagationContextPropagationTest in server/src/jvmTest/ to explicitly prove:

Prevention